Starting Point: Basic Test Structure
Your starting point looks something like this:
import { test, expect } from '@playwright/test';
test('has the expected title', async ({ page }) => {
await page.goto('/');
expect(page).toHaveTitle('Playwright');
});This simple test navigates to 'https://ray.run/', grabs the page's title, and asserts that it matches the expected string.
Playwright in Action: Common Actions
Navigating the Web
// URLs are relative to the base URL specified in playwright.config.ts.
await page.goto('/blog');
// You can also navigate to a specific URL.
await page.goto('https://ray.run/');Seeking Out Page Elements
Playwright provides several ways to locate elements on a page.
The recommended way is use locators:
// to locate by explicit and implicit accessibility attributes
page.getByRole('heading', { name: 'Sign up' });
// to locate by text content
page.getByText('Sign up');
page.getByText('Sign up', { exact: true });
page.getByText(/sign up/i);
// to locate a form control by associated label's text
page.getByLabel('Password');
// to locate an input by placeholder
page.getByPlaceholder('name@example.com');
// to locate an element, usually image, by its text alternative
page.getByAltText('playwright logo');
// to locate an element by its title attribute
page.getByTitle('Issues count')
// to locate an element based on its data-testid attribute
page.getByTestId('directions');Here's how you can use CSS or XPath page.locator() method:
Not recommended if you can use locators.
// CSS
page.locator('css=button');
// short form CSS
page.locator('button');
// XPath
page.locator('xpath=//button');Entering Text Into Fields
await page.getByLabel('Password').fill('Hello, World!');Clicking Elements
Clicking elements is as easy as finding the locator and using the click() method:
await page.getByRole('button').click();Handling Dropdowns
To interact with a dropdown, simply select the option you want:
// Single selection matching the value
await page.getByLabel('Choose a color').selectOption('blue');
// Single selection matching the label
await page.getByLabel('Choose a color').selectOption({ label: 'blue' });
// Multiple selected items
await page.getByLabel('Choose a color').selectOption(['red', 'green', 'blue']);Dealing with Checkboxes and Radio Buttons
Interacting with checkboxes and radio buttons is straightforward:
await page.getByRole('checkbox').check();
await page.getByRole('checkbox').uncheck();
expect(await page.getByLabel('checkbox').isChecked()).toBeTruthy();Diving into iFrames
If you need to interact with elements within an iFrame, use the frameLocator() method:
const iframeLocator = page.frameLocator('#iframeId');
await iframeLocator.locator('#inputField').fill('Sample Text');Handling Alerts and Dialogs
For accepting or dismissing browser dialogs and alerts, simply listen for the 'dialog' event:
page.on('dialog', async (dialog) => {
await dialog.accept();
});
await page.getByRole('button').click();Making Assertions
Playwright integrates seamlessly with assertion libraries, helping you validate your tests. Here are a couple of examples:
Checking the Page Title
await expect(page).toHaveTitle('Playwright');Checking if an Element is Visible
Note: This is typically unnecessary as most actions (
click(),fill(), ...) will wait for the element to be visible by default.
await expect(page.locator('#elementId')).toBeVisible();Leveling Up: Advanced Scenarios
Playwright can handle a wide range of advanced scenarios, from browser context management to mobile emulation. Let's dive into a few:
Managing Browser Contexts
You can create isolated browsing sessions using browser contexts:
const { context } = await browser.newContext();
const page = await context.newPage();Capturing Screenshots
// Capture a screenshot of the visible portion of the page
await page.screenshot({ path: 'screenshot.png' });
// As if you had a very tall screen and the page could fit the the entire page
await page.screenshot({ path: 'screenshot.png', fullPage: true });
// Screenshot a specific element
await page.locator('#foo').screenshot({ path: 'screenshot.png' });Emulating Mobile Devices
Playwright comes with a registry of device parameters using playwright.devices for selected desktop, tablet and mobile devices.
const iPhone = devices['iPhone 13'];
const context = await browser.newContext({ ...iPhone });
const page = await context.newPage();
await page.goto('/');Managing Cookies
Playwright makes it easy to add, get, and delete cookies:
await context.addCookies([{ name: 'cookieName', value: 'cookieValue', domain: 'ray.run' }]);
const cookies = await context.cookies('https://ray.run/');
await context.clearCookies();Pressing Keys on the Keyboard
In most cases, you should use
locator.fill()instead. You only need to press keys one by one if there is special keyboard handling on the page.
// Types instantly
await page.getByLabel('Password').pressSequentially('Hello');
// Types slower, like a user
await page.getByLabel('Password').pressSequentially('World', { delay: 100 });Pressing Special Keys
await page.getByLabel('Password').press('Enter'); // Control, ArrowDown, ...Performing Drag-and-Drop
Need to drag and drop elements? No problem:
const source = await page.locator('#sourceElement');
const target = await page.locator('#targetElement');
await source.dragAndDrop(target);Waiting for Events or Conditions
You can wait for specific events, elements, or custom conditions:
await page.waitForLoadState('networkidle');
await page.waitForSelector('#elementId');
await page.waitForFunction(() => document.querySelector('#elementId').innerText === 'Expected Text');Fine-Tuning: Test Configuration
Adjusting Timeouts
You can configure global and action-specific timeouts to suit your needs:
// Set global test timeout to 30 seconds
test.setTimeout(30000);
// Set action-specific timeout to 5 seconds
await page.locator('#elementId').click({ timeout: 5000 });Running Tests in Parallel
Running tests concurrently can save you a lot of time. Here's how you do it:
// In playwright.config.ts
export default {
workers: 4, // Run 4 tests concurrently
};Running Tests Across Browsers
You can configure your tests to run on multiple browsers:
// In playwright.config.ts
export default {
projects: [
{
name: 'chrome',
use: { browserName: 'chromium' },
},
{
name: 'firefox',
use: { browserName: 'firefox' },
},
],
};Automating It All: Continuous Integration
Integrating with GitHub Actions
You can configure GitHub Actions to run your Playwright tests automatically:
# .github/workflows/playwright.yml
name: Playwright
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected]
- name: Setup node
uses: actions/[email protected]
with:
node-version: 14
- name: Install dependencies
run: npm ci
- name: Run Playwright tests
run: npm run testRetrying Failed Tests
Sometimes, tests fail unexpectedly. You can configure Playwright to retry failed tests automatically:
// In playwright.config.ts
export default {
// Retry failed tests 2 times in CI
retries: process.env.CI ? 2 : 0,
};Troubleshooting: Debugging
Pausing Tests for Debugging
If you need to inspect something during a test, you can pause the test execution:
// Pause test execution to debug
await page.pause();Debugging Test Failures
When a test fails, it's important to understand why. Playwright can collect trace information, screenshots, and logs to help you:
// In playwright.config.ts
export default {
use: {
// Save trace information when a test fails
trace: 'on-first-retry',
},
};And there you have it! With this comprehensive @playwright/test cheat sheet, you're well on your way to becoming a Playwright pro. Happy testing!