From 26f6228dc90d0863bdee2510d0b7cc640c763a5f Mon Sep 17 00:00:00 2001 From: Kukhyeon Heo Date: Mon, 10 Aug 2020 17:33:07 +0900 Subject: [PATCH] feat: Improve clicking with modifiers. (#8114) Co-authored-by: Jennifer Shehane --- cli/types/cypress.d.ts | 48 +++++++++ cli/types/tests/chainer-examples.ts | 3 + .../driver/cypress/fixtures/issue-486.html | 33 +++++++ .../commands/actions/click_spec.js | 99 +++++++++++++++++++ .../driver/src/cy/commands/actions/click.js | 32 +++++- 5 files changed, 214 insertions(+), 1 deletion(-) create mode 100644 packages/driver/cypress/fixtures/issue-486.html diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index 7031603da8fd..4a6424ee12fe 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -2319,6 +2319,54 @@ declare namespace Cypress { * @default false */ multiple: boolean + /** + * Activates the control key during click + * + * @default false + */ + ctrlKey: boolean + /** + * Activates the control key during click + * + * @default false + */ + controlKey: boolean + /** + * Activates the alt key (option key for Mac) during click + * + * @default false + */ + altKey: boolean + /** + * Activates the alt key (option key for Mac) during click + * + * @default false + */ + optionKey: boolean + /** + * Activates the shift key during click + * + * @default false + */ + shiftKey: boolean + /** + * Activates the meta key (Windows key or command key for Mac) during click + * + * @default false + */ + metaKey: boolean + /** + * Activates the meta key (Windows key or command key for Mac) during click + * + * @default false + */ + commandKey: boolean + /** + * Activates the meta key (Windows key or command key for Mac) during click + * + * @default false + */ + cmdKey: boolean } interface ResolvedConfigOptions { diff --git a/cli/types/tests/chainer-examples.ts b/cli/types/tests/chainer-examples.ts index 7538a638b297..6f72b6f5af1a 100644 --- a/cli/types/tests/chainer-examples.ts +++ b/cli/types/tests/chainer-examples.ts @@ -467,6 +467,9 @@ cy.writeFile('../file.path', '', { }) cy.get('foo').click() +cy.get('foo').click({ + ctrlKey: true, +}) cy.get('foo').rightclick() cy.get('foo').dblclick() diff --git a/packages/driver/cypress/fixtures/issue-486.html b/packages/driver/cypress/fixtures/issue-486.html new file mode 100644 index 000000000000..0f5954a16764 --- /dev/null +++ b/packages/driver/cypress/fixtures/issue-486.html @@ -0,0 +1,33 @@ + + + + Issue 486 + + + +
Result
+ + + diff --git a/packages/driver/cypress/integration/commands/actions/click_spec.js b/packages/driver/cypress/integration/commands/actions/click_spec.js index deb601cfa0a3..674c299ade04 100644 --- a/packages/driver/cypress/integration/commands/actions/click_spec.js +++ b/packages/driver/cypress/integration/commands/actions/click_spec.js @@ -882,6 +882,105 @@ describe('src/cy/commands/actions/click', () => { }) }) + describe('modifier options', () => { + beforeEach(() => { + cy.visit('/fixtures/issue-486.html') + }) + + it('ctrl', () => { + cy.get('#button').click({ + ctrlKey: true, + }) + + cy.get('#result').should('contain', '{Ctrl}') + + // ctrl should be released + cy.get('#button').click() + cy.get('#result').should('not.contain', '{Ctrl}') + + cy.get('#button').click({ + controlKey: true, + }) + + cy.get('#result').should('contain', '{Ctrl}') + }) + + it('alt', () => { + cy.get('#button').click({ + altKey: true, + }) + + cy.get('#result').should('contain', '{Alt}') + + // alt should be released + cy.get('#button').click() + cy.get('#result').should('not.contain', '{Alt}') + + cy.get('#button').click({ + optionKey: true, + }) + + cy.get('#result').should('contain', '{Alt}') + }) + + it('shift', () => { + cy.get('#button').click({ + shiftKey: true, + }) + + cy.get('#result').should('contain', '{Shift}') + + // shift should be released + cy.get('#button').click() + cy.get('#result').should('not.contain', '{Shift}') + }) + + it('meta', () => { + cy.get('#button').click({ + metaKey: true, + }) + + cy.get('#result').should('contain', '{Meta}') + + // shift should be released + cy.get('#button').click() + cy.get('#result').should('not.contain', '{Meta}') + + cy.get('#button').click({ + commandKey: true, + }) + + cy.get('#result').should('contain', '{Meta}') + + cy.get('#button').click({ + cmdKey: true, + }) + + cy.get('#result').should('contain', '{Meta}') + }) + + it('multiple', () => { + cy.get('#button').click({ + ctrlKey: true, + altKey: true, + shiftKey: true, + metaKey: true, + }) + + cy.get('#result').should('contain', '{Ctrl}') + cy.get('#result').should('contain', '{Alt}') + cy.get('#result').should('contain', '{Shift}') + cy.get('#result').should('contain', '{Meta}') + + // modifiers should be released + cy.get('#button').click() + cy.get('#result').should('not.contain', '{Ctrl}') + cy.get('#result').should('not.contain', '{Alt}') + cy.get('#result').should('not.contain', '{Shift}') + cy.get('#result').should('not.contain', '{Meta}') + }) + }) + describe('pointer-events:none', () => { beforeEach(function () { cy.$$('
behind #ptrNone
').appendTo(cy.$$('#dom')) diff --git a/packages/driver/src/cy/commands/actions/click.js b/packages/driver/src/cy/commands/actions/click.js index db6ba8de67d3..09ead09029f5 100644 --- a/packages/driver/src/cy/commands/actions/click.js +++ b/packages/driver/src/cy/commands/actions/click.js @@ -34,7 +34,7 @@ const formatMouseEvents = (events) => { } module.exports = (Commands, Cypress, cy, state, config) => { - const { mouse } = cy.devices + const { mouse, keyboard } = cy.devices const mouseAction = (eventName, { subject, positionOrX, y, userOptions, onReady, onTable, defaultOptions }) => { let position @@ -54,6 +54,14 @@ module.exports = (Commands, Cypress, cy, state, config) => { errorOnSelect: true, waitForAnimations: config('waitForAnimations'), animationDistanceThreshold: config('animationDistanceThreshold'), + ctrlKey: false, + controlKey: false, + altKey: false, + optionKey: false, + shiftKey: false, + metaKey: false, + commandKey: false, + cmdKey: false, ...defaultOptions, }) @@ -65,6 +73,24 @@ module.exports = (Commands, Cypress, cy, state, config) => { }) } + const flagModifiers = (press) => { + if (options.ctrlKey || options.controlKey) { + keyboard.flagModifier({ key: 'Control' }, press) + } + + if (options.altKey || options.optionKey) { + keyboard.flagModifier({ key: 'Alt' }, press) + } + + if (options.shiftKey) { + keyboard.flagModifier({ key: 'Shift' }, press) + } + + if (options.metaKey || options.commandKey || options.cmdKey) { + keyboard.flagModifier({ key: 'Meta' }, press) + } + } + const perform = (el) => { let deltaOptions const $el = $dom.wrap(el) @@ -158,8 +184,12 @@ module.exports = (Commands, Cypress, cy, state, config) => { const moveEvents = mouse.move(fromElViewport, forceEl) + flagModifiers(true) + const onReadyProps = onReady(fromElViewport, forceEl) + flagModifiers(false) + return createLog({ moveEvents, ...onReadyProps,