Skip to content

Commit

Permalink
test: cleanup text-field unit tests covered by mixins tests (#8715)
Browse files Browse the repository at this point in the history
  • Loading branch information
web-padawan authored Feb 21, 2025
1 parent f67d18c commit 560ad43
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 190 deletions.
4 changes: 4 additions & 0 deletions packages/field-base/test/clear-button-mixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ const runTests = (defineHelper, baseMixin) => {
expect(event.defaultPrevented).to.be.true;
});

it('should set clearButtonVisible to false by default', () => {
expect(element.clearButtonVisible).to.be.false;
});

it('should reflect clearButtonVisible property to attribute', async () => {
element.clearButtonVisible = true;
await nextUpdate(element);
Expand Down
12 changes: 11 additions & 1 deletion packages/field-base/test/input-control-mixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,12 +298,22 @@ const runTests = (defineHelper, baseMixin) => {
input = element.querySelector('[slot=input]');
});

it('should select the input content when autoselect is set', () => {
it('should set autoselect to false by default', () => {
expect(element.autoselect).to.be.false;
});

it('should select the input content on focus when autoselect is true', () => {
const spy = sinon.spy(input, 'select');
element.autoselect = true;
input.focus();
expect(spy.calledOnce).to.be.true;
});

it('should not select the input content on focus when autoselect is false', () => {
const spy = sinon.spy(input, 'select');
input.focus();
expect(spy).to.be.not.called;
});
});

describe('allowed char pattern', () => {
Expand Down
13 changes: 13 additions & 0 deletions packages/field-base/test/input-mixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ const runTests = (defineHelper, baseMixin) => {
expect(element.hasAttribute('has-value')).to.be.true;
});

// User could accidentally set a 0 or false value
it('should set has-value attribute when the value is a number', async () => {
element.value = 0;
await nextUpdate(element);
expect(element.hasAttribute('has-value')).to.be.true;
});

it('should set has-value attribute when the value is a boolean', async () => {
element.value = false;
await nextUpdate(element);
expect(element.hasAttribute('has-value')).to.be.true;
});

it('should remove has-value attribute when value is removed', async () => {
element.value = 'foo';
await nextUpdate(element);
Expand Down
207 changes: 18 additions & 189 deletions packages/text-field/test/text-field.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { expect } from '@vaadin/chai-plugins';
import { aTimeout, fire, fixtureSync, nextRender, nextUpdate } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import { fixtureSync, nextRender, nextUpdate } from '@vaadin/testing-helpers';
import '../src/vaadin-text-field.js';

describe('text-field', () => {
Expand All @@ -13,138 +12,37 @@ describe('text-field', () => {
});

describe('properties', () => {
describe('native', () => {
async function assertAttrCanBeSet(prop, value) {
textField[prop] = value;
describe('delegation', () => {
it('should delegate pattern property to the input', async () => {
textField.pattern = '[A-Z]+';
await nextUpdate(textField);

const attrValue = input.getAttribute(prop);

if (value === true) {
expect(attrValue).not.to.be.null;
} else if (value === false) {
expect(attrValue).to.be.null;
} else if (value) {
expect(attrValue).to.be.equal(String(value));
}
}

['pattern', 'placeholder', 'value', 'title'].forEach((prop) => {
it(`should set string property ${prop}`, async () => {
textField[prop] = 'foo';
await nextUpdate(textField);
expect(input[prop]).to.be.equal('foo');
});
});

['disabled'].forEach((prop) => {
it(`should set boolean property ${prop}`, async () => {
textField[prop] = true;
await nextUpdate(textField);
expect(input[prop]).to.be.true;

textField[prop] = false;
await nextUpdate(textField);
expect(input[prop]).to.be.false;
});
});

['maxlength', 'minlength'].forEach((prop) => {
it(`should set numeric attribute ${prop}`, async () => {
await assertAttrCanBeSet(prop, 2);
});
});

['autocomplete'].forEach((prop) => {
it(`should set boolean attribute ${prop}`, async () => {
await assertAttrCanBeSet(prop, 'on');
});
});

['autocapitalize'].forEach((prop) => {
it(`should set boolean attribute ${prop}`, async () => {
await assertAttrCanBeSet(prop, 'none');
});
});

['autocomplete', 'autocorrect', 'readonly', 'required'].forEach((prop) => {
it(`should set boolean attribute ${prop}`, async () => {
await assertAttrCanBeSet(prop, true);
await assertAttrCanBeSet(prop, false);
});
});
});

describe('clear button', () => {
it('should set clearButtonVisible to false by default', () => {
expect(textField.clearButtonVisible).to.be.false;
});

it('should clear the value when clear button is clicked', async () => {
textField.clearButtonVisible = true;
textField.value = 'Foo';
await nextUpdate(textField);
textField.$.clearButton.click();
expect(textField.value).not.to.be.ok;
});

it('should clear the native input value when clear button is clicked', async () => {
textField.clearButtonVisible = true;
textField.value = 'Foo';
await nextUpdate(textField);
textField.$.clearButton.click();
expect(input.value).to.equal('');
expect(input.pattern).to.be.equal('[A-Z]+');
});

it('should dispatch input event when clear button is clicked', async () => {
const inputSpy = sinon.spy();
textField.addEventListener('input', inputSpy);

textField.clearButtonVisible = true;
textField.value = 'Foo';
it('should delegate minlength property to the input', async () => {
textField.minlength = 2;
await nextUpdate(textField);

textField.$.clearButton.click();
expect(inputSpy.calledOnce).to.be.true;
expect(input.getAttribute('minlength')).to.be.equal('2');
});

it('should dispatch change event when clear button is clicked', async () => {
const changeSpy = sinon.spy();
textField.addEventListener('change', changeSpy);

textField.clearButtonVisible = true;
textField.value = 'Foo';
it('should delegate maxlength property to the input', async () => {
textField.maxlength = 2;
await nextUpdate(textField);

textField.$.clearButton.click();
expect(changeSpy.calledOnce).to.be.true;
});

it('should prevent default on clear button click', () => {
const event = new Event('click', { cancelable: true });
textField.$.clearButton.dispatchEvent(event);
expect(event.defaultPrevented).to.be.true;
expect(input.getAttribute('maxlength')).to.be.equal('2');
});
});

describe('binding', () => {
it('default value should be empty string', () => {
expect(textField.value).to.be.equal('');
describe('internal', () => {
it('should store reference to the clear button element', () => {
expect(textField.clearElement).to.equal(textField.$.clearButton);
});

it('setting input value updates value', () => {
input.value = 'foo';
fire(input, 'input');
expect(textField.value).to.be.equal('foo');
it('should set ariaTarget property to the input element', () => {
expect(textField.ariaTarget).to.equal(textField.inputElement);
});

it('setting value to undefined should clear the native input value', async () => {
textField.value = 'foo';
await nextUpdate(textField);

textField.value = undefined;
await nextUpdate(textField);
expect(input.value).to.equal('');
it('should set focusElement property to the input element', () => {
expect(textField.focusElement).to.equal(textField.inputElement);
});
});

Expand All @@ -159,74 +57,5 @@ describe('text-field', () => {
expect(textField.hasAttribute('focused')).to.be.true;
});
});

describe('autoselect', () => {
it('default value of autoselect should be false', () => {
expect(textField.autoselect).to.be.false;
});

it('should not select content on focus when autoselect is false', async () => {
textField.value = '123';
input.dispatchEvent(new CustomEvent('focus', { bubbles: false }));
await aTimeout(1);
expect(input.selectionEnd - input.selectionStart).to.equal(0);
});

it('should select content on focus when autoselect is true', async () => {
textField.value = '123';
textField.autoselect = true;
await nextUpdate(textField);
input.dispatchEvent(new CustomEvent('focus', { bubbles: false }));
await aTimeout(1);
expect(input.selectionEnd - input.selectionStart).to.equal(3);
});
});
});

describe('has-value attribute', () => {
it('should toggle the attribute on value change', async () => {
textField.value = 'foo';
await nextUpdate(textField);
expect(textField.hasAttribute('has-value')).to.be.true;

textField.value = undefined;
await nextUpdate(textField);
expect(textField.hasAttribute('has-value')).to.be.false;
});

it('should not add the attribute when the value is an empty string', async () => {
textField.value = '';
await nextUpdate(textField);
expect(textField.hasAttribute('has-value')).to.be.false;
});

// User could accidentally set a 0 or false value
it('should add the attribute when the value is a number', async () => {
textField.value = 0;
await nextUpdate(textField);
expect(textField.hasAttribute('has-value')).to.be.true;
});

it('should add the attribute when the value is a boolean', async () => {
textField.value = false;
await nextUpdate(textField);
expect(textField.hasAttribute('has-value')).to.be.true;
});
});

describe(`methods`, () => {
it('should clear the value when clear() is called', async () => {
textField.value = 'Foo';
await nextUpdate(textField);
textField.clear();
expect(textField.value).not.to.be.ok;
});

it('should clear the value of native input when clear() is called', async () => {
textField.value = 'Foo';
await nextUpdate(textField);
textField.clear();
expect(input.value).to.equal('');
});
});
});
24 changes: 24 additions & 0 deletions packages/text-field/test/typings/text-field.types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
import '../../vaadin-text-field.js';
import type { DelegateFocusMixinClass } from '@vaadin/a11y-base/src/delegate-focus-mixin.js';
import type { DisabledMixinClass } from '@vaadin/a11y-base/src/disabled-mixin.js';
import type { FocusMixinClass } from '@vaadin/a11y-base/src/focus-mixin.js';
import type { KeyboardMixinClass } from '@vaadin/a11y-base/src/keyboard-mixin.js';
import type { ControllerMixinClass } from '@vaadin/component-base/src/controller-mixin.js';
import type { DelegateStateMixinClass } from '@vaadin/component-base/src/delegate-state-mixin.js';
import type { ElementMixinClass } from '@vaadin/component-base/src/element-mixin.js';
import type { SlotStylesMixinClass } from '@vaadin/component-base/src/slot-styles-mixin.js';
import type { ClearButtonMixinClass } from '@vaadin/field-base/src/clear-button-mixin.js';
import type { FieldMixinClass } from '@vaadin/field-base/src/field-mixin.js';
import type { InputConstraintsMixinClass } from '@vaadin/field-base/src/input-constraints-mixin.js';
import type { InputControlMixinClass } from '@vaadin/field-base/src/input-control-mixin.js';
import type { InputFieldMixinClass } from '@vaadin/field-base/src/input-field-mixin.js';
import type { InputMixinClass } from '@vaadin/field-base/src/input-mixin.js';
import type { LabelMixinClass } from '@vaadin/field-base/src/label-mixin.js';
import type { PatternMixinClass } from '@vaadin/field-base/src/pattern-mixin.js';
import type { ValidateMixinClass } from '@vaadin/field-base/src/validate-mixin.js';
import type { ThemableMixinClass } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
import type {
TextField,
Expand All @@ -20,9 +32,21 @@ const field = document.createElement('vaadin-text-field');
// Mixins
assertType<ClearButtonMixinClass>(field);
assertType<ControllerMixinClass>(field);
assertType<DelegateFocusMixinClass>(field);
assertType<DelegateStateMixinClass>(field);
assertType<DisabledMixinClass>(field);
assertType<ElementMixinClass>(field);
assertType<FieldMixinClass>(field);
assertType<FocusMixinClass>(field);
assertType<InputConstraintsMixinClass>(field);
assertType<InputControlMixinClass>(field);
assertType<InputFieldMixinClass>(field);
assertType<InputMixinClass>(field);
assertType<KeyboardMixinClass>(field);
assertType<LabelMixinClass>(field);
assertType<PatternMixinClass>(field);
assertType<SlotStylesMixinClass>(field);
assertType<ValidateMixinClass>(field);
assertType<ThemableMixinClass>(field);

// Events
Expand Down

0 comments on commit 560ad43

Please sign in to comment.