@balazsbarta/mp-skills 0.1.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/.agents/skills/brainstorming/SKILL.md +201 -0
- package/.agents/skills/brainstorming/references/option-evaluation.md +64 -0
- package/.agents/skills/brainstorming/references/questioning-playbook.md +57 -0
- package/.agents/skills/brainstorming/references/repo-analysis.md +60 -0
- package/.agents/skills/conventional-commits/SKILL.md +124 -0
- package/.agents/skills/conventional-commits/references/commit-types-scopes.md +75 -0
- package/.agents/skills/conventional-commits/references/semantic-release.md +71 -0
- package/.agents/skills/jest/SKILL.md +219 -0
- package/.agents/skills/jest/references/common-errors.md +274 -0
- package/.agents/skills/jest/references/configuration.md +175 -0
- package/.agents/skills/jest/references/embedded-docs.md +44 -0
- package/.agents/skills/jest/references/mocking.md +206 -0
- package/.agents/skills/jest/references/remote-docs.md +19 -0
- package/.agents/skills/jest/references/snapshot-testing.md +181 -0
- package/.agents/skills/jest/references/transforms.md +216 -0
- package/.agents/skills/maestro/SKILL.md +230 -0
- package/.agents/skills/maestro/references/assertions-commands.md +259 -0
- package/.agents/skills/maestro/references/common-errors.md +273 -0
- package/.agents/skills/maestro/references/eas-ci-integration.md +219 -0
- package/.agents/skills/maestro/references/flow-authoring.md +224 -0
- package/.agents/skills/maestro/references/remote-docs.md +23 -0
- package/.agents/skills/mastra/SKILL.md +159 -0
- package/.agents/skills/mastra/references/common-errors.md +535 -0
- package/.agents/skills/mastra/references/create-mastra.md +220 -0
- package/.agents/skills/mastra/references/embedded-docs.md +123 -0
- package/.agents/skills/mastra/references/migration-guide.md +180 -0
- package/.agents/skills/mastra/references/remote-docs.md +193 -0
- package/.agents/skills/next-js/SKILL.md +209 -0
- package/.agents/skills/next-js/references/api-routes.md +213 -0
- package/.agents/skills/next-js/references/app-router.md +206 -0
- package/.agents/skills/next-js/references/caching-revalidation.md +211 -0
- package/.agents/skills/next-js/references/common-errors.md +251 -0
- package/.agents/skills/next-js/references/embedded-docs.md +43 -0
- package/.agents/skills/next-js/references/metadata-seo.md +257 -0
- package/.agents/skills/next-js/references/remote-docs.md +22 -0
- package/.agents/skills/playwright/SKILL.md +218 -0
- package/.agents/skills/playwright/references/ci-configuration.md +208 -0
- package/.agents/skills/playwright/references/common-errors.md +258 -0
- package/.agents/skills/playwright/references/embedded-docs.md +41 -0
- package/.agents/skills/playwright/references/fixtures-assertions.md +208 -0
- package/.agents/skills/playwright/references/page-objects.md +167 -0
- package/.agents/skills/playwright/references/remote-docs.md +23 -0
- package/.agents/skills/playwright/references/visual-regression.md +206 -0
- package/.agents/skills/pull-request-lifecycle/SKILL.md +116 -0
- package/.agents/skills/pull-request-lifecycle/references/changelog-versioning.md +72 -0
- package/.agents/skills/pull-request-lifecycle/references/merge-strategies.md +33 -0
- package/.agents/skills/pull-request-lifecycle/references/pr-description-template.md +72 -0
- package/.agents/skills/pull-request-lifecycle/references/review-process.md +54 -0
- package/.agents/skills/pull-request-lifecycle/scripts/code_review.py +220 -0
- package/.agents/skills/react-native-expo/SKILL.md +212 -0
- package/.agents/skills/react-native-expo/references/common-errors.md +251 -0
- package/.agents/skills/react-native-expo/references/eas-build-submit.md +238 -0
- package/.agents/skills/react-native-expo/references/embedded-docs.md +42 -0
- package/.agents/skills/react-native-expo/references/native-modules.md +181 -0
- package/.agents/skills/react-native-expo/references/navigation-setup.md +229 -0
- package/.agents/skills/react-native-expo/references/remote-docs.md +23 -0
- package/.agents/skills/supabase/SKILL.md +216 -0
- package/.agents/skills/supabase/references/auth-setup.md +206 -0
- package/.agents/skills/supabase/references/common-errors.md +285 -0
- package/.agents/skills/supabase/references/edge-functions.md +178 -0
- package/.agents/skills/supabase/references/embedded-docs.md +43 -0
- package/.agents/skills/supabase/references/migrations.md +193 -0
- package/.agents/skills/supabase/references/remote-docs.md +24 -0
- package/.agents/skills/supabase/references/rls-policies.md +187 -0
- package/.agents/skills/supabase/references/storage.md +182 -0
- package/.agents/skills/task-breakdown/SKILL.md +179 -0
- package/.agents/skills/task-breakdown/references/acceptance-criteria.md +165 -0
- package/.agents/skills/task-breakdown/references/epic-story-format.md +209 -0
- package/.agents/skills/task-breakdown/references/estimation-guide.md +140 -0
- package/.agents/skills/vitest/SKILL.md +219 -0
- package/.agents/skills/vitest/references/common-errors.md +271 -0
- package/.agents/skills/vitest/references/component-testing.md +182 -0
- package/.agents/skills/vitest/references/configuration.md +184 -0
- package/.agents/skills/vitest/references/coverage.md +179 -0
- package/.agents/skills/vitest/references/embedded-docs.md +43 -0
- package/.agents/skills/vitest/references/mocking.md +182 -0
- package/.agents/skills/vitest/references/remote-docs.md +22 -0
- package/README.md +235 -0
- package/package.json +20 -0
- package/scripts/skills.mjs +849 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# Playwright Common Errors
|
|
2
|
+
|
|
3
|
+
Solutions for frequently encountered Playwright errors.
|
|
4
|
+
|
|
5
|
+
## When to use this reference
|
|
6
|
+
|
|
7
|
+
- Debugging test failures or timeouts
|
|
8
|
+
- Fixing browser installation issues
|
|
9
|
+
- Resolving selector and assertion problems
|
|
10
|
+
|
|
11
|
+
## Browser errors
|
|
12
|
+
|
|
13
|
+
### "Browser was not installed"
|
|
14
|
+
|
|
15
|
+
**Symptoms:**
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
Error: browserType.launch: Executable doesn't exist
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Solutions:**
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Install specific browser
|
|
25
|
+
npx playwright install chromium
|
|
26
|
+
|
|
27
|
+
# Install with system dependencies
|
|
28
|
+
npx playwright install --with-deps chromium
|
|
29
|
+
|
|
30
|
+
# Install all browsers
|
|
31
|
+
npx playwright install --with-deps
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### "Browser closed unexpectedly"
|
|
35
|
+
|
|
36
|
+
**Symptoms:**
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
Error: Browser closed unexpectedly
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Causes:**
|
|
43
|
+
- Out of memory in CI
|
|
44
|
+
- Missing system dependencies
|
|
45
|
+
|
|
46
|
+
**Solutions:**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Install system dependencies
|
|
50
|
+
npx playwright install-deps
|
|
51
|
+
|
|
52
|
+
# Limit workers to reduce memory
|
|
53
|
+
npx playwright test --workers=1
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Selector errors
|
|
57
|
+
|
|
58
|
+
### "Timeout waiting for selector"
|
|
59
|
+
|
|
60
|
+
**Symptoms:**
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
Error: locator.click: Timeout 30000ms exceeded
|
|
64
|
+
waiting for getByRole('button', { name: 'Submit' })
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Causes:**
|
|
68
|
+
- Element doesn't exist on page
|
|
69
|
+
- Element exists but is hidden or disabled
|
|
70
|
+
- Wrong selector
|
|
71
|
+
- Element takes too long to appear
|
|
72
|
+
|
|
73
|
+
**Solutions:**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Debug with UI mode to inspect the page
|
|
77
|
+
npx playwright test --ui
|
|
78
|
+
|
|
79
|
+
# Or debug mode
|
|
80
|
+
npx playwright test --debug
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Check your selector:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// Try highlighting the element
|
|
87
|
+
await page.getByRole('button', { name: 'Submit' }).highlight();
|
|
88
|
+
|
|
89
|
+
// Check if element exists
|
|
90
|
+
const count = await page.getByRole('button', { name: 'Submit' }).count();
|
|
91
|
+
console.log(`Found ${count} elements`);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### "Strict mode violation"
|
|
95
|
+
|
|
96
|
+
**Symptoms:**
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Error: locator.click: Error: strict mode violation: getByRole('button') resolved to 3 elements
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Causes:**
|
|
103
|
+
- Locator matches multiple elements
|
|
104
|
+
|
|
105
|
+
**Solutions:**
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Be more specific
|
|
109
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
110
|
+
|
|
111
|
+
// Use first() or nth()
|
|
112
|
+
await page.getByRole('button').first().click();
|
|
113
|
+
await page.getByRole('button').nth(2).click();
|
|
114
|
+
|
|
115
|
+
// Scope to container
|
|
116
|
+
await page.getByTestId('login-form')
|
|
117
|
+
.getByRole('button', { name: 'Submit' })
|
|
118
|
+
.click();
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Navigation errors
|
|
122
|
+
|
|
123
|
+
### "net::ERR_CONNECTION_REFUSED"
|
|
124
|
+
|
|
125
|
+
**Symptoms:**
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Error: page.goto: net::ERR_CONNECTION_REFUSED at http://localhost:3000
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Causes:**
|
|
132
|
+
- Dev server not running
|
|
133
|
+
- Wrong port
|
|
134
|
+
|
|
135
|
+
**Solutions:**
|
|
136
|
+
|
|
137
|
+
Add `webServer` to config:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// playwright.config.ts
|
|
141
|
+
export default defineConfig({
|
|
142
|
+
webServer: {
|
|
143
|
+
command: 'npm run dev',
|
|
144
|
+
port: 3000,
|
|
145
|
+
reuseExistingServer: !process.env.CI,
|
|
146
|
+
timeout: 120000,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### "Navigation timeout"
|
|
152
|
+
|
|
153
|
+
**Symptoms:**
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Error: page.goto: Timeout 30000ms exceeded
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Solutions:**
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// Increase navigation timeout
|
|
163
|
+
await page.goto('/', { timeout: 60000 });
|
|
164
|
+
|
|
165
|
+
// Or globally
|
|
166
|
+
export default defineConfig({
|
|
167
|
+
use: {
|
|
168
|
+
navigationTimeout: 60000,
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Assertion errors
|
|
174
|
+
|
|
175
|
+
### "Expected to be visible but was hidden"
|
|
176
|
+
|
|
177
|
+
**Symptoms:**
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
Error: expect(locator).toBeVisible()
|
|
181
|
+
Locator: getByText('Welcome')
|
|
182
|
+
Expected: visible
|
|
183
|
+
Received: hidden
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Causes:**
|
|
187
|
+
- Element is in the DOM but hidden via CSS
|
|
188
|
+
- Element hasn't appeared yet (timeout too short)
|
|
189
|
+
|
|
190
|
+
**Solutions:**
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Increase assertion timeout
|
|
194
|
+
await expect(page.getByText('Welcome')).toBeVisible({ timeout: 10000 });
|
|
195
|
+
|
|
196
|
+
// Check if element is actually attached
|
|
197
|
+
await expect(page.getByText('Welcome')).toBeAttached();
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Flaky test patterns
|
|
201
|
+
|
|
202
|
+
### Common causes and fixes
|
|
203
|
+
|
|
204
|
+
| Cause | Fix |
|
|
205
|
+
| --- | --- |
|
|
206
|
+
| Race conditions | Use web-first assertions |
|
|
207
|
+
| `waitForTimeout` | Replace with `expect().toBeVisible()` |
|
|
208
|
+
| Animations | Disable with `prefers-reduced-motion` |
|
|
209
|
+
| Network timing | Mock API responses |
|
|
210
|
+
| Shared test state | Use test isolation (fresh context per test) |
|
|
211
|
+
|
|
212
|
+
### Network mocking for stability
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
test('mocked API', async ({ page }) => {
|
|
216
|
+
await page.route('**/api/users', (route) => {
|
|
217
|
+
route.fulfill({
|
|
218
|
+
status: 200,
|
|
219
|
+
contentType: 'application/json',
|
|
220
|
+
body: JSON.stringify([{ id: 1, name: 'Alice' }]),
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
await page.goto('/users');
|
|
224
|
+
await expect(page.getByText('Alice')).toBeVisible();
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Debugging tools
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Interactive UI mode
|
|
232
|
+
npx playwright test --ui
|
|
233
|
+
|
|
234
|
+
# Step-by-step debugging
|
|
235
|
+
npx playwright test --debug
|
|
236
|
+
|
|
237
|
+
# Generate and view trace
|
|
238
|
+
npx playwright test --trace on
|
|
239
|
+
npx playwright show-trace test-results/trace.zip
|
|
240
|
+
|
|
241
|
+
# Run single test
|
|
242
|
+
npx playwright test -g "login test"
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Performance issues
|
|
246
|
+
|
|
247
|
+
### Tests running slowly
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
# Parallel execution
|
|
251
|
+
npx playwright test --workers=4
|
|
252
|
+
|
|
253
|
+
# Run only changed tests
|
|
254
|
+
npx playwright test --only-changed
|
|
255
|
+
|
|
256
|
+
# Skip browser install check
|
|
257
|
+
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci
|
|
258
|
+
```
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Embedded Docs Reference
|
|
2
|
+
|
|
3
|
+
Use installed package versions and local config first.
|
|
4
|
+
|
|
5
|
+
## Why local-first
|
|
6
|
+
|
|
7
|
+
- Playwright behavior can differ by package and browser engine versions.
|
|
8
|
+
- Local `playwright.config.*` controls retries, projects, and web server orchestration.
|
|
9
|
+
|
|
10
|
+
## Lookup workflow
|
|
11
|
+
|
|
12
|
+
1. Check installed versions:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx playwright --version
|
|
16
|
+
npm ls @playwright/test --depth=0
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Inspect local config:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ls playwright.config.* 2>/dev/null
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. Inspect available CLI behavior:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx playwright test --help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
4. Inspect local type definitions when API signature is unclear:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ls node_modules/@playwright/test/types/test.d.ts 2>/dev/null
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Use this when
|
|
38
|
+
|
|
39
|
+
- Timeout/retry behavior is unexpected
|
|
40
|
+
- Projects/browsers in CI differ from local runs
|
|
41
|
+
- Test APIs differ from examples online
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Fixtures and Assertions
|
|
2
|
+
|
|
3
|
+
Custom fixtures and assertion patterns for Playwright tests.
|
|
4
|
+
|
|
5
|
+
## When to use this reference
|
|
6
|
+
|
|
7
|
+
- Creating custom test fixtures (authenticated state, test data)
|
|
8
|
+
- Using Playwright's web-first assertions
|
|
9
|
+
- Setting up shared test state
|
|
10
|
+
|
|
11
|
+
## Built-in fixtures
|
|
12
|
+
|
|
13
|
+
| Fixture | Type | Purpose |
|
|
14
|
+
| --- | --- | --- |
|
|
15
|
+
| `page` | Page | Browser page for interaction |
|
|
16
|
+
| `context` | BrowserContext | Browser context (cookies, storage) |
|
|
17
|
+
| `browser` | Browser | Browser instance |
|
|
18
|
+
| `request` | APIRequestContext | API testing without browser |
|
|
19
|
+
| `browserName` | string | Current browser name |
|
|
20
|
+
|
|
21
|
+
## Custom fixtures
|
|
22
|
+
|
|
23
|
+
### Basic fixture
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// fixtures.ts
|
|
27
|
+
import { test as base } from '@playwright/test';
|
|
28
|
+
|
|
29
|
+
type MyFixtures = {
|
|
30
|
+
todoPage: TodoPage;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const test = base.extend<MyFixtures>({
|
|
34
|
+
todoPage: async ({ page }, use) => {
|
|
35
|
+
const todoPage = new TodoPage(page);
|
|
36
|
+
await todoPage.goto();
|
|
37
|
+
await use(todoPage);
|
|
38
|
+
// Cleanup after test (optional)
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Authenticated fixture
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { test as base } from '@playwright/test';
|
|
47
|
+
|
|
48
|
+
export const test = base.extend({
|
|
49
|
+
authenticatedPage: async ({ page }, use) => {
|
|
50
|
+
// Login before test
|
|
51
|
+
await page.goto('/login');
|
|
52
|
+
await page.getByLabel('Email').fill('test@example.com');
|
|
53
|
+
await page.getByLabel('Password').fill('password');
|
|
54
|
+
await page.getByRole('button', { name: 'Log in' }).click();
|
|
55
|
+
await page.waitForURL('/dashboard');
|
|
56
|
+
await use(page);
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Shared storage state (faster auth)
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// auth.setup.ts — run once to save auth state
|
|
65
|
+
import { test as setup } from '@playwright/test';
|
|
66
|
+
|
|
67
|
+
setup('authenticate', async ({ page }) => {
|
|
68
|
+
await page.goto('/login');
|
|
69
|
+
await page.getByLabel('Email').fill('test@example.com');
|
|
70
|
+
await page.getByLabel('Password').fill('password');
|
|
71
|
+
await page.getByRole('button', { name: 'Log in' }).click();
|
|
72
|
+
await page.waitForURL('/dashboard');
|
|
73
|
+
await page.context().storageState({ path: '.auth/user.json' });
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
// playwright.config.ts
|
|
79
|
+
export default defineConfig({
|
|
80
|
+
projects: [
|
|
81
|
+
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
|
|
82
|
+
{
|
|
83
|
+
name: 'chromium',
|
|
84
|
+
dependencies: ['setup'],
|
|
85
|
+
use: { storageState: '.auth/user.json' },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Test data fixture
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
export const test = base.extend<{ testUser: User }>({
|
|
95
|
+
testUser: async ({ request }, use) => {
|
|
96
|
+
// Create test data via API
|
|
97
|
+
const response = await request.post('/api/test/users', {
|
|
98
|
+
data: { name: 'Test User', email: `test-${Date.now()}@example.com` },
|
|
99
|
+
});
|
|
100
|
+
const user = await response.json();
|
|
101
|
+
await use(user);
|
|
102
|
+
// Cleanup: delete test user
|
|
103
|
+
await request.delete(`/api/test/users/${user.id}`);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Web-first assertions
|
|
109
|
+
|
|
110
|
+
Assertions that auto-retry until condition is met or timeout:
|
|
111
|
+
|
|
112
|
+
### Page assertions
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
await expect(page).toHaveURL('/dashboard');
|
|
116
|
+
await expect(page).toHaveTitle('Dashboard');
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Locator assertions
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
const button = page.getByRole('button', { name: 'Submit' });
|
|
123
|
+
|
|
124
|
+
await expect(button).toBeVisible();
|
|
125
|
+
await expect(button).toBeEnabled();
|
|
126
|
+
await expect(button).toBeDisabled();
|
|
127
|
+
await expect(button).toHaveText('Submit');
|
|
128
|
+
await expect(button).toHaveAttribute('type', 'submit');
|
|
129
|
+
await expect(button).toHaveClass(/primary/);
|
|
130
|
+
await expect(button).toHaveCount(1);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Negation
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
await expect(page.getByText('Loading')).not.toBeVisible();
|
|
137
|
+
await expect(page.getByRole('alert')).not.toBeAttached();
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Soft assertions (don't stop test)
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
await expect.soft(page.getByText('Title')).toBeVisible();
|
|
144
|
+
await expect.soft(page.getByText('Subtitle')).toBeVisible();
|
|
145
|
+
// Test continues even if soft assertions fail
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## API assertions
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const response = await request.get('/api/users/1');
|
|
152
|
+
expect(response.ok()).toBeTruthy();
|
|
153
|
+
expect(response.status()).toBe(200);
|
|
154
|
+
expect(await response.json()).toEqual(
|
|
155
|
+
expect.objectContaining({ name: 'Alice' })
|
|
156
|
+
);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Custom matchers
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
// fixtures.ts
|
|
163
|
+
import { expect as baseExpect } from '@playwright/test';
|
|
164
|
+
|
|
165
|
+
export const expect = baseExpect.extend({
|
|
166
|
+
async toHaveNotification(page, message: string) {
|
|
167
|
+
const notification = page.getByRole('alert');
|
|
168
|
+
try {
|
|
169
|
+
await baseExpect(notification).toHaveText(message);
|
|
170
|
+
return { pass: true, message: () => '' };
|
|
171
|
+
} catch {
|
|
172
|
+
return {
|
|
173
|
+
pass: false,
|
|
174
|
+
message: () => `Expected notification "${message}" but not found`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Assertion timeouts
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Per assertion
|
|
185
|
+
await expect(page.getByText('Loaded')).toBeVisible({ timeout: 10000 });
|
|
186
|
+
|
|
187
|
+
// Global default
|
|
188
|
+
// playwright.config.ts
|
|
189
|
+
export default defineConfig({
|
|
190
|
+
expect: {
|
|
191
|
+
timeout: 10000,
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Troubleshooting
|
|
197
|
+
|
|
198
|
+
### Assertion timing out
|
|
199
|
+
|
|
200
|
+
- Use `--debug` mode to see what's on the page
|
|
201
|
+
- Check if the element is inside a shadow DOM
|
|
202
|
+
- Verify the locator matches the correct element with `page.getByRole(...).highlight()`
|
|
203
|
+
|
|
204
|
+
### Flaky assertions
|
|
205
|
+
|
|
206
|
+
- Use web-first assertions (not `expect(await page.textContent(...))`)
|
|
207
|
+
- Avoid `waitForTimeout` — use `expect(locator).toBeVisible()` instead
|
|
208
|
+
- Check for animations that delay element visibility
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Page Object Model
|
|
2
|
+
|
|
3
|
+
Structure Playwright tests using the page object pattern for maintainability.
|
|
4
|
+
|
|
5
|
+
## When to use this reference
|
|
6
|
+
|
|
7
|
+
- Organizing tests for large applications
|
|
8
|
+
- Reducing duplication across test files
|
|
9
|
+
- Making tests resilient to UI changes
|
|
10
|
+
|
|
11
|
+
## Page object pattern
|
|
12
|
+
|
|
13
|
+
A page object encapsulates page interactions in a class:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// pages/LoginPage.ts
|
|
17
|
+
import { type Page, type Locator } from '@playwright/test';
|
|
18
|
+
|
|
19
|
+
export class LoginPage {
|
|
20
|
+
readonly page: Page;
|
|
21
|
+
readonly emailInput: Locator;
|
|
22
|
+
readonly passwordInput: Locator;
|
|
23
|
+
readonly submitButton: Locator;
|
|
24
|
+
readonly errorMessage: Locator;
|
|
25
|
+
|
|
26
|
+
constructor(page: Page) {
|
|
27
|
+
this.page = page;
|
|
28
|
+
this.emailInput = page.getByLabel('Email');
|
|
29
|
+
this.passwordInput = page.getByLabel('Password');
|
|
30
|
+
this.submitButton = page.getByRole('button', { name: 'Log in' });
|
|
31
|
+
this.errorMessage = page.getByRole('alert');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async goto() {
|
|
35
|
+
await this.page.goto('/login');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async login(email: string, password: string) {
|
|
39
|
+
await this.emailInput.fill(email);
|
|
40
|
+
await this.passwordInput.fill(password);
|
|
41
|
+
await this.submitButton.click();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Using page objects in tests
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// tests/login.spec.ts
|
|
50
|
+
import { test, expect } from '@playwright/test';
|
|
51
|
+
import { LoginPage } from '../pages/LoginPage';
|
|
52
|
+
|
|
53
|
+
test('successful login', async ({ page }) => {
|
|
54
|
+
const loginPage = new LoginPage(page);
|
|
55
|
+
await loginPage.goto();
|
|
56
|
+
await loginPage.login('user@example.com', 'password');
|
|
57
|
+
await expect(page).toHaveURL('/dashboard');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('shows error for invalid credentials', async ({ page }) => {
|
|
61
|
+
const loginPage = new LoginPage(page);
|
|
62
|
+
await loginPage.goto();
|
|
63
|
+
await loginPage.login('user@example.com', 'wrong');
|
|
64
|
+
await expect(loginPage.errorMessage).toBeVisible();
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Page object with fixtures
|
|
69
|
+
|
|
70
|
+
Combine page objects with Playwright fixtures for cleaner tests:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// fixtures.ts
|
|
74
|
+
import { test as base } from '@playwright/test';
|
|
75
|
+
import { LoginPage } from '../pages/LoginPage';
|
|
76
|
+
import { DashboardPage } from '../pages/DashboardPage';
|
|
77
|
+
|
|
78
|
+
type Fixtures = {
|
|
79
|
+
loginPage: LoginPage;
|
|
80
|
+
dashboardPage: DashboardPage;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const test = base.extend<Fixtures>({
|
|
84
|
+
loginPage: async ({ page }, use) => {
|
|
85
|
+
await use(new LoginPage(page));
|
|
86
|
+
},
|
|
87
|
+
dashboardPage: async ({ page }, use) => {
|
|
88
|
+
await use(new DashboardPage(page));
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export { expect } from '@playwright/test';
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// tests/login.spec.ts
|
|
97
|
+
import { test, expect } from '../fixtures';
|
|
98
|
+
|
|
99
|
+
test('successful login', async ({ loginPage }) => {
|
|
100
|
+
await loginPage.goto();
|
|
101
|
+
await loginPage.login('user@example.com', 'password');
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Directory structure
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
tests/
|
|
109
|
+
├── fixtures.ts # Custom fixtures
|
|
110
|
+
├── pages/
|
|
111
|
+
│ ├── LoginPage.ts
|
|
112
|
+
│ ├── DashboardPage.ts
|
|
113
|
+
│ └── SettingsPage.ts
|
|
114
|
+
├── auth/
|
|
115
|
+
│ ├── login.spec.ts
|
|
116
|
+
│ └── signup.spec.ts
|
|
117
|
+
└── dashboard/
|
|
118
|
+
└── overview.spec.ts
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Page object guidelines
|
|
122
|
+
|
|
123
|
+
### Do
|
|
124
|
+
|
|
125
|
+
- Expose **actions** (login, fillForm) not implementation details
|
|
126
|
+
- Use **semantic locators** (getByRole, getByLabel) inside page objects
|
|
127
|
+
- Keep assertions in **test files**, not page objects
|
|
128
|
+
- Create **one page object per page/component**
|
|
129
|
+
|
|
130
|
+
### Don't
|
|
131
|
+
|
|
132
|
+
- Put assertions in page objects (exceptions: navigation verification)
|
|
133
|
+
- Expose raw locators publicly (use methods instead)
|
|
134
|
+
- Create deeply nested page object hierarchies
|
|
135
|
+
- Share state between page objects
|
|
136
|
+
|
|
137
|
+
## Component objects (for reusable components)
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// components/Navbar.ts
|
|
141
|
+
import { type Page, type Locator } from '@playwright/test';
|
|
142
|
+
|
|
143
|
+
export class Navbar {
|
|
144
|
+
readonly container: Locator;
|
|
145
|
+
|
|
146
|
+
constructor(page: Page) {
|
|
147
|
+
this.container = page.getByRole('navigation');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async clickLink(name: string) {
|
|
151
|
+
await this.container.getByRole('link', { name }).click();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async search(query: string) {
|
|
155
|
+
await this.container.getByRole('searchbox').fill(query);
|
|
156
|
+
await this.container.getByRole('searchbox').press('Enter');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Troubleshooting
|
|
162
|
+
|
|
163
|
+
### Page object methods timing out
|
|
164
|
+
|
|
165
|
+
- Ensure the page has navigated before interacting
|
|
166
|
+
- Add `await page.waitForLoadState()` in `goto()` if needed
|
|
167
|
+
- Check that locators match the current page structure
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Remote Docs Reference
|
|
2
|
+
|
|
3
|
+
Use official Playwright docs for canonical API and configuration behavior.
|
|
4
|
+
|
|
5
|
+
## Official sources
|
|
6
|
+
|
|
7
|
+
- Docs home: https://playwright.dev/docs/intro
|
|
8
|
+
- API reference: https://playwright.dev/docs/api/class-playwright
|
|
9
|
+
- Locator docs: https://playwright.dev/docs/locators
|
|
10
|
+
- Assertions: https://playwright.dev/docs/test-assertions
|
|
11
|
+
- Configuration: https://playwright.dev/docs/test-configuration
|
|
12
|
+
- CI guides: https://playwright.dev/docs/ci
|
|
13
|
+
|
|
14
|
+
## Lookup workflow
|
|
15
|
+
|
|
16
|
+
1. Start with local config and installed version.
|
|
17
|
+
2. Open the matching official docs page.
|
|
18
|
+
3. Reconcile with local `playwright.config.*` and project constraints.
|
|
19
|
+
|
|
20
|
+
## Notes
|
|
21
|
+
|
|
22
|
+
- Prioritize official docs over blog recipes for selectors/retries/timeouts.
|
|
23
|
+
- Validate recommendations with `npx playwright test --debug` when needed.
|