Skip to content

Commit 26f6228

Browse files
feat: Improve clicking with modifiers. (#8114)
Co-authored-by: Jennifer Shehane <jennifer@cypress.io>
1 parent 1690d41 commit 26f6228

File tree

5 files changed

+214
-1
lines changed

5 files changed

+214
-1
lines changed

cli/types/cypress.d.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,6 +2319,54 @@ declare namespace Cypress {
23192319
* @default false
23202320
*/
23212321
multiple: boolean
2322+
/**
2323+
* Activates the control key during click
2324+
*
2325+
* @default false
2326+
*/
2327+
ctrlKey: boolean
2328+
/**
2329+
* Activates the control key during click
2330+
*
2331+
* @default false
2332+
*/
2333+
controlKey: boolean
2334+
/**
2335+
* Activates the alt key (option key for Mac) during click
2336+
*
2337+
* @default false
2338+
*/
2339+
altKey: boolean
2340+
/**
2341+
* Activates the alt key (option key for Mac) during click
2342+
*
2343+
* @default false
2344+
*/
2345+
optionKey: boolean
2346+
/**
2347+
* Activates the shift key during click
2348+
*
2349+
* @default false
2350+
*/
2351+
shiftKey: boolean
2352+
/**
2353+
* Activates the meta key (Windows key or command key for Mac) during click
2354+
*
2355+
* @default false
2356+
*/
2357+
metaKey: boolean
2358+
/**
2359+
* Activates the meta key (Windows key or command key for Mac) during click
2360+
*
2361+
* @default false
2362+
*/
2363+
commandKey: boolean
2364+
/**
2365+
* Activates the meta key (Windows key or command key for Mac) during click
2366+
*
2367+
* @default false
2368+
*/
2369+
cmdKey: boolean
23222370
}
23232371

23242372
interface ResolvedConfigOptions {

cli/types/tests/chainer-examples.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@ cy.writeFile('../file.path', '', {
467467
})
468468

469469
cy.get('foo').click()
470+
cy.get('foo').click({
471+
ctrlKey: true,
472+
})
470473
cy.get('foo').rightclick()
471474
cy.get('foo').dblclick()
472475

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Issue 486</title>
5+
</head>
6+
<body>
7+
<button id="button">modifier test</button>
8+
<div id="result">Result</div>
9+
<script type="text/javascript">
10+
document.getElementById('button').addEventListener('click', (e) => {
11+
const result = document.getElementById('result')
12+
13+
result.innerText = ''
14+
15+
if (e.ctrlKey) {
16+
result.innerText += '{Ctrl}'
17+
}
18+
19+
if (e.altKey) {
20+
result.innerText += '{Alt}'
21+
}
22+
23+
if (e.shiftKey) {
24+
result.innerText += '{Shift}'
25+
}
26+
27+
if (e.metaKey) {
28+
result.innerText += '{Meta}'
29+
}
30+
})
31+
</script>
32+
</body>
33+
</html>

packages/driver/cypress/integration/commands/actions/click_spec.js

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,105 @@ describe('src/cy/commands/actions/click', () => {
882882
})
883883
})
884884

