Playwright is an open source cross-browser end-to-end testing framework, maintained by Microsoft and developed by the team who created Puppeteer.
Compared to other e2e testing frameworks, it has fewer dependencies, it’s fast, and it doesn’t need various plugins to fill in the gaps. The Playwright library can be used with various test runners or with its own test runner, Playwright Test. Playwright Test provides a test function to declare tests and an expect function to write assertions. It can:
Playwright Test is based on the concept of test fixtures, which are used to establish an isolated environment for each test. This means tests can be run quickly in parallel, are able to retry efficiently, avoid cascading failures, and are highly configurable.
// example-test.spec.ts
import { test, expect } from '@playwright/test';
test.describe('navigation', () => {
test.use({ storageState: 'userStorageState.json' });
test('view inventory', async ({ page }) => {
const title = page.locator('.inventory_details_desc_container');
await page.goto('https://www.saucedemo.com/inventory.html');
await expect(page).toHaveURL('https://www.saucedemo.com/inventory.html');
await page.click('text=Sauce Labs Bolt T-Shirt');
await expect(page).toHaveURL('https://www.saucedemo.com/inventory-item.html?id=1');
await expect(title).toHaveText(/Sauce Labs Bolt T-Shirt/);
});
});
In Playwright you’re able to log in once and reuse the signed-in state across tests by creating a global setup script. It’s possible to use multiple user accounts by saving their state to different files.
// global-setup.ts
import { chromium, FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
const browser = await chromium.launch();
const standardUser = await browser.newPage();
await standardUser.goto('https://www.saucedemo.com/');
await standardUser.fill('[data-test="username"]', 'standard_user');
await standardUser.fill('[data-test="password"]', 'secret_sauce');
await standardUser.click('[data-test="login-button"]');
await standardUser.context().storageState({ path: 'userStorageState.json' });
const problemUser = await browser.newPage();
await problemUser.goto('https://www.saucedemo.com/');
await problemUser.fill('[data-test="username"]', 'problem_user');
await problemUser.fill('[data-test="password"]', 'secret_sauce');
await problemUser.click('[data-test="login-button"]');
await problemUser.context().storageState({ path: 'problemUserStorageState.json' });
await browser.close();
}
export default globalSetup;
Playwright is highly configurable with the ability to specify options globally in the configuration file and locally per-file or per-suite.
// playwright.config.ts
import { PlaywrightTestConfig, devices } from '@playwright/test';
const config: PlaywrightTestConfig = {
globalSetup: require.resolve('./global-setup.ts'),
use: {
storageState: 'userStorageState.json',
},
projects: [
{
name: 'Desktop_Safari',
use: {
browserName: 'webkit',
viewport: { width: 1200, height: 750 },
}
},
{
name: 'Desktop_Firefox',
use: {
browserName: 'firefox',
colorScheme: 'dark',
locale: 'fr-FR',
timezoneId: 'Europe/Paris',
geolocation: { longitude: 48.858455, latitude: 2.294474 },
permissions: ['geolocation'],
}
},
{
name: 'Pixel_4',
use: {
browserName: 'chromium',
...devices['Pixel 4'],
},
},
],
};
export default config;
While still being relatively new, Playwright offers lots of cool functionality out of the box, with new features shipping often. It’s definitely something to keep an eye on and I’m excited to see what they release next.
Software tester. Automation enthusiast. Always learning.