Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve clicking with modifiers. #8114

Merged
merged 12 commits into from Aug 10, 2020
48 changes: 48 additions & 0 deletions cli/types/cypress.d.ts
Expand Up @@ -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 {
Expand Down
3 changes: 3 additions & 0 deletions cli/types/tests/chainer-examples.ts
Expand Up @@ -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()

Expand Down
33 changes: 33 additions & 0 deletions packages/driver/cypress/fixtures/issue-486.html
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<title>Issue 486</title>
</head>
<body>
<button id="button">modifier test</button>
<div id="result">Result</div>
<script type="text/javascript">
document.getElementById('button').addEventListener('click', (e) => {
const result = document.getElementById('result')

result.innerText = ''

if (e.ctrlKey) {
result.innerText += '{Ctrl}'
}

if (e.altKey) {
result.innerText += '{Alt}'
}

if (e.shiftKey) {
result.innerText += '{Shift}'
}

if (e.metaKey) {
result.innerText += '{Meta}'
}
})
</script>
</body>
</html>
99 changes: 99 additions & 0 deletions packages/driver/cypress/integration/commands/actions/click_spec.js
Expand Up @@ -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.$$('<div id="ptr" style="position:absolute;width:200px;height:200px;background-color:#08c18d;">behind #ptrNone</div>').appendTo(cy.$$('#dom'))
Expand Down
32 changes: 31 additions & 1 deletion packages/driver/src/cy/commands/actions/click.js
Expand Up @@ -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
Expand All @@ -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,
})

Expand All @@ -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)
Expand Down Expand Up @@ -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,
Expand Down