Everything you use daily in Playwright with TypeScript, on one page: commands, locators, actions, assertions, waits, config, fixtures, API testing, debugging and CI. Bookmark it and keep it open while you code.
๐ What You’ll Learn: CLI commands, test structure and annotations, locators, actions, assertions, waits, playwright.config.ts essentials, fixtures and page objects, API testing and network mocking, debugging and reports, a minimal CI workflow, AI tools, and the top 10 mistakes to avoid.
๐ How to Use This Cheat Sheet
A one-page reference for Playwright Test with TypeScript. Each section links to the full lesson in the Playwright Tutorial with TypeScript. To keep a copy, use your browser’s Print, Save as PDF.
โ๏ธ Setup and CLI
npm init playwright@latest # new project (choose TypeScript)
npx playwright install --with-deps # browsers + Linux dependencies
npx playwright test # run all tests
npx playwright test login.spec.ts:12 # one test by line
npx playwright test -g "checkout" # by title
npx playwright test --grep @smoke # by tag
npx playwright test --project=firefox # one browser project
npx playwright test --headed # visible browser
npx playwright test --ui # UI mode
npx playwright test --debug # Inspector
npx playwright test --workers=4 --retries=2
npx playwright test --repeat-each=10 # find flaky tests
npx playwright test --last-failed
npx playwright test --shard=1/3 --reporter=blob
npx playwright merge-reports --reporter html ./all-blob-reports
npx playwright show-report
npx playwright show-trace trace.zip
npx playwright codegen https://example.com
npx playwright test --update-snapshots
Lessons: install, CLI commands, codegen
๐งช Test Structure
import { test, expect } from '@playwright/test';
test.describe('Cart', { tag: '@regression' }, () => {
test.beforeEach(async ({ page }) => { await page.goto('/'); });
test('adds an item', { tag: '@smoke' }, async ({ page }, testInfo) => {
await test.step('add backpack', async () => { /* ... */ });
});
});
test.only(...); test.skip(...); test.fixme(...); test.slow();
test.describe.configure({ mode: 'parallel' }); // or 'serial'
test.use({ viewport: { width: 390, height: 844 } });
Lessons: first test, hooks, tags, annotations
๐ฏ Locators
| Locator | Example |
|---|---|
| Role | page.getByRole('button', { name: 'Login' }) |
| Label | page.getByLabel('Email') |
| Placeholder | page.getByPlaceholder('Username') |
| Text | page.getByText('Products', { exact: true }) |
| Alt text / title | page.getByAltText('logo'), page.getByTitle('Close') |
| Test id | page.getByTestId('checkout') |
| CSS | page.locator('#user-name'), page.locator('[data-test="error"]') |
| XPath | page.locator("//td[text()='Jason']/following-sibling::td[2]") |
| Filter | page.locator('tr').filter({ hasText: 'Jason' }) |
| Chain | page.locator('form').getByRole('button') |
| Pick one | .first(), .last(), .nth(2) |
| iFrame | page.frameLocator('#frame').getByRole('button') |
Lessons: locators, CSS and XPath
๐ฑ๏ธ Actions
await page.goto('/inventory.html');
await locator.click(); // { button: 'right' }, { clickCount: 2 }, { modifiers: ['Shift'] }
await locator.dblclick();
await locator.fill('text'); // clear + set value
await locator.pressSequentially('abc', { delay: 100 });
await locator.press('Enter'); // 'Control+A', 'ArrowDown', 'Tab'
await locator.check(); await locator.uncheck(); await locator.setChecked(true);
await locator.selectOption({ label: 'Option 2' });
await locator.setInputFiles('data/file.pdf');
await locator.hover();
await locator.dragTo(target);
await locator.scrollIntoViewIfNeeded();
await page.keyboard.press('Escape');
Lessons: actions, alerts, popups, iframes, tabs
โ Assertions
| Assertion | Use |
|---|---|
await expect(page).toHaveURL(/inventory/) | Current URL |
await expect(page).toHaveTitle('Swag Labs') | Page title |
await expect(locator).toBeVisible() / toBeHidden() | Visibility |
await expect(locator).toHaveText('Products') | Exact text |
await expect(locator).toContainText('locked') | Partial text |
await expect(locator).toHaveValue('42') | Input value |
await expect(locator).toHaveCount(6) | Number of elements |
await expect(locator).toBeChecked() / toBeEnabled() / toBeDisabled() | State |
await expect(locator).toHaveAttribute('href', '/cart') | Attribute |
await expect(locator).toHaveClass(/active/) | CSS class |
await expect(page).toHaveScreenshot('home.png') | Visual comparison |
await expect(response).toBeOK() | API response 2xx |
expect.soft(...) | Continue after a failure |
expect(value).toEqual(obj) / toMatchObject(obj) | Plain values (no await) |
Lessons: assertions, visual testing
โณ Waits
await expect(locator).toBeVisible({ timeout: 10_000 }); // preferred
await locator.waitFor({ state: 'hidden' });
await page.waitForURL('**/inventory.html');
await page.waitForLoadState('domcontentloaded');
const resp = page.waitForResponse(r => r.url().includes('/api/') && r.ok());
await button.click(); await resp; // start waiting BEFORE the action
const popup = page.waitForEvent('popup'); await link.click(); const newTab = await popup;
await expect.poll(async () => getStatus()).toBe('DONE');
// Avoid: page.waitForTimeout(5000)
Lesson: Playwright waits
๐ ๏ธ playwright.config.ts Essentials
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
timeout: 30_000,
expect: { timeout: 5_000 },
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 2 : undefined,
reporter: [['list'], ['html', { open: 'never' }], ['junit', { outputFile: 'results/junit.xml' }]],
use: {
baseURL: process.env.BASE_URL ?? 'https://www.saucedemo.com',
testIdAttribute: 'data-test',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
},
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{ name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json' }, dependencies: ['setup'] },
{ name: 'mobile', use: { ...devices['iPhone 13'] } },
],
});
Lessons: config file, cross-browser, mobile, login sessions
๐งฉ Fixtures and Page Objects
// Page object
export class LoginPage {
readonly username: Locator;
constructor(private readonly page: Page) {
this.username = page.getByPlaceholder('Username');
}
async login(u: string, p: string) { /* fill + click */ }
}
// Custom fixtures
export const test = base.extend<{ loginPage: LoginPage }>({
loginPage: async ({ page }, use) => { await use(new LoginPage(page)); },
});
// Worker-scoped fixture
account: [async ({}, use, workerInfo) => { await use('user_' + workerInfo.workerIndex); }, { scope: 'worker' }],
Lessons: POM, fixtures, custom fixtures, framework structure
๐ API Testing and Network
const res = await request.get('/posts', { params: { userId: 1 } });
await request.post('/posts', { data: { title: 'x' } }); // JSON body
await request.post('/login', { form: { email, password } }); // form body
await request.put('/posts/1', { data }); await request.patch('/posts/1', { data });
await request.delete('/posts/1');
expect(res.status()).toBe(200); const body = await res.json();
await page.route('**/api/items', r => r.fulfill({ json: [] })); // mock
await page.route('**/api/items', async r => { const resp = await r.fetch(); await r.fulfill({ response: resp, json: { ...(await resp.json()), extra: 1 } }); });
await page.route('**/*.{png,jpg}', r => r.abort()); // block
page.on('console', m => console.log(m.text()));
Lessons: API testing, network mocking
๐ธ Debugging, Screenshots and Reports
await page.pause(); // open Inspector (headed)
await page.screenshot({ path: 'shot.png', fullPage: true, mask: [locator] });
await locator.screenshot({ path: 'element.png' });
await testInfo.attach('data', { body: JSON.stringify(obj), contentType: 'application/json' });
console.log(testInfo.retry, testInfo.workerIndex, testInfo.tags);
Lessons: debugging, Trace Viewer, screenshots and videos, reporters
๐ CI in One Minute (GitHub Actions)
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: lts/* }
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: always()
with: { name: playwright-report, path: playwright-report/ }
Lessons: parallel and sharding, GitHub Actions, Jenkins, Docker
๐ค AI Tools
claude mcp add playwright npx @playwright/mcp@latest # Playwright MCP in Claude Code
npx playwright init-agents --loop=vscode # planner, generator, healer agents
Lessons: Playwright MCP, Test Agents
๐ซ Top 10 Mistakes to Avoid
- Missing
awaitbefore actions and web-first assertions. page.waitForTimeout()instead of waiting for a condition.expect(await locator.textContent())instead ofawait expect(locator).toHaveText().force: trueto “fix” covered elements.- Long CSS or absolute XPath selectors.
- Tests that depend on each other or share data.
- Logging in through the UI in every test instead of
storageState. - Selectors and URLs hard-coded inside tests.
- Committing
test.only,page.pause()or secrets. - Raising retries instead of fixing flaky tests.
โ FAQ
๐ค Is there a Playwright cheat sheet PDF?
Use your browser’s Print, Save as PDF on this page to keep an offline copy. The page is updated as Playwright evolves.
๐ค What are the most important Playwright commands to remember?
npx playwright test with -g, --grep, --project, --headed, --ui and --debug, plus show-report, show-trace and codegen.
๐ค Which Playwright locators should I memorize first?
getByRole, getByLabel, getByPlaceholder, getByText, getByTestId, and locator() with filter for everything else.
๐ฏ Next Steps
- ๐ผ Interview Questions for Experienced
- ๐ Module-wise Practice Assignments
- ๐งช Playwright with TypeScript MCQ Assessment
- ๐ญ Playwright Tutorial with TypeScript
๐ฌ Watch the full Playwright tutorial series on YouTube!
Subscribe to SqaToolsByDY • Practice on sqatools.in