docs(test runner): put more example in various sections (#6812)

This commit is contained in:
Dmitry Gozman 2021-05-31 22:01:21 -07:00 committed by GitHub
parent 98fc8b1739
commit 5fd15d8a5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 327 additions and 154 deletions

View file

@ -1,12 +1,10 @@
--- ---
id: test-advanced id: test-advanced
title: "Advanced: Configuration" title: "Advanced: configuration"
--- ---
<!-- TOC --> <!-- TOC -->
<br/>
## Project configuration ## Project configuration
- `metadata: any` - Any JSON-serializable metadata that will be put directly to the test report. - `metadata: any` - Any JSON-serializable metadata that will be put directly to the test report.

View file

@ -1,6 +1,6 @@
--- ---
id: test-cli id: test-cli
title: "Advanced: Command Line" title: "Advanced: command line"
--- ---
```sh ```sh

View file

@ -305,3 +305,127 @@ There are many more things you can do with projects:
:::note :::note
`--browser` command line option is not compatible with projects. Specify `browserName` in each project instead. `--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
});
```

View file

@ -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!");
});
```

View file

@ -1,6 +1,6 @@
--- ---
id: test-fixtures id: test-fixtures
title: "Advanced: Fixtures" title: "Advanced: fixtures"
--- ---
<!-- TOC --> <!-- TOC -->

144
docs/src/test-pom.md Normal file
View 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'
]);
});
```

View file

@ -194,7 +194,7 @@ module.exports = {
}; };
``` ```
```js ```ts
// playwright.config.ts // playwright.config.ts
import { PlaywrightTestConfig } from 'playwright/test'; import { PlaywrightTestConfig } from 'playwright/test';
@ -221,7 +221,7 @@ module.exports = {
}; };
``` ```
```js ```ts
// playwright.config.ts // playwright.config.ts
import { PlaywrightTestConfig } from 'playwright/test'; import { PlaywrightTestConfig } from 'playwright/test';

View file

@ -1,9 +1,9 @@
--- ---
id: test-snapshots 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 ```js
// example.spec.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. 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.