diff --git a/packages/number-field/src/NumberField.ts b/packages/number-field/src/NumberField.ts index b5b42d6b1a..375efaf430 100644 --- a/packages/number-field/src/NumberField.ts +++ b/packages/number-field/src/NumberField.ts @@ -160,7 +160,7 @@ export class NumberField extends TextfieldBase { } const oldValue = this._value; this._value = value; - if (!this.managedInput && this.lastCommitedValue != this.value) { + if (!this.managedInput && this.lastCommitedValue !== this.value) { this.dispatchEvent( new Event('change', { bubbles: true, composed: true }) ); @@ -287,7 +287,7 @@ export class NumberField extends TextfieldBase { this.buttons.releasePointerCapture(event.pointerId); cancelAnimationFrame(this.nextChange); clearTimeout(this.safty); - if (this.lastCommitedValue != this.value) { + if (this.lastCommitedValue !== this.value) { this.dispatchEvent( new Event('change', { bubbles: true, composed: true }) ); @@ -406,7 +406,7 @@ export class NumberField extends TextfieldBase { } this.value = value; this.inputElement.value = this.formattedValue; - if (this.lastCommitedValue != this.value) { + if (this.lastCommitedValue !== this.value) { this.lastCommitedValue = this.value; super.handleChange(); } diff --git a/packages/number-field/test/number-field.test.ts b/packages/number-field/test/number-field.test.ts index fd5f5de563..d21e8df5fc 100644 --- a/packages/number-field/test/number-field.test.ts +++ b/packages/number-field/test/number-field.test.ts @@ -362,6 +362,16 @@ describe('NumberField', () => { changeSpy((event.target as NumberField)?.value); }); }); + it('on changing `value`', async () => { + el.focus(); + await elementUpdated(el); + expect(el.focused).to.be.true; + el.value = 51; + expect(changeSpy.callCount).to.equal(1); + await elementUpdated(el); + el.value = 52; + expect(changeSpy.callCount).to.equal(2); + }); it('via scroll', async () => { el.focus(); await elementUpdated(el); @@ -507,6 +517,72 @@ describe('NumberField', () => { expect(el.value).to.equal(50); }); it('many input, but one change', async () => { + const buttonUp = el.shadowRoot.querySelector( + '.step-up' + ) as HTMLElement; + const buttonUpRect = buttonUp.getBoundingClientRect(); + const buttonUpPosition: [number, number] = [ + buttonUpRect.x + buttonUpRect.width / 2, + buttonUpRect.y + buttonUpRect.height / 2, + ]; + const buttonDown = el.shadowRoot.querySelector( + '.step-down' + ) as HTMLElement; + const buttonDownRect = buttonDown.getBoundingClientRect(); + const buttonDownPosition: [number, number] = [ + buttonDownRect.x + buttonDownRect.width / 2, + buttonDownRect.y + buttonDownRect.height / 2, + ]; + sendMouse({ + steps: [ + { + type: 'move', + position: buttonUpPosition, + }, + { + type: 'down', + }, + ], + }); + await oneEvent(el, 'input'); + expect(el.value).to.equal(51); + expect(inputSpy.callCount).to.equal(1); + expect(changeSpy.callCount).to.equal(0); + await oneEvent(el, 'input'); + expect(el.value).to.equal(52); + expect(inputSpy.callCount).to.equal(2); + expect(changeSpy.callCount).to.equal(0); + await oneEvent(el, 'input'); + expect(el.value).to.equal(53); + expect(inputSpy.callCount).to.equal(3); + expect(changeSpy.callCount).to.equal(0); + sendMouse({ + steps: [ + { + type: 'move', + position: buttonDownPosition, + }, + ], + }); + let framesToWait = FRAMES_PER_CHANGE * 2; + while (framesToWait) { + // input is only processed onces per FRAMES_PER_CHANGE number of frames + framesToWait -= 1; + await nextFrame(); + } + expect(inputSpy.callCount).to.equal(5); + expect(changeSpy.callCount).to.equal(0); + await sendMouse({ + steps: [ + { + type: 'up', + }, + ], + }); + expect(inputSpy.callCount).to.equal(5); + expect(changeSpy.callCount).to.equal(1); + }); + it('no change in committed value - using buttons', async () => { const buttonUp = el.shadowRoot.querySelector( '.step-up' ) as HTMLElement; @@ -566,7 +642,10 @@ describe('NumberField', () => { ], }); expect(inputSpy.callCount).to.equal(4); - expect(changeSpy.callCount).to.equal(0); // the actual value hasn't changed so changespy won't be called + expect( + changeSpy.callCount, + 'value does not change from initial value so no "change" event is dispatched' + ).to.equal(0); }); }); it('accepts pointer interactions with the stepper UI', async () => { @@ -751,7 +830,10 @@ describe('NumberField', () => { await sendKeys({ press: 'Enter' }); await elementUpdated(el); expect(lastInputValue, 'last input value').to.equal(10); - expect(lastChangeValue, 'last change value').to.equal(0); // value wouldn't go beyond max, so it remains unchanged after pressing enter and thus no changeSpy called + expect(lastChangeValue, 'last change value').to.equal( + 0, + 'value does not change from initial value so no "change" event is dispatched' + ); expect(el.formattedValue).to.equal('10'); expect(el.valueAsString).to.equal('10'); expect(el.value).to.equal(10); @@ -785,6 +867,14 @@ describe('NumberField', () => { expect(el.valueAsString).to.equal('5'); expect(el.value).to.equal(5); }); + it('dispatches onchange on setting max value', async () => { + el.value = 5; + await elementUpdated(el); + expect(lastChangeValue, 'last change value').to.equal(5); + el.value = 15; + await elementUpdated(el); + expect(lastChangeValue, 'last change value').to.equal(10); + }); }); describe('min', () => { let el: NumberField; @@ -811,11 +901,22 @@ describe('NumberField', () => { await sendKeys({ press: 'Enter' }); await elementUpdated(el); expect(lastInputValue, 'last input value').to.equal(10); - expect(lastChangeValue, 'last change value').to.equal(0); + expect(lastChangeValue, 'last change value').to.equal( + 0, + 'value does not change from initial value so no "change" event is dispatched' + ); expect(el.formattedValue).to.equal('10'); expect(el.valueAsString).to.equal('10'); expect(el.value).to.equal(10); }); + it('dispatches onchange on setting min value', async () => { + el.value = 15; + await elementUpdated(el); + expect(lastChangeValue, 'last change value').to.equal(15); + el.value = 5; + await elementUpdated(el); + expect(lastChangeValue, 'last change value').to.equal(10); + }); xit('manages `inputMode` in iPhone', async () => { // setUserAgent is not currently supported by Playwright await setUserAgent(