Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: revert types resolution from @jest/globals #604

Merged
merged 1 commit into from
Oct 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
524 changes: 333 additions & 191 deletions README.md

Large diffs are not rendered by default.

37 changes: 18 additions & 19 deletions packages/expect-puppeteer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Modify your Jest configuration:

Writing integration test is very hard, especially when you are testing a Single Page Applications. Data are loaded asynchronously and it is difficult to know exactly when an element will be displayed in the page.

[Puppeteer API](https://pptr.dev/api) is great, but it is low level and not designed for integration testing.
[Puppeteer API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md) is great, but it is low level and not designed for integration testing.

This API is designed for integration testing:

Expand Down Expand Up @@ -81,11 +81,11 @@ await expect(page).toMatchElement("div.inner", { text: "some text" });

Expect an element to be in the page or element, then click on it.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to click on.
- `options` <[Object]> Optional parameters
- `button` <"left"|"right"|"middle"> Defaults to `left`.
- `count` <[number]> defaults to 1. See [UIEvent.detail].
- `clickCount` <[number]> defaults to 1. See [UIEvent.detail].
- `delay` <[number]> Time to wait between `mousedown` and `mouseup` in milliseconds. Defaults to 0.
- `text` <[string]|[RegExp]> A text or a RegExp to match in element `textContent`.

Expand All @@ -111,8 +111,8 @@ const dialog = await expect(page).toDisplayDialog(async () => {

Expect a control to be in the page or element, then fill it with text.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to match field
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]> A [selector] to match field
- `value` <[string]> Value to fill
- `options` <[Object]> Optional parameters
- `delay` <[number]> delay to pass to [the puppeteer `element.type` API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#elementhandletypetext-options)
Expand All @@ -125,8 +125,8 @@ await expect(page).toFill('input[name="firstName"]', "James");

Expect a form to be in the page or element, then fill its controls.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to match form
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]> A [selector] to match form
- `values` <[Object]> Values to fill
- `options` <[Object]> Optional parameters
- `delay` <[number]> delay to pass to [the puppeteer `element.type` API](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#elementhandletypetext-options)
Expand All @@ -142,7 +142,7 @@ await expect(page).toFillForm('form[name="myForm"]', {

Expect a text or a string RegExp to be present in the page or element.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `instance` <[Page]|[ElementHandle]> Context
- `matcher` <[string]|[RegExp]> A text or a RegExp to match in page
- `options` <[Object]> Optional parameters
- `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
Expand All @@ -162,8 +162,8 @@ await expect(page).toMatchTextContent(/lo.*/);

Expect an element be present in the page or element.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to match element
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]> A [selector] to match element
- `options` <[Object]> Optional parameters
- `polling` <[string]|[number]> An interval at which the `pageFunction` is executed, defaults to `raf`. If `polling` is a number, then it is treated as an interval in milliseconds at which the function would be executed. If `polling` is a string, then it can be one of the following values:
- `raf` - to constantly execute `pageFunction` in `requestAnimationFrame` callback. This is the tightest polling mode which is suitable to observe styling changes.
Expand All @@ -183,8 +183,8 @@ await expect(row).toClick("td:nth-child(3) a");

Expect a select control to be present in the page or element, then select the specified option.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to match select [element]
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]> A [selector] to match select [element]
- `valueOrText` <[string]> Value or text matching option

```js
Expand All @@ -195,9 +195,9 @@ await expect(page).toSelect('select[name="choices"]', "Choice 1");

Expect a input file control to be present in the page or element, then fill it with a local file.

- `instance` <[Page]|[Frame]|[ElementHandle]> Context
- `selector` <[string]|[MatchSelector](#MatchSelector)> A [selector] or a [MatchSelector](#MatchSelector) to match input [element]
- `filePath` <[string]|[Array]<[string]>> A file path or array of file paths
- `instance` <[Page]|[ElementHandle]> Context
- `selector` <[string]> A [selector] to match input [element]
- `filePath` <[string]> A file path

```js
import { join } from "node:path";
Expand All @@ -208,7 +208,7 @@ await expect(page).toUploadFile(
);
```

### <a name="MatchSelector"></a>Match Selector
### <a name="MatchSelector"></a>{type: [string], value: [string]}

An object used as parameter in order to select an element.

Expand Down Expand Up @@ -242,7 +242,6 @@ setDefaultOptions({ timeout: 1000 });
[element]: https://developer.mozilla.org/en-US/docs/Web/API/element "Element"
[map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map "Map"
[selector]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors "selector"
[page]: https://pptr.dev/api/puppeteer.page "Page"
[frame]: https://pptr.dev/api/puppeteer.frame "Frame"
[elementhandle]: https://pptr.dev/api/puppeteer.elementhandle/ "ElementHandle"
[page]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-page "Page"
[elementhandle]: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#class-elementhandle "ElementHandle"
[uievent.detail]: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail
1 change: 1 addition & 0 deletions packages/expect-puppeteer/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getDefaultOptions, setDefaultOptions } from "expect-puppeteer";

// import globals
import "jest-puppeteer";
import "expect-puppeteer";

expect.addSnapshotSerializer({
print: () => "hello",
Expand Down
91 changes: 41 additions & 50 deletions packages/expect-puppeteer/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ type Wrapper<T> = T extends (
? (...args: A) => R
: never;

// declare common matchers list
type InstanceMatchers<T> = T extends PuppeteerInstance
// declare matchers list
type PuppeteerMatchers<T> = T extends PuppeteerInstance
? {
// common
toClick: Wrapper<typeof toClick>;
Expand All @@ -64,24 +64,24 @@ type InstanceMatchers<T> = T extends PuppeteerInstance
: never;

// declare page matchers list
interface PageMatchers extends InstanceMatchers<Page> {
interface PageMatchers extends PuppeteerMatchers<Page> {
// instance specific
toDisplayDialog: Wrapper<typeof toDisplayDialog>;
// inverse matchers
not: InstanceMatchers<Page>[`not`] & {};
not: PuppeteerMatchers<Page>[`not`] & {};
}

// declare frame matchers list
interface FrameMatchers extends InstanceMatchers<Frame> {
interface FrameMatchers extends PuppeteerMatchers<Frame> {
// inverse matchers
not: InstanceMatchers<Frame>[`not`] & {};
not: PuppeteerMatchers<Frame>[`not`] & {};
}

// declare element matchers list
interface ElementHandleMatchers
extends InstanceMatchers<ElementHandle<Element>> {
extends PuppeteerMatchers<ElementHandle<Element>> {
// inverse matchers
not: InstanceMatchers<ElementHandle<Element>>[`not`] & {};
not: PuppeteerMatchers<ElementHandle<Element>>[`not`] & {};
}

// declare matchers per instance type
Expand All @@ -103,50 +103,43 @@ type GlobalWithExpect = typeof globalThis & { expect: PuppeteerExpect };

// ---------------------------

// not possible to use PMatchersPerType directly ...
interface PuppeteerMatchers<T> {
// common
toClick: T extends PuppeteerInstance ? Wrapper<typeof toClick> : never;
toFill: T extends PuppeteerInstance ? Wrapper<typeof toFill> : never;
toFillForm: T extends PuppeteerInstance ? Wrapper<typeof toFillForm> : never;
toMatchTextContent: T extends PuppeteerInstance
? Wrapper<typeof toMatchTextContent>
: never;
toMatchElement: T extends PuppeteerInstance
? Wrapper<typeof toMatchElement>
: never;
toSelect: T extends PuppeteerInstance ? Wrapper<typeof toSelect> : never;
toUploadFile: T extends PuppeteerInstance
? Wrapper<typeof toUploadFile>
: never;
// page
toDisplayDialog: T extends Page ? Wrapper<typeof toDisplayDialog> : never;
// inverse matchers
not: {
toMatchTextContent: T extends PuppeteerInstance
? Wrapper<typeof notToMatchTextContent>
: never;
toMatchElement: T extends PuppeteerInstance
? Wrapper<typeof notToMatchElement>
: never;
};
}

// support for @types/jest
// extend global jest object
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unused-vars
interface Matchers<R, T> extends PuppeteerMatchers<T> {}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface Matchers<R, T> {
// common
toClick: T extends PuppeteerInstance ? Wrapper<typeof toClick> : never;
toFill: T extends PuppeteerInstance ? Wrapper<typeof toFill> : never;
toFillForm: T extends PuppeteerInstance
? Wrapper<typeof toFillForm>
: never;
toMatchTextContent: T extends PuppeteerInstance
? Wrapper<typeof toMatchTextContent>
: never;
toMatchElement: T extends PuppeteerInstance
? Wrapper<typeof toMatchElement>
: never;
toSelect: T extends PuppeteerInstance ? Wrapper<typeof toSelect> : never;
toUploadFile: T extends PuppeteerInstance
? Wrapper<typeof toUploadFile>
: never;
// page
toDisplayDialog: T extends Page ? Wrapper<typeof toDisplayDialog> : never;
// inverse matchers
not: {
toMatchTextContent: T extends PuppeteerInstance
? Wrapper<typeof notToMatchTextContent>
: never;
toMatchElement: T extends PuppeteerInstance
? Wrapper<typeof notToMatchElement>
: never;
};
}
}
}

// support for @jest/types
declare module "@jest/expect" {
// eslint-disable-next-line @typescript-eslint/no-empty-object-type, @typescript-eslint/no-unused-vars
interface Matchers<R, T> extends PuppeteerMatchers<T> {}
}

// ---------------------------
// @ts-expect-error global node object w/ initial jest expect prop attached
const jestExpect = global.expect as JestExpect;
Expand All @@ -158,7 +151,7 @@ const wrapMatcher = <T extends PuppeteerInstance>(
instance: T,
) =>
async function throwingMatcher(...args: unknown[]): Promise<unknown> {
// update the assertions counter
// ???
jestExpect.getState().assertionCalls += 1;
try {
// run async matcher
Expand All @@ -183,9 +176,7 @@ const puppeteerExpect = <T extends PuppeteerInstance>(instance: T) => {
];

if (!isPage && !isFrame && !isHandle)
throw new Error(
`${String(instance?.constructor?.name ?? `current instance`)} is not supported`,
);
throw new Error(`${instance} is not supported`);

// retrieve matchers
const expectation = {
Expand Down
4 changes: 2 additions & 2 deletions packages/expect-puppeteer/src/matchers/toClick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function toClick(
selector: Selector | string,
options: ToClickOptions = {},
) {
const { delay, button, count, offset, ...otherOptions } = options;
const { delay, button, clickCount, offset, ...otherOptions } = options;
const element = await toMatchElement(instance, selector, otherOptions);
await element.click({ delay, button, count, offset });
await element.click({ delay, button, clickCount, offset });
}
11 changes: 0 additions & 11 deletions packages/jest-environment-puppeteer/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [10.1.3](https://github.com/argos-ci/jest-puppeteer/compare/v10.1.2...v10.1.3) (2024-10-22)


### Bug Fixes

* fix types resolution when importing jest types from @jest/globals ([#602](https://github.com/argos-ci/jest-puppeteer/issues/602)) ([e5b2e1a](https://github.com/argos-ci/jest-puppeteer/commit/e5b2e1a7c0282aba496ffe2806201778b84a96fc))





## [10.1.2](https://github.com/argos-ci/jest-puppeteer/compare/v10.1.1...v10.1.2) (2024-10-10)


Expand Down
15 changes: 0 additions & 15 deletions packages/jest-environment-puppeteer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,6 @@ describe("Google", () => {
});
```

## Use with TypeScript

_Note : If you have upgraded to version v10.1.2 or above, we strongly recommend that you uninstall the community provided types :_

```bash
npm uninstall --save-dev @types/jest-environment-puppeteer @types/expect-puppeteer
```

If using TypeScript, jest-puppeteer has to be explicitly imported in order to expose the global API :

```ts
// import jest-puppeteer globals
import "jest-puppeteer";
```

## API

### `global.browser`
Expand Down
1 change: 1 addition & 0 deletions packages/jest-environment-puppeteer/tests/basic.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("Basic", () => {
beforeAll(async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("browserContext", () => {
const test = process.env.INCOGNITO ? it : it.skip;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("browserContext", () => {
const test = process.env.INCOGNITO ? it : it.skip;
Expand Down
1 change: 1 addition & 0 deletions packages/jest-environment-puppeteer/tests/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readConfig } from "../src/config";

// import globals
import "jest-puppeteer";
import "expect-puppeteer";

// This test does not run on Node.js < v20 (segfault)
xdescribe("readConfig", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("resetBrowser", () => {
test("should reset browser", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("resetPage", () => {
test("should reset page", async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// import globals
import "jest-puppeteer";
import "expect-puppeteer";

describe("runBeforeUnloadOnClose", () => {
it("shouldn’t call page.close with runBeforeUnload by default", async () => {
Expand Down
Loading