Skip to content

Commit

Permalink
feat: Support alt/control/meta modifiers for keyboard events (#569)
Browse files Browse the repository at this point in the history
* support all modifiers for events

* update modifiers test

* add new tests for modifiers

* add test for combination of modifiers

* correct description

* address the ESLint errors

* address Prettier errors
  • Loading branch information
snapris committed Nov 2, 2023
1 parent ef93985 commit 021ca12
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 49 deletions.
64 changes: 40 additions & 24 deletions cypress/e2e/modifiers.cy.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,50 @@
describe("Events behavior with shiftKey modifier applied", () => {
describe("Events behavior with single modifier applied", () => {
beforeEach(() => {
cy.visit("./cypress/fixtures/modifiers-test.html");
});

// NOTE: for some reason after upgrading CI to use Chrome 116 and Cypress 13 this particular test fails
// and only on CI. Figure out if this is a real issue or some version conflict | cypress bug.
//
// @see https://app.circleci.com/pipelines/github/dmtrKovalenko/cypress-real-events/842/workflows/1f98e690-ec69-4dcf-9e0e-3f8eb67dc709/jobs/2332/parallel-runs/0?filterBy=ALL
it.skip("detects shift key modifier on click", () => {
cy.get("#action-button").realClick({ shiftKey: true });
cy.contains("Shift key was pressed");
});
const modifierKeys = ["shiftKey", "altKey", "ctrlKey", "metaKey"];

it("detects shift key modifier on hover", () => {
cy.get("#mouse-move-div").realHover({ shiftKey: true });
cy.contains("Shift key was pressed");
});
function createModifierObject(modifierKey: string) {
const options = {};
options[modifierKey] = true;
return options;
}

it("detects shift key modifier on mousedown", () => {
cy.get("#mouse-down-div").realMouseDown({ shiftKey: true });
cy.contains("Shift key was pressed");
});
modifierKeys.forEach((modifierKey) => {
// NOTE: for some reason after upgrading CI to use Chrome 116 and Cypress 13 this particular test fails
// and only on CI. Figure out if this is a real issue or some version conflict | cypress bug.
//
// @see https://app.circleci.com/pipelines/github/dmtrKovalenko/cypress-real-events/842/workflows/1f98e690-ec69-4dcf-9e0e-3f8eb67dc709/jobs/2332/parallel-runs/0?filterBy=ALL
it.skip(`detects ${modifierKey} modifier on click`, () => {
cy.get("#action-button").realClick(createModifierObject(modifierKey));
cy.contains(`${modifierKey} was pressed`);
});

it("detects shift key modifier on mpuseup", () => {
cy.get("#mouse-up-div").realMouseUp({ shiftKey: true });
cy.contains("Shift key was pressed");
});
it(`detects ${modifierKey} modifier on hover`, () => {
cy.get("#mouse-move-div").realHover(createModifierObject(modifierKey));
cy.contains(`${modifierKey} was pressed`);
});

it(`detects ${modifierKey} modifier on mousedown`, () => {
cy.get("#mouse-down-div").realMouseDown(
createModifierObject(modifierKey),
);
cy.contains(`${modifierKey} was pressed`);
});

it(`detects ${modifierKey} modifier on mpuseup`, () => {
cy.get("#mouse-up-div").realMouseUp(createModifierObject(modifierKey));
cy.contains(`${modifierKey} was pressed`);
});

it("detects shift key modifier on mousemove", () => {
cy.get("#mouse-move-div").realMouseMove(100, 50, { shiftKey: true });
cy.contains("Shift key was pressed");
it(`detects ${modifierKey} modifier on mousemove`, () => {
cy.get("#mouse-move-div").realMouseMove(
100,
50,
createModifierObject(modifierKey),
);
cy.contains(`${modifierKey} was pressed`);
});
});
});
60 changes: 60 additions & 0 deletions cypress/e2e/modifiers_combination.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
describe("Events behavior with modifiers combination applied", () => {
beforeEach(() => {
cy.visit("./cypress/fixtures/modifiers-test.html");
});

const modifierKeys = ["shiftKey", "altKey", "ctrlKey"];

function createModifierObject(
modifierKeys: string[],
): Record<string, boolean> {
const options = {};
for (const key of modifierKeys) {
options[key] = true;
}
return options;
}

// NOTE: for some reason after upgrading CI to use Chrome 116 and Cypress 13 this particular test fails
// and only on CI. Figure out if this is a real issue or some version conflict | cypress bug.
//
// @see https://app.circleci.com/pipelines/github/dmtrKovalenko/cypress-real-events/842/workflows/1f98e690-ec69-4dcf-9e0e-3f8eb67dc709/jobs/2332/parallel-runs/0?filterBy=ALL
it.skip(`detects ${modifierKeys} modifiers on click`, () => {
cy.get("#action-button").realClick(createModifierObject(modifierKeys));
for (const key of modifierKeys) {
cy.contains(`${key} was pressed`);
}
});

it(`detects ${modifierKeys} modifiers on hover`, () => {
cy.get("#mouse-move-div").realHover(createModifierObject(modifierKeys));
for (const key of modifierKeys) {
cy.contains(`${key} was pressed`);
}
});

it(`detects ${modifierKeys} modifiers on mousedown`, () => {
cy.get("#mouse-down-div").realMouseDown(createModifierObject(modifierKeys));
for (const key of modifierKeys) {
cy.contains(`${key} was pressed`);
}
});

it(`detects ${modifierKeys} modifiers on mpuseup`, () => {
cy.get("#mouse-up-div").realMouseUp(createModifierObject(modifierKeys));
for (const key of modifierKeys) {
cy.contains(`${key} was pressed`);
}
});

it(`detects ${modifierKeys} modifiers on mousemove`, () => {
cy.get("#mouse-move-div").realMouseMove(
100,
50,
createModifierObject(modifierKeys),
);
for (const key of modifierKeys) {
cy.contains(`${key} was pressed`);
}
});
});
15 changes: 10 additions & 5 deletions cypress/fixtures/modifiers-test.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<body>
<button id="action-button">Click on me with shift pressed</button>
<button id="action-button">Click on me with modifier(s) (shift/alt/ctrl/meta) pressed</button>
<hr />
<div id="mouse-move-div">Hover/mousemove over me with shift pressed</div>
<div id="mouse-move-div">Hover/mousemove over me with modifier(s) (shift/alt/ctrl/meta) pressed</div>
<hr />
<div id="mouse-down-div">Initiate mouse down with shift pressed</div>
<div id="mouse-down-div">Initiate mouse down with modifie(s) (shift/alt/ctrl/meta) pressed</div>
<hr />
<div id="mouse-up-div">Initiate mouse up with shift pressed</div>
<div id="mouse-up-div">Initiate mouse up with modifier(s) (shift/alt/ctrl/meta) pressed</div>
<hr />

<p id="result"></p>
Expand All @@ -17,7 +17,12 @@

function commonHandler(e) {
resultBox.innerHTML = "";
if (e.shiftKey) resultBox.innerHTML = "Shift key was pressed";
const modifiers = ['shiftKey', 'altKey', 'ctrlKey', 'metaKey'];
for (let mod of modifiers) {
if (e[mod]) {
resultBox.innerHTML += `${mod} was pressed<br>`;
}
}
}

document
Expand Down
11 changes: 8 additions & 3 deletions src/commands/mouseDown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Position,
} from "../getCypressElementCoordinates";
import { mouseButtonNumbers } from "../mouseButtonNumbers";
import { keyToModifierBitMap } from "../keyToModifierBitMap";
import { getModifiers } from "../getModifiers";

export interface realMouseDownOptions {
/** Pointer type for realMouseDown, if "pen" touch simulated */
Expand Down Expand Up @@ -39,10 +39,13 @@ export interface realMouseDownOptions {
*/
y?: number;
/**
* Indicates whether the shift key was pressed or not when an event occurred
* Indicates whether any modifier (shiftKey | altKey | ctrlKey | metaKey) was pressed or not when an event occurred
* @example cy.realMouseDown({ shiftKey: true });
*/
shiftKey?: boolean;
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
/**
* The normalized pressure, which has a range of [0,1]. It affects the `pressure` property of the triggered
* pointerdown event.
Expand Down Expand Up @@ -76,6 +79,8 @@ export async function realMouseDown(
}),
});

const modifiers = getModifiers(options);

log.snapshot("before");
await fireCdpCommand("Input.dispatchMouseEvent", {
type: "mousePressed",
Expand All @@ -85,7 +90,7 @@ export async function realMouseDown(
buttons: mouseButtonNumbers[options.button ?? "left"],
pointerType: options.pointer ?? "mouse",
button: options.button ?? "left",
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
force: options.pressure ?? 0.5,
});

Expand Down
13 changes: 9 additions & 4 deletions src/commands/mouseMove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
Position,
ScrollBehaviorOptions,
} from "../getCypressElementCoordinates";
import { keyToModifierBitMap } from "../keyToModifierBitMap";
import { getModifiers } from "../getModifiers";

export interface RealMouseMoveOptions {
/**
Expand All @@ -19,10 +19,13 @@ export interface RealMouseMoveOptions {
*/
scrollBehavior?: ScrollBehaviorOptions;
/**
* Indicates whether the shift key was pressed or not when an event occurred
* @example cy.realMouseMove({ shiftKey: true });
* Indicates whether any modifier (shiftKey | altKey | ctrlKey | metaKey) was pressed or not when an event occurred
* @example cy.realMouseDown({ shiftKey: true });
*/
shiftKey?: boolean;
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
}

/** @ignore this, update documentation for this function at index.d.ts */
Expand All @@ -47,12 +50,14 @@ export async function realMouseMove(
}),
});

const modifiers = getModifiers(options);

log.snapshot("before");
await fireCdpCommand("Input.dispatchMouseEvent", {
type: "mouseMoved",
x: x * basePosition.frameScale + basePosition.x,
y: y * basePosition.frameScale + basePosition.y,
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
});

log.snapshot("after").end();
Expand Down
13 changes: 9 additions & 4 deletions src/commands/mouseUp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Position,
} from "../getCypressElementCoordinates";
import { mouseButtonNumbers } from "../mouseButtonNumbers";
import { keyToModifierBitMap } from "../keyToModifierBitMap";
import { getModifiers } from "../getModifiers";

export interface realMouseUpOptions {
/** Pointer type for realMouseUp, if "pen" touch simulated */
Expand Down Expand Up @@ -37,10 +37,13 @@ export interface realMouseUpOptions {
*/
y?: number;
/**
* Indicates whether the shift key was pressed or not when an event occurred
* @example cy.realMouseUp({ shiftKey: true });
* Indicates whether any modifier (shiftKey | altKey | ctrlKey | metaKey) was pressed or not when an event occurred
* @example cy.realMouseDown({ shiftKey: true });
*/
shiftKey?: boolean;
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
}

/** @ignore this, update documentation for this function at index.d.ts */
Expand All @@ -66,6 +69,8 @@ export async function realMouseUp(
}),
});

