docs(test runner): put more example in various sections (#6812)
This commit is contained in:
parent
98fc8b1739
commit
5fd15d8a5e
|
|
@ -1,12 +1,10 @@
|
|||
---
|
||||
id: test-advanced
|
||||
title: "Advanced: Configuration"
|
||||
title: "Advanced: configuration"
|
||||
---
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
<br/>
|
||||
|
||||
## Project configuration
|
||||
|
||||
- `metadata: any` - Any JSON-serializable metadata that will be put directly to the test report.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
id: test-cli
|
||||
title: "Advanced: Command Line"
|
||||
title: "Advanced: command line"
|
||||
---
|
||||
|
||||
```sh
|
||||
|
|
|
|||
|
|
@ -305,3 +305,127 @@ There are many more things you can do with projects:
|
|||
:::note
|
||||
`--browser` command line option is not compatible with projects. Specify `browserName` in each project instead.
|
||||
:::
|
||||
|
||||
## Mobile emulation
|
||||
|
||||
You can use configuration file to make default `context` emulate a mobile device.
|
||||
|
||||
Here is an example configuration that runs tests in "Pixel 4" and "iPhone 11" emulation modes. Note that it uses the [projects](./test-advanced.md#projects) feature to run the same set of tests in multiple configurations.
|
||||
|
||||
```js
|
||||
// playwright.config.js
|
||||
const { devices } = require('playwright');
|
||||
|
||||
module.exports = {
|
||||
projects: [
|
||||
// "Pixel 4" tests use Chromium browser.
|
||||
{
|
||||
name: 'Pixel 4',
|
||||
use: {
|
||||
browserName: 'chromium',
|
||||
...devices['Pixel 4'],
|
||||
},
|
||||
},
|
||||
|
||||
// "iPhone 11" tests use WebKit browser.
|
||||
{
|
||||
name: 'iPhone 11',
|
||||
use: {
|
||||
browserName: 'webkit',
|
||||
...devices['iPhone 11'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
// playwright.config.ts
|
||||
import { PlaywrightTestConfig } from 'playwright/test';
|
||||
import { devices } from 'playwright';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
projects: [
|
||||
// "Pixel 4" tests use Chromium browser.
|
||||
{
|
||||
name: 'Pixel 4',
|
||||
use: {
|
||||
browserName: 'chromium',
|
||||
...devices['Pixel 4'],
|
||||
},
|
||||
},
|
||||
|
||||
// "iPhone 11" tests use WebKit browser.
|
||||
{
|
||||
name: 'iPhone 11',
|
||||
use: {
|
||||
browserName: 'webkit',
|
||||
...devices['iPhone 11'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
export default config;
|
||||
```
|
||||
|
||||
## Network mocking
|
||||
|
||||
You don't have to configure anything to mock network requests. Just define a custom [Route] that mocks network for a browser context.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test, expect } = require('playwright/test');
|
||||
|
||||
test.beforeEach(async ({ context }) => {
|
||||
// Block any css requests for each test in this file.
|
||||
await context.route(/.css/, route => route.abort());
|
||||
});
|
||||
|
||||
test('loads page without css', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
// ... test goes here
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test, expect } from 'playwright/test';
|
||||
|
||||
test.beforeEach(async ({ context }) => {
|
||||
// Block any css requests for each test in this file.
|
||||
await context.route(/.css/, route => route.abort());
|
||||
});
|
||||
|
||||
test('loads page without css', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
// ... test goes here
|
||||
});
|
||||
```
|
||||
|
||||
Alternatively, you can use [`method: Page.route`] to mock network in a single test.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test, expect } = require('playwright/test');
|
||||
|
||||
test('loads page without images', async ({ page }) => {
|
||||
// Block png and jpeg images.
|
||||
await page.route(/(png|jpeg)$/, route => route.abort());
|
||||
|
||||
await page.goto('https://playwright.dev');
|
||||
// ... test goes here
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test, expect } from 'playwright/test';
|
||||
|
||||
test('loads page without images', async ({ page }) => {
|
||||
// Block png and jpeg images.
|
||||
await page.route(/(png|jpeg)$/, route => route.abort());
|
||||
|
||||
await page.goto('https://playwright.dev');
|
||||
// ... test goes here
|
||||
});
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,145 +0,0 @@
|
|||
---
|
||||
id: test-examples
|
||||
title: "Examples"
|
||||
---
|
||||
|
||||
<!-- TOC -->
|
||||
|
||||
## Multiple pages
|
||||
|
||||
The default `context` argument is a [BrowserContext]. Browser contexts are isolated execution environments that can host multiple pages. See [multi-page scenarios](./multi-pages.md) for more examples.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test } = require('playwright/test');
|
||||
|
||||
test('tests on multiple web pages', async ({ context }) => {
|
||||
const pageFoo = await context.newPage();
|
||||
const pageBar = await context.newPage();
|
||||
// Test function
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test } from 'playwright/test';
|
||||
|
||||
test('tests on multiple web pages', async ({ context }) => {
|
||||
const pageFoo = await context.newPage();
|
||||
const pageBar = await context.newPage();
|
||||
// Test function
|
||||
});
|
||||
```
|
||||
|
||||
## Mobile emulation
|
||||
|
||||
`use` section in the configuration file can be used to configure mobile emulation in the default `context`.
|
||||
|
||||
```js
|
||||
// config.ts
|
||||
import { PlaywrightTestConfig } from "playwright/test";
|
||||
import { devices } from "playwright";
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
timeout: 30000,
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: {
|
||||
browserName: 'chromium',
|
||||
headless: true,
|
||||
...devices["Pixel 2"],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
export default config;
|
||||
```
|
||||
|
||||
## Network mocking
|
||||
|
||||
Define a custom route that mocks network calls for a browser context.
|
||||
|
||||
```js
|
||||
// In foo.spec.ts
|
||||
import { test, expect } from "playwright/test";
|
||||
|
||||
test.beforeEach(async ({ context }) => {
|
||||
// Block any css requests for each test in this file.
|
||||
await context.route(/.css/, route => route.abort());
|
||||
});
|
||||
|
||||
test("loads page without css", async ({ page }) => {
|
||||
// Alternatively, block any png requests just for this test.
|
||||
await page.route(/.png/, route => route.abort());
|
||||
|
||||
// Test function code.
|
||||
await page.goto("https://stackoverflow.com");
|
||||
});
|
||||
```
|
||||
|
||||
## Visual comparisons
|
||||
|
||||
The `expect` API supports visual comparisons with `toMatchSnapshot`. This uses the [pixelmatch](https://github.com/mapbox/pixelmatch) library, and you can pass `threshold` as an option.
|
||||
|
||||
```js
|
||||
import { test, expect } from "playwright/test";
|
||||
|
||||
test("compares page screenshot", async ({ page }) => {
|
||||
await page.goto("https://stackoverflow.com");
|
||||
const screenshot = await page.screenshot();
|
||||
expect(screenshot).toMatchSnapshot(`test.png`, { threshold: 0.2 });
|
||||
});
|
||||
```
|
||||
|
||||
On first execution, this will generate golden snapshots. Subsequent runs will compare against the golden snapshots. To update golden snapshots with new actual values, run with the `--update-snapshots` flag.
|
||||
|
||||
```sh
|
||||
# Update golden snapshots when they differ from actual
|
||||
npx playwright test --update-snapshots
|
||||
```
|
||||
|
||||
### Page object model
|
||||
|
||||
To introduce a Page Object for a particular page, create a class that will use the `page` object.
|
||||
|
||||
Create a `LoginPage` helper class to encapsulate common operations on the login page.
|
||||
```js
|
||||
// login-page.ts
|
||||
import type { Page } from "playwright";
|
||||
|
||||
export class LoginPage {
|
||||
page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto("https://example.com/login");
|
||||
}
|
||||
|
||||
async login() {
|
||||
await this.page.fill("#username", TEST_USERNAME);
|
||||
await this.page.fill("#password", TEST_PASSWORD);
|
||||
await this.page.click("text=Login");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use the `LoginPage` class in the tests.
|
||||
```js
|
||||
// my.spec.ts
|
||||
import { test, expect } from "playwright/test";
|
||||
import { LoginPage } from "./login-page";
|
||||
|
||||
test('login works', async ({ page }) => {
|
||||
// Create the login page and perform operations.
|
||||
const loginPage = new LoginPage(page);
|
||||
await loginPage.goto();
|
||||
await loginPage.login();
|
||||
|
||||
// Verify it worked.
|
||||
expect(await page.textContent("#user-info")).toBe("Welcome, Test User!");
|
||||
});
|
||||
```
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
id: test-fixtures
|
||||
title: "Advanced: Fixtures"
|
||||
title: "Advanced: fixtures"
|
||||
---
|
||||
|
||||
<!-- TOC -->
|
||||
|
|
|
|||
144
docs/src/test-pom.md
Normal file
144
docs/src/test-pom.md
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
---
|
||||
id: test-pom
|
||||
title: "Page Object Model"
|
||||
---
|
||||
|
||||
Page Object Model is a common pattern that introduces abstractions over web app pages to simplify interactions with them in multiple tests. It is best explained by an example.
|
||||
|
||||
We will create a `PlaywrightDevPage` helper class to encapsulate common operations on the `playwright.dev` page. Internally, it will use the `page` object.
|
||||
|
||||
```js
|
||||
// playwright-dev-page.js
|
||||
exports.PlaywrightDevPage = class PlaywrightDevPage {
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto('https://playwright.dev');
|
||||
}
|
||||
|
||||
async toc() {
|
||||
const text = await this.page.innerText('article ul');
|
||||
return text.split('\n').filter(line => !!line);
|
||||
}
|
||||
|
||||
async getStarted() {
|
||||
await this.page.click('text=Get started');
|
||||
await this.page.waitForSelector(`text=Core concepts`);
|
||||
}
|
||||
|
||||
async coreConcepts() {
|
||||
await this.getStarted();
|
||||
await this.page.click('text=Core concepts');
|
||||
await this.page.waitForSelector(`h1:has-text("Core concepts")`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// playwright-dev-page.ts
|
||||
import type { Page } from 'playwright';
|
||||
|
||||
export class PlaywrightDevPage {
|
||||
readonly page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto('https://playwright.dev');
|
||||
}
|
||||
|
||||
async toc() {
|
||||
const text = await this.page.innerText('article ul');
|
||||
return text.split('\n').filter(line => !!line);
|
||||
}
|
||||
|
||||
async getStarted() {
|
||||
await this.page.click('text=Get started');
|
||||
await this.page.waitForSelector(`text=Core concepts`);
|
||||
}
|
||||
|
||||
async coreConcepts() {
|
||||
await this.getStarted();
|
||||
await this.page.click('text=Core concepts');
|
||||
await this.page.waitForSelector(`h1:has-text("Core concepts")`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now we can use the `PlaywrightDevPage` class in our tests.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test, expect } = require('playwright/test');
|
||||
const { PlaywrightDevPage } = require('./playwright-dev-page');
|
||||
|
||||
test('Get Started table of contents', async ({ page }) => {
|
||||
const playwrightDev = new PlaywrightDevPage(page);
|
||||
await playwrightDev.goto();
|
||||
await playwrightDev.getStarted();
|
||||
expect(await playwrightDev.toc()).toEqual([
|
||||
'Installation',
|
||||
'Usage',
|
||||
'First script',
|
||||
'Record scripts',
|
||||
'TypeScript support',
|
||||
'System requirements',
|
||||
'Release notes'
|
||||
]);
|
||||
});
|
||||
|
||||
test('Core Concepts table of contents', async ({ page }) => {
|
||||
const playwrightDev = new PlaywrightDevPage(page);
|
||||
await playwrightDev.goto();
|
||||
await playwrightDev.coreConcepts();
|
||||
expect(await playwrightDev.toc()).toEqual([
|
||||
'Browser',
|
||||
'Browser contexts',
|
||||
'Pages and frames',
|
||||
'Selectors',
|
||||
'Auto-waiting',
|
||||
'Execution contexts: Playwright and Browser',
|
||||
'Evaluation Argument'
|
||||
]);
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test, expect } from 'playwright/test';
|
||||
import { PlaywrightDevPage } from './playwright-dev-page';
|
||||
|
||||
test('Get Started table of contents', async ({ page }) => {
|
||||
const playwrightDev = new PlaywrightDevPage(page);
|
||||
await playwrightDev.goto();
|
||||
await playwrightDev.getStarted();
|
||||
expect(await playwrightDev.toc()).toEqual([
|
||||
'Installation',
|
||||
'Usage',
|
||||
'First script',
|
||||
'Record scripts',
|
||||
'TypeScript support',
|
||||
'System requirements',
|
||||
'Release notes'
|
||||
]);
|
||||
});
|
||||
|
||||
test('Core Concepts table of contents', async ({ page }) => {
|
||||
const playwrightDev = new PlaywrightDevPage(page);
|
||||
await playwrightDev.goto();
|
||||
await playwrightDev.coreConcepts();
|
||||
expect(await playwrightDev.toc()).toEqual([
|
||||
'Browser',
|
||||
'Browser contexts',
|
||||
'Pages and frames',
|
||||
'Selectors',
|
||||
'Auto-waiting',
|
||||
'Execution contexts: Playwright and Browser',
|
||||
'Evaluation Argument'
|
||||
]);
|
||||
});
|
||||
```
|
||||
|
|
@ -194,7 +194,7 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
```js
|
||||
```ts
|
||||
// playwright.config.ts
|
||||
import { PlaywrightTestConfig } from 'playwright/test';
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
```js
|
||||
```ts
|
||||
// playwright.config.ts
|
||||
import { PlaywrightTestConfig } from 'playwright/test';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
id: test-snapshots
|
||||
title: "Snapshots"
|
||||
title: "Visual comparisons"
|
||||
---
|
||||
|
||||
Playwright Test includes the ability to produce and compare snapshots. For that, use `expect(value).toMatchSnapshot()`. Test runner auto-detects the content type, and includes built-in matchers for text, png and jpeg images, and arbitrary binary data.
|
||||
Playwright Test includes the ability to produce and visually compare screenshots using `expect(value).toMatchSnapshot()`. On first execution, Playwright test will generate reference screenshots. Subsequent runs will compare against the reference.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
|
|
@ -25,4 +25,56 @@ test('example test', async ({ page }) => {
|
|||
});
|
||||
```
|
||||
|
||||
Sometimes you need to update the reference screenshot, for example when the page has changed. Do this with the `--update-snapshots` flag.
|
||||
|
||||
```sh
|
||||
npx playwright test --update-snapshots
|
||||
```
|
||||
|
||||
Playwright Test uses the [pixelmatch](https://github.com/mapbox/pixelmatch) library. You can pass comparison `threshold` as an option.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test, expect } = require('playwright/test');
|
||||
|
||||
test('example test', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
expect(await page.screenshot()).toMatchSnapshot({ threshold: 0.2 });
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test, expect } from 'playwright/test';
|
||||
|
||||
test('example test', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
expect(await page.screenshot()).toMatchSnapshot({ threshold: 0.2 });
|
||||
});
|
||||
```
|
||||
|
||||
Apart from screenshots, `expect(value).toMatchSnapshot()` can also be used to compare text, png and jpeg images, or arbitrary binary data. Playwright Test auto-detects the content type and uses the appropriate comparison algorithm.
|
||||
|
||||
Here we compare text content against the reference.
|
||||
|
||||
```js
|
||||
// example.spec.js
|
||||
const { test, expect } = require('playwright/test');
|
||||
|
||||
test('example test', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
expect(await page.textContent('.hero__title')).toMatchSnapshot();
|
||||
});
|
||||
```
|
||||
|
||||
```ts
|
||||
// example.spec.ts
|
||||
import { test, expect } from 'playwright/test';
|
||||
|
||||
test('example test', async ({ page }) => {
|
||||
await page.goto('https://playwright.dev');
|
||||
expect(await page.textContent('.hero__title')).toMatchSnapshot();
|
||||
});
|
||||
```
|
||||
|
||||
Snapshots are stored next to the test file, in a separate directory. For example, `my.spec.js` file will produce and store snapshots in the `my.spec.js-snapshots` directory. You should commit this directory to your version control (e.g. `git`), and review any changes to it.
|
||||
|
|
|
|||
Loading…
Reference in a new issue