E2E Testing with Playwright

Playwright is an open source cross-browser end-to-end testing framework, maintained by Microsoft and developed by the team who created Puppeteer.

Why Playwright?

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:

  • Run tests across Chromium, Firefox, and Webkit.
  • Handle multi-page scenarios across domains, browsers, and tabs.
  • Execute tests in parallel.
  • Create browser contexts for full isolation.
  • Retry automatically.
  • Emulate devices, geolocation, and permissions.
  • Record tests with CodeGen.
  • Capture and compare screenshots or videos.
  • Debug with the Inspector or Trace Viewer.
  • Upload and download files.

Test Isolation

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/);
    });
});

Authentication

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;

Configuration

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;

Closing Thoughts

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.

Emma Elkan

Software tester. Automation enthusiast. Always learning.