Skip to content

Commit

Permalink
1.3.0 (#35)
Browse files Browse the repository at this point in the history
* feat: add option changing scrolling behavior (#30)

* feat: allow changing scrolling behavior for realClick and realHover

* feat: Fallback to Cypress.config('scrollBehavior')

* feat: Add specs for scrollBehavior to click and hover

* fix: ignore TS errors or Cypress <6.1.0

* fix: remove false option for scrollBehavior

* fix: bump dev dependency for cypress to 6.1 for compilation error

* [] Move scrollBehavior specs directly into click.spec and hover.spec

* [] Fix failing swipe tests by passing scrollBehavior

* Reduce renames

* Remove unused option

Co-authored-by: Dmitriy Kovalenko <[email protected]>

* Add support for radius options in realTouch (#31)

* test: add test for radius options in realTouch (#32)

* fix(realTouch): accept 0 for position x/y values (#33)

* feat: Transpile files to cjs (#34)

* fix: calculate positions for elements inside iframes correctly (#29)

* fix: calculate positions for elements inside iframes correctly

* Handle iframes with scale transforms

* [] Refactor getCypressElementCoordinates to better handle scaled frames

* [] Add tests for click and hover in iframes

* [] Add HTML files to fixtures folder

* Remove unnecessary @ts-expect-error

* Change logic of get cypress element

* Make swipe tests retryable

Co-authored-by: Dmitriy Kovalenko <[email protected]>

* Fix touch radius test

Co-authored-by: Kevin Fleischman <[email protected]>
Co-authored-by: Mateusz Burzyński <[email protected]>
Co-authored-by: Izhaki <[email protected]>
Co-authored-by: Kevin Fleischman <[email protected]>
  • Loading branch information
5 people authored Mar 5, 2021
1 parent 857dae6 commit db00220
Show file tree
Hide file tree
Showing 15 changed files with 539 additions and 43 deletions.
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ If you are using typescript, also add the following to `cypress/tsconfig.json`

## API

The idea of the commands – they should be as similar as possible to cypress default commands (like `cy.type`), but starts with `real` – `cy.realType`.
The idea of the commands – they should be as similar as possible to cypress default commands (like `cy.type`), but starts with `real` – `cy.realType`.

Here is an overview of the available **real** event commands:
- [cy.realClick](#cyrealclick)
Expand All @@ -90,7 +90,7 @@ cy.get("button").realClick();
cy.get("button").realClick(options);
```

Example:
Example:

```js
cy.get("button").realClick({ position: "topLeft" }) // click on the top left corner of button
Expand All @@ -101,11 +101,11 @@ Options:

- `Optional` **button**: \"none\" \| \"left\" \| \"right\" \| \"middle\" \| \"back\" \| \"forward\"
- `Optional` **pointer**: \"mouse\" \| \"pen\"
- `Optional` x coordinate to click **x**: number
- `Optional` x coordinate to click **x**: number
- `Optional` y coordinate to click **y**: number
- `Optional` **position**: "topLeft" | "top" | "topRight" | "left" | "center" | "right" | "bottomLeft" | "bottom" | "bottomRight"

> Make sure that `x` and `y` has a bigger priority than `position`.
> Make sure that `x` and `y` has a bigger priority than `position`.
## cy.realHover

Expand All @@ -124,7 +124,7 @@ Options:
## cy.realPress

Fires native press event. It can fire one key event or the "shortcut" like Shift+Control+M.
Make sure that event is global, it means that it is required to **firstly** focus any control before firing this event.
Make sure that event is global, it means that it is required to **firstly** focus any control before firing this event.

```jsx
cy.realPress("Tab"); // switch the focus for a11y testing
Expand Down Expand Up @@ -154,7 +154,7 @@ cy.get("button").realTouch();
cy.get("button").realTouch(options);
```

##### Usage:
##### Usage:

```js
cy.get("button").realTouch({ position: "topLeft" }) // touches the top left corner of button
Expand All @@ -166,6 +166,9 @@ Options:
- `Optional` **x**: undefined \| number **`default`** 30
- `Optional` **y**: undefined \| false \| true **`default`** true
- `Optional` **position**: "topLeft" | "top" | "topRight" | "left" | "center" | "right" | "bottomLeft" | "bottom" | "bottomRight"
- `Optional` **radius**: undefined \| number **`default`** 1
- `Optional` **radiusX**: undefined \| number **`default`** 1
- `Optional` **radiusY**: undefined \| number **`default`** 1

### cy.realType

Expand Down Expand Up @@ -204,7 +207,7 @@ Options:

Runs a native swipe events. It means that **touch events** will be fired. Actually a sequence of `touchStart` -> `touchMove` -> `touchEnd`. It can perfectly swipe drawers and other tools [like this one](https://csb-dhe0i-qj8xxmx8y.vercel.app/).

> Make sure to enable mobile viewport :)
> Make sure to enable mobile viewport :)

```js
Expand All @@ -229,7 +232,7 @@ cy.realType(direction, options);
Options:

- `Optional` **length**: undefined \| number **`default`** 10
- `Optional` x coordinate to touch **x**: number
- `Optional` x coordinate to touch **x**: number
- `Optional` y coordinate to touch **y**: number
- `Optional` **touchPosition**: "topLeft" | "top" | "topRight" | "left" | "center" | "right" | "bottomLeft" | "bottom" | "bottomRight"

Expand Down
15 changes: 15 additions & 0 deletions cypress/fixtures/frame-one.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html>
<body>
<main style="background-color: yellow; height: 100%; padding: 50px;">
<iframe style="width: 100%; height: 100%; " src="./frame-two.html"></iframe>
</main>
</body>

<style>
* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; }
</style>
</html>

22 changes: 22 additions & 0 deletions cypress/fixtures/frame-two.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<!doctype html>
<html>
<body>
<main style="background-color: blue; height: 100%; padding: 50px;">
<div id="target"></div>
</main>
</body>

<script type="text/javascript">
document.getElementById('target').onclick = function(e) { e.target.textContent = "clicked" };
</script>

<style>
#target { width: 100px; height: 100px; background: green; }
#target:hover { background: pink; }

* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; }
</style>
</html>

14 changes: 14 additions & 0 deletions cypress/fixtures/iframe-page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html>
<body>
<main style="background-color: red; height: 100%; padding: 50px;">
<iframe style="width: 100%; height: 100%; " src="./frame-one.html"></iframe>
</main>
</body>

<style>
* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; }
</style>
</html>
138 changes: 137 additions & 1 deletion cypress/integration/click.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,146 @@ describe("cy.realClick", () => {
.realClick({ x: 100, y: 185 })
.realClick({ x: 125, y: 190 })
.realClick({ x: 150, y: 185 })
.realClick({ x: 170, y: 165 } )
.realClick({ x: 170, y: 165 });
});

it("opens system native event on right click", () => {
cy.get(".action-btn").realClick({ button: "right" });
});

describe("scroll behavior", () => {
function getScreenEdges() {
const cypressAppWindow = window.parent.document.querySelector("iframe")
.contentWindow;
const windowTopEdge = cypressAppWindow.document.documentElement.scrollTop;
const windowBottomEdge = windowTopEdge + cypressAppWindow.innerHeight;
const windowCenter = windowTopEdge + cypressAppWindow.innerHeight / 2;

return {
top: windowTopEdge,
bottom: windowBottomEdge,
center: windowCenter,
};
}

function getElementEdges($el: JQuery) {
const $elTop = $el.offset().top;

return {
top: $elTop,
bottom: $elTop + $el.outerHeight(),
};
}

beforeEach(() => {
cy.window().scrollTo("top");
});

it("defaults to scrolling the element to the top of the viewport", () => {
cy.get("#action-canvas")
.realClick()
.then(($canvas: JQuery) => {
const { top: $elTop } = getElementEdges($canvas);
const { top: screenTop } = getScreenEdges();

expect($elTop).to.equal(screenTop);
});
});

it("scrolls the element to center of viewport", () => {
cy.get("#action-canvas")
.realClick({ scrollBehavior: "center" })
.then(($canvas: JQuery) => {
const { top: $elTop, bottom: $elBottom } = getElementEdges($canvas);
const { top: screenTop, bottom: screenBottom } = getScreenEdges();

const screenCenter = screenTop + (screenBottom - screenTop) / 2;

expect($elTop).to.equal(screenCenter - $canvas.outerHeight() / 2);
expect($elBottom).to.equal(screenCenter + $canvas.outerHeight() / 2);
});
});

it("scrolls the element to the top of the viewport", () => {
cy.get("#action-canvas")
.realClick({ scrollBehavior: "top" })
.then(($canvas: JQuery) => {
const { top: $elTop } = getElementEdges($canvas);
const { top: screenTop } = getScreenEdges();

expect($elTop).to.equal(screenTop);
});
});

it("scrolls the element to the bottom of the viewport", () => {
cy.get("#action-canvas")
.realClick({ scrollBehavior: "bottom" })
.then(($canvas: JQuery) => {
const { bottom: $elBottom } = getElementEdges($canvas);
const { bottom: screenBottom } = getScreenEdges();

expect($elBottom).to.equal(screenBottom);
});
});

it("scrolls the element to the nearest edge of the viewport", () => {
cy.window().scrollTo("bottom");

cy.get("#action-canvas")
.realClick({ scrollBehavior: "nearest" })
.then(($canvas: JQuery) => {
const { top: $elTop } = getElementEdges($canvas);
const { top: screenTop } = getScreenEdges();

expect($elTop).to.equal(screenTop);
});

cy.window().scrollTo("top");

cy.get("#action-canvas")
.realClick({ scrollBehavior: "nearest" })
.then(($canvas: JQuery) => {
const { bottom: $elBottom } = getElementEdges($canvas);
const { bottom: screenBottom } = getScreenEdges();

expect($elBottom).to.equal(screenBottom);
});
});
});
});

describe("iframe behavior", () => {
beforeEach(() => {
cy.visit("./cypress/fixtures/iframe-page.html");
});

it("clicks elements inside iframes", () => {
cy.get("iframe")
.then(($firstIframe) => {
return cy.wrap($firstIframe.contents().find("iframe"));
})
.then(($secondIframe) => {
return cy.wrap($secondIframe.contents().find("body"));
})
.within(() => {
cy.get("#target").contains("clicked").should("not.exist");
cy.get("#target").realClick().contains("clicked").should("exist");
});
});

it("clicks elements inside transformed iframes", () => {
cy.get("iframe")
.then(($firstIframe) => {
$firstIframe.css("transform", "scale(.5)");
return cy.wrap($firstIframe.contents().find("iframe"));
})
.then(($secondIframe) => {
$secondIframe.css("transform", "scale(.75)");
return cy.wrap($secondIframe.contents().find("body"));
})
.within(() => {
cy.get("#target").contains("clicked").should("not.exist");
cy.get("#target").realClick().contains("clicked").should("exist");
});
});
});
Loading

0 comments on commit db00220

Please sign in to comment.