Skip to content

Commit

Permalink
chore: Release 1.11
Browse files Browse the repository at this point in the history
Release 1.11
  • Loading branch information
dmtrKovalenko committed Nov 2, 2023
2 parents 8532c2f + 43a64d0 commit 12ae8e0
Show file tree
Hide file tree
Showing 13 changed files with 286 additions and 58 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

Cypress default events are simulated. That means that all events like `cy.click` or `cy.type` are fired from javascript. That's why these events will be untrusted (`event.isTrusted` will be `false`) and they can behave a little different from real native events. But for some cases, it can be impossible to use simulated events, for example, to fill a native alert or copy to the clipboard. This plugin solves this problem.

<img src="https://forthebadge.com/images/badges/it-works-why.svg">
## How?

Thanks to [Chrome Devtools Protocol](https://chromedevtools.github.io/devtools-protocol/). Cypress is connecting to CDP for tasks like screenshots, setting viewport, and others. This project utilizes the same connection to fire system events. The event firing system works literally like in puppeteer. And as a result, unlocks such features like **hovering** and **native focus management via Tab**.

Expand Down
35 changes: 35 additions & 0 deletions cypress/e2e/click.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,41 @@ describe("cy.realClick", () => {
cy.get(".navbar-brand").realClick({ button: "right" });
});

it("results in pointerdown events with the default pressure of 0.5", () => {
const handler = cy.stub();
cy.get(".action-btn")
.then(($button) => {
$button[0].addEventListener("pointerdown", (e) =>
handler("pointerdown", e.pressure),
);
$button[0].addEventListener("pointerup", (e) =>
handler("pointerup", e.pressure),
);
})
.realClick();
cy.wrap(handler).should("be.calledWith", "pointerdown", 0.5);
cy.wrap(handler).should("be.calledWith", "pointerup", 0);
});

it("allows for setting pressure of the pointerdown event", () => {
const handler = cy.stub();
cy.get(".action-btn")
.then(($button) => {
$button[0].addEventListener("pointerdown", (e) =>
handler("pointerdown", Math.round(e.pressure * 100) / 100),
);
$button[0].addEventListener("pointerup", (e) =>
handler("pointerup", Math.round(e.pressure * 100) / 100),
);
})
.realClick({ pressure: 0 })
.realClick({ pressure: 0.4 });
cy.wrap(handler)
.should("be.calledWith", "pointerdown", 0)
.should("be.calledWith", "pointerdown", 0.4)
.should("be.calledWith", "pointerup", 0);
});

describe("scroll behavior", () => {
function getScreenEdges() {
const cypressAppWindow =
Expand Down
62 changes: 38 additions & 24 deletions cypress/e2e/modifiers.cy.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
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 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 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 ${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`);
}
});
});
27 changes: 27 additions & 0 deletions cypress/e2e/mouse.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,33 @@ describe("cy.realMouseDown and cy.realMouseUp", () => {
.realMouseUp({ position: "bottomRight" });
});

it("results in pointerdown events with the default pressure of 0.5", () => {
const handler = cy.stub();
cy.get(".action-btn")
.then(($button) => {
$button[0].addEventListener("pointerdown", (e) =>
handler("pointerdown", e.pressure),
);
})
.realMouseDown();
cy.wrap(handler).should("be.calledWith", "pointerdown", 0.5);
});

it("allows for setting pressure of the pointerdown event", () => {
const handler = cy.stub();
cy.get(".action-btn")
.then(($button) => {
$button[0].addEventListener("pointerdown", (e) =>
handler("pointerdown", Math.round(e.pressure * 100) / 100),
);
})
.realMouseDown({ pressure: 0 })
.realMouseDown({ pressure: 0.4 });
cy.wrap(handler)
.should("be.calledWith", "pointerdown", 0)
.should("be.calledWith", "pointerdown", 0.4);
});

describe("options.button", () => {
it("should allow to press down mouse using middle button", (done) => {
cy.get(".action-btn")
Expand Down
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
20 changes: 17 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,21 @@ 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.
*
* @type {number}
* @default {0.5}
*/
pressure?: number;
}

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

const modifiers = getModifiers(options);

log.snapshot("before");
await fireCdpCommand("Input.dispatchMouseEvent", {
type: "mousePressed",
Expand All @@ -77,7 +90,8 @@ 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,
});

log.snapshot("after").end();
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

0 comments on commit 12ae8e0

Please sign in to comment.