From 9c9bf5b690fccbea55361192ec75706359a4da26 Mon Sep 17 00:00:00 2001 From: Vladyslav Nosal <88045184+thevladisss@users.noreply.github.com> Date: Tue, 18 Jun 2024 07:47:04 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20"type"=20action=20with=20{upArrow}=20and?= =?UTF-8?q?=20{downArrow}=20arguments=20to=20simula=E2=80=A6=20(#29636)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: "type" action with {upArrow} and {downArrow} arguments to simulate native behavior of input[type=number] * Add changelog entry for the fix --------- Co-authored-by: Jennifer Shehane --- cli/CHANGELOG.md | 1 + .../cypress/e2e/commands/actions/type.cy.js | 48 +++++++++++++++++++ packages/driver/src/dom/selection.ts | 11 +++++ 3 files changed, 60 insertions(+) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index d89a2315498..927f308ea38 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -9,6 +9,7 @@ _Released 6/18/2024 (PENDING)_ **Bugfixes:** +- We now trigger `input` and `change` events when typing `{upArrow}` and `{downArrow}` via `.type()` on `input[type=number]` elements. Fixes [#29611](https://github.com/cypress-io/cypress/issues/29611) - Fixed an issue where auto scrolling the reporter would sometimes be disabled without the user's intent. Fixes [#25084](https://github.com/cypress-io/cypress/issues/25084). - Fixed an issue where `inlineSourceMaps` was still being used when `sourceMaps` was provided in a users typescript config for typescript version 5. Fixes [#26203](https://github.com/cypress-io/cypress/issues/26203). - When capture protocol script fails verification, an appropriate error is now displayed. Previously, an error regarding Test Replay archive location was shown. Addressed in [#29603](https://github.com/cypress-io/cypress/pull/29603). diff --git a/packages/driver/cypress/e2e/commands/actions/type.cy.js b/packages/driver/cypress/e2e/commands/actions/type.cy.js index 8789e698169..1e52478c62a 100644 --- a/packages/driver/cypress/e2e/commands/actions/type.cy.js +++ b/packages/driver/cypress/e2e/commands/actions/type.cy.js @@ -1305,6 +1305,54 @@ describe('src/cy/commands/actions/type - #type', () => { .type('100{enter}') .should('have.value', '100') }) + + context('can utilize up and down arrow keys', () => { + beforeEach(() => { + cy.get('#number-with-value').then(($input) => $input.val(1)) + }) + + it('can utilize {upArrow}', () => { + cy.get('#number-with-value') + .type('{upArrow}') + .should('have.value', 2) + }) + + it('{upArrow} triggers events on input', () => { + cy.get('#number-with-value') + .then(($input) => { + $input.on('change', cy.spy().as('spyChange')) + $input.on('input', cy.spy().as('spyInput')) + + return $input + }) + .type('{upArrow}') + + cy.get('@spyInput').should('have.been.calledOnce') + cy.get('@spyChange').should('have.been.calledOnce') + }) + + it('can utilize {downArrow}', () => { + cy.get('#number-with-value').then(($input) => $input.val(1)) + + cy.get('#number-with-value') + .type('{downArrow}') + .should('have.value', 0) + }) + + it('{downArrow} triggers events on input', () => { + cy.get('#number-with-value') + .then(($input) => { + $input.on('change', cy.spy().as('spyChange')) + $input.on('input', cy.spy().as('spyInput')) + + return $input + }) + .type('{downArrow}') + + cy.get('@spyChange').should('have.been.calledOnce') + cy.get('@spyInput').should('have.been.calledOnce') + }) + }) }) describe('input[type=email]', () => { diff --git a/packages/driver/src/dom/selection.ts b/packages/driver/src/dom/selection.ts index a4ad9af6593..e203302b650 100644 --- a/packages/driver/src/dom/selection.ts +++ b/packages/driver/src/dom/selection.ts @@ -338,11 +338,22 @@ const _moveCursorUpOrDown = function (up: boolean, el: HTMLElement) { if ($elements.isInputType(el, 'number')) { if (up) { if (typeof el.stepUp === 'function') { + const changeEvent = new Event('change') + + const inputEvent = new Event('input') + el.stepUp() + el.dispatchEvent(inputEvent) + el.dispatchEvent(changeEvent) } } else { if (typeof el.stepDown === 'function') { + const changeEvent = new Event('change') + const inputEvent = new Event('input') + el.stepDown() + el.dispatchEvent(inputEvent) + el.dispatchEvent(changeEvent) } } }