From 1f34531a223e024004c8866d214b37b988419842 Mon Sep 17 00:00:00 2001 From: Debbie O'Brien Date: Thu, 8 Sep 2022 18:57:20 +0200 Subject: [PATCH] docs: Emulation improvements (#17090) --- docs/src/emulation.md | 453 +++++++++++++++++++++++------- docs/src/test-configuration-js.md | 130 +-------- 2 files changed, 357 insertions(+), 226 deletions(-) diff --git a/docs/src/emulation.md b/docs/src/emulation.md index 786f184209..12b7a9d6f0 100644 --- a/docs/src/emulation.md +++ b/docs/src/emulation.md @@ -3,37 +3,69 @@ id: emulation title: "Emulation" --- -Playwright allows overriding various parameters of the device where the browser is running: -- viewport size, device scale factor, touch support -- locale, timezone -- color scheme -- geolocation - -Most of these parameters are configured during the browser context construction, but some of them such as viewport size -can be changed for individual pages. - - - -## Playwright Test vs. Library -* langs: js - -:::caution -This guide is for [Playwright Library](./library.md), if you are using Playwright Test (`@playwright/test`) see [here](./test-configuration.md). -::: +With Playwright you can test your app on any browser as well as emulate a real device such as a mobile phone or tablet. Simply configure the devices you would like to emulate and Playwright will simulate the browser behavior such as `"userAgent"`, `"screenSize"`, `"viewport"` and if it `"hasTouch"` enabled. You can also emulate the `"geolocation"`, `"locale"` and `"timezone"` for all tests or for a specific test as well as set the `"permissions"` to show notifications or change the `"colorScheme"`. ## Devices -* langs: js, python, csharp +* langs: js, csharp, python -Playwright comes with a registry of device parameters for selected mobile devices. It can be used to simulate browser -behavior on a mobile device: +Playwright comes with a [registry of device parameters](https://github.com/microsoft/playwright/blob/main/packages/playwright-core/src/server/deviceDescriptorsSource.json) using [`property: Playwright.devices`] for selected desktop, tablet and mobile devices. It can be used to simulate browser behavior for a specific device such as user agent, screen size, viewport and if it has touch enabled. All tests will run with the specified device parameters. -```js +```js tab=js-ts +// playwright.config.ts +import { type PlaywrightTestConfig, devices } from '@playwright/test'; // import devices + +const config: PlaywrightTestConfig = { + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + { + name: 'Mobile Safari', + use: { + ...devices['iPhone 12'], + }, + }, + ], +}; +export default config; +``` + +```js tab=js-js +// playwright.config.js +// @ts-check +const { devices } = require('@playwright/test'); // require devices + +/** @type {import('@playwright/test').PlaywrightTestConfig} */ +const config = { + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + { + name: 'Mobile Safari', + use: { + ...devices['iPhone 12'], + }, + }, + ], +}; + +module.exports = config; +``` + +```js tab=js-library const { chromium, devices } = require('playwright'); const browser = await chromium.launch(); -const pixel2 = devices['Pixel 2']; +const iphone12 = devices['iPhone 12']; const context = await browser.newContext({ - ...pixel2, + ...iphone12, }); ``` @@ -42,10 +74,10 @@ import asyncio from playwright.async_api import async_playwright async def run(playwright): - pixel_2 = playwright.devices['Pixel 2'] + iphone_12 = playwright.devices['iPhone 12'] browser = await playwright.webkit.launch(headless=False) context = await browser.new_context( - **pixel_2, + **iphone_12, ) async def main(): @@ -58,10 +90,10 @@ asyncio.run(main()) from playwright.sync_api import sync_playwright def run(playwright): - pixel_2 = playwright.devices['Pixel 2'] + iphone_12 = playwright.devices['iPhone 12'] browser = playwright.webkit.launch(headless=False) context = browser.new_context( - **pixel_2, + **iphone_12, ) with sync_playwright() as playwright: @@ -81,61 +113,43 @@ class Program { Headless: False }); - var pixel2 = playwright.Devices["Pixel 2"]; - await using var context = await browser.NewContextAsync(pixel2); + var iphone12 = playwright.Devices["iPhone 12"]; + await using var context = await browser.NewContextAsync(iphone12); } } ``` -All pages created in the context above will share the same device parameters. +## Viewport -### API reference -- [`property: Playwright.devices`] -- [`method: Browser.newContext`] +The viewport is included in the device but you can override it for some tests with [`method: Page.setViewportSize`]. -
+```js tab=js-ts +import { test, expect } from '@playwright/test'; -## User agent +// Run tests in this file with portrait-like viewport. +test.use({ + viewport: { width: 600, height: 900 }, +}); -All pages created in the context above will share the user agent specified: - -```js -const context = await browser.newContext({ - userAgent: 'My user agent' +test('my portrait test', async ({ page }) => { + // ... }); ``` -```java -BrowserContext context = browser.newContext(new Browser.NewContextOptions() - .setUserAgent("My user agent")); +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +// Run tests in this file with portrait-like viewport. +test.use({ + viewport: { width: 600, height: 900 }, +}); + +test('my portrait test', async ({ page }) => { + // ... +}); ``` -```python async -context = await browser.new_context( - user_agent='My user agent' -) -``` - -```python sync -context = browser.new_context( - user_agent='My user agent' -) -``` - -```csharp -var context = await browser.NewContextAsync(new BrowserNewContextOptions { UserAgent = "My User Agent" }); -``` - -### API reference -- [`method: Browser.newContext`] - -
- -## Viewport - -Create a context with custom viewport size: - -```js +```js tab=js-library // Create context with given viewport const context = await browser.newContext({ viewport: { width: 1280, height: 1024 } @@ -150,6 +164,33 @@ const context = await browser.newContext({ deviceScaleFactor: 2, }); ``` +The same works inside a describe block. + +```js tab=js-ts +import { test, expect } from '@playwright/test'; + +test.describe('locale block', () => { + // Run tests in this describe block with portrait-like viewport. + test.use({ viewport: { width: 600, height: 900 } }); + + test('my portrait test', async ({ page }) => { + // ... + }); +}); +``` + +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.describe('locale block', () => { + // Run tests in this describe block with portrait-like viewport. + test.use({ viewport: { width: 600, height: 900 } }); + + test('my portrait test', async ({ page }) => { + // ... + }); +}); +``` ```java // Create context with given viewport @@ -213,16 +254,37 @@ await using var context = await browser.NewContextAsync(new() DeviceScaleFactor = 2 }); ``` +## Locale & Timezone -### API reference -- [`method: Browser.newContext`] -- [`method: Page.setViewportSize`] +Emulate the user Locale and Timezone which can be set globally for all tests in the config and then overridden for particular tests. -
+```js tab=js-ts +import { test, expect } from '@playwright/test'; -## Locale & timezone +test.use({ + locale: 'de-DE', + timezoneId: 'Europe/Berlin', +}); -```js +test('my test for de lang in Berlin timezone', async ({ page }) => { + // ... +}); +``` + +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.use({ + locale: 'de-DE', + timezoneId: 'Europe/Berlin', +}); + +test('my test for de lang in Berlin timezone', async ({ page }) => { + // ... +}); +``` + +```js tab=js-library // Emulate locale and time const context = await browser.newContext({ locale: 'de-DE', @@ -260,17 +322,34 @@ await using var context = await browser.NewContextAsync(new() TimezoneId = "Europe/Berlin" }); ``` - -### API reference -- [`method: Browser.newContext`] - -
- ## Permissions -Allow all pages in the context to show system notifications: +Allow app to show system notifications. -```js +```js tab=js-js +// @ts-check + +/** @type {import('@playwright/test').PlaywrightTestConfig} */ +const config = { + use: { + permissions: ['notifications'], + }, +}; + +module.exports = config; +``` + +```js tab=js-ts +import type { PlaywrightTestConfig } from '@playwright/test'; +const config: PlaywrightTestConfig = { + use: { + permissions: ['notifications'], + }, +}; +export default config; +``` + +```js tab=js-library const context = await browser.newContext({ permissions: ['notifications'], }); @@ -293,9 +372,32 @@ context = browser.new_context( ) ``` -Grant all pages in the existing context access to current location: +Allow test to request current location. -```js +```js tab=js-js +// @ts-check + +/** @type {import('@playwright/test').PlaywrightTestConfig} */ +const config = { + use: { + permissions: ['geolocation'], + }, +}; + +module.exports = config; +``` + +```js tab=js-ts +import type { PlaywrightTestConfig } from '@playwright/test'; +const config: PlaywrightTestConfig = { + use: { + permissions: ['geolocation'], + }, +}; +export default config; +``` + +```js tab=js-library await context.grantPermissions(['geolocation']); ``` @@ -315,9 +417,32 @@ context.grant_permissions(['geolocation']) await context.GrantPermissionsAsync(new[] { "geolocation" }); ``` -Grant notifications access from a specific domain: +Allow notifications for a specific domain. -```js +```js tab=js-js +// @ts-check + +/** @type {import('@playwright/test').PlaywrightTestConfig} */ +const config = { + use: { + permissions: ['notifications'], {origin: 'https://skype.com'}, + }, +}; + +module.exports = config; +``` + +```js tab=js-ts +import type { PlaywrightTestConfig } from '@playwright/test'; +const config: PlaywrightTestConfig = { + use: { + permissions: ['notifications'], {origin: 'https://skype.com'}, + }, +}; +export default config; +``` + +```js tab=js-library await context.grantPermissions(['notifications'], {origin: 'https://skype.com'} ); ``` @@ -338,9 +463,10 @@ context.grant_permissions(['notifications'], origin='https://skype.com') await context.GrantPermissionsAsync(new[] { "notifications" }, origin: "https://skype.com"); ``` -Revoke all permissions: +Revoke all permissions with [`method: BrowserContext.clearPermissions`]. ```js +// Library await context.clearPermissions(); ``` @@ -359,23 +485,42 @@ context.clear_permissions() ```csharp await context.ClearPermissionsAsync(); ``` - -### API reference -- [`method: Browser.newContext`] -- [`method: BrowserContext.grantPermissions`] -- [`method: BrowserContext.clearPermissions`] - -
- ## Geolocation -Create a context with `"geolocation"` permissions granted: +Create a test with `"geolocation"` permissions granted and geolocation set to a specific area. -```js +```js tab=js-ts +import { test, expect } from '@playwright/test'; + +test.use({ + geolocation: { longitude: 48.858455, latitude: 2.294474 }, + permissions: ['geolocation'], +}); + +test('my test with geolocation', async ({ page }) => { + // ... +}); +``` + +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.use({ + geolocation: { longitude: 48.858455, latitude: 2.294474 }, + permissions: ['geolocation'], +}); + +test('my test with geolocation', async ({ page }) => { + // ... +}); +``` + +```js tab=js-library const context = await browser.newContext({ geolocation: { longitude: 48.858455, latitude: 2.294474 }, permissions: ['geolocation'] }); + ``` ```java @@ -429,18 +574,35 @@ await context.SetGeolocationAsync(new Geolocation() { Longitude = 48.858455f, La ``` **Note** you can only change geolocation for all pages in the context. +## Color Scheme and Media -### API reference -- [`method: Browser.newContext`] -- [`method: BrowserContext.setGeolocation`] +Create a test that emulates the users `"colorScheme"`. Supported values are 'light', 'dark', 'no-preference'. You can also emulate the media type with [`method: Page.emulateMedia`]. -
+```js tab=js-ts +import { test, expect } from '@playwright/test'; -## Color scheme and media +test.use({ + colorScheme: 'dark' // or 'light' +}); -Create a context with dark or light mode. Pages created in this context will follow this color scheme preference. +test('my test with dark mode', async ({ page }) => { + // ... +}); +``` -```js +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.use({ + colorScheme: 'dark' // or 'light' +}); + +test('my test with dark mode', async ({ page }) => { + // ... +}); +``` + +```js tab=js-library // Create context with dark mode const context = await browser.newContext({ colorScheme: 'dark' // or 'light' @@ -535,7 +697,82 @@ await page.EmulateMediaAsync(new() Media = Media.Print }); ``` +## User Agent -### API reference -- [`method: Browser.newContext`] -- [`method: Page.emulateMedia`] \ No newline at end of file +The User Agent is included in the device and therefore you will rarely need to change it however if you do need to test a different user agent you can override it with the `userAgent` property. + +```js tab=js-ts +import { test, expect } from '@playwright/test'; + +test.use({ userAgent: 'My user agent'}); + +test('my user agent test', async ({ page }) => { + // ... +}); +``` + +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.use({ userAgent: 'My user agent' }); + +test('my user agent test', async ({ page }) => { + // ... +}); +``` + +```js tab=js-library +const context = await browser.newContext({ + userAgent: 'My user agent' +}); +``` + +```java +BrowserContext context = browser.newContext(new Browser.NewContextOptions() + .setUserAgent("My user agent")); +``` + +```python async +context = await browser.new_context( + user_agent='My user agent' +) +``` + +```python sync +context = browser.new_context( + user_agent='My user agent' +) +``` + +```csharp +var context = await browser.NewContextAsync(new BrowserNewContextOptions { UserAgent = "My User Agent" }); +``` +## JavaScript Enabled + +Emulate a user scenario where JavaScript is disabled. + +```js tab=js-ts +import { test, expect } from '@playwright/test'; + +test.use({ javaScriptEnabled: false }); + +test('test with no JavaScript', async ({ page }) => { + // ... +}); +``` + +```js tab=js-js +const { test, expect } = require('@playwright/test'); + +test.use({ javaScriptEnabled: false }); + +test('test with no JavaScript', async ({ page }) => { + // ... +}); +``` + +```js tab=js-library +const context = await browser.newContext({ + javaScriptEnabled: false +}); +``` \ No newline at end of file diff --git a/docs/src/test-configuration-js.md b/docs/src/test-configuration-js.md index aa2ebbd943..820cdf2789 100644 --- a/docs/src/test-configuration-js.md +++ b/docs/src/test-configuration-js.md @@ -5,7 +5,7 @@ title: "Configuration" Playwright Test provides options to configure the default `browser`, `context` and `page` fixtures. For example there are options for `headless`, `viewport` and `ignoreHTTPSErrors`. You can also record a video or a trace for the test or capture a screenshot at the end. -Finally, there are plenty of testing options like `timeout` or `testDir` that configure how your tests are collected and executed. +There are plenty of testing options like `timeout` or `testDir` that configure how your tests are collected and executed. You can specify any options globally in the configuration file, and most of them locally in a test file. @@ -13,7 +13,7 @@ See the full list of [test options][TestOptions] and all [configuration properti ## Global configuration -Create `playwright.config.js` (or `playwright.config.ts`) and specify options in the [`property: TestConfig.use`] section. +Create a `playwright.config.js` (or `playwright.config.ts`) and specify options in the [`property: TestConfig.use`] section. ```js tab=js-js // @ts-check @@ -47,7 +47,7 @@ export default config; Now run tests as usual, Playwright Test will pick up the configuration file automatically. ```bash -npx playwright test --browser=firefox +npx playwright test ``` If you put your configuration file in a different place, pass it with `--config` option. @@ -58,15 +58,13 @@ npx playwright test --config=tests/my.config.js ## Local configuration -With [`method: Test.use`] you can override some options for a file or a [`method: Test.describe#1`] block. +You can override some options for a file or describe block. ```js tab=js-js // example.spec.js const { test, expect } = require('@playwright/test'); - // Run tests in this file with portrait-like viewport. test.use({ viewport: { width: 600, height: 900 } }); - test('my portrait test', async ({ page }) => { // ... }); @@ -75,10 +73,8 @@ test('my portrait test', async ({ page }) => { ```js tab=js-ts // example.spec.ts import { test, expect } from '@playwright/test'; - // Run tests in this file with portrait-like viewport. test.use({ viewport: { width: 600, height: 900 } }); - test('my portrait test', async ({ page }) => { // ... }); @@ -89,11 +85,9 @@ The same works inside describe. ```js tab=js-js // example.spec.js const { test, expect } = require('@playwright/test'); - test.describe('locale block', () => { // Run tests in this describe block with portrait-like viewport. test.use({ viewport: { width: 600, height: 900 } }); - test('my portrait test', async ({ page }) => { // ... }); @@ -103,11 +97,9 @@ test.describe('locale block', () => { ```js tab=js-ts // example.spec.ts import { test, expect } from '@playwright/test'; - test.describe('locale block', () => { // Run tests in this describe block with portrait-like viewport. test.use({ viewport: { width: 600, height: 900 } }); - test('my portrait test', async ({ page }) => { // ... }); @@ -116,7 +108,9 @@ test.describe('locale block', () => { ## Basic options -These are commonly used options for various scenarios. You usually set them globally in [configuration file](#global-configuration). +Normally you would start with emulating a device, for example Desktop Chromium. See our [Emulation](./emulation.md) guide to learn more. + +Here are some of the commonly used options for various scenarios. You usually set them globally in the [configuration file](#global-configuration). - `actionTimeout` - Timeout for each Playwright action in milliseconds. Defaults to `0` (no timeout). Learn more about [various timeouts](./test-timeouts.md). - `baseURL` - Base URL used for all pages in the context. Allows navigating by using just the path, for example `page.goto('/settings')`. @@ -126,6 +120,11 @@ These are commonly used options for various scenarios. You usually set them glob - `headless` - Whether to run the browser in headless mode. - `viewport` - Viewport used for all pages in the context. - `storageState` - Populates context with given storage state. Useful for easy authentication, [learn more](./auth.md). +- `colorScheme` - Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. +- `geolocation` - Context geolocation. +- `locale` - [Emulates](./emulation.md) the user locale, for example `en-GB`, `de-DE`, etc. +- `permissions` - A list of permissions to grant to all pages in the context. +- `timezoneId` - Changes the timezone of the context. ```js tab=js-js // @ts-check @@ -231,111 +230,6 @@ Running 1 test using 1 worker ✓ [firefox] › example.spec.ts:3:1 › basic test (2s) ``` -## Emulation - -Playwright can [emulate different environments](./emulation.md) like mobile device, locale or timezone. - -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 tab=js-js -// playwright.config.js -// @ts-check -const { devices } = require('@playwright/test'); - -/** @type {import('@playwright/test').PlaywrightTestConfig} */ -const config = { - 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'], - }, - }, - ], -}; - -module.exports = config; -``` - -```js tab=js-ts -// playwright.config.ts -import { type PlaywrightTestConfig, devices } from '@playwright/test'; - -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; -``` - -You can specify options separately instead of using predefined devices. There are also more options such as locale, geolocation, and timezone which can be configured. - -- `colorScheme` - Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. -- `deviceScaleFactor` - Specify device scale factor (can be thought of as dpr). Defaults to `1`. -- `geolocation` - Context geolocation. -- `hasTouch` - Specifies if device supports touch events. -- `isMobile` - Whether the `meta viewport` tag is taken into account and touch events are enabled. -- `javaScriptEnabled` - Whether or not to enable JavaScript in the context. -- `locale` - User locale, for example `en-GB`, `de-DE`, etc. -- `permissions` - A list of permissions to grant to all pages in the context. -- `timezoneId` - Changes the timezone of the context. -- `userAgent` - Specific user agent to use in the context. - -```js tab=js-js -// @ts-check - -/** @type {import('@playwright/test').PlaywrightTestConfig} */ -const config = { - use: { - locale: 'fr-FR', - geolocation: { longitude: 48.858455, latitude: 2.294474 }, - permissions: ['geolocation'], - }, -}; - -module.exports = config; -``` - -```js tab=js-ts -import type { PlaywrightTestConfig } from '@playwright/test'; -const config: PlaywrightTestConfig = { - use: { - locale: 'fr-FR', - geolocation: { longitude: 48.858455, latitude: 2.294474 }, - permissions: ['geolocation'], - }, -}; -export default config; -``` - ## Network Available options to configure networking: