Playwright Cheat Sheet

16Playwright Cheat Sheet

One-page reference

  • Install / run / debug commands
  • Locators
  • Actions
  • Web-first assertions
  • Network
  • Fixtures / config
  • Events / dialogs / popups
  • Visual / API / debug

16.1 CLI

npm init playwright@latest                      # scaffold project
npx playwright install --with-deps              # download browsers + OS libs
npx playwright test                             # run all tests
npx playwright test login.spec.ts -g "happy"    # filter by file + name
npx playwright test --project=chromium          # one project only
npx playwright test --workers=4 --headed --slowmo=500
npx playwright test --debug                     # open inspector + pause
npx playwright test --ui                        # UI mode (best dev XP)
npx playwright test --shard=1/4                 # CI sharding
npx playwright test --update-snapshots          # regen visual baselines
npx playwright codegen https://site.com         # record actions
npx playwright show-report                      # open last HTML report
npx playwright show-trace trace.zip             # open a specific trace

16.2 Locators

page.getByRole('button', { name: 'Buy', exact: true });
page.getByLabel('Email');
page.getByPlaceholder('Search');
page.getByText('Welcome', { exact: false });
page.getByText(/total: \$\d+/);
page.getByAltText('Logo');
page.getByTitle('Open menu');
page.getByTestId('cart-count');
page.locator('css=button.primary');
page.locator('//button[contains(text(),"Save")]');   // xpath
page.locator('button:has-text("Buy")');
page.locator('div:has(span.badge)');
// Narrowing
.first(); .last(); .nth(n);
.filter({ hasText: 'Alice' });
.filter({ has: page.getByRole('checkbox') });
.filter({ hasNotText: 'archived' });
// Chaining
page.getByRole('row', { name: /alice/i }).getByRole('button', { name: 'Delete' });

16.3 Actions

await locator.click({ button: 'right', clickCount: 2, modifiers: ['Shift'] });
await locator.dblclick();
await locator.fill('text');
await locator.clear();
await locator.pressSequentially('h', { delay: 50 });
await locator.press('Enter');
await locator.check(); await locator.uncheck();
await locator.selectOption('IN'); selectOption({ label: 'India' }); selectOption({ index: 2 });
await locator.hover(); await locator.focus(); await locator.blur();
await locator.dragTo(target);
await locator.setInputFiles('a.pdf');
await locator.screenshot({ path: 'el.png' });
await locator.scrollIntoViewIfNeeded();

// Page-level
await page.goto(url); await page.reload(); await page.goBack();
await page.keyboard.press('Escape');
await page.mouse.move(x,y); await page.mouse.click(x,y);
await page.touchscreen.tap(x,y);
await page.evaluate(() => window.scrollTo(0, 0));
await page.exposeFunction('name', fn);
await page.addInitScript(() => { /* ... */ });

16.4 Web-first assertions

await expect(loc).toBeVisible(); toBeHidden(); toBeAttached(); toBeFocused();
await expect(loc).toHaveText('x'); toContainText('e'); toHaveText([...]);
await expect(loc).toHaveValue('x'); toHaveAttribute('href', '/x');
await expect(loc).toHaveClass(/active/); toHaveCSS('color', 'rgb(...)');
await expect(loc).toBeEnabled(); toBeDisabled(); toBeEditable(); toBeChecked(); toBeEmpty();
await expect(loc).toHaveCount(3);
await expect(page).toHaveTitle(/x/); toHaveURL(/\/dash/);
await expect(response).toBeOK();
await expect(loc).toBeVisible({ timeout: 10_000 });
// Soft
expect.soft(loc).toHaveText('x');
// Poll
await expect.poll(async () => (await api.getStatus()).value).toBe('ready');
// Negation
await expect(loc).not.toBeVisible();

16.5 Network

// Mock
await page.route('**/api/x', route => route.fulfill({ status: 200, body: '[]' }));
// Modify request
await page.route('**/api/x', async route => {
  const body = JSON.parse(route.request().postData() || '{}');
  body.x = 1;
  await route.continue({ postData: JSON.stringify(body) });
});
// Modify response
await page.route('**/api/x', async route => {
  const r = await route.fetch();
  const j = await r.json();
  j.price = 0;
  await route.fulfill({ response: r, json: j });
});
// Abort
await page.route('**/*.png', r => r.abort());
// Wait for specific call
const [res] = await Promise.all([
  page.waitForResponse(r => r.url().includes('/api/orders') && r.request().method() === 'POST'),
  page.click('#submit'),
]);
// HAR
await context.routeFromHAR('flow.har', { update: true });

