Skip to content

Commit

Permalink
feat: position option for cy.realClick and cy.realhover
Browse files Browse the repository at this point in the history
  • Loading branch information
dmtrKovalenko committed Nov 29, 2020
1 parent cb4fa12 commit 816a668
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 13 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ module.exports = {
],
rules: {
"no-only-tests/no-only-tests": "error",
"@typescript-eslint/explicit-module-boundary-types": "off"
},
};
24 changes: 22 additions & 2 deletions cypress/integration/click.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,28 @@ describe("cy.realClick", () => {
cy.get("#email1").realClick().should("be.focused");
});

it("clicks on the canvas", () => {
cy.get("#action-canvas").realClick();
it("clicks on different positions", () => {
cy.get("#action-canvas")
.realClick({ position: "topLeft" })
.realClick({ position: "top" })
.realClick({ position: "topRight" })
.realClick({ position: "left" })
.realClick({ position: "center" })
.realClick({ position: "right" })
.realClick({ position: "bottomLeft" })
.realClick({ position: "bottom" })
.realClick({ position: "bottomRight" });
});

it("clicks on custom coordinates", () => {
cy.get("#action-canvas")
.realClick({ x: 80, y: 75 })
.realClick({ x: 170, y: 75 })
.realClick({ x: 80, y: 165 })
.realClick({ x: 100, y: 185 })
.realClick({ x: 125, y: 190 })
.realClick({ x: 150, y: 185 })
.realClick({ x: 170, y: 165 } )
});

it("opens system native event on right click", () => {
Expand Down
2 changes: 1 addition & 1 deletion cypress/integration/type.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe("cy.realType", () => {
);
});

it("do not types if element is not focused", () => {
it("does not type if element is not focused", () => {
cy.realPress("Tab"); // move focus out
cy.realType("pressing keys");
cy.get("input[name=q]").should("have.value", "");
Expand Down
34 changes: 30 additions & 4 deletions src/commands/realClick.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
import { fireCdpCommand } from "../fireCdpCommand";
import { getCypressElementCoordinates } from "../getCypressElementCoordinates";
import {
getCypressElementCoordinates,
Position,
} from "../getCypressElementCoordinates";

export interface RealClickOptions {
/** Pointer type for realClick, if "pen" touch simulated */
pointer?: "mouse" | "pen";
/** The button on mouse that clicked. Simulates real browser behavior. */
button?: "none" | "left" | "right" | "middle" | "back" | "forward";
/**
* Position of the click event relative to the element
* @example cy.realClick({ position: "topLeft" })
*/
position?: Position;
/** X coordinate to click, relative to the Element. Overrides `position`.
* @example
* cy.get("canvas").realClick({ x: 100, y: 115 })
* cy.get("body").realClick({ x: 11, y: 12 }) // global click by coordinates
*/
x?: number;
/** X coordinate to click, relative to the Element. Overrides `position`.
* @example
* cy.get("canvas").realClick({ x: 100, y: 115 })
* cy.get("body").realClick({ x: 11, y: 12 }) // global click by coordinates
*/
y?: number;
}


/** @ignore this, update documentation for this function at index.d.ts */
export async function realClick(
subject: JQuery,
options: RealClickOptions = {}
) {
const { x, y } = getCypressElementCoordinates(subject);
// prettier-ignore
const position = options.x && options.y
? { x: options.x, y: options.y }
: options.position;

const { x, y } = getCypressElementCoordinates(subject, position);

const log = Cypress.log({
$el: subject,
name: "realClick",
consoleProps: () => ({
"Applied To": subject.get(0),
"Absolute Coords": { x, y },
"Absolute Coordinates": { x, y },
}),
});

Expand Down
15 changes: 13 additions & 2 deletions src/commands/realHover.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import { fireCdpCommand } from "../fireCdpCommand";
import { getCypressElementCoordinates } from "../getCypressElementCoordinates";
import {
Position,
getCypressElementCoordinates,
} from "../getCypressElementCoordinates";

export interface RealHoverOptions {
/**
* If set to `pen`, simulates touch based hover (via long press)
*/
pointer?: "mouse" | "pen";
/**
* Position relative to the element where to hover the element.
* @example cy.realHover({ position: "topLeft" })
*/
position?: Position;
}

/** @ignore this, update documentation for this function at index.d.ts */
export async function realHover(
subject: JQuery,
options: RealHoverOptions = {}
) {
const { x, y } = getCypressElementCoordinates(subject);
const { x, y } = getCypressElementCoordinates(subject, options.position);

const log = Cypress.log({
$el: subject,
Expand Down
65 changes: 61 additions & 4 deletions src/getCypressElementCoordinates.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
export type Position =
| "topLeft"
| "top"
| "topRight"
| "left"
| "center"
| "right"
| "bottomLeft"
| "bottom"
| "bottomRight"
| { x: number; y: number };

function getPositionedCoordinates(
x0: number,
y0: number,
width: number,
height: number,
position: Position
) {
if (typeof position === "object" && position !== null) {
const { x, y } = position;
return [x0 + x, y0 + y];
}

switch (position) {
case "topLeft":
return [x0, y0];
case "top":
return [x0 + width / 2, y0];
case "topRight":
return [x0 + width - 1, y0];
case "left":
return [x0, y0 + height / 2];
case "right":
return [x0 + width - 1, y0 + height / 2];
case "bottomLeft":
return [x0, y0 + height - 1];
case "bottom":
return [x0 + width / 2, y0 + height - 1];
case "bottomRight":
return [x0 + width - 1, y0 + height - 1];
// center by default
default:
return [x0 + width / 2, y0 + height / 2];
}
}

/**
* Cypress Automation debuggee is the whole tab.
* Cypress Automation debugee is the whole tab.
* This function returns the element coordinates relative to the whole tab rot.
* @param jqueryEl the element to introspect
*/
export function getCypressElementCoordinates(jqueryEl: JQuery) {
export function getCypressElementCoordinates(
jqueryEl: JQuery,
position: Position | undefined
) {
const htmlElement = jqueryEl.get(0);
const cypressAppFrame = window.parent.document.querySelector("iframe");

Expand All @@ -25,9 +75,16 @@ export function getCypressElementCoordinates(jqueryEl: JQuery) {

htmlElement.scrollIntoView({ block: "center" });
const { x, y, width, height } = htmlElement.getBoundingClientRect();
const [posX, posY] = getPositionedCoordinates(
x,
y,
width,
height,
position ?? "center"
);

return {
x: appFrameX + (x + window.pageXOffset + width / 2) * appFrameScale,
y: appFrameY + (y + window.pageYOffset + height / 2) * appFrameScale,
x: appFrameX + (window.pageXOffset + posX) * appFrameScale,
y: appFrameY + (window.pageYOffset + posY) * appFrameScale,
};
}

0 comments on commit 816a668

Please sign in to comment.