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('[email protected]');
// 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 test
Retrying 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!