@arcadialdev/arcality 2.2.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/e2e-testing-expert/SKILL.md +28 -0
- package/.agents/skills/frontend-design/LICENSE.txt +177 -0
- package/.agents/skills/frontend-design/SKILL.md +42 -0
- package/.agents/skills/nodejs-backend-patterns/SKILL.md +639 -0
- package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
- package/.agents/skills/playwright-best-practices/LICENSE.md +7 -0
- package/.agents/skills/playwright-best-practices/README.md +147 -0
- package/.agents/skills/playwright-best-practices/SKILL.md +303 -0
- package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +360 -0
- package/.agents/skills/playwright-best-practices/advanced/authentication.md +871 -0
- package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +364 -0
- package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +409 -0
- package/.agents/skills/playwright-best-practices/advanced/multi-context.md +288 -0
- package/.agents/skills/playwright-best-practices/advanced/multi-user.md +393 -0
- package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +452 -0
- package/.agents/skills/playwright-best-practices/advanced/third-party.md +464 -0
- package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +363 -0
- package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +369 -0
- package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +383 -0
- package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +391 -0
- package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +403 -0
- package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +504 -0
- package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +403 -0
- package/.agents/skills/playwright-best-practices/core/annotations.md +424 -0
- package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +361 -0
- package/.agents/skills/playwright-best-practices/core/configuration.md +452 -0
- package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +417 -0
- package/.agents/skills/playwright-best-practices/core/global-setup.md +434 -0
- package/.agents/skills/playwright-best-practices/core/locators.md +242 -0
- package/.agents/skills/playwright-best-practices/core/page-object-model.md +315 -0
- package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +453 -0
- package/.agents/skills/playwright-best-practices/core/test-data.md +492 -0
- package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +361 -0
- package/.agents/skills/playwright-best-practices/core/test-tags.md +298 -0
- package/.agents/skills/playwright-best-practices/debugging/console-errors.md +420 -0
- package/.agents/skills/playwright-best-practices/debugging/debugging.md +504 -0
- package/.agents/skills/playwright-best-practices/debugging/error-testing.md +360 -0
- package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +496 -0
- package/.agents/skills/playwright-best-practices/frameworks/angular.md +530 -0
- package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +469 -0
- package/.agents/skills/playwright-best-practices/frameworks/react.md +531 -0
- package/.agents/skills/playwright-best-practices/frameworks/vue.md +574 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +468 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +283 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +546 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +397 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +521 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +371 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +453 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +424 -0
- package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +497 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +359 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +719 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +506 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +493 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +500 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +576 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +509 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +377 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +562 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +561 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +331 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +508 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +476 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +430 -0
- package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +634 -0
- package/.env.example +21 -0
- package/README.md +30 -0
- package/bin/arcality.mjs +86 -0
- package/package.json +66 -0
- package/playwright.config.ts +12 -0
- package/scripts/cleanup-qmsdev.mjs +63 -0
- package/scripts/discover-view.mjs +52 -0
- package/scripts/extract-view.mjs +64 -0
- package/scripts/gen-and-run.mjs +838 -0
- package/scripts/init.mjs +290 -0
- package/scripts/migrate-to-central-out.mjs +157 -0
- package/scripts/postinstall.mjs +63 -0
- package/scripts/rebrand-report.mjs +241 -0
- package/scripts/setup.mjs +166 -0
- package/src/KnowledgeService.ts +239 -0
- package/src/arcalityClient.mjs +266 -0
- package/src/configLoader.mjs +179 -0
- package/src/configManager.mjs +172 -0
- package/src/consoleBanner.ts +32 -0
- package/src/envSetup.ts +205 -0
- package/src/index.ts +25 -0
- package/src/projectInspector.ts +42 -0
- package/src/services/collectiveMemoryService.ts +178 -0
- package/src/testRunner.ts +201 -0
- package/tests/_helpers/ArcalityReporter.ts +490 -0
- package/tests/_helpers/agentic-runner.spec.ts +741 -0
- package/tests/_helpers/ai-agent-helper.ts +1573 -0
- package/tests/_helpers/discover-view.spec.ts +238 -0
- package/tests/_helpers/extract-view.spec.ts +118 -0
- package/tests/_helpers/qa-tools.ts +333 -0
- package/tests/_helpers/smart-action.spec.ts +1458 -0
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
# Performance & Parallelization
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Parallel Execution](#parallel-execution)
|
|
6
|
+
2. [Sharding](#sharding)
|
|
7
|
+
3. [Test Optimization](#test-optimization)
|
|
8
|
+
4. [Network Optimization](#network-optimization)
|
|
9
|
+
5. [Isolation and Parallel Execution](#isolation-and-parallel-execution)
|
|
10
|
+
6. [Resource Management](#resource-management)
|
|
11
|
+
7. [Benchmarking](#benchmarking)
|
|
12
|
+
|
|
13
|
+
## Parallel Execution
|
|
14
|
+
|
|
15
|
+
### Configuration
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
// playwright.config.ts
|
|
19
|
+
export default defineConfig({
|
|
20
|
+
// Run test files in parallel
|
|
21
|
+
fullyParallel: true,
|
|
22
|
+
|
|
23
|
+
// Number of worker processes
|
|
24
|
+
workers: process.env.CI ? 1 : undefined, // undefined = half CPU cores
|
|
25
|
+
|
|
26
|
+
// Or explicit count
|
|
27
|
+
// workers: 4,
|
|
28
|
+
// workers: '50%', // Percentage of CPU cores
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Serial Execution When Needed
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Entire file serial
|
|
36
|
+
test.describe.configure({ mode: "serial" });
|
|
37
|
+
|
|
38
|
+
test.describe("Sequential Tests", () => {
|
|
39
|
+
test("first", async ({ page }) => {
|
|
40
|
+
// Runs first
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("second", async ({ page }) => {
|
|
44
|
+
// Runs after first
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
// Single describe block serial
|
|
51
|
+
test.describe("Parallel Tests", () => {
|
|
52
|
+
test("a", async () => {}); // Parallel
|
|
53
|
+
test("b", async () => {}); // Parallel
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test.describe.serial("Serial Tests", () => {
|
|
57
|
+
test("c", async () => {}); // Serial
|
|
58
|
+
test("d", async () => {}); // Serial
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Parallel Projects
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// playwright.config.ts
|
|
66
|
+
export default defineConfig({
|
|
67
|
+
projects: [
|
|
68
|
+
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
|
|
69
|
+
{ name: "firefox", use: { ...devices["Desktop Firefox"] } },
|
|
70
|
+
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Run all projects in parallel
|
|
77
|
+
npx playwright test
|
|
78
|
+
|
|
79
|
+
# Run specific project
|
|
80
|
+
npx playwright test --project=chromium
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Sharding
|
|
84
|
+
|
|
85
|
+
### Basic Sharding
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Split tests across 4 machines
|
|
89
|
+
# Machine 1:
|
|
90
|
+
npx playwright test --shard=1/4
|
|
91
|
+
|
|
92
|
+
# Machine 2:
|
|
93
|
+
npx playwright test --shard=2/4
|
|
94
|
+
|
|
95
|
+
# Machine 3:
|
|
96
|
+
npx playwright test --shard=3/4
|
|
97
|
+
|
|
98
|
+
# Machine 4:
|
|
99
|
+
npx playwright test --shard=4/4
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Sharding Strategy
|
|
103
|
+
|
|
104
|
+
Tests are distributed evenly by file. For optimal sharding:
|
|
105
|
+
|
|
106
|
+
- Keep test files similar in size
|
|
107
|
+
- Use `fullyParallel: true` for even distribution
|
|
108
|
+
- Balance slow tests across files
|
|
109
|
+
|
|
110
|
+
### CI Sharding Pattern
|
|
111
|
+
|
|
112
|
+
```yaml
|
|
113
|
+
# GitHub Actions
|
|
114
|
+
jobs:
|
|
115
|
+
test:
|
|
116
|
+
strategy:
|
|
117
|
+
matrix:
|
|
118
|
+
shard: [1, 2, 3, 4]
|
|
119
|
+
steps:
|
|
120
|
+
- run: npx playwright test --shard=${{ matrix.shard }}/4
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> **For comprehensive CI sharding** (blob reports, merging sharded results, full workflows), see [ci-cd.md](ci-cd.md#sharding).
|
|
124
|
+
|
|
125
|
+
## Test Optimization
|
|
126
|
+
|
|
127
|
+
### Reuse Authentication
|
|
128
|
+
|
|
129
|
+
Avoid logging in for every test. Use setup projects with storage state to authenticate once and reuse the session.
|
|
130
|
+
|
|
131
|
+
> **For authentication patterns** (storage state, multiple auth states, setup projects), see [fixtures-hooks.md](fixtures-hooks.md#authentication-patterns).
|
|
132
|
+
|
|
133
|
+
### Reuse Page State (serial only — trade-off with isolation)
|
|
134
|
+
|
|
135
|
+
Sharing a single page/context across tests with `beforeAll`/`afterAll` is **not recommended** for most suites: it breaks test isolation, causes state leak between tests, and makes failures harder to debug. Prefer a fresh `page` per test (Playwright default). Use shared page only when you explicitly need serial execution and accept no isolation.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// ⚠️ Serial only, no isolation: state from one test leaks into the next.
|
|
139
|
+
// Prefer test.describe.configure({ mode: 'serial' }) + fresh page per test, or beforeEach + page.goto().
|
|
140
|
+
test.describe.configure({ mode: "serial" });
|
|
141
|
+
test.describe("Dashboard", () => {
|
|
142
|
+
let page: Page;
|
|
143
|
+
|
|
144
|
+
test.beforeAll(async ({ browser }) => {
|
|
145
|
+
const context = await browser.newContext({
|
|
146
|
+
storageState: ".auth/user.json",
|
|
147
|
+
});
|
|
148
|
+
page = await context.newPage();
|
|
149
|
+
await page.goto("/dashboard");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test.afterAll(async () => {
|
|
153
|
+
await page?.close();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test("shows stats", async () => {
|
|
157
|
+
await expect(page.getByTestId("stats")).toBeVisible();
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("shows chart", async () => {
|
|
161
|
+
await expect(page.getByTestId("chart")).toBeVisible();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Lazy Navigation
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
// Bad: Navigate in every test
|
|
170
|
+
test("check header", async ({ page }) => {
|
|
171
|
+
await page.goto("/products");
|
|
172
|
+
await expect(page.getByRole("heading")).toBeVisible();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("check footer", async ({ page }) => {
|
|
176
|
+
await page.goto("/products");
|
|
177
|
+
await expect(page.getByRole("contentinfo")).toBeVisible();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Good: Share navigation
|
|
181
|
+
test.describe("Products Page", () => {
|
|
182
|
+
test.beforeEach(async ({ page }) => {
|
|
183
|
+
await page.goto("/products");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test("check header", async ({ page }) => {
|
|
187
|
+
await expect(page.getByRole("heading")).toBeVisible();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("check footer", async ({ page }) => {
|
|
191
|
+
await expect(page.getByRole("contentinfo")).toBeVisible();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Skip Unnecessary Setup
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
// Use test.skip for conditional execution
|
|
200
|
+
test("admin feature", async ({ page }) => {
|
|
201
|
+
test.skip(!process.env.ADMIN_ENABLED, "Admin features disabled");
|
|
202
|
+
// ...
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Use test.fixme for known broken tests
|
|
206
|
+
test.fixme("broken feature", async ({ page }) => {
|
|
207
|
+
// Skipped but tracked
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Network Optimization
|
|
212
|
+
|
|
213
|
+
### Mock APIs
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
test.beforeEach(async ({ page }) => {
|
|
217
|
+
// Mock slow/heavy endpoints
|
|
218
|
+
await page.route("**/api/analytics", (route) =>
|
|
219
|
+
route.fulfill({ json: { views: 1000 } }),
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
await page.route("**/api/recommendations", (route) =>
|
|
223
|
+
route.fulfill({ json: [] }),
|
|
224
|
+
);
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Block Unnecessary Resources
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
test.beforeEach(async ({ page }) => {
|
|
232
|
+
// Block analytics, ads, tracking
|
|
233
|
+
await page.route("**/*", (route) => {
|
|
234
|
+
const url = route.request().url();
|
|
235
|
+
if (
|
|
236
|
+
url.includes("google-analytics") ||
|
|
237
|
+
url.includes("facebook") ||
|
|
238
|
+
url.includes("hotjar")
|
|
239
|
+
) {
|
|
240
|
+
return route.abort();
|
|
241
|
+
}
|
|
242
|
+
return route.continue();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Block Resource Types
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Block images and fonts for faster tests
|
|
251
|
+
await page.route("**/*", (route) => {
|
|
252
|
+
const resourceType = route.request().resourceType();
|
|
253
|
+
if (["image", "font", "stylesheet"].includes(resourceType)) {
|
|
254
|
+
return route.abort();
|
|
255
|
+
}
|
|
256
|
+
return route.continue();
|
|
257
|
+
});
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Cache API Responses
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
const apiCache = new Map<string, object>();
|
|
264
|
+
|
|
265
|
+
test.beforeEach(async ({ page }) => {
|
|
266
|
+
await page.route("**/api/**", async (route) => {
|
|
267
|
+
const url = route.request().url();
|
|
268
|
+
|
|
269
|
+
if (apiCache.has(url)) {
|
|
270
|
+
return route.fulfill({ json: apiCache.get(url) });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const response = await route.fetch();
|
|
274
|
+
const json = await response.json();
|
|
275
|
+
apiCache.set(url, json);
|
|
276
|
+
return route.fulfill({ json });
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Isolation and Parallel Execution
|
|
282
|
+
|
|
283
|
+
### Default: one context per test
|
|
284
|
+
|
|
285
|
+
Playwright gives each test its own browser context (and page). That gives isolation: no shared cookies, storage, or DOM between tests, so failures don’t carry over and you can run tests in any order or in parallel. Keep this default unless you have a clear reason to share state.
|
|
286
|
+
|
|
287
|
+
### Avoiding state leak in parallel runs
|
|
288
|
+
|
|
289
|
+
- **Do not** rely on shared mutable state (e.g. a single `page` or `context` in `beforeAll`) when tests can run in parallel. State from one test can leak into another and cause flaky, order-dependent failures.
|
|
290
|
+
- Use **fixtures** for setup/teardown and **`beforeEach`** for per-test navigation so each test gets a fresh page or a clean slate.
|
|
291
|
+
- For **backend or DB state** shared across tests, isolate per worker so parallel workers don’t collide. Use a worker-scoped fixture and `testInfo.workerIndex` (or `process.env.TEST_WORKER_INDEX`) to create unique data per worker (e.g. unique user or DB prefix). See [fixtures-hooks.md](../core/fixtures-hooks.md) for worker-scoped fixtures and [debugging.md](../debugging/debugging.md) for debugging flaky parallel runs.
|
|
292
|
+
|
|
293
|
+
### Debugging flaky parallel runs
|
|
294
|
+
|
|
295
|
+
If a test is flaky only with multiple workers:
|
|
296
|
+
|
|
297
|
+
1. **Reproduce**: Run with default workers and `--repeat-each=10` (or `--repeat-each=100 --max-failures=1`).
|
|
298
|
+
2. **Confirm parallel-specific**: Run with `--workers=1`. If the failure disappears, the cause is likely shared state or non-isolated backend/DB data.
|
|
299
|
+
3. **Fix**: Remove shared page/context; use per-test fixtures and `beforeEach`; isolate test data per worker with `workerIndex` in a worker-scoped fixture.
|
|
300
|
+
|
|
301
|
+
Workers are restarted after a test failure so subsequent tests in that worker get a clean environment; fixing isolation still prevents the initial flakiness.
|
|
302
|
+
|
|
303
|
+
## Resource Management
|
|
304
|
+
|
|
305
|
+
### Browser Contexts
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
// Recommended: One context per test (default) — full isolation
|
|
309
|
+
test("isolated test", async ({ page }) => {
|
|
310
|
+
// Fresh context automatically
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
// Manual context for specific needs
|
|
314
|
+
test("multiple tabs", async ({ browser }) => {
|
|
315
|
+
const context = await browser.newContext();
|
|
316
|
+
const page1 = await context.newPage();
|
|
317
|
+
const page2 = await context.newPage();
|
|
318
|
+
|
|
319
|
+
// Clean up
|
|
320
|
+
await context.close();
|
|
321
|
+
});
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Memory Management
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
// playwright.config.ts
|
|
328
|
+
export default defineConfig({
|
|
329
|
+
// Limit concurrent workers
|
|
330
|
+
workers: 2,
|
|
331
|
+
|
|
332
|
+
// Limit parallel tests per worker
|
|
333
|
+
use: {
|
|
334
|
+
// Lower memory usage
|
|
335
|
+
launchOptions: {
|
|
336
|
+
args: ["--disable-dev-shm-usage"],
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Timeouts
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// playwright.config.ts
|
|
346
|
+
export default defineConfig({
|
|
347
|
+
// Global test timeout
|
|
348
|
+
timeout: 30000,
|
|
349
|
+
|
|
350
|
+
// Assertion timeout
|
|
351
|
+
expect: {
|
|
352
|
+
timeout: 5000,
|
|
353
|
+
},
|
|
354
|
+
|
|
355
|
+
// Navigation timeout
|
|
356
|
+
use: {
|
|
357
|
+
navigationTimeout: 15000,
|
|
358
|
+
actionTimeout: 10000,
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Benchmarking
|
|
364
|
+
|
|
365
|
+
### Measure Test Duration
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
test("performance test", async ({ page }, testInfo) => {
|
|
369
|
+
const startTime = Date.now();
|
|
370
|
+
|
|
371
|
+
await page.goto("/");
|
|
372
|
+
|
|
373
|
+
const loadTime = Date.now() - startTime;
|
|
374
|
+
console.log(`Page load: ${loadTime}ms`);
|
|
375
|
+
|
|
376
|
+
// Add to test report
|
|
377
|
+
testInfo.annotations.push({
|
|
378
|
+
type: "performance",
|
|
379
|
+
description: `Load time: ${loadTime}ms`,
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Performance Metrics
|
|
385
|
+
|
|
386
|
+
```typescript
|
|
387
|
+
test("collect metrics", async ({ page }) => {
|
|
388
|
+
await page.goto("/");
|
|
389
|
+
|
|
390
|
+
const metrics = await page.evaluate(() => ({
|
|
391
|
+
// Navigation timing
|
|
392
|
+
loadTime:
|
|
393
|
+
performance.timing.loadEventEnd - performance.timing.navigationStart,
|
|
394
|
+
domContentLoaded:
|
|
395
|
+
performance.timing.domContentLoadedEventEnd -
|
|
396
|
+
performance.timing.navigationStart,
|
|
397
|
+
|
|
398
|
+
// Performance entries
|
|
399
|
+
resources: performance.getEntriesByType("resource").length,
|
|
400
|
+
|
|
401
|
+
// Memory (Chrome only)
|
|
402
|
+
// @ts-ignore
|
|
403
|
+
memory: performance.memory?.usedJSHeapSize,
|
|
404
|
+
}));
|
|
405
|
+
|
|
406
|
+
console.log("Metrics:", metrics);
|
|
407
|
+
expect(metrics.loadTime).toBeLessThan(3000);
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Lighthouse Integration
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
import { playAudit } from "playwright-lighthouse";
|
|
415
|
+
|
|
416
|
+
test("lighthouse audit", async ({ page }) => {
|
|
417
|
+
await page.goto("/");
|
|
418
|
+
|
|
419
|
+
const audit = await playAudit({
|
|
420
|
+
page,
|
|
421
|
+
thresholds: {
|
|
422
|
+
performance: 80,
|
|
423
|
+
accessibility: 90,
|
|
424
|
+
"best-practices": 80,
|
|
425
|
+
seo: 80,
|
|
426
|
+
},
|
|
427
|
+
port: 9222,
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
expect(audit.lhr.categories.performance.score * 100).toBeGreaterThanOrEqual(
|
|
431
|
+
80,
|
|
432
|
+
);
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Performance Checklist
|
|
437
|
+
|
|
438
|
+
| Optimization | Impact |
|
|
439
|
+
| ------------------------------ | ---------- |
|
|
440
|
+
| Enable `fullyParallel` | High |
|
|
441
|
+
| Reuse authentication | High |
|
|
442
|
+
| Mock heavy APIs | High |
|
|
443
|
+
| Block tracking scripts | Medium |
|
|
444
|
+
| Use sharding in CI | High |
|
|
445
|
+
| Reduce workers if memory-bound | Medium |
|
|
446
|
+
| Cache API responses | Medium |
|
|
447
|
+
| Skip unnecessary tests | Low-Medium |
|
|
448
|
+
|
|
449
|
+
## Related References
|
|
450
|
+
|
|
451
|
+
- **CI/CD sharding**: See [ci-cd.md](ci-cd.md) for CI configuration
|
|
452
|
+
- **Test organization**: See [test-suite-structure.md](../core/test-suite-structure.md) for structuring tests
|
|
453
|
+
- **Fixtures for reuse**: See [fixtures-hooks.md](../core/fixtures-hooks.md) for authentication patterns
|