16.6 Fixtures & config

// Custom fixture
export const test = base.extend<{ loginPage: LoginPage }>({
  loginPage: async ({ page }, use) => { await use(new LoginPage(page)); },
});
// Worker-scoped
mySvc: [async ({}, use) => { /*…*/ await use(s); /*…*/ }, { scope: 'worker' }],

// Override built-in
context: async ({ browser }, use) => { const c = await browser.newContext({ locale: 'en-IN' }); await use(c); await c.close(); },

// Config snippets
use: { baseURL: 'https://app', viewport: { width: 1440, height: 900 },
       trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure',
       actionTimeout: 10_000, navigationTimeout: 30_000, locale: 'en-US', timezoneId: 'UTC',
       testIdAttribute: 'data-testid', extraHTTPHeaders: { 'x-test': '1' } }
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] }, dependencies: ['setup'] }],
webServer: { command: 'npm start', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI }

16.7 Events

// Dialog
page.on('dialog', d => d.accept('value'));
// Popup / new tab
const [popup] = await Promise.all([context.waitForEvent('page'), page.click('#open')]);
// Download
const [dl] = await Promise.all([page.waitForEvent('download'), page.click('#export')]);
await dl.saveAs('out.csv');
// File chooser (custom button)
const [fc] = await Promise.all([page.waitForEvent('filechooser'), page.click('#add-file')]);
await fc.setFiles('file.pdf');
// Console / errors
page.on('console', m => console.log(m.type(), m.text()));
page.on('pageerror', e => console.error(e.message));

16.8 iframes

const f = page.frameLocator('iframe[name="card"]');
await f.getByPlaceholder('CVC').fill('123');
// Nested
const inner = page.frameLocator('#outer').frameLocator('#inner');

16.9 Visual

await expect(page).toHaveScreenshot('home.png', {
  fullPage: true,
  animations: 'disabled',
  caret: 'hide',
  mask: [page.locator('.date')],
  maxDiffPixelRatio: 0.01,
});

16.10 API

// In test
test('api', async ({ request }) => {
  const r = await request.post('/api/x', { data: { a: 1 }, headers: { Authorization: 'Bearer t' } });
  expect(r.status()).toBe(201);
  const body = await r.json();
});
// Standalone
const api = await playwright.request.newContext({ baseURL: 'https://api', extraHTTPHeaders: { Authorization: 't' } });
await api.dispose();

16.11 Debug

await page.pause();                // breakpoint — opens inspector
await page.screenshot({ path: 'd.png' });
await context.tracing.start({ screenshots: true, snapshots: true });
await context.tracing.stop({ path: 't.zip' });
// View later
// npx playwright show-trace t.zip

16.12 Common one-liners

// Block third-party
await context.route('**/*', r => /analytics|hotjar/.test(r.request().url()) ? r.abort() : r.continue());
// Add cookie
await context.addCookies([{ name: 'x', value: '1', url: 'https://site' }]);
// Set storage
await context.addInitScript(() => localStorage.setItem('flag', 'on'));
// Use existing browser session
const ctx = await chromium.launchPersistentContext('./userdir', { headless: false });
// Connect to remote browser
const browser = await chromium.connect({ wsEndpoint: 'wss://...' });

16.13 Most-used Q's in interviews — 30-sec answers

QA in 1 sentence
Locator vs ElementHandle?Locator is a re-resolved description; ElementHandle is a stale handle.
Why use getByRole?Matches how assistive tech sees the page; survives styling changes.
How to wait for a network call?Promise.all([page.waitForResponse(...), page.click(...)]).
How to mock?page.route(url, route => route.fulfill({status,body})).
How to reuse auth?Setup project saves storageState JSON; other projects load it.
How does parallel work?Workers (processes) × shards (machines). Each test gets its own context.
How to handle popup?Promise-first: [popup] = await Promise.all([context.waitForEvent('page'), action]).
How to fix flaky test?Replace waitForTimeout with web-first assertion; isolate data; mock unstable upstream.
How to assert text?expect(locator).toHaveText('...') — never extract then assert.
What's the trace viewer?Time-travel debugger; DOM snapshots + network + console + screenshots per action.