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

docs: added guide for Playwright #11498

Closed
wants to merge 1 commit into from
Closed
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
191 changes: 191 additions & 0 deletions docs/Playwright.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
id: playwright
title: Using with Playwright
---

With the [Global Setup/Teardown](Configuration.md#globalsetup-string) and [Async Test Environment](Configuration.md#testenvironment-string) APIs, Jest can work smoothly with [Playwright](https://github.com/microsoft/playwright).

## Use jest-playwright Preset

[jest-playwright-preset](https://github.com/playwright-community/jest-playwright) provides all required configuration to run your tests using Playwright.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +8 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
## Use jest-playwright Preset
[jest-playwright-preset](https://github.com/playwright-community/jest-playwright) provides all required configuration to run your tests using Playwright.
## Playwright Test
The recommended approach to using Playwright is the [Playwright Test](https://playwright.dev/docs/intro) test runner, which heavily uses Jest's [`expect`](https://jestjs.io/docs/expect) internally, to power assertions. `expect` is also exposed via [`test.expect`](https://playwright.dev/docs/api/class-test#test-expect).
## Jest Playwright
[jest-playwright-preset](https://github.com/playwright-community/jest-playwright) provides all required configuration to run your tests using Playwright.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Just in case this PR is revived later, here's the small addition I wrote over the weekend, but hadn't gotten around to submitting)


1. First, install `jest-playwright-preset` and `playwright`

```
yarn add --dev jest-playwright-preset playwright
```

2. Specify preset in your [Jest configuration](Configuration.md):

```js
module.exports = {
'preset': 'jest-playwright-preset',
// It's useful to have it > 30 seconds because Playwright will wait by default up to 30 seconds
// e.g. for a click and otherwise there is no good error reporting guaranteed.
'testTimeout': 60000,
}
```

3. Write your test

```js
describe('Google', () => {
beforeAll(async () => {
await page.goto('https://www.google.com');
});

it('should be titled "Google"', async () => {
expect(await page.title()).toBe('Google');
});
});
```

There's no need to launch the browser manually. Playwright's `page`, `context`, and `browser` classes will automatically be exposed as global variables see [here](https://github.com/playwright-community/jest-playwright#globals).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There's no need to launch the browser manually. Playwright's `page`, `context`, and `browser` classes will automatically be exposed as global variables see [here](https://github.com/playwright-community/jest-playwright#globals).
There's no need to launch the browser manually. Playwright's `page`, `context`, and `browser` classes will automatically be exposed as global variables see [here](https://github.com/playwright-community/jest-playwright/blob/master/README.md#globals).

otherwise link doesn't work on mobile

Copy link
Contributor

@mrienstra mrienstra Oct 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option (not necessarily any better than @SimenB's suggestion), tested on iOS:
https://github.com/playwright-community/jest-playwright#user-content-globals

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works on android as well 🙂


You can also create a new context and page for each test to have them isolated from each other, see [here](https://github.com/playwright-community/jest-playwright#reset-current-context).

## Custom example without jest-playwright-preset

You can also hook up Playwright with Jest from scratch. The basic idea is to:

1. launch a Playwright BrowserServer and save the websocket endpoint to disk with Global Setup
2. connect to Playwright from each Test Environment
3. close the BrowserServer with Global Teardown

We have a small constants file where we store our shared used variables:

```js
// constants.js
const os = require('os');
const path = require('path');

const BROWSER_NAME = process.env.BROWSER || 'chromium';
const ENVIRONMENT_DATA_TRANSFER_DIR = path.join(os.tmpdir(), 'jest_playwright_global_setup');
const ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT = path.join(ENVIRONMENT_DATA_TRANSFER_DIR, 'ws_endpoint');

module.exports = {
BROWSER_NAME,
ENVIRONMENT_DATA_TRANSFER_DIR,
ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT,
}
```

Here's an example of the GlobalSetup script

```js
// setup.js
const fs = require('fs');
const mkdirp = require('mkdirp');
const playwright = require('playwright');
const { ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT, BROWSER_NAME, ENVIRONMENT_DATA_TRANSFER_DIR } = require('./constants.js');

module.exports = async function () {
const browser = await playwright[BROWSER_NAME].launchServer();
// This global is not available inside tests but only in global teardown
global.__BROWSER_GLOBAL__ = browser;
// Instead, we expose the connection details via file system to be used in tests
await mkdirp(ENVIRONMENT_DATA_TRANSFER_DIR);
await fs.promises.writeFile(ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT, browser.wsEndpoint());
}
```

Then we need a custom Test Environment for Playwright

```js
// playwright_environment.js
const fs = require('fs');
const playwright = require('playwright');
const NodeEnvironment = require('jest-environment-node');
const { BROWSER_NAME, ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT } = require('./constants.js');

class PlaywrightEnvironment extends NodeEnvironment {
async setup() {
await super.setup();
const wsEndpoint = await fs.promises.readFile(ENVIRONMENT_DATA_TRANSFER_WS_ENDPOINT, 'utf8');
if (!wsEndpoint) {
throw new Error('wsEndpoint not found');
}
this.global.__BROWSER_NAME__ = BROWSER_NAME;
this.global.__BROWSER__ = await playwright[BROWSER_NAME].connect({
wsEndpoint,
});
}

async teardown() {
await this.global.__BROWSER__.close();
await super.teardown();
}
/**
// For having a new context in each test, you can use the following method where Jest will internally
// send the events to, and based on the events new context/page instances get created/closed.

async handleTestEvent(event, state) {
switch (event.name) {
case 'test_start':
this.global.context = await this.global.__BROWSER__.newContext();
this.global.page = await this.global.context.newPage();
break;
case 'test_done':
await this.global.context.close();
break;
}
}
*/
}

module.exports = PlaywrightEnvironment
```

Finally, we can close the Playwright BrowserServer and clean-up the file

```js
// teardown.js
const rimraf = require('rimraf');
const { ENVIRONMENT_DATA_TRANSFER_DIR } = require('./constants');

module.exports = async function() {
await global.__BROWSER_GLOBAL__.close();
rimraf.sync(ENVIRONMENT_DATA_TRANSFER_DIR);
}
```

With all the things set up, we can now write our tests like this:

```js
// test.js

describe('/ (Home Page)', () => {
/** @type {import('playwright').Page} */
let page;
/** @type {import('playwright').BrowserContext} */
let context;
beforeAll(async () => {
context = await global.__BROWSER__.newContext();
page = await context.newPage();
await page.goto('https://www.google.com');
});

afterAll(async () => {
await context.close();
})

it('should load without error', async () => {
const text = await page.evaluate(() => document.body.textContent);
expect(text).toContain('google');
});
});
```

Finally, set `jest.config.js` to read from these files. (The `jest-playwright-preset` does something like this under the hood.)

```js
module.exports = {
globalSetup: './setup.js',
globalTeardown: './teardown.js',
testEnvironment: './playwright_environment.js',
// It's useful to have it > 30 seconds because Playwright will wait by default up to 30 seconds and otherwise there is no good error reporting guaranteed.
testTimeout: 60000,
};
```

Here's the code of a [full working example](https://github.com/mxschmitt/jest-playwright-example) and [here](https://github.com/mxschmitt/jest-playwright-example-esm) with ES modules.
10 changes: 3 additions & 7 deletions website/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Jest website

The Jest website is based on [Docusaurus 2](http://v2.docusaurus.io/).
The Jest website is based on [Docusaurus 2](https://docusaurus.io).

## Run the dev server

Expand All @@ -12,22 +12,18 @@ The first time, get all the dependencies loaded via
yarn
```

in the root directory.

Fetch `backers.json` file by running

```bash
node fetchSupporters.js
yarn workspace jest-website fetchSupporters
```

Then, run the server via

```bash
yarn start
yarn workspace jest-website start
```

Note, you can also use `yarn workspace jest-website start` from the root of the Jest monorepo.

## Publish the website

The site is deployed on each PR merged to master by Netlify:
Expand Down
1 change: 1 addition & 0 deletions website/sidebars.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"ecmascript-modules",
"webpack",
"puppeteer",
"playwright",
"mongodb",
"dynamodb",
"tutorial-jquery",
Expand Down