@assertrx/dino 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +293 -0
- package/extensions/dino.ts +70 -0
- package/extensions/mabl-mcp.ts +306 -0
- package/extensions/playwright-mcp.ts +142 -0
- package/package.json +47 -0
- package/prompts/create-pr.md +110 -0
- package/prompts/generate-bdd-from-url.md +65 -0
- package/prompts/generate-pom-from-url-cli.md +48 -0
- package/prompts/generate-pom-from-url.md +45 -0
- package/prompts/generate-spec-from-feature.md +64 -0
- package/prompts/heal-playwright-failures.md +106 -0
- package/prompts/setup-playwright.md +81 -0
- package/scripts/start-dino.cmd +8 -0
- package/scripts/start-dino.mjs +226 -0
- package/scripts/start-dino.ps1 +9 -0
- package/scripts/start-dino.sh +10 -0
- package/skills/acli/SKILL.md +292 -0
- package/skills/bdd-gherkin/SKILL.md +552 -0
- package/skills/build-review-interface/SKILL.md +96 -0
- package/skills/error-analysis/SKILL.md +164 -0
- package/skills/eval-audit/SKILL.md +183 -0
- package/skills/evaluate-rag/SKILL.md +177 -0
- package/skills/generate-synthetic-data/SKILL.md +131 -0
- package/skills/mabl-mcp/SKILL.md +79 -0
- package/skills/playwright-cli/SKILL.md +246 -0
- package/skills/playwright-cli/advanced-workflows.md +679 -0
- package/skills/playwright-cli/core-commands.md +375 -0
- package/skills/playwright-cli/device-emulation.md +475 -0
- package/skills/playwright-cli/request-mocking.md +373 -0
- package/skills/playwright-cli/running-custom-code.md +553 -0
- package/skills/playwright-cli/screenshots-and-media.md +457 -0
- package/skills/playwright-cli/session-management.md +425 -0
- package/skills/playwright-cli/storage-and-auth.md +487 -0
- package/skills/playwright-cli/test-generation.md +336 -0
- package/skills/playwright-cli/tracing-and-debugging.md +501 -0
- package/skills/playwright-core/SKILL.md +101 -0
- package/skills/playwright-core/accessibility.md +1517 -0
- package/skills/playwright-core/angular.md +1086 -0
- package/skills/playwright-core/api-testing.md +1623 -0
- package/skills/playwright-core/assertions-and-waiting.md +703 -0
- package/skills/playwright-core/auth-flows.md +1081 -0
- package/skills/playwright-core/authentication.md +1409 -0
- package/skills/playwright-core/browser-apis.md +673 -0
- package/skills/playwright-core/browser-extensions.md +319 -0
- package/skills/playwright-core/canvas-and-webgl.md +494 -0
- package/skills/playwright-core/clock-and-time-mocking.md +427 -0
- package/skills/playwright-core/common-pitfalls.md +1318 -0
- package/skills/playwright-core/component-testing.md +1179 -0
- package/skills/playwright-core/configuration.md +731 -0
- package/skills/playwright-core/crud-testing.md +945 -0
- package/skills/playwright-core/debugging.md +827 -0
- package/skills/playwright-core/drag-and-drop.md +992 -0
- package/skills/playwright-core/electron-testing.md +622 -0
- package/skills/playwright-core/error-and-edge-cases.md +1181 -0
- package/skills/playwright-core/error-index.md +1903 -0
- package/skills/playwright-core/file-operations.md +749 -0
- package/skills/playwright-core/file-upload-download.md +1012 -0
- package/skills/playwright-core/fixtures-and-hooks.md +1072 -0
- package/skills/playwright-core/flaky-tests.md +883 -0
- package/skills/playwright-core/forms-and-validation.md +1056 -0
- package/skills/playwright-core/i18n-and-localization.md +622 -0
- package/skills/playwright-core/iframes-and-shadow-dom.md +488 -0
- package/skills/playwright-core/locator-strategy.md +588 -0
- package/skills/playwright-core/locators.md +743 -0
- package/skills/playwright-core/mobile-and-responsive.md +1669 -0
- package/skills/playwright-core/multi-context-and-popups.md +581 -0
- package/skills/playwright-core/multi-user-and-collaboration.md +477 -0
- package/skills/playwright-core/network-mocking.md +1395 -0
- package/skills/playwright-core/nextjs.md +1013 -0
- package/skills/playwright-core/performance-testing.md +608 -0
- package/skills/playwright-core/react.md +1082 -0
- package/skills/playwright-core/search-and-filter.md +1366 -0
- package/skills/playwright-core/security-testing.md +624 -0
- package/skills/playwright-core/service-workers-and-pwa.md +524 -0
- package/skills/playwright-core/test-architecture.md +569 -0
- package/skills/playwright-core/test-data-management.md +1209 -0
- package/skills/playwright-core/test-organization.md +947 -0
- package/skills/playwright-core/third-party-integrations.md +754 -0
- package/skills/playwright-core/trace-analysis.md +161 -0
- package/skills/playwright-core/visual-regression.md +1027 -0
- package/skills/playwright-core/vue.md +1162 -0
- package/skills/playwright-core/websockets-and-realtime.md +623 -0
- package/skills/playwright-core/when-to-mock.md +827 -0
- package/skills/playwright-pom/SKILL.md +94 -0
- package/skills/playwright-pom/page-object-model.md +921 -0
- package/skills/playwright-pom/pom-vs-fixtures-vs-helpers.md +937 -0
- package/skills/validate-evaluator/SKILL.md +215 -0
- package/skills/write-judge-prompt/SKILL.md +144 -0
- package/themes/dino.json +66 -0
|
@@ -0,0 +1,827 @@
|
|
|
1
|
+
# Debugging Playwright Tests
|
|
2
|
+
|
|
3
|
+
> **When to use**: A test is failing and you need to understand why — wrong selectors, timing issues, network failures, or unexpected application state.
|
|
4
|
+
|
|
5
|
+
## Quick Reference
|
|
6
|
+
|
|
7
|
+
| Tool | Command | Best For |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| UI Mode | `npx playwright test --ui` | Interactive exploration, visual timeline, re-running tests |
|
|
10
|
+
| Playwright Inspector | `PWDEBUG=1 npx playwright test` | Step-through debugging, selector playground |
|
|
11
|
+
| Trace Viewer | `npx playwright show-trace trace.zip` | Post-mortem CI failure analysis |
|
|
12
|
+
| CLI debugger | `npx playwright test --debug=cli` | Agent workflows, SSH sessions, terminal-first debugging |
|
|
13
|
+
| Headed mode | `npx playwright test --headed` | Watching the browser during test execution |
|
|
14
|
+
| Slow motion | `npx playwright test --headed --slow-mo=500` | Visually following fast interactions |
|
|
15
|
+
| `page.pause()` | Insert in test code | Pausing at an exact point to inspect state |
|
|
16
|
+
| Verbose API logs | `DEBUG=pw:api npx playwright test` | Seeing every Playwright API call with timing |
|
|
17
|
+
| VS Code extension | Playwright Test for VS Code | Breakpoints, step-through, pick locator |
|
|
18
|
+
|
|
19
|
+
## Systematic Debugging Workflow
|
|
20
|
+
|
|
21
|
+
Follow this order. Do not skip to step 5 — most issues resolve by step 2.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
1. Read the full error message
|
|
25
|
+
└─ Check troubleshooting/error-index.md for known patterns
|
|
26
|
+
2. Run with --ui to see what happened visually
|
|
27
|
+
└─ Timeline shows every action, screenshot at failure point
|
|
28
|
+
3. Enable tracing if not already on
|
|
29
|
+
└─ use: { trace: 'on' } temporarily in config
|
|
30
|
+
4. Check the network tab in trace for API failures
|
|
31
|
+
└─ Missing responses, 4xx/5xx, CORS errors
|
|
32
|
+
5. Insert page.pause() at the failure point
|
|
33
|
+
└─ Inspect live DOM, try selectors in console
|
|
34
|
+
6. Check browser console for JavaScript errors
|
|
35
|
+
└─ page.on('console') or console tab in trace
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Patterns
|
|
39
|
+
|
|
40
|
+
### Pattern 1: UI Mode for Interactive Debugging
|
|
41
|
+
|
|
42
|
+
**Use when**: Developing new tests, investigating failures locally, exploring application behavior.
|
|
43
|
+
**Avoid when**: CI environments (use traces instead).
|
|
44
|
+
|
|
45
|
+
UI Mode provides a visual timeline, DOM snapshots at each step, network waterfall, and the ability to re-run individual tests.
|
|
46
|
+
|
|
47
|
+
**TypeScript**
|
|
48
|
+
```typescript
|
|
49
|
+
// Launch UI Mode from terminal:
|
|
50
|
+
// npx playwright test --ui
|
|
51
|
+
|
|
52
|
+
// Run a specific test file in UI Mode:
|
|
53
|
+
// npx playwright test tests/checkout.spec.ts --ui
|
|
54
|
+
|
|
55
|
+
// playwright.config.ts — configure for UI Mode convenience
|
|
56
|
+
import { defineConfig } from '@playwright/test';
|
|
57
|
+
|
|
58
|
+
export default defineConfig({
|
|
59
|
+
use: {
|
|
60
|
+
// Traces are always available in UI Mode regardless of this setting,
|
|
61
|
+
// but this ensures traces are captured for CI failures too
|
|
62
|
+
trace: 'on-first-retry',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
For flaky tests on Playwright 1.59+, consider `trace: 'retain-on-failure-and-retries'` so you can compare the failing attempt with any passing retries instead of keeping only one trace artifact.
|
|
68
|
+
|
|
69
|
+
**JavaScript**
|
|
70
|
+
```javascript
|
|
71
|
+
// Launch UI Mode from terminal:
|
|
72
|
+
// npx playwright test --ui
|
|
73
|
+
|
|
74
|
+
// Run a specific test file in UI Mode:
|
|
75
|
+
// npx playwright test tests/checkout.spec.js --ui
|
|
76
|
+
|
|
77
|
+
// playwright.config.js
|
|
78
|
+
const { defineConfig } = require('@playwright/test');
|
|
79
|
+
|
|
80
|
+
module.exports = defineConfig({
|
|
81
|
+
use: {
|
|
82
|
+
trace: 'on-first-retry',
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Pattern 2: Playwright Inspector with PWDEBUG
|
|
88
|
+
|
|
89
|
+
**Use when**: You need to step through actions one at a time, test selectors interactively, or see the exact state before and after each action.
|
|
90
|
+
**Avoid when**: The failure is visible from the error message or trace alone.
|
|
91
|
+
|
|
92
|
+
**TypeScript**
|
|
93
|
+
```typescript
|
|
94
|
+
// Launch Inspector from terminal:
|
|
95
|
+
// PWDEBUG=1 npx playwright test tests/login.spec.ts
|
|
96
|
+
|
|
97
|
+
// On Windows PowerShell:
|
|
98
|
+
// $env:PWDEBUG=1; npx playwright test tests/login.spec.ts
|
|
99
|
+
|
|
100
|
+
// On Windows CMD:
|
|
101
|
+
// set PWDEBUG=1 && npx playwright test tests/login.spec.ts
|
|
102
|
+
|
|
103
|
+
// Inspector opens automatically. Use these controls:
|
|
104
|
+
// - "Step over" button: execute one action at a time
|
|
105
|
+
// - "Pick locator" button: hover elements to see the best locator
|
|
106
|
+
// - "Resume" button: run to the next page.pause() or end
|
|
107
|
+
|
|
108
|
+
import { test, expect } from '@playwright/test';
|
|
109
|
+
|
|
110
|
+
test('debug login flow', async ({ page }) => {
|
|
111
|
+
await page.goto('/login');
|
|
112
|
+
|
|
113
|
+
// Inspector pauses before each action when PWDEBUG=1
|
|
114
|
+
await page.getByLabel('Email').fill('user@example.com');
|
|
115
|
+
await page.getByLabel('Password').fill('password123');
|
|
116
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
117
|
+
|
|
118
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**JavaScript**
|
|
123
|
+
```javascript
|
|
124
|
+
// Launch Inspector from terminal:
|
|
125
|
+
// PWDEBUG=1 npx playwright test tests/login.spec.js
|
|
126
|
+
|
|
127
|
+
const { test, expect } = require('@playwright/test');
|
|
128
|
+
|
|
129
|
+
test('debug login flow', async ({ page }) => {
|
|
130
|
+
await page.goto('/login');
|
|
131
|
+
|
|
132
|
+
await page.getByLabel('Email').fill('user@example.com');
|
|
133
|
+
await page.getByLabel('Password').fill('password123');
|
|
134
|
+
await page.getByRole('button', { name: 'Sign in' }).click();
|
|
135
|
+
|
|
136
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Pattern 3: Trace Viewer for CI Failure Analysis
|
|
141
|
+
|
|
142
|
+
**Use when**: A test fails in CI and you need to understand what happened without re-running locally.
|
|
143
|
+
**Avoid when**: You can reproduce the failure locally (use UI Mode or Inspector instead).
|
|
144
|
+
|
|
145
|
+
**TypeScript**
|
|
146
|
+
```typescript
|
|
147
|
+
// playwright.config.ts — trace configuration
|
|
148
|
+
import { defineConfig } from '@playwright/test';
|
|
149
|
+
|
|
150
|
+
export default defineConfig({
|
|
151
|
+
retries: process.env.CI ? 2 : 0,
|
|
152
|
+
use: {
|
|
153
|
+
// 'on-first-retry' — captures trace on first retry only (recommended for CI)
|
|
154
|
+
// 'on' — captures every run (use temporarily for stubborn failures)
|
|
155
|
+
// 'retain-on-failure' — captures every run, keeps only failures
|
|
156
|
+
trace: 'on-first-retry',
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// After CI failure, download the trace artifact and open it:
|
|
161
|
+
// npx playwright show-trace test-results/tests-login-Login-test-chromium/trace.zip
|
|
162
|
+
|
|
163
|
+
// Or open from URL:
|
|
164
|
+
// npx playwright show-trace https://ci.example.com/artifacts/trace.zip
|
|
165
|
+
|
|
166
|
+
// Or use trace.playwright.dev to view traces in the browser — drag and drop the zip file
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**JavaScript**
|
|
170
|
+
```javascript
|
|
171
|
+
// playwright.config.js
|
|
172
|
+
const { defineConfig } = require('@playwright/test');
|
|
173
|
+
|
|
174
|
+
module.exports = defineConfig({
|
|
175
|
+
retries: process.env.CI ? 2 : 0,
|
|
176
|
+
use: {
|
|
177
|
+
trace: 'on-first-retry',
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// After CI failure, download the trace artifact and open it:
|
|
182
|
+
// npx playwright show-trace test-results/tests-login-Login-test-chromium/trace.zip
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Reading a trace — what to check in order:**
|
|
186
|
+
|
|
187
|
+
1. **Actions tab** — see every Playwright action with before/after screenshots
|
|
188
|
+
2. **Console tab** — browser console output (errors, warnings, logs)
|
|
189
|
+
3. **Network tab** — every HTTP request with status, timing, request/response bodies
|
|
190
|
+
4. **Source tab** — test source code highlighting the failing line
|
|
191
|
+
5. **Call tab** — exact arguments and return values of each Playwright call
|
|
192
|
+
|
|
193
|
+
### Pattern 3b: CLI Debugger for Agent Workflows
|
|
194
|
+
|
|
195
|
+
**Use when**: You are debugging from a terminal, remote machine, or coding-agent workflow where opening the full inspector is awkward.
|
|
196
|
+
**Avoid when**: You want the richest interactive UI locally; use UI Mode or Inspector for that.
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Start a paused debugging session
|
|
200
|
+
npx playwright test --debug=cli
|
|
201
|
+
|
|
202
|
+
# Attach from another terminal using the session id printed by Playwright
|
|
203
|
+
playwright-cli attach tw-87b59e
|
|
204
|
+
playwright-cli --session=tw-87b59e snapshot
|
|
205
|
+
playwright-cli --session=tw-87b59e step-over
|
|
206
|
+
playwright-cli --session=tw-87b59e console error
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
This flow is ideal when an agent or teammate needs to inspect the live browser state without leaving the command line.
|
|
210
|
+
|
|
211
|
+
### Pattern 3c: Terminal Trace Analysis
|
|
212
|
+
|
|
213
|
+
**Use when**: You have a trace archive but need fast answers from a shell, CI worker, or remote box.
|
|
214
|
+
**Avoid when**: You need the full visual timeline; use Trace Viewer for that.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
npx playwright trace open test-results/checkout-chromium/trace.zip
|
|
218
|
+
npx playwright trace actions --grep="expect"
|
|
219
|
+
npx playwright trace action 9
|
|
220
|
+
npx playwright trace snapshot 9 --name after
|
|
221
|
+
npx playwright trace close
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
This is especially helpful for agentic repair loops and flaky-test triage, where opening a GUI trace viewer adds friction.
|
|
225
|
+
|
|
226
|
+
### Pattern 4: Headed Mode with Slow Motion
|
|
227
|
+
|
|
228
|
+
**Use when**: You want to watch the browser during execution without the full Inspector overhead.
|
|
229
|
+
**Avoid when**: The test runs too fast to follow even with slow-mo (use Inspector instead).
|
|
230
|
+
|
|
231
|
+
**TypeScript**
|
|
232
|
+
```typescript
|
|
233
|
+
// From terminal — quick visual debugging:
|
|
234
|
+
// npx playwright test tests/checkout.spec.ts --headed --slow-mo=500
|
|
235
|
+
|
|
236
|
+
// playwright.config.ts — configure headed mode for local development
|
|
237
|
+
import { defineConfig } from '@playwright/test';
|
|
238
|
+
|
|
239
|
+
export default defineConfig({
|
|
240
|
+
use: {
|
|
241
|
+
// Do NOT commit these — use CLI flags or environment checks instead
|
|
242
|
+
headless: !process.env.HEADED,
|
|
243
|
+
launchOptions: {
|
|
244
|
+
slowMo: process.env.SLOW_MO ? parseInt(process.env.SLOW_MO) : 0,
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Then run:
|
|
250
|
+
// HEADED=1 SLOW_MO=500 npx playwright test tests/checkout.spec.ts
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**JavaScript**
|
|
254
|
+
```javascript
|
|
255
|
+
// From terminal:
|
|
256
|
+
// npx playwright test tests/checkout.spec.js --headed --slow-mo=500
|
|
257
|
+
|
|
258
|
+
// playwright.config.js
|
|
259
|
+
const { defineConfig } = require('@playwright/test');
|
|
260
|
+
|
|
261
|
+
module.exports = defineConfig({
|
|
262
|
+
use: {
|
|
263
|
+
headless: !process.env.HEADED,
|
|
264
|
+
launchOptions: {
|
|
265
|
+
slowMo: process.env.SLOW_MO ? parseInt(process.env.SLOW_MO) : 0,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Pattern 5: VS Code Integration
|
|
272
|
+
|
|
273
|
+
**Use when**: You prefer IDE-based debugging with breakpoints, variable inspection, and integrated test running.
|
|
274
|
+
**Avoid when**: You are debugging CI-only failures that do not reproduce locally.
|
|
275
|
+
|
|
276
|
+
Install the **Playwright Test for VS Code** extension (`ms-playwright.playwright`).
|
|
277
|
+
|
|
278
|
+
**Key capabilities:**
|
|
279
|
+
- **Run/debug individual tests** — click the green play button in the gutter next to any `test()`
|
|
280
|
+
- **Set breakpoints** — click the gutter to set breakpoints; tests pause at them automatically
|
|
281
|
+
- **Pick locator** — use the "Pick locator" command to hover over elements and get the best selector
|
|
282
|
+
- **Show browser** — check "Show Browser" in the testing sidebar to see the browser during execution
|
|
283
|
+
- **Watch mode** — enable to re-run tests on file save
|
|
284
|
+
|
|
285
|
+
**TypeScript**
|
|
286
|
+
```typescript
|
|
287
|
+
// When debugging in VS Code, use test.only() to focus on one test
|
|
288
|
+
// instead of running the entire suite through the debugger
|
|
289
|
+
import { test, expect } from '@playwright/test';
|
|
290
|
+
|
|
291
|
+
test.only('debug this specific test', async ({ page }) => {
|
|
292
|
+
await page.goto('/products');
|
|
293
|
+
|
|
294
|
+
// Set a VS Code breakpoint on this line, then inspect `page` in the debug panel
|
|
295
|
+
const productCard = page.getByRole('listitem').filter({ hasText: 'Widget' });
|
|
296
|
+
await expect(productCard).toBeVisible();
|
|
297
|
+
|
|
298
|
+
await productCard.getByRole('button', { name: 'Add to cart' }).click();
|
|
299
|
+
await expect(page.getByTestId('cart-count')).toHaveText('1');
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**JavaScript**
|
|
304
|
+
```javascript
|
|
305
|
+
const { test, expect } = require('@playwright/test');
|
|
306
|
+
|
|
307
|
+
test.only('debug this specific test', async ({ page }) => {
|
|
308
|
+
await page.goto('/products');
|
|
309
|
+
|
|
310
|
+
const productCard = page.getByRole('listitem').filter({ hasText: 'Widget' });
|
|
311
|
+
await expect(productCard).toBeVisible();
|
|
312
|
+
|
|
313
|
+
await productCard.getByRole('button', { name: 'Add to cart' }).click();
|
|
314
|
+
await expect(page.getByTestId('cart-count')).toHaveText('1');
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Pattern 6: Capturing Browser Console Logs
|
|
319
|
+
|
|
320
|
+
**Use when**: Suspecting JavaScript errors, failed client-side API calls, or application-level logging that explains the failure.
|
|
321
|
+
**Avoid when**: The issue is clearly a selector or timing problem visible in the trace.
|
|
322
|
+
|
|
323
|
+
**TypeScript**
|
|
324
|
+
```typescript
|
|
325
|
+
import { test, expect } from '@playwright/test';
|
|
326
|
+
|
|
327
|
+
test('capture console output', async ({ page }) => {
|
|
328
|
+
// Collect all console messages
|
|
329
|
+
const consoleLogs: string[] = [];
|
|
330
|
+
page.on('console', (msg) => {
|
|
331
|
+
consoleLogs.push(`[${msg.type()}] ${msg.text()}`);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// Capture uncaught exceptions
|
|
335
|
+
page.on('pageerror', (error) => {
|
|
336
|
+
console.error('Page error:', error.message);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
await page.goto('/dashboard');
|
|
340
|
+
await page.getByRole('button', { name: 'Load data' }).click();
|
|
341
|
+
await expect(page.getByRole('table')).toBeVisible();
|
|
342
|
+
|
|
343
|
+
// Print collected logs on failure for debugging context
|
|
344
|
+
console.log('Browser console output:', consoleLogs);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Reusable fixture for console logging across all tests
|
|
348
|
+
import { test as base } from '@playwright/test';
|
|
349
|
+
|
|
350
|
+
type ConsoleFixtures = {
|
|
351
|
+
consoleMessages: string[];
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
export const test = base.extend<ConsoleFixtures>({
|
|
355
|
+
consoleMessages: async ({ page }, use) => {
|
|
356
|
+
const messages: string[] = [];
|
|
357
|
+
page.on('console', (msg) => messages.push(`[${msg.type()}] ${msg.text()}`));
|
|
358
|
+
page.on('pageerror', (err) => messages.push(`[pageerror] ${err.message}`));
|
|
359
|
+
await use(messages);
|
|
360
|
+
},
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**JavaScript**
|
|
365
|
+
```javascript
|
|
366
|
+
const { test, expect } = require('@playwright/test');
|
|
367
|
+
|
|
368
|
+
test('capture console output', async ({ page }) => {
|
|
369
|
+
const consoleLogs = [];
|
|
370
|
+
page.on('console', (msg) => {
|
|
371
|
+
consoleLogs.push(`[${msg.type()}] ${msg.text()}`);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
page.on('pageerror', (error) => {
|
|
375
|
+
console.error('Page error:', error.message);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
await page.goto('/dashboard');
|
|
379
|
+
await page.getByRole('button', { name: 'Load data' }).click();
|
|
380
|
+
await expect(page.getByRole('table')).toBeVisible();
|
|
381
|
+
|
|
382
|
+
console.log('Browser console output:', consoleLogs);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Reusable fixture for console logging
|
|
386
|
+
const { test: base } = require('@playwright/test');
|
|
387
|
+
|
|
388
|
+
const test = base.extend({
|
|
389
|
+
consoleMessages: async ({ page }, use) => {
|
|
390
|
+
const messages = [];
|
|
391
|
+
page.on('console', (msg) => messages.push(`[${msg.type()}] ${msg.text()}`));
|
|
392
|
+
page.on('pageerror', (err) => messages.push(`[pageerror] ${err.message}`));
|
|
393
|
+
await use(messages);
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
module.exports = { test };
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
#### Pinpointing Uncaught Errors With `webError.location()` (Playwright 1.60+)
|
|
401
|
+
|
|
402
|
+
`page.on('pageerror')` gives you the error, but not *where* it came from. Playwright 1.60 adds `webError.location()` (on the `context`-level `weberror` event), mirroring `consoleMessage.location()` — so you get the URL, line, and column of an uncaught exception.
|
|
403
|
+
|
|
404
|
+
**TypeScript**
|
|
405
|
+
```typescript
|
|
406
|
+
import { test, expect } from '@playwright/test';
|
|
407
|
+
|
|
408
|
+
test('capture uncaught errors with their source location', async ({ context, page }) => {
|
|
409
|
+
context.on('weberror', (webError) => {
|
|
410
|
+
const loc = webError.location(); // { url, line, column } — 0-based
|
|
411
|
+
console.error(
|
|
412
|
+
`Uncaught: ${webError.error().message} @ ${loc.url}:${loc.line}:${loc.column}`
|
|
413
|
+
);
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
await page.goto('/dashboard');
|
|
417
|
+
await page.getByRole('button', { name: 'Load data' }).click();
|
|
418
|
+
await expect(page.getByRole('table')).toBeVisible();
|
|
419
|
+
});
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
The location makes it far quicker to map a browser-side exception back to the exact source file and line, especially with source maps enabled.
|
|
423
|
+
|
|
424
|
+
### Pattern 7: Screenshots on Failure
|
|
425
|
+
|
|
426
|
+
**Use when**: You need a visual snapshot at the exact moment of failure.
|
|
427
|
+
**Avoid when**: Traces are enabled (they already include screenshots at every step).
|
|
428
|
+
|
|
429
|
+
**TypeScript**
|
|
430
|
+
```typescript
|
|
431
|
+
// playwright.config.ts — automatic screenshots on failure
|
|
432
|
+
import { defineConfig } from '@playwright/test';
|
|
433
|
+
|
|
434
|
+
export default defineConfig({
|
|
435
|
+
use: {
|
|
436
|
+
// 'off' — no screenshots (default)
|
|
437
|
+
// 'on' — screenshot after every test
|
|
438
|
+
// 'only-on-failure' — screenshot only when test fails (recommended)
|
|
439
|
+
screenshot: 'only-on-failure',
|
|
440
|
+
},
|
|
441
|
+
});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
// Manual screenshot at a specific point
|
|
446
|
+
import { test, expect } from '@playwright/test';
|
|
447
|
+
|
|
448
|
+
test('debug visual state', async ({ page }) => {
|
|
449
|
+
await page.goto('/checkout');
|
|
450
|
+
await page.getByLabel('Promo code').fill('SAVE20');
|
|
451
|
+
await page.getByRole('button', { name: 'Apply' }).click();
|
|
452
|
+
|
|
453
|
+
// Capture screenshot before assertion for debugging
|
|
454
|
+
await page.screenshot({ path: 'test-results/before-discount.png', fullPage: true });
|
|
455
|
+
|
|
456
|
+
await expect(page.getByTestId('discount-amount')).toHaveText('-$20.00');
|
|
457
|
+
});
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**JavaScript**
|
|
461
|
+
```javascript
|
|
462
|
+
// playwright.config.js
|
|
463
|
+
const { defineConfig } = require('@playwright/test');
|
|
464
|
+
|
|
465
|
+
module.exports = defineConfig({
|
|
466
|
+
use: {
|
|
467
|
+
screenshot: 'only-on-failure',
|
|
468
|
+
},
|
|
469
|
+
});
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
```javascript
|
|
473
|
+
// Manual screenshot
|
|
474
|
+
const { test, expect } = require('@playwright/test');
|
|
475
|
+
|
|
476
|
+
test('debug visual state', async ({ page }) => {
|
|
477
|
+
await page.goto('/checkout');
|
|
478
|
+
await page.getByLabel('Promo code').fill('SAVE20');
|
|
479
|
+
await page.getByRole('button', { name: 'Apply' }).click();
|
|
480
|
+
|
|
481
|
+
await page.screenshot({ path: 'test-results/before-discount.png', fullPage: true });
|
|
482
|
+
|
|
483
|
+
await expect(page.getByTestId('discount-amount')).toHaveText('-$20.00');
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Pattern 8: Network Debugging
|
|
488
|
+
|
|
489
|
+
**Use when**: Suspecting API failures, wrong request payloads, missing auth headers, or slow responses causing timeouts.
|
|
490
|
+
**Avoid when**: The trace network tab already shows the problem.
|
|
491
|
+
|
|
492
|
+
**TypeScript**
|
|
493
|
+
```typescript
|
|
494
|
+
import { test, expect } from '@playwright/test';
|
|
495
|
+
|
|
496
|
+
test('debug network requests', async ({ page }) => {
|
|
497
|
+
// Log all requests
|
|
498
|
+
page.on('request', (request) => {
|
|
499
|
+
console.log(`>> ${request.method()} ${request.url()}`);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// Log all responses with status
|
|
503
|
+
page.on('response', (response) => {
|
|
504
|
+
console.log(`<< ${response.status()} ${response.url()}`);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Log failed requests (network errors, not HTTP errors)
|
|
508
|
+
page.on('requestfailed', (request) => {
|
|
509
|
+
console.log(`FAILED: ${request.url()} ${request.failure()?.errorText}`);
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
await page.goto('/dashboard');
|
|
513
|
+
await page.getByRole('button', { name: 'Refresh' }).click();
|
|
514
|
+
await expect(page.getByRole('table')).toBeVisible();
|
|
515
|
+
});
|
|
516
|
+
|
|
517
|
+
// Wait for a specific API response and inspect it
|
|
518
|
+
test('inspect API response', async ({ page }) => {
|
|
519
|
+
await page.goto('/products');
|
|
520
|
+
|
|
521
|
+
const responsePromise = page.waitForResponse(
|
|
522
|
+
(resp) => resp.url().includes('/api/products') && resp.status() === 200
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
await page.getByRole('button', { name: 'Load products' }).click();
|
|
526
|
+
|
|
527
|
+
const response = await responsePromise;
|
|
528
|
+
const body = await response.json();
|
|
529
|
+
console.log('API response:', JSON.stringify(body, null, 2));
|
|
530
|
+
|
|
531
|
+
await expect(page.getByRole('listitem')).toHaveCount(body.products.length);
|
|
532
|
+
});
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**JavaScript**
|
|
536
|
+
```javascript
|
|
537
|
+
const { test, expect } = require('@playwright/test');
|
|
538
|
+
|
|
539
|
+
test('debug network requests', async ({ page }) => {
|
|
540
|
+
page.on('request', (request) => {
|
|
541
|
+
console.log(`>> ${request.method()} ${request.url()}`);
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
page.on('response', (response) => {
|
|
545
|
+
console.log(`<< ${response.status()} ${response.url()}`);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
page.on('requestfailed', (request) => {
|
|
549
|
+
console.log(`FAILED: ${request.url()} ${request.failure()?.errorText}`);
|
|
550
|
+
});
|
|
551
|
+
|
|
552
|
+
await page.goto('/dashboard');
|
|
553
|
+
await page.getByRole('button', { name: 'Refresh' }).click();
|
|
554
|
+
await expect(page.getByRole('table')).toBeVisible();
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
test('inspect API response', async ({ page }) => {
|
|
558
|
+
await page.goto('/products');
|
|
559
|
+
|
|
560
|
+
const responsePromise = page.waitForResponse(
|
|
561
|
+
(resp) => resp.url().includes('/api/products') && resp.status() === 200
|
|
562
|
+
);
|
|
563
|
+
|
|
564
|
+
await page.getByRole('button', { name: 'Load products' }).click();
|
|
565
|
+
|
|
566
|
+
const response = await responsePromise;
|
|
567
|
+
const body = await response.json();
|
|
568
|
+
console.log('API response:', JSON.stringify(body, null, 2));
|
|
569
|
+
|
|
570
|
+
await expect(page.getByRole('listitem')).toHaveCount(body.products.length);
|
|
571
|
+
});
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
### Pattern 9: Verbose API Logs
|
|
575
|
+
|
|
576
|
+
**Use when**: You need to see every single Playwright API call with timing to identify where the test is spending time or getting stuck.
|
|
577
|
+
**Avoid when**: You already know which action is failing (use Inspector or `page.pause()` instead).
|
|
578
|
+
|
|
579
|
+
```bash
|
|
580
|
+
# See all Playwright API calls with timestamps
|
|
581
|
+
DEBUG=pw:api npx playwright test tests/slow-test.spec.ts
|
|
582
|
+
|
|
583
|
+
# See browser protocol messages (very verbose — use sparingly)
|
|
584
|
+
DEBUG=pw:protocol npx playwright test tests/slow-test.spec.ts
|
|
585
|
+
|
|
586
|
+
# Combine multiple debug channels
|
|
587
|
+
DEBUG=pw:api,pw:browser npx playwright test tests/slow-test.spec.ts
|
|
588
|
+
|
|
589
|
+
# Windows PowerShell
|
|
590
|
+
$env:DEBUG="pw:api"; npx playwright test tests/slow-test.spec.ts
|
|
591
|
+
|
|
592
|
+
# Windows CMD
|
|
593
|
+
set DEBUG=pw:api && npx playwright test tests/slow-test.spec.ts
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
### Pattern 10: `page.pause()` — Inline Breakpoints
|
|
597
|
+
|
|
598
|
+
**Use when**: You need to pause execution at a precise point to inspect the live DOM, try locators, or check application state.
|
|
599
|
+
**Avoid when**: You can use `PWDEBUG=1` which pauses at every step automatically.
|
|
600
|
+
|
|
601
|
+
**TypeScript**
|
|
602
|
+
```typescript
|
|
603
|
+
import { test, expect } from '@playwright/test';
|
|
604
|
+
|
|
605
|
+
test('debug with pause', async ({ page }) => {
|
|
606
|
+
await page.goto('/checkout');
|
|
607
|
+
await page.getByLabel('Email').fill('user@example.com');
|
|
608
|
+
|
|
609
|
+
// Execution pauses here — Inspector opens with:
|
|
610
|
+
// - Live DOM inspection
|
|
611
|
+
// - Selector playground (try locators in the console)
|
|
612
|
+
// - Step through remaining actions
|
|
613
|
+
await page.pause();
|
|
614
|
+
|
|
615
|
+
// These actions wait until you click "Resume" in the Inspector
|
|
616
|
+
await page.getByRole('button', { name: 'Continue' }).click();
|
|
617
|
+
await expect(page.getByText('Order confirmed')).toBeVisible();
|
|
618
|
+
});
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**JavaScript**
|
|
622
|
+
```javascript
|
|
623
|
+
const { test, expect } = require('@playwright/test');
|
|
624
|
+
|
|
625
|
+
test('debug with pause', async ({ page }) => {
|
|
626
|
+
await page.goto('/checkout');
|
|
627
|
+
await page.getByLabel('Email').fill('user@example.com');
|
|
628
|
+
|
|
629
|
+
// Execution pauses here — Inspector opens
|
|
630
|
+
await page.pause();
|
|
631
|
+
|
|
632
|
+
await page.getByRole('button', { name: 'Continue' }).click();
|
|
633
|
+
await expect(page.getByText('Order confirmed')).toBeVisible();
|
|
634
|
+
});
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
**Important**: Remove `page.pause()` before committing. It will hang indefinitely in CI. Use this lint rule or CI check:
|
|
638
|
+
|
|
639
|
+
```bash
|
|
640
|
+
# Add to your pre-commit hook or CI pipeline
|
|
641
|
+
grep -r "page.pause()" tests/ && echo "ERROR: Remove page.pause() before committing" && exit 1
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Pattern 11: Styled Highlights and `errorContext` (Playwright 1.60+)
|
|
645
|
+
|
|
646
|
+
**Use when**: You're visually debugging which element a locator resolves to (especially in headed mode or while recording a video), or you want richer diagnostics attached to assertion failures.
|
|
647
|
+
**Avoid when**: A trace already answers the question — it shows the resolved element per step.
|
|
648
|
+
|
|
649
|
+
Playwright 1.60 adds a `style` option to `locator.highlight()` (custom inline CSS on the highlight box) plus `page.hideHighlight()` to clear it. It also surfaces `testInfoError.errorContext`, which carries extra diagnostics — such as the aria snapshot of the element when an `expect()` matcher failed.
|
|
650
|
+
|
|
651
|
+
**TypeScript**
|
|
652
|
+
```typescript
|
|
653
|
+
import { test, expect } from '@playwright/test';
|
|
654
|
+
|
|
655
|
+
test('highlight an element while debugging headed', async ({ page }) => {
|
|
656
|
+
await page.goto('/dashboard');
|
|
657
|
+
|
|
658
|
+
const cta = page.getByRole('button', { name: 'Upgrade' });
|
|
659
|
+
await cta.highlight({ style: 'outline: 3px solid magenta; background: rgba(255,0,255,.15)' });
|
|
660
|
+
|
|
661
|
+
// ... inspect visually / take a screenshot ...
|
|
662
|
+
await page.hideHighlight();
|
|
663
|
+
});
|
|
664
|
+
|
|
665
|
+
test.afterEach(async ({}, testInfo) => {
|
|
666
|
+
// On failure, surface the diagnostic context Playwright captured
|
|
667
|
+
for (const err of testInfo.errors) {
|
|
668
|
+
if (err.errorContext) {
|
|
669
|
+
console.log('Failure context:\n', err.errorContext);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
**JavaScript**
|
|
676
|
+
```javascript
|
|
677
|
+
const { test, expect } = require('@playwright/test');
|
|
678
|
+
|
|
679
|
+
test('highlight an element while debugging headed', async ({ page }) => {
|
|
680
|
+
await page.goto('/dashboard');
|
|
681
|
+
|
|
682
|
+
const cta = page.getByRole('button', { name: 'Upgrade' });
|
|
683
|
+
await cta.highlight({ style: 'outline: 3px solid magenta' });
|
|
684
|
+
|
|
685
|
+
await page.hideHighlight();
|
|
686
|
+
});
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
`errorContext` is most useful in custom reporters and `afterEach` hooks where you want to log *why* a matcher failed beyond the bare message.
|
|
690
|
+
|
|
691
|
+
## Decision Guide
|
|
692
|
+
|
|
693
|
+
Use this table to pick the right tool based on the failure type.
|
|
694
|
+
|
|
695
|
+
| Failure Type | First Tool | Why |
|
|
696
|
+
|---|---|---|
|
|
697
|
+
| **Element not found** (selector wrong) | UI Mode (`--ui`) | See the DOM at the moment of failure, try selectors in Pick Locator |
|
|
698
|
+
| **Element not found** (timing issue) | Trace Viewer — Actions tab | Compare before/after screenshots to see if element appeared after timeout |
|
|
699
|
+
| **Wrong text / value** | Trace Viewer — Actions tab | Inspect the actual DOM content at each action step |
|
|
700
|
+
| **Test hangs / times out** | `DEBUG=pw:api` | See which API call is waiting and never resolving |
|
|
701
|
+
| **Network / API failure** | Trace Viewer — Network tab | See request/response status codes, payloads, timing |
|
|
702
|
+
| **Auth / session issues** | Network debugging (`page.on('response')`) | Check for 401/403 responses, missing cookies/tokens |
|
|
703
|
+
| **Visual rendering wrong** | `--headed --slow-mo=500` | Watch the actual rendering in the browser |
|
|
704
|
+
| **JavaScript error in app** | Console logging (`page.on('console')`) | Catch uncaught exceptions and error logs |
|
|
705
|
+
| **CI-only failure** | Trace Viewer (from CI artifact) | Reproduce the exact CI state without running locally |
|
|
706
|
+
| **Flaky / intermittent** | Trace on every run (`trace: 'on'`) + retries | Compare passing and failing traces side by side |
|
|
707
|
+
| **State pollution** | Run single test with `test.only()` | Isolate from other tests; if it passes alone, state leaks from another test |
|
|
708
|
+
|
|
709
|
+
## Anti-Patterns
|
|
710
|
+
|
|
711
|
+
### Adding `waitForTimeout` to fix timing issues
|
|
712
|
+
|
|
713
|
+
```typescript
|
|
714
|
+
// WRONG — arbitrary delays mask the real problem and make tests slow and flaky
|
|
715
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
716
|
+
await page.waitForTimeout(3000); // "It works with this delay"
|
|
717
|
+
await expect(page.getByText('Success')).toBeVisible();
|
|
718
|
+
|
|
719
|
+
// RIGHT — wait for the actual condition
|
|
720
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
721
|
+
await expect(page.getByText('Success')).toBeVisible(); // Auto-retries for up to 5s
|
|
722
|
+
```
|
|
723
|
+
|
|
724
|
+
If the default timeout is insufficient, investigate *why* the operation is slow, then either:
|
|
725
|
+
- Fix the application performance
|
|
726
|
+
- Increase the specific assertion timeout: `await expect(locator).toBeVisible({ timeout: 15000 })`
|
|
727
|
+
- Wait for a prerequisite: `await page.waitForResponse('**/api/submit')`
|
|
728
|
+
|
|
729
|
+
### Commenting out tests to isolate a failure
|
|
730
|
+
|
|
731
|
+
```typescript
|
|
732
|
+
// WRONG — commenting out tests to find which one causes the failure
|
|
733
|
+
// test('test A', ...);
|
|
734
|
+
// test('test B', ...);
|
|
735
|
+
test('test C — this one fails', async ({ page }) => { /* ... */ });
|
|
736
|
+
|
|
737
|
+
// RIGHT — use .only to run a single test
|
|
738
|
+
test.only('test C — this one fails', async ({ page }) => { /* ... */ });
|
|
739
|
+
|
|
740
|
+
// RIGHT — use grep to run tests matching a pattern
|
|
741
|
+
// npx playwright test --grep "test C"
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
### Not reading the full error message
|
|
745
|
+
|
|
746
|
+
Playwright error messages include:
|
|
747
|
+
- The **expected** vs **actual** value
|
|
748
|
+
- The **locator** that was used
|
|
749
|
+
- A **call log** showing what Playwright tried before timing out
|
|
750
|
+
- The **line number** in your test
|
|
751
|
+
|
|
752
|
+
Read all of it. The call log alone often shows exactly what went wrong (e.g., "waiting for selector to be visible" when the element exists but is hidden).
|
|
753
|
+
|
|
754
|
+
### Debugging in CI without traces
|
|
755
|
+
|
|
756
|
+
```typescript
|
|
757
|
+
// WRONG — no traces in CI, no way to debug failures
|
|
758
|
+
export default defineConfig({
|
|
759
|
+
use: {
|
|
760
|
+
trace: 'off',
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
// RIGHT — always capture traces on failure in CI
|
|
765
|
+
export default defineConfig({
|
|
766
|
+
retries: process.env.CI ? 2 : 0,
|
|
767
|
+
use: {
|
|
768
|
+
trace: 'on-first-retry',
|
|
769
|
+
},
|
|
770
|
+
});
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
### Using `console.log` instead of proper debugging tools
|
|
774
|
+
|
|
775
|
+
```typescript
|
|
776
|
+
// WRONG — sprinkling console.log everywhere
|
|
777
|
+
test('debug with logs', async ({ page }) => {
|
|
778
|
+
await page.goto('/dashboard');
|
|
779
|
+
console.log('page loaded');
|
|
780
|
+
const el = page.getByRole('button', { name: 'Save' });
|
|
781
|
+
console.log('button found:', await el.isVisible());
|
|
782
|
+
console.log('button text:', await el.textContent());
|
|
783
|
+
// ...20 more console.log calls
|
|
784
|
+
|
|
785
|
+
// RIGHT — use page.pause() at the point of interest
|
|
786
|
+
await page.goto('/dashboard');
|
|
787
|
+
await page.pause(); // Inspect everything interactively
|
|
788
|
+
});
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
### Leaving `page.pause()` or `test.only()` in committed code
|
|
792
|
+
|
|
793
|
+
```typescript
|
|
794
|
+
// WRONG — these should never reach CI
|
|
795
|
+
test.only('focused test', async ({ page }) => { // Skips all other tests
|
|
796
|
+
await page.goto('/');
|
|
797
|
+
await page.pause(); // Hangs forever in CI
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// Add a CI guard if needed during development
|
|
801
|
+
if (!process.env.CI) {
|
|
802
|
+
await page.pause();
|
|
803
|
+
}
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
## Troubleshooting
|
|
807
|
+
|
|
808
|
+
| Symptom | Likely Cause | Fix |
|
|
809
|
+
|---|---|---|
|
|
810
|
+
| Inspector does not open with `PWDEBUG=1` | Running in headless mode or workers > 1 | Run with `--headed` and `--workers=1` |
|
|
811
|
+
| Trace is empty or missing | `trace: 'off'` in config, or test did not retry | Set `trace: 'on'` temporarily, or `trace: 'retain-on-failure'` |
|
|
812
|
+
| UI Mode shows stale test results | File watcher did not pick up changes | Stop UI Mode, clear `test-results/`, restart |
|
|
813
|
+
| `page.pause()` does nothing | `PWDEBUG` is not set and running headless | Run with `--headed` or set `PWDEBUG=1` |
|
|
814
|
+
| Screenshots are blank or wrong size | Viewport not set or test runs on wrong project | Set `viewport` in config; check which browser project ran |
|
|
815
|
+
| Verbose logs are overwhelming | Using `DEBUG=pw:protocol` | Use `DEBUG=pw:api` for a manageable level of detail |
|
|
816
|
+
| Trace file is too large | `trace: 'on'` for all tests, including passing | Switch to `trace: 'on-first-retry'` or `trace: 'retain-on-failure'` |
|
|
817
|
+
| VS Code does not detect tests | Wrong `testDir` or `testMatch` config | Ensure config paths match and extension settings point to your `playwright.config` |
|
|
818
|
+
| Network events not firing | Request was made before listener was attached | Attach `page.on('request')` and `page.on('response')` before `page.goto()` |
|
|
819
|
+
|
|
820
|
+
## Related
|
|
821
|
+
|
|
822
|
+
- [core/error-index.md](error-index.md) — look up specific error messages
|
|
823
|
+
- [core/flaky-tests.md](flaky-tests.md) — intermittent failure patterns and fixes
|
|
824
|
+
- [core/common-pitfalls.md](common-pitfalls.md) — common beginner mistakes
|
|
825
|
+
- [core/assertions-and-waiting.md](assertions-and-waiting.md) — web-first assertions and auto-waiting
|
|
826
|
+
- [core/configuration.md](configuration.md) — trace, screenshot, and retry configuration
|
|
827
|
+
- [ci/reporting-and-artifacts.md](../ci/reporting-and-artifacts.md) — CI artifact collection for traces and screenshots
|