885+
describe('modifier options', () => {
886+
beforeEach(() => {
887+
cy.visit('/fixtures/issue-486.html')
888+
})
889+
890+
it('ctrl', () => {
891+
cy.get('#button').click({
892+
ctrlKey: true,
893+
})
894+
895+
cy.get('#result').should('contain', '{Ctrl}')
896+
897+
// ctrl should be released
898+
cy.get('#button').click()
899+
cy.get('#result').should('not.contain', '{Ctrl}')
900+
901+
cy.get('#button').click({
902+
controlKey: true,
903+
})
904+
905+
cy.get('#result').should('contain', '{Ctrl}')
906+
})
907+
908+
it('alt', () => {
909+
cy.get('#button').click({
910+
altKey: true,
911+
})
912+
913+
cy.get('#result').should('contain', '{Alt}')
914+
915+
// alt should be released
916+
cy.get('#button').click()
917+
cy.get('#result').should('not.contain', '{Alt}')
918+
919+
cy.get('#button').click({
920+
optionKey: true,
921+
})
922+
923+
cy.get('#result').should('contain', '{Alt}')
924+
})
925+
926+
it('shift', () => {
927+
cy.get('#button').click({
928+
shiftKey: true,
929+
})
930+
931+
cy.get('#result').should('contain', '{Shift}')
932+
933+
// shift should be released
934+
cy.get('#button').click()
935+
cy.get('#result').should('not.contain', '{Shift}')
936+
})
937+
938+
it('meta', () => {
939+
cy.get('#button').click({
940+
metaKey: true,
941+
})
942+
943+
cy.get('#result').should('contain', '{Meta}')
944+
945+
// shift should be released
946+
cy.get('#button').click()
947+
cy.get('#result').should('not.contain', '{Meta}')
948+
949+
cy.get('#button').click({
950+
commandKey: true,
951+
})
952+
953+
cy.get('#result').should('contain', '{Meta}')
954+
955+
cy.get('#button').click({
956+
cmdKey: true,
957+
})
958+
959+
cy.get('#result').should('contain', '{Meta}')
960+
})
961+
962+
it('multiple', () => {
963+
cy.get('#button').click({
964+
ctrlKey: true,
965+
altKey: true,
966+
shiftKey: true,
967+
metaKey: true,
968+
})
969+
970+
cy.get('#result').should('contain', '{Ctrl}')
971+
cy.get('#result').should('contain', '{Alt}')
972+
cy.get('#result').should('contain', '{Shift}')
973+
cy.get('#result').should('contain', '{Meta}')
974+
975+
// modifiers should be released
976+
cy.get('#button').click()
977+
cy.get('#result').should('not.contain', '{Ctrl}')
978+
cy.get('#result').should('not.contain', '{Alt}')
979+
cy.get('#result').should('not.contain', '{Shift}')
980+
cy.get('#result').should('not.contain', '{Meta}')
981+
})
982+
})
983+
885984
describe('pointer-events:none', () => {
886985
beforeEach(function () {
887986
cy.$$('<div id="ptr" style="position:absolute;width:200px;height:200px;background-color:#08c18d;">behind #ptrNone</div>').appendTo(cy.$$('#dom'))

packages/driver/src/cy/commands/actions/click.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const formatMouseEvents = (events) => {
3434
}
3535

3636
module.exports = (Commands, Cypress, cy, state, config) => {
37-
const { mouse } = cy.devices
37+
const { mouse, keyboard } = cy.devices
3838

3939
const mouseAction = (eventName, { subject, positionOrX, y, userOptions, onReady, onTable, defaultOptions }) => {
4040
let position
@@ -54,6 +54,14 @@ module.exports = (Commands, Cypress, cy, state, config) => {
5454
errorOnSelect: true,
5555
waitForAnimations: config('waitForAnimations'),
5656
animationDistanceThreshold: config('animationDistanceThreshold'),
57+
ctrlKey: false,
58+
controlKey: false,
59+
altKey: false,
60+
optionKey: false,
61+
shiftKey: false,
62+
metaKey: false,
63+
commandKey: false,
64+
cmdKey: false,
5765
...defaultOptions,
5866
})
5967

@@ -65,6 +73,24 @@ module.exports = (Commands, Cypress, cy, state, config) => {
6573
})
6674
}
6775

76+
const flagModifiers = (press) => {
77+
if (options.ctrlKey || options.controlKey) {
78+
keyboard.flagModifier({ key: 'Control' }, press)
79+
}
80+
81+
if (options.altKey || options.optionKey) {
82+
keyboard.flagModifier({ key: 'Alt' }, press)
83+
}
84+
85+
if (options.shiftKey) {
86+
keyboard.flagModifier({ key: 'Shift' }, press)
87+
}
88+
89+
if (options.metaKey || options.commandKey || options.cmdKey) {
90+
keyboard.flagModifier({ key: 'Meta' }, press)
91+
}
92+
}
93+
6894
const perform = (el) => {
6995
let deltaOptions
7096
const $el = $dom.wrap(el)
@@ -158,8 +184,12 @@ module.exports = (Commands, Cypress, cy, state, config) => {
158184

159185
const moveEvents = mouse.move(fromElViewport, forceEl)
160186

187+
flagModifiers(true)
188+
161189
const onReadyProps = onReady(fromElViewport, forceEl)
162190

191+
flagModifiers(false)
192+
163193
return createLog({
164194
moveEvents,
165195
...onReadyProps,

0 commit comments

Comments
 (0)