From 5c992bf34765fcbe43ba9088b49eb78029863f27 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Sat, 25 Jun 2022 23:09:15 +0300 Subject: [PATCH 1/4] test: extract validation tests --- .../number-field/test/number-field.test.js | 254 ---------------- packages/number-field/test/validation.test.js | 273 ++++++++++++++++++ 2 files changed, 273 insertions(+), 254 deletions(-) create mode 100644 packages/number-field/test/validation.test.js diff --git a/packages/number-field/test/number-field.test.js b/packages/number-field/test/number-field.test.js index ac50855055..84a0057671 100644 --- a/packages/number-field/test/number-field.test.js +++ b/packages/number-field/test/number-field.test.js @@ -655,260 +655,6 @@ describe('number-field', () => { }); }); }); - - describe('input validation', () => { - it('should be valid with numeric values', () => { - expect(numberField.validate()).to.be.true; - - numberField.value = '1'; - expect(input.value).to.be.equal('1'); - expect(numberField.validate()).to.be.true; - }); - - it('should prevent setting non-numeric values', () => { - numberField.value = 'foo'; - expect(numberField.value).to.be.empty; - expect(numberField.validate()).to.be.true; - }); - - it('should align checkValidity with the native input element', () => { - numberField.value = -1; - numberField.min = 0; - - expect(numberField.checkValidity()).to.equal(input.checkValidity()); - }); - - it('should not validate when explicitly set to invalid', () => { - numberField.invalid = true; - - expect(numberField.value).to.be.empty; - expect(numberField.validate()).to.be.false; - - expect(numberField.invalid).to.be.true; - }); - - it('should allow setting decimals', () => { - numberField.value = 7.6; - expect(numberField.value).to.be.equal('7.6'); - }); - - it('should not prevent invalid values applied programmatically (step)', () => { - numberField.step = 0.1; - numberField.value = 7.686; - expect(numberField.value).to.be.equal('7.686'); - }); - - it('should not prevent invalid values applied programmatically (min)', () => { - numberField.min = 2; - numberField.value = 1; - expect(numberField.value).to.be.equal('1'); - }); - - it('should not prevent invalid values applied programmatically (max)', () => { - numberField.max = 2; - numberField.value = 3; - expect(numberField.value).to.be.equal('3'); - }); - - it('should validate when setting limits', () => { - numberField.min = 2; - numberField.max = 4; - - numberField.value = ''; - expect(numberField.validate(), 'empty value is allowed because not required').to.be.true; - - numberField.value = '3'; - expect(numberField.validate(), 'valid value should be in the range').to.be.true; - - numberField.value = '1'; - expect(numberField.validate(), 'value should not be below min').to.be.false; - - numberField.value = '3'; - expect(numberField.validate(), 'invalid status should be reset when setting valid value').to.be.true; - - numberField.value = '5'; - expect(numberField.validate(), 'value should not be greater than max').to.be.false; - }); - - it('should dispatch change event after validation', () => { - const validateSpy = sinon.spy(numberField, 'validate'); - const changeSpy = sinon.spy(); - numberField.required = true; - numberField.addEventListener('change', changeSpy); - numberField.value = '123'; - input.dispatchEvent(new CustomEvent('change')); - expect(validateSpy.calledOnce).to.be.true; - expect(changeSpy.calledAfter(validateSpy)).to.be.true; - }); - - describe('step values', () => { - beforeEach(() => { - numberField.step = 1.5; - }); - - [-6, -1.5, 0, 1.5, 4.5].forEach((validValue) => { - it(`should validate valid value "${validValue}" by step when defined by user`, () => { - numberField.value = validValue; - expect(numberField.validate()).to.be.true; - }); - }); - - [-3.5, -1, 2, 2.5].forEach((invalidValue) => { - it(`should validate invalid value "${invalidValue}" by step when defined by user`, () => { - numberField.value = invalidValue; - expect(numberField.validate()).to.be.false; - }); - }); - }); - - describe('step basis', () => { - beforeEach(() => { - numberField.min = 1; - numberField.step = 1.5; - }); - - [1, 2.5, 4, 5.5].forEach((validValue) => { - it(`should validate valid value "${validValue}" using min as basis`, () => { - numberField.value = validValue; - expect(numberField.validate()).to.be.true; - }); - }); - - [1.5, 3, 5].forEach((invalidValue) => { - it(`should validate invalid value "${invalidValue}" using min as basis`, () => { - numberField.value = invalidValue; - expect(numberField.validate()).to.be.false; - }); - }); - }); - - it('should not validate by step when only min and max are set', () => { - numberField.min = 1; - numberField.max = 5; - numberField.value = 1.5; // Would be invalid by default step=1 - expect(numberField.validate()).to.be.true; - }); - - describe('removing validation constraints', () => { - it('should update "invalid" state when "min" is removed', () => { - numberField.value = '42'; - numberField.min = 50; - numberField.validate(); - expect(numberField.invalid).to.be.true; - - numberField.min = ''; - expect(numberField.invalid).to.be.false; - }); - - it('should update "invalid" state when "max" is removed', () => { - numberField.value = '42'; - numberField.max = 20; - numberField.validate(); - expect(numberField.invalid).to.be.true; - - numberField.max = ''; - expect(numberField.invalid).to.be.false; - }); - - it('should update "invalid" state when "step" is removed', () => { - numberField.value = '3'; - numberField.min = 0; - numberField.step = 2; - numberField.validate(); - expect(numberField.invalid).to.be.true; - - numberField.step = ''; - expect(numberField.invalid).to.be.false; - }); - - it('should not set "invalid" to false when "min" is set to 0', () => { - numberField.value = '-5'; - numberField.min = -1; - numberField.validate(); - expect(numberField.invalid).to.be.true; - - numberField.min = 0; - expect(numberField.invalid).to.be.true; - }); - - it('should not set "invalid" to false when "max" is set to 0', () => { - numberField.value = '5'; - numberField.max = 1; - numberField.validate(); - expect(numberField.invalid).to.be.true; - - numberField.max = 0; - expect(numberField.invalid).to.be.true; - }); - }); - }); -}); - -describe('step attribute', () => { - let numberField; - - beforeEach(() => { - numberField = fixtureSync(''); - }); - - it('should validate by step when defined as attribute', () => { - numberField.value = 1; - expect(numberField.validate()).to.be.false; - numberField.value = 1.5; - expect(numberField.validate()).to.be.true; - }); -}); - -describe('default step attribute', () => { - let numberField; - - beforeEach(() => { - numberField = fixtureSync(''); - }); - - it('should validate by step when default value defined as attribute', () => { - numberField.value = 1.5; - expect(numberField.validate()).to.be.false; - numberField.value = 1; - expect(numberField.validate()).to.be.true; - }); -}); - -describe('checkValidity', () => { - it('should return true when called before connected to the DOM', () => { - const numberField = document.createElement('vaadin-number-field'); - expect(numberField.checkValidity()).to.be.true; - }); - - it('should return false when called before connected to the DOM and invalid', () => { - const numberField = document.createElement('vaadin-number-field'); - numberField.invalid = true; - expect(numberField.checkValidity()).to.be.false; - }); -}); - -describe('invalid', () => { - let numberField; - - beforeEach(() => { - numberField = fixtureSync(''); - }); - - it('should not remove "invalid" state when ready', () => { - expect(numberField.invalid).to.be.true; - }); -}); - -describe('invalid with value', () => { - let numberField; - - beforeEach(() => { - numberField = fixtureSync(''); - }); - - it('should not remove "invalid" state when ready', () => { - expect(numberField.invalid).to.be.true; - }); }); describe('required', () => { diff --git a/packages/number-field/test/validation.test.js b/packages/number-field/test/validation.test.js new file mode 100644 index 0000000000..7e4f3292d7 --- /dev/null +++ b/packages/number-field/test/validation.test.js @@ -0,0 +1,273 @@ +import { expect } from '@esm-bundle/chai'; +import { fixtureSync } from '@vaadin/testing-helpers'; +import sinon from 'sinon'; +import '../src/vaadin-number-field.js'; + +describe('validation', () => { + let field, input; + + describe('basic', () => { + beforeEach(() => { + field = fixtureSync(''); + input = field.inputElement; + }); + + it('should be valid with numeric values', () => { + expect(field.validate()).to.be.true; + + field.value = '1'; + expect(input.value).to.be.equal('1'); + expect(field.validate()).to.be.true; + }); + + it('should prevent setting non-numeric values', () => { + field.value = 'foo'; + expect(field.value).to.be.empty; + expect(field.validate()).to.be.true; + }); + + it('should align checkValidity with the native input element', () => { + field.value = -1; + field.min = 0; + + expect(field.checkValidity()).to.equal(input.checkValidity()); + }); + + it('should not validate when explicitly set to invalid', () => { + field.invalid = true; + + expect(field.value).to.be.empty; + expect(field.validate()).to.be.false; + + expect(field.invalid).to.be.true; + }); + + it('should allow setting decimals', () => { + field.value = 7.6; + expect(field.value).to.be.equal('7.6'); + }); + + it('should not prevent invalid values applied programmatically (step)', () => { + field.step = 0.1; + field.value = 7.686; + expect(field.value).to.be.equal('7.686'); + }); + + it('should not prevent invalid values applied programmatically (min)', () => { + field.min = 2; + field.value = 1; + expect(field.value).to.be.equal('1'); + }); + + it('should not prevent invalid values applied programmatically (max)', () => { + field.max = 2; + field.value = 3; + expect(field.value).to.be.equal('3'); + }); + + it('should validate when setting limits', () => { + field.min = 2; + field.max = 4; + + field.value = ''; + expect(field.validate(), 'empty value is allowed because not required').to.be.true; + + field.value = '3'; + expect(field.validate(), 'valid value should be in the range').to.be.true; + + field.value = '1'; + expect(field.validate(), 'value should not be below min').to.be.false; + + field.value = '3'; + expect(field.validate(), 'invalid status should be reset when setting valid value').to.be.true; + + field.value = '5'; + expect(field.validate(), 'value should not be greater than max').to.be.false; + }); + + it('should dispatch change event after validation', () => { + const validateSpy = sinon.spy(field, 'validate'); + const changeSpy = sinon.spy(); + field.required = true; + field.addEventListener('change', changeSpy); + field.value = '123'; + input.dispatchEvent(new CustomEvent('change')); + expect(validateSpy.calledOnce).to.be.true; + expect(changeSpy.calledAfter(validateSpy)).to.be.true; + }); + }); + + describe('step', () => { + describe('default', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should not validate by step when only min and max are set', () => { + field.min = 1; + field.max = 5; + field.value = 1.5; // Would be invalid by default step=1 + expect(field.validate()).to.be.true; + }); + }); + + describe('values', () => { + beforeEach(() => { + field = fixtureSync(''); + field.step = 1.5; + }); + + [-6, -1.5, 0, 1.5, 4.5].forEach((validValue) => { + it(`should validate valid value "${validValue}" by step when defined by user`, () => { + field.value = validValue; + expect(field.validate()).to.be.true; + }); + }); + + [-3.5, -1, 2, 2.5].forEach((invalidValue) => { + it(`should validate invalid value "${invalidValue}" by step when defined by user`, () => { + field.value = invalidValue; + expect(field.validate()).to.be.false; + }); + }); + }); + + describe('basis', () => { + beforeEach(() => { + field = fixtureSync(''); + field.min = 1; + field.step = 1.5; + }); + + [1, 2.5, 4, 5.5].forEach((validValue) => { + it(`should validate valid value "${validValue}" using min as basis`, () => { + field.value = validValue; + expect(field.validate()).to.be.true; + }); + }); + + [1.5, 3, 5].forEach((invalidValue) => { + it(`should validate invalid value "${invalidValue}" using min as basis`, () => { + field.value = invalidValue; + expect(field.validate()).to.be.false; + }); + }); + }); + + describe('the default step is set initially', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should validate by step when default value defined as attribute', () => { + field.value = 1.5; + expect(field.validate()).to.be.false; + field.value = 1; + expect(field.validate()).to.be.true; + }); + }); + + describe('a custom step is set initially', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should validate by step when defined as attribute', () => { + field.value = 1; + expect(field.validate()).to.be.false; + field.value = 1.5; + expect(field.validate()).to.be.true; + }); + }); + }); + + describe('removing constraints', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should update "invalid" state when "min" is removed', () => { + field.value = '42'; + field.min = 50; + field.validate(); + expect(field.invalid).to.be.true; + + field.min = ''; + expect(field.invalid).to.be.false; + }); + + it('should update "invalid" state when "max" is removed', () => { + field.value = '42'; + field.max = 20; + field.validate(); + expect(field.invalid).to.be.true; + + field.max = ''; + expect(field.invalid).to.be.false; + }); + + it('should update "invalid" state when "step" is removed', () => { + field.value = '3'; + field.min = 0; + field.step = 2; + field.validate(); + expect(field.invalid).to.be.true; + + field.step = ''; + expect(field.invalid).to.be.false; + }); + + it('should not set "invalid" to false when "min" is set to 0', () => { + field.value = '-5'; + field.min = -1; + field.validate(); + expect(field.invalid).to.be.true; + + field.min = 0; + expect(field.invalid).to.be.true; + }); + + it('should not set "invalid" to false when "max" is set to 0', () => { + field.value = '5'; + field.max = 1; + field.validate(); + expect(field.invalid).to.be.true; + + field.max = 0; + expect(field.invalid).to.be.true; + }); + }); + + describe('invalid is set initially', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should not remove "invalid" state when ready', () => { + expect(field.invalid).to.be.true; + }); + }); + + describe('invalid and value are set initially', () => { + beforeEach(() => { + field = fixtureSync(''); + }); + + it('should not remove "invalid" state when ready', () => { + expect(field.invalid).to.be.true; + }); + }); + + describe('checkValidity', () => { + it('should return true when called before connected to the DOM', () => { + const field = document.createElement('vaadin-number-field'); + expect(field.checkValidity()).to.be.true; + }); + + it('should return false when called before connected to the DOM and invalid', () => { + const field = document.createElement('vaadin-number-field'); + field.invalid = true; + expect(field.checkValidity()).to.be.false; + }); + }); +}); From c95f0c6563169ce287bbe3ea2a0389652252d685 Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Sat, 25 Jun 2022 23:29:44 +0300 Subject: [PATCH 2/4] add more unit tests --- packages/number-field/test/validation.test.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/packages/number-field/test/validation.test.js b/packages/number-field/test/validation.test.js index 7e4f3292d7..17af9d83b3 100644 --- a/packages/number-field/test/validation.test.js +++ b/packages/number-field/test/validation.test.js @@ -12,6 +12,27 @@ describe('validation', () => { input = field.inputElement; }); + it('should pass validation when the field by default', () => { + expect(field.checkValidity()).to.be.true; + expect(field.validate()).to.be.true; + expect(field.invalid).to.be.false; + }); + + it('should not pass validation when the field is required and has no value', () => { + field.required = true; + expect(field.checkValidity()).to.be.false; + expect(field.validate()).to.be.false; + expect(field.invalid).to.be.true; + }); + + it('should pass validation when the field is required and has a valid value', () => { + field.required = true; + field.value = '1'; + expect(field.checkValidity()).to.be.true; + expect(field.validate()).to.be.true; + expect(field.invalid).to.be.false; + }); + it('should be valid with numeric values', () => { expect(field.validate()).to.be.true; @@ -186,6 +207,15 @@ describe('validation', () => { field = fixtureSync(''); }); + it('should update "invalid" state when "required" is removed', () => { + field.required = true; + field.validate(); + expect(field.invalid).to.be.true; + + field.required = false; + expect(field.invalid).to.be.false; + }); + it('should update "invalid" state when "min" is removed', () => { field.value = '42'; field.min = 50; @@ -217,6 +247,16 @@ describe('validation', () => { expect(field.invalid).to.be.false; }); + it('should not update "invalid" when "step" is removed but the field is still required', () => { + field.required = true; + field.step = 2; + field.validate(); + expect(field.invalid).to.be.true; + + field.step = ''; + expect(field.invalid).to.be.true; + }); + it('should not set "invalid" to false when "min" is set to 0', () => { field.value = '-5'; field.min = -1; From 8ca849bae4ac59457790206be80e6465d2529d0d Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 27 Jun 2022 11:04:03 +0300 Subject: [PATCH 3/4] Update packages/number-field/test/validation.test.js Co-authored-by: Serhii Kulykov --- packages/number-field/test/validation.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/number-field/test/validation.test.js b/packages/number-field/test/validation.test.js index 17af9d83b3..61c25b00c4 100644 --- a/packages/number-field/test/validation.test.js +++ b/packages/number-field/test/validation.test.js @@ -12,7 +12,7 @@ describe('validation', () => { input = field.inputElement; }); - it('should pass validation when the field by default', () => { + it('should pass validation by default', () => { expect(field.checkValidity()).to.be.true; expect(field.validate()).to.be.true; expect(field.invalid).to.be.false; From c86ed55958131dda9a0bf321151ecfbf148dfc0d Mon Sep 17 00:00:00 2001 From: Sergey Vinogradov Date: Mon, 27 Jun 2022 11:05:12 +0300 Subject: [PATCH 4/4] remove redundant assertion --- packages/number-field/test/validation.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/number-field/test/validation.test.js b/packages/number-field/test/validation.test.js index 61c25b00c4..49b9bd042e 100644 --- a/packages/number-field/test/validation.test.js +++ b/packages/number-field/test/validation.test.js @@ -34,8 +34,6 @@ describe('validation', () => { }); it('should be valid with numeric values', () => { - expect(field.validate()).to.be.true; - field.value = '1'; expect(input.value).to.be.equal('1'); expect(field.validate()).to.be.true;