{"id":4336,"date":"2026-03-30T11:30:27","date_gmt":"2026-03-30T06:00:27","guid":{"rendered":"https:\/\/www.getpanto.ai\/blog\/?p=4336"},"modified":"2026-04-03T13:25:42","modified_gmt":"2026-04-03T07:55:42","slug":"playwright-cheat-sheet","status":"publish","type":"post","link":"https:\/\/www.getpanto.ai\/blog\/playwright-cheat-sheet","title":{"rendered":"Playwright Cheatsheet 2026: Commands, Locators, Assertions, Debugging Guide"},"content":{"rendered":"\n<p>Playwright is one of the strongest choices for modern <a href=\"https:\/\/www.getpanto.ai\/blog\/automated-mobile-qa-ai-testing#evolution-from-unit-testing-to-holistic-user-journ\">end-to-end testing<\/a> because it combines browser automation, reliable waiting behavior, cross-browser support, and a clean developer experience. This Playwright cheatsheet is built for speed: scan the syntax, copy the patterns, and use the examples as a reference while you build or maintain tests.<\/p>\n\n\n<h2 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"what-this-playwright-cheatsheet-covers\"><span class=\"ez-toc-section\" id=\"what-this-playwright-cheatsheet-covers\"><\/span><strong>What this Playwright cheatsheet covers<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n<p>This page focuses on the Playwright fundamentals that teams use most often:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>installation and setup<\/li>\n\n\n\n<li>running tests from the CLI<\/li>\n\n\n\n<li>locators and selectors<\/li>\n\n\n\n<li>common actions<\/li>\n\n\n\n<li>assertions<\/li>\n\n\n\n<li>waiting and synchronization<\/li>\n\n\n\n<li>fixtures<\/li>\n\n\n\n<li>mocking and network control<\/li>\n\n\n\n<li>authentication<\/li>\n\n\n\n<li>debugging and trace-based investigation<\/li>\n\n\n\n<li>code generation<\/li>\n\n\n\n<li>best practices<\/li>\n\n\n\n<li>common mistakes<\/li>\n<\/ul>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"playwright-at-a-glance\"><span class=\"ez-toc-section\" id=\"playwright-at-a-glance\"><\/span><strong>Playwright at a glance<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p><a href=\"https:\/\/www.getpanto.ai\/blog\/playwright-mcp-for-mobile-app-testing#why-use-playwright-for-mobile-testing\">Playwright is a browser automation and testing framework<\/a> used for end-to-end testing, UI testing, and broader web testing workflows. Playwright is positioned around reliable browser automation, with strong support for locators, assertions, multiple browsers, test isolation, and debugging tools.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Use case<\/th><th>Why Playwright fits<\/th><\/tr><\/thead><tbody><tr><td>End-to-end testing<\/td><td>Covers full user journeys across browsers<\/td><\/tr><tr><td>UI automation<\/td><td>Interacts with modern front-end apps reliably<\/td><\/tr><tr><td>Regression testing<\/td><td>Good for repeatable browser checks<\/td><\/tr><tr><td>Cross-browser validation<\/td><td>Supports Chromium, Firefox, and WebKit<\/td><\/tr><tr><td>Authenticated flows<\/td><td>Handles reusable session state<\/td><\/tr><tr><td>API + UI testing<\/td><td>Works across both browser and network layers<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h2 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"core-playwright-commands\"><span class=\"ez-toc-section\" id=\"core-playwright-commands\"><\/span><strong>Core Playwright commands<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n<h3 class=\"wp-block-heading\" id=\"quick-command-recap\"><span class=\"ez-toc-section\" id=\"quick-command-recap\"><\/span><strong>Quick Command Recap<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Task<\/th><th>Command<\/th><\/tr><\/thead><tbody><tr><td>Install Playwright<\/td><td><code>npm init playwright@latest<\/code><\/td><\/tr><tr><td>Run all tests<\/td><td><code>npx playwright test<\/code><\/td><\/tr><tr><td>Run one file<\/td><td><code>npx playwright test tests\/example.spec.ts<\/code><\/td><\/tr><tr><td>Run in headed mode<\/td><td><code>npx playwright test --headed<\/code><\/td><\/tr><tr><td>Run in UI mode<\/td><td><code>npx playwright test --ui<\/code><\/td><\/tr><tr><td>Debug tests<\/td><td><code>npx playwright test --debug<\/code><\/td><\/tr><tr><td>Run last failed tests<\/td><td><code>npx playwright test --last-failed<\/code><\/td><\/tr><tr><td>Show HTML report<\/td><td><code>npx playwright show-report<\/code><\/td><\/tr><tr><td>Generate starter code<\/td><td><code>npx playwright codegen https:\/\/example.com<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"first-playwright-test\"><span class=\"ez-toc-section\" id=\"first-playwright-test\"><\/span><strong>First Playwright test<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>A typical Playwright setup starts with installing the package, initializing the project, and then writing your first test file.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import { test, expect } from '@playwright\/test';\n\ntest('homepage has title', async ({ page }) =&gt; {\n  await page.goto('https:\/\/example.com');\n  await expect(page).toHaveTitle(\/Example\/);\n});\n<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"setup-and-configuration\"><span class=\"ez-toc-section\" id=\"setup-and-configuration\"><\/span><strong>Setup and configuration<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n<h4 class=\"wp-block-heading\" id=\"typical-config-ideas\"><strong>Typical config ideas<\/strong><\/h4>\n\n\n<p><a href=\"https:\/\/www.getpanto.ai\/blog\/playwright-react-native-hybrid-testing#setting-up-the-playwright-test-environment\">A Playwright config<\/a> usually handles:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>browser projects<\/li>\n\n\n\n<li>base URL<\/li>\n\n\n\n<li>retries<\/li>\n\n\n\n<li>trace collection<\/li>\n\n\n\n<li>test timeout<\/li>\n\n\n\n<li>parallel execution<\/li>\n\n\n\n<li>screenshots and videos on failure<\/li>\n<\/ul>\n\n\n<h4 class=\"wp-block-heading\" id=\"example-config-snippet\"><strong>Example config snippet<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>import { defineConfig } from '@playwright\/test';\n\nexport default defineConfig({\n  use: {\n    baseURL: 'https:\/\/example.com',\n    trace: 'on-first-retry',\n  },\n});\n<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\" id=\"running-tests\"><span class=\"ez-toc-section\" id=\"running-tests\"><\/span><strong>Running Tests<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>The Playwright CLI is built for flexibility. You can run all tests, a single test file, a subset of tests, a specific browser project, or only the tests that failed last time. The docs also document <code>--debug<\/code> for Inspector-based <a href=\"https:\/\/www.getpanto.ai\/blog\/vibe-debugging-ai-qa-testing#what-is-vibe-debugging\">debugging<\/a>.<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"common-commands\"><strong>Common commands<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test<br>npx playwright test landing-page.spec.ts<br>npx playwright test tests\/todo-page\/<br>npx playwright test landing login<br>npx playwright test --last-failed<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"run-on-a-specific-browser-project\"><strong>Run on a specific browser project<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test --project webkit<br>npx playwright test --project firefox<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"debug-mode\"><strong>Debug mode<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test --debug<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"run-one-test-at-a-specific-line\"><strong>Run one test at a specific line<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test example.spec.ts:10 --debug<\/code><\/pre>\n\n\n\n<p>Playwright tests run in parallel by default, and projects let you target multiple browsers or device profiles from the same suite.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"locators-cheatsheet\"><span class=\"ez-toc-section\" id=\"locators-cheatsheet\"><\/span><strong>Locators cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Locators are one of the most <a href=\"https:\/\/www.getpanto.ai\/blog\/add-ai-to-an-existing-selenium-playwright-stack#1-visual-ai-testing\">important concepts in Playwright<\/a>. Playwright works best when you target the page the way a user would. That means preferring visible roles, labels, and text before falling back to CSS selectors.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Locator<\/th><th>Example<\/th><th>Best for<\/th><\/tr><\/thead><tbody><tr><td><code>getByRole()<\/code><\/td><td><code>page.getByRole('button', { name: 'Sign in' })<\/code><\/td><td>Buttons, links, menus, form controls<\/td><\/tr><tr><td><code>getByLabel()<\/code><\/td><td><code>page.getByLabel('Email')<\/code><\/td><td>Form fields<\/td><\/tr><tr><td><code>getByText()<\/code><\/td><td><code>page.getByText('Continue')<\/code><\/td><td>Visible text<\/td><\/tr><tr><td><code>getByPlaceholder()<\/code><\/td><td><code>page.getByPlaceholder('Search')<\/code><\/td><td>Inputs with placeholders<\/td><\/tr><tr><td><code>getByAltText()<\/code><\/td><td><code>page.getByAltText('Logo')<\/code><\/td><td>Images<\/td><\/tr><tr><td><code>getByTitle()<\/code><\/td><td><code>page.getByTitle('Help')<\/code><\/td><td>Tooltips and titles<\/td><\/tr><tr><td><code>getByTestId()<\/code><\/td><td><code>page.getByTestId('submit-btn')<\/code><\/td><td>Stable custom hooks<\/td><\/tr><tr><td><code>locator()<\/code><\/td><td><code>page.locator('.card')<\/code><\/td><td>CSS targeting<\/td><\/tr><tr><td><code>frameLocator()<\/code><\/td><td><code>page.frameLocator('iframe')<\/code><\/td><td>Embedded frames<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"locator-examples\"><strong>Locator examples<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.getByRole('button', { name: 'Save' }).click();\nawait page.getByLabel('Password').fill('secret');\nawait page.getByText('Continue').click();\n<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"common-actions\"><span class=\"ez-toc-section\" id=\"common-actions\"><\/span><strong>Common actions<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Once an element is located, <a href=\"https:\/\/www.getpanto.ai\/blog\/selenium-vs-playwright#what-playwright-does-better\">Playwright makes common user interactions straightforward<\/a>. These actions are most reliable when combined with resilient locators rather than CSS paths or arbitrary timeouts.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Action<\/th><th>Example<\/th><\/tr><\/thead><tbody><tr><td>Click<\/td><td><code>await page.getByRole('button', { name: 'Save' }).click();<\/code><\/td><\/tr><tr><td>Fill input<\/td><td><code>await page.getByLabel('Email').fill('me@example.com');<\/code><\/td><\/tr><tr><td>Type<\/td><td><code>await page.getByLabel('Search').type('playwright');<\/code><\/td><\/tr><tr><td>Select option<\/td><td><code>await page.getByLabel('Country').selectOption('IN');<\/code><\/td><\/tr><tr><td>Check checkbox<\/td><td><code>await page.getByLabel('Subscribe').check();<\/code><\/td><\/tr><tr><td>Uncheck checkbox<\/td><td><code>await page.getByLabel('Subscribe').uncheck();<\/code><\/td><\/tr><tr><td>Upload file<\/td><td><code>await page.getByLabel('Upload').setInputFiles('file.pdf');<\/code><\/td><\/tr><tr><td>Hover<\/td><td><code>await page.getByText('Menu').hover();<\/code><\/td><\/tr><tr><td>Press a key<\/td><td><code>await page.keyboard.press('Enter');<\/code><\/td><\/tr><tr><td>Double click<\/td><td><code>await page.getByText('Item').dblclick();<\/code><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"action-pattern\"><strong>Action pattern<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.getByRole('button', { name: 'Submit' }).click();\nawait page.getByLabel('Email').fill('me@example.com');\nawait page.getByRole('button', { name: 'Submit' }).click();\n<\/code><\/pre>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"assertions-cheatsheet\"><span class=\"ez-toc-section\" id=\"assertions-cheatsheet\"><\/span><strong>Assertions cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Assertions are one of the reasons Playwright feels stable. Assertions are written with <code>expect<\/code>, and emphasize async matchers that wait for the expected condition. This is a key reason Playwright tests are <a href=\"https:\/\/www.getpanto.ai\/blog\/detect-flaky-tests#what-makes-a-test-flaky\">less flaky than tests that rely on manual sleeps.<\/a><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Assertion<\/th><th>Example<\/th><th>Use case<\/th><\/tr><\/thead><tbody><tr><td><code>toBeVisible()<\/code><\/td><td><code>await expect(page.getByText('Success')).toBeVisible();<\/code><\/td><td>Element should appear<\/td><\/tr><tr><td><code>toBeHidden()<\/code><\/td><td><code>await expect(page.getByText('Loading')).toBeHidden();<\/code><\/td><td>Element should disappear<\/td><\/tr><tr><td><code>toHaveText()<\/code><\/td><td><code>await expect(page.getByTestId('status')).toHaveText('Done');<\/code><\/td><td>Exact text match<\/td><\/tr><tr><td><code>toContainText()<\/code><\/td><td><code>await expect(page.locator('h1')).toContainText('Dashboard');<\/code><\/td><td>Partial text match<\/td><\/tr><tr><td><code>toHaveCount()<\/code><\/td><td><code>await expect(page.locator('li')).toHaveCount(3);<\/code><\/td><td>Element count<\/td><\/tr><tr><td><code>toHaveURL()<\/code><\/td><td><code>await expect(page).toHaveURL(\/dashboard\/);<\/code><\/td><td>Navigation check<\/td><\/tr><tr><td><code>toHaveTitle()<\/code><\/td><td><code>await expect(page).toHaveTitle(\/Home\/);<\/code><\/td><td>Page title<\/td><\/tr><tr><td><code>toBeEnabled()<\/code><\/td><td><code>await expect(button).toBeEnabled();<\/code><\/td><td>Clickable state<\/td><\/tr><tr><td><code>toBeDisabled()<\/code><\/td><td><code>await expect(button).toBeDisabled();<\/code><\/td><td>Disabled state<\/td><\/tr><tr><td><code>toHaveValue()<\/code><\/td><td><code>await expect(input).toHaveValue('john');<\/code><\/td><td>Input value<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"assertion-example\"><strong>Assertion example<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();\nawait expect(page).toHaveURL(\/dashboard\/);\n<\/code><\/pre>\n\n\n\n<p>The docs recommend web-first assertions because they automatically wait for the page to reach the expected state. That makes them a better default than ad hoc polling or manual delays.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"waiting-and-synchronization\"><span class=\"ez-toc-section\" id=\"waiting-and-synchronization\"><\/span><strong>Waiting and synchronization<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Playwright is designed to wait intelligently. In most cases, you should wait for a visible outcome rather than hard-coding time. <a href=\"https:\/\/www.getpanto.ai\/blog\/playwright-vs-maestro#1-auto-waiting-flakiness-tolerance\">Playwright\u2019s auto-waiting<\/a> covers many common cases, so the default approach should be to rely on locators and assertions rather than fixed pauses.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Prefer<\/th><th>Avoid<\/th><\/tr><\/thead><tbody><tr><td><code>await expect(locator).toBeVisible()<\/code><\/td><td><code>await page.waitForTimeout(5000)<\/code><\/td><\/tr><tr><td><code>await expect(page).toHaveURL(...)<\/code><\/td><td>Manual polling<\/td><\/tr><tr><td><code>await locator.click()<\/code><\/td><td>Clicking before the element is ready<\/td><\/tr><tr><td><code>await expect(page.getByText('Saved')).toBeVisible()<\/code><\/td><td>Sleeping and hoping<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"better-pattern\"><strong>Better pattern<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.getByRole('button', { name: 'Submit' }).click();\nawait expect(page.getByText('Submitted')).toBeVisible();\n<\/code><\/pre>\n\n\n\n<p>Use explicit waits only when you truly need them, and prefer waiting for a visible application state instead of waiting for a duration. That keeps the suite faster and more deterministic.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"navigation-and-page-handling\"><span class=\"ez-toc-section\" id=\"navigation-and-page-handling\"><\/span><strong>Navigation and page handling<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Navigation and page handling are at the core of <a href=\"https:\/\/www.getpanto.ai\/blog\/why-playwright-mcp-isnt-enough-and-what-mobile-qa-teams-actually-need#deep-dive-playwright-mcp-model\">most Playwright tests<\/a>. Whether you are validating a simple redirect, handling multi-step workflows, or working with tabs and popups, Playwright provides built-in methods to control navigation reliably without introducing flakiness. <br><br><\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"common-page-actions\"><strong>Common page actions<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.goto('https:\/\/example.com');\nawait page.reload();\nawait page.goBack();\nawait page.goForward();\n<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"tabs-and-windows\"><strong>Tabs and windows<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>const newPage = await context.newPage();\nawait newPage.goto('https:\/\/example.com');\n<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"screenshots\"><strong>Screenshots<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.screenshot({ path: 'homepage.png', fullPage: true });\n<\/code><\/pre>\n\n\n\n<p>Understanding how to move between pages, manage browser contexts, and capture page state ensures your tests remain stable while accurately reflecting real user journeys.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"fixtures-cheatsheet\"><span class=\"ez-toc-section\" id=\"fixtures-cheatsheet\"><\/span><strong>Fixtures cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Fixtures make tests cleaner and more isolated. Fixtures are a way to give each test exactly what it needs while keeping <a href=\"https:\/\/www.getpanto.ai\/blog\/common-test-failure-patterns#2-environment-configuration-drift\">test environments isolated<\/a>. This helps prevent cascading failures and makes suites easier to organize.<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"why-fixtures-matter\"><strong>Why fixtures matter<\/strong><\/h4>\n\n\n<ul class=\"wp-block-list\">\n<li>simplify browser\/context lifecycle management<\/li>\n\n\n\n<li>isolate state between tests<\/li>\n\n\n\n<li>reduce duplicate setup<\/li>\n\n\n\n<li>group tests by meaning, not just shared code<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Fixture<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>page<\/code><\/td><td>New page for the test<\/td><\/tr><tr><td><code>context<\/code><\/td><td>Isolated browser context<\/td><\/tr><tr><td><code>browser<\/code><\/td><td>Launch browser instances<\/td><\/tr><tr><td>Custom fixtures<\/td><td>Share reusable setup logic<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"example\"><strong>Example<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>import { test, expect } from '@playwright\/test';\n\ntest('user can open dashboard', async ({ page }) =&gt; {\n  await page.goto('\/dashboard');\n  await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();\n});\n<\/code><\/pre>\n\n\n\n<p>Playwright\u2019s fixture model is especially useful when you need reusable setup such as authenticated contexts, seeded data, or API state.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"mocking-and-network-control\"><span class=\"ez-toc-section\" id=\"mocking-and-network-control\"><\/span><strong>Mocking and network control<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Playwright can intercept, modify, and mock HTTP and HTTPS traffic, including XHR and fetch requests. Playwright also provides support for mocking with HAR files, which is useful when you <a href=\"https:\/\/www.getpanto.ai\/products\/ai-automation-testing\">need deterministic tests<\/a> without calling live services.<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"typical-uses\"><strong>Typical uses<\/strong><\/h4>\n\n\n<ul class=\"wp-block-list\">\n<li>simulate a slow backend<\/li>\n\n\n\n<li>return controlled API responses<\/li>\n\n\n\n<li>isolate frontend behavior from unstable integrations<\/li>\n\n\n\n<li>replay network traffic from HAR<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Task<\/th><th>Example<\/th><\/tr><\/thead><tbody><tr><td>Mock API response<\/td><td><code>page.route()<\/code><\/td><\/tr><tr><td>Block request<\/td><td><code>route.abort()<\/code><\/td><\/tr><tr><td>Modify response<\/td><td><code>route.fulfill()<\/code><\/td><\/tr><tr><td>Replay traffic<\/td><td>HAR-based mocking<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"example-mock-an-api-response\"><strong>Example: mock an API response<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>await page.route('**\/api\/users', async route =&gt; {\n  await route.fulfill({\n    status: 200,\n    contentType: 'application\/json',\n    body: JSON.stringify(&#91;{ id: 1, name: 'Asha' }]),\n  });\n});\n<\/code><\/pre>\n\n\n\n<p>Mocking is especially valuable in regression suites where you want consistent results independent of backend volatility.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"authentication-cheatsheet\"><span class=\"ez-toc-section\" id=\"authentication-cheatsheet\"><\/span><strong>Authentication cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Playwright supports authenticated state reuse <a href=\"https:\/\/www.getpanto.ai\/products\/automated-cross-browser-testing\">through browser contexts<\/a>, which helps avoid logging in for every single test. Browser contexts are isolated, and existing authenticated state can be loaded to speed up tests and reduce repeated setup.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Pattern<\/th><th>Use when<\/th><\/tr><\/thead><tbody><tr><td>Login once and reuse state<\/td><td>You want faster suites<\/td><\/tr><tr><td>Save storage state<\/td><td>You need persistent auth<\/td><\/tr><tr><td>Separate auth setup<\/td><td>You want cleaner structure<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"example\"><strong>Example<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>test.use({ storageState: 'auth.json' });\n<\/code><\/pre>\n\n\n\n<p>This is useful for admin dashboards, role-based applications, and any suite where authentication is expensive or rate-limited.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"debugging-cheatsheet\"><span class=\"ez-toc-section\" id=\"debugging-cheatsheet\"><\/span><strong>Debugging cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p><a href=\"https:\/\/www.getpanto.ai\/blog\/vibe-debugging-mobile-qa#what-vibe-debugging-means-for-mobile-qa-teams\">Debugging<\/a> is a major Playwright strength. The docs recommend UI mode, Inspector debugging, and Trace Viewer to understand failures. Trace Viewer lets you step through a recorded test and inspect actions, snapshots, and network activity after the run.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Tool<\/th><th>Best for<\/th><\/tr><\/thead><tbody><tr><td><code>--debug<\/code><\/td><td>Step-by-step debugging<\/td><\/tr><tr><td>UI mode<\/td><td>Interactive test execution<\/td><\/tr><tr><td>Trace Viewer<\/td><td>Reviewing what happened after a failure<\/td><\/tr><tr><td>Screenshots<\/td><td>Visual checkpoints<\/td><\/tr><tr><td>Video<\/td><td>Capturing the full run<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"debug-commands\"><strong>Debug commands<\/strong><\/h4>\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test --debug\nnpx playwright test --ui\nnpx playwright show-report\n<\/code><\/pre>\n\n\n\n<p>Playwright Trace Viewer acts as a GUI that helps you explore recorded traces after the script finishes, which is especially useful for <a href=\"https:\/\/www.getpanto.ai\/blog\/why-do-tests-pass-locally-but-fail-in-ci#common-causes-of-ci-vs-local-test-failures\">CI failures<\/a>.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"code-generation-cheatsheet\"><span class=\"ez-toc-section\" id=\"code-generation-cheatsheet\"><\/span><strong>Code generation cheatsheet<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>Playwright\u2019s test generator, or codegen, can record interactions and <a href=\"https:\/\/www.getpanto.ai\/products\/no-code-test-automation-tools\">generate test code<\/a> while you browse. It prioritizes role, text, and test id locators, and improves locators when multiple elements match so the resulting test is more resilient.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Command<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>npx playwright codegen https:\/\/example.com<\/code><\/td><td>Record interactions and generate code<\/td><\/tr><tr><td><code>npx playwright codegen --target=typescript https:\/\/example.com<\/code><\/td><td>Generate TypeScript output<\/td><\/tr><tr><td><code>npx playwright codegen --device=\"iPhone 13\" https:\/\/example.com<\/code><\/td><td>Record against a device profile<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h4 class=\"wp-block-heading\" id=\"why-it-is-useful\"><strong>Why it is useful<\/strong><\/h4>\n\n\n<ul class=\"wp-block-list\">\n<li>bootstrap a new test quickly<\/li>\n\n\n\n<li>discover good locator patterns<\/li>\n\n\n\n<li>reduce manual setup time<\/li>\n\n\n\n<li>get a starting point for exploratory test creation<\/li>\n<\/ul>\n\n\n\n<p><a href=\"https:\/\/www.getpanto.ai\/blog\/ai-test-case-generation\">Code generation<\/a> is not the final answer for every test, but it is a strong accelerator when you need to build coverage fast.<\/p>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"best-practices\"><span class=\"ez-toc-section\" id=\"best-practices\"><\/span><strong>Best practices<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Do<\/th><th>Don\u2019t<\/th><\/tr><\/thead><tbody><tr><td>Use role\/label\/text locators<\/td><td>Start with brittle CSS chains<\/td><\/tr><tr><td>Prefer assertions over sleeps<\/td><td>Rely on <code>waitForTimeout()<\/code><\/td><\/tr><tr><td>Keep tests isolated<\/td><td>Share mutable state between tests<\/td><\/tr><tr><td>Mock unstable dependencies<\/td><td>Depend on flaky live services<\/td><\/tr><tr><td>Use traces for failures<\/td><td>Guess at the root cause<\/td><\/tr><tr><td>Reuse auth state<\/td><td>Log in manually in every test<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n<h3 class=\"wp-block-heading\" style=\"text-transform:capitalize\" id=\"common-mistakes-to-avoid\"><span class=\"ez-toc-section\" id=\"common-mistakes-to-avoid\"><\/span><strong>Common mistakes to avoid<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n<h4 class=\"wp-block-heading\" id=\"1-fragile-selectors\"><strong>1. Fragile selectors<\/strong><\/h4>\n\n\n<p><strong>Bad:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>page.locator('div &gt; div &gt; div:nth-child(2) &gt; button')\n<\/code><\/pre>\n\n\n\n<p><strong>Better:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>page.getByRole('button', { name: 'Save' })\n<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"2-fixed-delays\"><strong>2. Fixed delays<\/strong><\/h4>\n\n\n<p><strong>Bad:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>await page.waitForTimeout(3000);\n<\/code><\/pre>\n\n\n\n<p><strong>Better:<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>await expect(page.getByText('Saved')).toBeVisible();\n<\/code><\/pre>\n\n\n<h4 class=\"wp-block-heading\" id=\"3-overcomplicated-tests\"><strong>3. Overcomplicated tests<\/strong><\/h4>\n\n\n<p>Keep one test focused on one behavior. Long tests that do too much are <a href=\"https:\/\/www.getpanto.ai\/blog\/vibe-debugging-best-practices#5-embrace-responsible-ai-debugging\">harder to debug<\/a> and maintain.<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"4-testing-implementation-instead-of-behavior\"><strong>4. Testing implementation instead of behavior<\/strong><\/h4>\n\n\n<p>Test what the user sees and does. Avoid coupling tests to internal structure unless there is no better option.<\/p>\n\n\n\n<p>A good Playwright test suite is not defined by how many tests you write, but by how reliably those tests reflect real user behavior. The patterns in this cheatsheet are what separate <a href=\"https:\/\/www.getpanto.ai\/\">stable, scalable test suites<\/a> from brittle ones. As your application grows, these fundamentals help reduce flakiness, speed up execution, and make failures easier to debug and trust.<\/p>\n\n\n\n<p>Use this Playwright cheatsheet as a working reference, not just a one-time read. Whether you are writing new tests, debugging failures, or improving an existing suite, <a href=\"https:\/\/www.getpanto.ai\/products\/automated-performance-testing-tools\">the goal is consistency and clarity<\/a>. Over time, applying these practices will help your team move faster with confidence, ship fewer regressions, and build a testing workflow that scales alongside your product.<\/p>\n\n\n<h3 class=\"wp-block-heading\" id=\"faqs\"><span class=\"ez-toc-section\" id=\"faqs\"><\/span><strong>FAQ&#8217;s<\/strong><span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-what-is-playwright-used-for\"><strong>Q: What is Playwright used for?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Playwright is used for browser automation, end-to-end testing, UI testing, and cross-browser validation. It is particularly effective for modern web applications that require reliable, repeatable interaction testing across multiple browsers.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-is-playwright-better-than-selenium\"><strong>Q: Is Playwright better than Selenium?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> For many modern test suites, Playwright is easier to use due to its built-in waiting mechanisms, powerful debugging tools, and more streamlined developer experience. However, the choice depends on existing infrastructure and team familiarity.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-what-is-the-best-locator-strategy-in-playwright\"><strong>Q: What is the best locator strategy in Playwright?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> The recommended approach is to use user-facing locators such as <code>getByRole<\/code> and <code>getByLabel<\/code>. These are more resilient and maintainable compared to CSS selectors or deeply nested DOM paths.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-how-do-i-run-tests-in-headed-mode\"><strong>Q: How do I run tests in headed mode?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> You can run Playwright tests in headed mode using the following command:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>npx playwright test --headed<\/code><\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-how-do-i-debug-a-failing-playwright-test\"><strong>Q: How do I debug a failing Playwright test?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Use Playwright\u2019s debugging tools such as debug mode, UI mode, screenshots, and trace reports. These allow you to step through test execution and identify failures precisely.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-can-playwright-mock-apis\"><strong>Q: Can Playwright mock APIs?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Yes. Playwright allows you to intercept network requests, modify responses, abort calls, and even replay traffic using HAR files, making it effective for isolating frontend behavior.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-does-playwright-support-authenticated-testing\"><strong>Q: Does Playwright support authenticated testing?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Yes. You can persist authentication state using storage snapshots, allowing tests to bypass repeated login flows and improve execution speed.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-how-do-i-keep-playwright-tests-stable\"><strong>Q: How do I keep Playwright tests stable?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Use resilient locators, rely on built-in assertions that auto-wait, isolate test state with fixtures, and mock unstable external dependencies to reduce flakiness.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-is-playwright-good-for-regression-testing\"><strong>Q: Is Playwright good for regression testing?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Yes. Playwright is well suited for regression testing due to its stable automation engine, support for parallel execution, strong debugging capabilities, and reusable test architecture.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-should-i-use-waitfortimeout-in-playwright\"><strong>Q: Should I use <code>waitForTimeout()<\/code> in Playwright?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Only in rare cases. It is better to wait for actual UI states or use assertions that automatically retry, as fixed delays can lead to flaky and slow tests.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n\n\n<h4 class=\"wp-block-heading\" id=\"q-how-do-i-generate-tests-faster-in-playwright\"><strong>Q: How do I generate tests faster in Playwright?<\/strong><\/h4>\n\n\n<p><strong>A:<\/strong> Use Playwright\u2019s codegen feature to record interactions and generate a baseline test. Afterward, refine locators and assertions to make the test more stable and maintainable.<\/p>\n\n\n\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Playwright is one of the strongest choices for modern end-to-end testing because it combines browser automation, reliable waiting behavior, cross-browser support, and a clean developer experience. This Playwright cheatsheet is built for speed: scan the syntax, copy the patterns, and use the examples as a reference while you build or maintain tests. What this Playwright [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":4339,"comment_status":"open","ping_status":"open","sticky":false,"template":"wp-custom-template-panto-blogs-v3","format":"standard","meta":{"footnotes":""},"categories":[110],"tags":[],"class_list":["post-4336","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-vibe-debugging"],"_links":{"self":[{"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/posts\/4336","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/comments?post=4336"}],"version-history":[{"count":0,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/posts\/4336\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/media\/4339"}],"wp:attachment":[{"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/media?parent=4336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/categories?post=4336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.getpanto.ai\/blog\/wp-json\/wp\/v2\/tags?post=4336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}