playwright/docs/core-concepts.md
Dmitry Gozman f9f5fd03b0
feat(selectors): allow to capture intermediate result (#1978)
This introduces the `*name=body` syntax to capture intermediate result.
For example, `*css=section >> "Title"` will capture a section that contains "Title".
2020-04-27 10:14:09 -07:00

9.7 KiB

Core concepts

Playwright provides a set of APIs to automate Chromium, Firefox and WebKit browsers. By using the Playwright API, you can write JavaScript code to create new browser pages, navigate to URLs and then interact with elements on a page.

Along with a test runner Playwright can be used to automate user interactions to validate and test web applications. The Playwright API enables this through the following primitives.

Contents


Browser

A Browser refers to an instance of Chromium, Firefox or WebKit. Playwright scripts generally start with launching a browser instance and end with closing the browser. Browser instances can be launched in headless (without a GUI) or headful mode.

const { chromium } = require('playwright');  // Or 'firefox' or 'webkit'.

const browser = await chromium.launch({ headless: false });
await browser.close();

Launching a browser instance can be expensive, and Playwright is designed to maximize what a single instance can do through multiple browser contexts.

API reference


Browser contexts

A BrowserContext is an isolated incognito-alike session within a browser instance. Browser contexts are fast and cheap to create. Browser contexts can be used to parallelize isolated test executions.

const browser = await chromium.launch();
const context = await browser.newContext();

Browser contexts can also be used to emulate multi-page scenarios involving mobile devices, permissions, locale and color scheme.

const { devices } = require('playwright');
const iPhone = devices['iPhone 11 Pro'];

const context = await browser.newContext({
  ...iPhone,
  permissions: ['geolocation'],
  geolocation: { latitude: 52.52, longitude: 13.39},
  colorScheme: 'dark',
  locale: 'de-DE'
});

API reference


Pages and frames

A Browser context can have multiple pages. A Page refers to a single tab or a popup window within a browser context. It should be used to navigate to URLs and interact with the page content.

// Create a page.
const page = await context.newPage();
// Navigate explicitly, similar to entering a URL in the browser.
await page.goto('http://example.com');
// Fill an input.
await page.fill('#search', 'query');
// Navigate implicitly by clicking a link.
await page.click('#submit');
// Expect a new url.
console.log(page.url());
// Page can navigate from the script - this will be picked up by Playwright.
window.location.href = 'https://example.com';

A page can have one or more Frame objects attached to it. Each page has a main frame and page-level interactions (like click) are assumed to operate in the main frame.

A page can have additional frames attached with the iframe HTML tag. These frames can be accessed for interactions inside the frame.

// To interact with elements in an iframe
const frame = page.frame('frame-login');
await frame.fill('#username-input', 'John');

API reference

To learn more about navigation and loading, read this document.


Selectors

Playwright can search for elements using CSS selectors, XPath selectors, HTML attributes like id, data-test-id and even text content.

You can explicitly specify the selector engine you are using or let Playwright detect it.

All selector engines except for XPath pierce shadow DOM by default. If you want to enforce regular DOM selection, you can use the *:light versions of the selectors. You don't typically need to though.

Learn more about selectors and selector engines here.

Some examples below:

// Using data-test-id= selector engine
await page.click('data-test-id=foo');
// CSS and XPath selector engines are automatically detected
await page.click('div');
await page.click('//html/body/div');
// Find node by text substring
await page.click('text=Hello w');
// Explicit CSS and XPath notation
await page.click('css=div');
await page.click('xpath=//html/body/div');
// Only search light DOM, outside WebComponent shadow DOM:
await page.click('css:light=div');

Selectors using the same or different engines can be combined using the >> separator. For example,

// Click an element with text 'Sign Up' inside of a #free-month-promo.
await page.click('#free-month-promo >> text=Sign Up');
// Capture textContent of a section that contains an element with text 'Selectors'.
const sectionText = await page.$eval('*css=section >> text=Selectors', e => e.textContent);

Auto-waiting

Actions like click and fill auto-wait for the element to be visible and actionable. For example, click will:

  • wait for element with given selector to be in DOM
  • wait for it to become displayed, i.e. not display:none,
  • wait for it to stop moving, for example, until css transition finishes
  • scroll the element into view
  • wait for it to receive pointer events at the action point, for example, waits until element becomes non-obscured by other elements
// Playwright waits for #search element to be in DOM
await page.fill('#search', 'query');
// Playwright waits for element to stop animating
// and accept clicks.
await page.click('#search');

You can explicitly wait for element to become available in DOM and to become visible:

await page.waitForSelector('#search', { waitFor: 'visible' });

... or to become hidden or detached

await page.waitForSelector('#search', { waitFor: 'detached' });

API reference


Node.js and browser execution contexts

Playwright scripts run in your Node.js environment. You page scripts run in the page environment. Those environments don't intersect, they are running in different virtual machines in different processes and potentially on different computers.

IMAGE PLACEHOLDER

The page.evaluate API can run a JavaScript function in the context of the web page and bring results back to the Node.js environment. Globals like window and document along with the web page runtime can be used in evaluate.

Right:

const data = { text: 'some data', value: 1 };
// Pass |data| as a parameter.
const result = await page.evaluate(data => {
  window.myApp.use(data);
}, data);

Wrong:

const data = { text: 'some data', value: 1 };
const result = await page.evaluate(() => {
  // There is no |data| in the web page.
  window.myApp.use(data);
});

Evaluation parameters are serialized and sent into your web page over the wire. You can pass primitive types, JSON-alike objects and remote object handles received from the page.


Object & element handles

Playwright has an API to create Node-side handles to the page DOM elements or any other objects inside the page. These handles live in the Node.js process, whereas the actual objects reside in browser.

IMAGE PLACEHOLDER

There are two types of handles:

  • JSHandle to reference any javascript objects in the page
  • ElementHandle to reference DOM elements in the page

Note that since any DOM element in the page is also a javascript object, Playwright's ElementHandle extends JSHandle.

Handles Lifetime:

Here is how you can use these handles:

// The first parameter of the elementHandle.evaluate callback is the element handle points to.
const ulElementHandle = await page.$('ul');
await ulElementHandle.evaluate(ulElement => getComputedStyle(ulElement).getPropertyValue('display'));

Alternatively, handles can be passed as arguments to page.evaluate function:

// In the page API, you can pass handle as a parameter.
const ulElementHandle = await page.$('ul');
await page.evaluate(uiElement => getComputedStyle(uiElement).getPropertyValue('display'), uiElement);

API reference