const modifiers = getModifiers(options);

log.snapshot("before");
await fireCdpCommand("Input.dispatchMouseEvent", {
type: "mouseReleased",
Expand All @@ -75,7 +80,7 @@ export async function realMouseUp(
buttons: mouseButtonNumbers[options.button ?? "left"],
pointerType: options.pointer ?? "mouse",
button: options.button ?? "left",
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
});

log.snapshot("after").end();
Expand Down
15 changes: 10 additions & 5 deletions src/commands/realClick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Position,
} from "../getCypressElementCoordinates";
import { mouseButtonNumbers } from "../mouseButtonNumbers";
import { keyToModifierBitMap } from "../keyToModifierBitMap";
import { getModifiers } from "../getModifiers";

export interface RealClickOptions {
/** Pointer type for realClick, if "pen" touch simulated */
Expand Down Expand Up @@ -40,10 +40,13 @@ export interface RealClickOptions {
*/
clickCount?: number;
/**
* Indicates whether the shift key was pressed or not when an event occurred
* @example cy.realClick({ shiftKey: true });
* Indicates whether any modifier (shiftKey | altKey | ctrlKey | metaKey) was pressed or not when an event occurred
* @example cy.realMouseDown({ shiftKey: true });
*/
shiftKey?: boolean;
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;

/**
* The normalized pressure, which has a range of [0,1]. It affects the `pressure` property of the triggered
Expand Down Expand Up @@ -78,6 +81,8 @@ export async function realClick(
}),
});

const modifiers = getModifiers(options);

log.snapshot("before");

const { clickCount = 1 } = options;
Expand All @@ -91,7 +96,7 @@ export async function realClick(
buttons: mouseButtonNumbers[options.button ?? "left"],
pointerType: options.pointer ?? "mouse",
button: options.button ?? "left",
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
force: options.pressure ?? 0.5,
});

Expand All @@ -103,7 +108,7 @@ export async function realClick(
buttons: mouseButtonNumbers[options.button ?? "left"],
pointerType: options.pointer ?? "mouse",
button: options.button ?? "left",
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
});
}

Expand Down
13 changes: 9 additions & 4 deletions src/commands/realHover.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
ScrollBehaviorOptions,
getCypressElementCoordinates,
} from "../getCypressElementCoordinates";
import { keyToModifierBitMap } from "../keyToModifierBitMap";
import { getModifiers } from "../getModifiers";

export interface RealHoverOptions {
/**
Expand All @@ -22,10 +22,13 @@ export interface RealHoverOptions {
*/
scrollBehavior?: ScrollBehaviorOptions;
/**
* Indicates whether the shift key was pressed or not when an event occurred
* @example cy.realHover({ shiftKey: true });
* Indicates whether any modifier (shiftKey | altKey | ctrlKey | metaKey) was pressed or not when an event occurred
* @example cy.realMouseDown({ shiftKey: true });
*/
shiftKey?: boolean;
altKey?: boolean;
ctrlKey?: boolean;
metaKey?: boolean;
}

/** @ignore this, update documentation for this function at index.d.ts */
Expand All @@ -48,13 +51,15 @@ export async function realHover(
}),
});

const modifiers = getModifiers(options);

await fireCdpCommand("Input.dispatchMouseEvent", {
x,
y,
type: "mouseMoved",
button: "none",
pointerType: options.pointer ?? "mouse",
modifiers: options.shiftKey ? keyToModifierBitMap.Shift : 0,
modifiers: modifiers,
});

log.snapshot().end();
Expand Down

0 comments on commit 021ca12

Please sign in to comment.