@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,361 @@
|
|
|
1
|
+
# Test Suite Structure
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Configuration](#configuration)
|
|
6
|
+
2. [E2E Tests](#e2e-tests)
|
|
7
|
+
3. [Component Tests](#component-tests)
|
|
8
|
+
4. [API Tests](#api-tests)
|
|
9
|
+
5. [Visual Regression Tests](#visual-regression-tests)
|
|
10
|
+
6. [Directory Structure](#directory-structure)
|
|
11
|
+
7. [Tagging & Filtering](#tagging--filtering)
|
|
12
|
+
|
|
13
|
+
### Project Setup
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm init playwright@latest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Configuration
|
|
20
|
+
|
|
21
|
+
### Essential Configuration
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// playwright.config.ts
|
|
25
|
+
import { defineConfig, devices } from "@playwright/test";
|
|
26
|
+
|
|
27
|
+
export default defineConfig({
|
|
28
|
+
testDir: "./tests",
|
|
29
|
+
fullyParallel: true,
|
|
30
|
+
forbidOnly: !!process.env.CI,
|
|
31
|
+
retries: process.env.CI ? 2 : 0,
|
|
32
|
+
workers: process.env.CI ? 1 : undefined,
|
|
33
|
+
reporter: [["html"], ["list"]],
|
|
34
|
+
use: {
|
|
35
|
+
baseURL: "http://localhost:3000",
|
|
36
|
+
trace: "on-first-retry",
|
|
37
|
+
screenshot: "only-on-failure",
|
|
38
|
+
},
|
|
39
|
+
projects: [
|
|
40
|
+
{ name: "setup", testMatch: /.*\.setup\.ts/ },
|
|
41
|
+
{
|
|
42
|
+
name: "chromium",
|
|
43
|
+
use: { ...devices["Desktop Chrome"] },
|
|
44
|
+
dependencies: ["setup"],
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
webServer: {
|
|
48
|
+
command: "npm run dev",
|
|
49
|
+
url: "http://localhost:3000",
|
|
50
|
+
reuseExistingServer: !process.env.CI,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## E2E Tests
|
|
56
|
+
|
|
57
|
+
Full user journey tests through the browser.
|
|
58
|
+
|
|
59
|
+
### Structure
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// tests/e2e/checkout.spec.ts
|
|
63
|
+
import { test, expect } from "@playwright/test";
|
|
64
|
+
|
|
65
|
+
test.describe("Checkout Flow", () => {
|
|
66
|
+
test.beforeEach(async ({ page }) => {
|
|
67
|
+
await page.goto("/products");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("complete purchase as guest", async ({ page }) => {
|
|
71
|
+
// Add to cart
|
|
72
|
+
await page.getByRole("button", { name: "Add to Cart" }).first().click();
|
|
73
|
+
await expect(page.getByTestId("cart-count")).toHaveText("1");
|
|
74
|
+
|
|
75
|
+
// Go to checkout
|
|
76
|
+
await page.getByRole("link", { name: "Cart" }).click();
|
|
77
|
+
await page.getByRole("button", { name: "Checkout" }).click();
|
|
78
|
+
|
|
79
|
+
// Fill shipping
|
|
80
|
+
await page.getByLabel("Email").fill("guest@example.com");
|
|
81
|
+
await page.getByLabel("Address").fill("123 Test St");
|
|
82
|
+
await page.getByRole("button", { name: "Continue" }).click();
|
|
83
|
+
|
|
84
|
+
// Payment
|
|
85
|
+
await page.getByLabel("Card Number").fill("4242424242424242");
|
|
86
|
+
await page.getByRole("button", { name: "Pay Now" }).click();
|
|
87
|
+
|
|
88
|
+
// Confirmation
|
|
89
|
+
await expect(page.getByRole("heading")).toHaveText("Order Confirmed");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("apply discount code", async ({ page }) => {
|
|
93
|
+
await page.getByRole("button", { name: "Add to Cart" }).first().click();
|
|
94
|
+
await page.getByRole("link", { name: "Cart" }).click();
|
|
95
|
+
|
|
96
|
+
await page.getByLabel("Discount Code").fill("SAVE10");
|
|
97
|
+
await page.getByRole("button", { name: "Apply" }).click();
|
|
98
|
+
|
|
99
|
+
await expect(page.getByText("10% discount applied")).toBeVisible();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Best Practices
|
|
105
|
+
|
|
106
|
+
- Test critical user journeys
|
|
107
|
+
- Keep tests independent
|
|
108
|
+
- Use realistic data
|
|
109
|
+
- Clean up test data in teardown
|
|
110
|
+
|
|
111
|
+
## Component Tests
|
|
112
|
+
|
|
113
|
+
Test individual components in isolation using Playwright Component Testing.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npm init playwright@latest -- --ct
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For comprehensive component testing patterns including mounting, props, events, slots, mocking, and framework-specific examples (React, Vue, Svelte), see **[component-testing.md](../testing-patterns/component-testing.md)**.
|
|
120
|
+
|
|
121
|
+
## API Tests
|
|
122
|
+
|
|
123
|
+
Test backend APIs without browser.
|
|
124
|
+
|
|
125
|
+
### API Mocking Patterns
|
|
126
|
+
|
|
127
|
+
For E2E tests that need to mock API responses:
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Mock single endpoint
|
|
131
|
+
test("displays mocked users", async ({ page }) => {
|
|
132
|
+
await page.route("**/api/users", (route) =>
|
|
133
|
+
route.fulfill({
|
|
134
|
+
status: 200,
|
|
135
|
+
json: [{ id: 1, name: "Test User" }],
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
await page.goto("/users");
|
|
140
|
+
await expect(page.getByText("Test User")).toBeVisible();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Mock with different responses
|
|
144
|
+
test("handles API errors", async ({ page }) => {
|
|
145
|
+
await page.route("**/api/users", (route) =>
|
|
146
|
+
route.fulfill({
|
|
147
|
+
status: 500,
|
|
148
|
+
json: { error: "Server error" },
|
|
149
|
+
})
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
await page.goto("/users");
|
|
153
|
+
await expect(page.getByText("Server error")).toBeVisible();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Conditional mocking
|
|
157
|
+
test("mocks based on request", async ({ page }) => {
|
|
158
|
+
await page.route("**/api/users", (route, request) => {
|
|
159
|
+
if (request.method() === "GET") {
|
|
160
|
+
route.fulfill({ json: [{ id: 1, name: "User" }] });
|
|
161
|
+
} else {
|
|
162
|
+
route.continue();
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// Mock with delay (simulate slow network)
|
|
168
|
+
test("handles slow API", async ({ page }) => {
|
|
169
|
+
await page.route("**/api/data", (route) =>
|
|
170
|
+
route.fulfill({
|
|
171
|
+
json: { data: "test" },
|
|
172
|
+
delay: 2000, // 2 second delay
|
|
173
|
+
})
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
await page.goto("/dashboard");
|
|
177
|
+
await expect(page.getByText("Loading...")).toBeVisible();
|
|
178
|
+
await expect(page.getByText("test")).toBeVisible();
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
For advanced patterns (GraphQL mocking, HAR recording, request modification, network throttling), see **[network-advanced.md](../advanced/network-advanced.md)**.
|
|
183
|
+
|
|
184
|
+
## Visual Regression Tests
|
|
185
|
+
|
|
186
|
+
Compare screenshots to detect visual changes.
|
|
187
|
+
|
|
188
|
+
### Basic Visual Test
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
// tests/visual/homepage.spec.ts
|
|
192
|
+
import { test, expect } from "@playwright/test";
|
|
193
|
+
|
|
194
|
+
test("homepage visual", async ({ page }) => {
|
|
195
|
+
await page.goto("/");
|
|
196
|
+
await expect(page).toHaveScreenshot("homepage.png");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("component visual", async ({ page }) => {
|
|
200
|
+
await page.goto("/components");
|
|
201
|
+
|
|
202
|
+
const button = page.getByRole("button", { name: "Primary" });
|
|
203
|
+
await expect(button).toHaveScreenshot("primary-button.png");
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Visual Test Options
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
test("dashboard visual", async ({ page }) => {
|
|
211
|
+
await page.goto("/dashboard");
|
|
212
|
+
|
|
213
|
+
await expect(page).toHaveScreenshot("dashboard.png", {
|
|
214
|
+
fullPage: true, // Capture entire scrollable page
|
|
215
|
+
maxDiffPixels: 100, // Allow up to 100 different pixels
|
|
216
|
+
maxDiffPixelRatio: 0.01, // Or 1% difference
|
|
217
|
+
threshold: 0.2, // Pixel comparison threshold
|
|
218
|
+
animations: "disabled", // Disable animations
|
|
219
|
+
mask: [page.getByTestId("date")], // Mask dynamic content
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Handling Dynamic Content
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
test("page with dynamic content", async ({ page }) => {
|
|
228
|
+
await page.goto("/profile");
|
|
229
|
+
|
|
230
|
+
// Mask elements that change
|
|
231
|
+
await expect(page).toHaveScreenshot("profile.png", {
|
|
232
|
+
mask: [
|
|
233
|
+
page.getByTestId("timestamp"),
|
|
234
|
+
page.getByTestId("avatar"),
|
|
235
|
+
page.getByRole("img"),
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Or hide elements via CSS
|
|
241
|
+
test("page hiding dynamic elements", async ({ page }) => {
|
|
242
|
+
await page.goto("/profile");
|
|
243
|
+
|
|
244
|
+
await page.addStyleTag({
|
|
245
|
+
content: `
|
|
246
|
+
.dynamic-content { visibility: hidden !important; }
|
|
247
|
+
[data-testid="ad-banner"] { display: none !important; }
|
|
248
|
+
`,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
await expect(page).toHaveScreenshot("profile-stable.png");
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Visual Test Configuration
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
// playwright.config.ts
|
|
259
|
+
export default defineConfig({
|
|
260
|
+
expect: {
|
|
261
|
+
toHaveScreenshot: {
|
|
262
|
+
maxDiffPixels: 50,
|
|
263
|
+
animations: "disabled",
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
projects: [
|
|
267
|
+
{
|
|
268
|
+
name: "visual-chrome",
|
|
269
|
+
use: {
|
|
270
|
+
...devices["Desktop Chrome"],
|
|
271
|
+
viewport: { width: 1280, height: 720 },
|
|
272
|
+
},
|
|
273
|
+
testMatch: /.*visual.*\.spec\.ts/,
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
});
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Update Snapshots
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# Update all snapshots
|
|
283
|
+
npx playwright test --update-snapshots
|
|
284
|
+
|
|
285
|
+
# Update specific test
|
|
286
|
+
npx playwright test homepage.spec.ts --update-snapshots
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Directory Structure
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
tests/
|
|
293
|
+
├── e2e/ # End-to-end tests
|
|
294
|
+
│ ├── auth.spec.ts
|
|
295
|
+
│ ├── checkout.spec.ts
|
|
296
|
+
│ └── dashboard.spec.ts
|
|
297
|
+
├── component/ # Component tests
|
|
298
|
+
│ ├── Button.spec.tsx
|
|
299
|
+
│ └── Modal.spec.tsx
|
|
300
|
+
├── api/ # API tests
|
|
301
|
+
│ ├── users.spec.ts
|
|
302
|
+
│ └── products.spec.ts
|
|
303
|
+
├── visual/ # Visual regression tests
|
|
304
|
+
│ └── homepage.spec.ts
|
|
305
|
+
├── fixtures/ # Custom fixtures
|
|
306
|
+
│ ├── auth.fixture.ts
|
|
307
|
+
│ └── api.fixture.ts
|
|
308
|
+
└── pages/ # Page objects
|
|
309
|
+
├── login.page.ts
|
|
310
|
+
└── dashboard.page.ts
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## Anti-Patterns to Avoid
|
|
314
|
+
|
|
315
|
+
| Anti-Pattern | Problem | Solution |
|
|
316
|
+
| ------------------------------------- | ---------------------------------- | ------------------------- |
|
|
317
|
+
| Long test files | Hard to maintain, slow to navigate | Split by feature, use POM |
|
|
318
|
+
| Tests depend on execution order | Flaky, hard to debug | Keep tests independent |
|
|
319
|
+
| Testing multiple features in one test | Hard to debug failures | One feature per test |
|
|
320
|
+
|
|
321
|
+
## Related References
|
|
322
|
+
|
|
323
|
+
- **Component Testing**: See [component-testing.md](../testing-patterns/component-testing.md) for comprehensive CT patterns
|
|
324
|
+
- **Projects**: See [projects-dependencies.md](projects-dependencies.md) for project-based filtering
|
|
325
|
+
- **Page Objects**: See [page-object-model.md](page-object-model.md) for organizing page interactions
|
|
326
|
+
- **Test Data**: See [fixtures-hooks.md](fixtures-hooks.md) for managing test data
|
|
327
|
+
|
|
328
|
+
## Tagging & Filtering
|
|
329
|
+
|
|
330
|
+
### Using Tags
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
test("user login @smoke @auth", async ({ page }) => {
|
|
334
|
+
// ...
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("checkout flow @e2e @critical", async ({ page }) => {
|
|
338
|
+
// ...
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
test.describe("API tests @api", () => {
|
|
342
|
+
test("create user", async ({ request }) => {
|
|
343
|
+
// ...
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Running Tagged Tests
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# Run smoke tests
|
|
352
|
+
npx playwright test --grep @smoke
|
|
353
|
+
|
|
354
|
+
# Run all except slow tests
|
|
355
|
+
npx playwright test --grep-invert @slow
|
|
356
|
+
|
|
357
|
+
# Combine tags
|
|
358
|
+
npx playwright test --grep "@smoke|@critical"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
For project-based filtering and advanced project configuration, see **[projects-dependencies.md](projects-dependencies.md)**.
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
# Test Tags
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
|
|
5
|
+
1. [Basic Tagging](#basic-tagging)
|
|
6
|
+
2. [Tagging Describe Blocks](#tagging-describe-blocks)
|
|
7
|
+
3. [Running Tagged Tests](#running-tagged-tests)
|
|
8
|
+
4. [Filtering by Tags](#filtering-by-tags)
|
|
9
|
+
5. [Configuration-Based Filtering](#configuration-based-filtering)
|
|
10
|
+
6. [Tag Organization Patterns](#tag-organization-patterns)
|
|
11
|
+
7. [Common Tag Categories](#common-tag-categories)
|
|
12
|
+
8. [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
|
|
13
|
+
9. [Related References](#related-references)
|
|
14
|
+
|
|
15
|
+
## Basic Tagging
|
|
16
|
+
|
|
17
|
+
### Tag via Details Object
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { test, expect } from "@playwright/test";
|
|
21
|
+
|
|
22
|
+
test(
|
|
23
|
+
"test login page",
|
|
24
|
+
{
|
|
25
|
+
tag: "@fast",
|
|
26
|
+
},
|
|
27
|
+
async ({ page }) => {
|
|
28
|
+
await page.goto("/login");
|
|
29
|
+
await expect(page.getByRole("heading")).toBeVisible();
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
test(
|
|
34
|
+
"test dashboard",
|
|
35
|
+
{
|
|
36
|
+
tag: "@slow",
|
|
37
|
+
},
|
|
38
|
+
async ({ page }) => {
|
|
39
|
+
await page.goto("/dashboard");
|
|
40
|
+
await expect(page.getByTestId("charts")).toBeVisible();
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Tag via Title (not recommended)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
test("test full report @slow", async ({ page }) => {
|
|
49
|
+
await page.goto("/reports/full");
|
|
50
|
+
await expect(page.getByText("Report loaded")).toBeVisible();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("quick validation @fast @smoke", async ({ page }) => {
|
|
54
|
+
await page.goto("/");
|
|
55
|
+
await expect(page.locator("body")).toBeVisible();
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Tagging Describe Blocks
|
|
60
|
+
|
|
61
|
+
### Tag All Tests in Group
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
test.describe(
|
|
65
|
+
"report tests",
|
|
66
|
+
{
|
|
67
|
+
tag: "@report",
|
|
68
|
+
},
|
|
69
|
+
() => {
|
|
70
|
+
test("test report header", async ({ page }) => {
|
|
71
|
+
// Inherits @report tag
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("test report footer", async ({ page }) => {
|
|
75
|
+
// Inherits @report tag
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Combine Group and Test Tags
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
test.describe(
|
|
85
|
+
"admin features",
|
|
86
|
+
{
|
|
87
|
+
tag: "@admin",
|
|
88
|
+
},
|
|
89
|
+
() => {
|
|
90
|
+
test("admin dashboard", async ({ page }) => {
|
|
91
|
+
// Has @admin tag
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test(
|
|
95
|
+
"admin settings",
|
|
96
|
+
{
|
|
97
|
+
tag: ["@slow", "@critical"],
|
|
98
|
+
},
|
|
99
|
+
async ({ page }) => {
|
|
100
|
+
// Has @admin, @slow, @critical tags
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Running Tagged Tests
|
|
108
|
+
|
|
109
|
+
### Run Tests with Specific Tag
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Run all @fast tests
|
|
113
|
+
npx playwright test --grep @fast
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Exclude Tests with Tag
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
# Run all tests except @slow
|
|
120
|
+
npx playwright test --grep-invert @slow
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Filtering by Tags
|
|
124
|
+
|
|
125
|
+
### Logical OR (Either Tag)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Run tests with @fast OR @smoke
|
|
129
|
+
npx playwright test --grep "@fast|@smoke"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Logical AND (Both Tags)
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Run tests with both @fast AND @critical
|
|
136
|
+
npx playwright test --grep "(?=.*@fast)(?=.*@critical)"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Complex Patterns
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Run @e2e tests that are also @critical
|
|
143
|
+
npx playwright test --grep "(?=.*@e2e)(?=.*@critical)"
|
|
144
|
+
|
|
145
|
+
# Run @api tests excluding @slow
|
|
146
|
+
npx playwright test --grep "@api" --grep-invert "@slow"
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Configuration-Based Filtering
|
|
150
|
+
|
|
151
|
+
### Filter in playwright.config.ts
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
import { defineConfig } from "@playwright/test";
|
|
155
|
+
|
|
156
|
+
export default defineConfig({
|
|
157
|
+
grep: /@smoke/,
|
|
158
|
+
grepInvert: /@flaky/,
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Project-Specific Tags
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { defineConfig } from "@playwright/test";
|
|
166
|
+
|
|
167
|
+
export default defineConfig({
|
|
168
|
+
projects: [
|
|
169
|
+
{
|
|
170
|
+
name: "smoke",
|
|
171
|
+
grep: /@smoke/,
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "regression",
|
|
175
|
+
grepInvert: /@smoke/,
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "critical-only",
|
|
179
|
+
grep: /@critical/,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Environment-Based Filtering
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
import { defineConfig } from "@playwright/test";
|
|
189
|
+
|
|
190
|
+
const isCI = !!process.env.CI;
|
|
191
|
+
|
|
192
|
+
export default defineConfig({
|
|
193
|
+
grep: isCI ? /@smoke|@critical/ : undefined,
|
|
194
|
+
grepInvert: isCI ? /@flaky/ : undefined,
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Tag Organization Patterns
|
|
199
|
+
|
|
200
|
+
### By Test Type
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Smoke tests - quick validation
|
|
204
|
+
test("homepage loads", { tag: "@smoke" }, async ({ page }) => {});
|
|
205
|
+
test("login works", { tag: "@smoke" }, async ({ page }) => {});
|
|
206
|
+
|
|
207
|
+
// Regression tests - comprehensive
|
|
208
|
+
test("full checkout flow", { tag: "@regression" }, async ({ page }) => {});
|
|
209
|
+
test("all payment methods", { tag: "@regression" }, async ({ page }) => {});
|
|
210
|
+
|
|
211
|
+
// E2E tests - user journeys
|
|
212
|
+
test("complete user journey", { tag: "@e2e" }, async ({ page }) => {});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### By Priority
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
test(
|
|
219
|
+
"payment processing",
|
|
220
|
+
{
|
|
221
|
+
tag: ["@critical", "@p0"],
|
|
222
|
+
},
|
|
223
|
+
async ({ page }) => {}
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
test(
|
|
227
|
+
"user preferences",
|
|
228
|
+
{
|
|
229
|
+
tag: ["@p1"],
|
|
230
|
+
},
|
|
231
|
+
async ({ page }) => {}
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
test(
|
|
235
|
+
"theme customization",
|
|
236
|
+
{
|
|
237
|
+
tag: ["@p2"],
|
|
238
|
+
},
|
|
239
|
+
async ({ page }) => {}
|
|
240
|
+
);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### By Feature Area
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
test.describe(
|
|
247
|
+
"authentication",
|
|
248
|
+
{
|
|
249
|
+
tag: "@auth",
|
|
250
|
+
},
|
|
251
|
+
() => {
|
|
252
|
+
test("login @smoke", async ({ page }) => {});
|
|
253
|
+
test("logout", async ({ page }) => {});
|
|
254
|
+
test("password reset @slow", async ({ page }) => {});
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
test.describe(
|
|
259
|
+
"payments",
|
|
260
|
+
{
|
|
261
|
+
tag: "@payments",
|
|
262
|
+
},
|
|
263
|
+
() => {
|
|
264
|
+
test("credit card @critical", async ({ page }) => {});
|
|
265
|
+
test("paypal @critical", async ({ page }) => {});
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Common Tag Categories
|
|
271
|
+
|
|
272
|
+
| Category | Tags | Purpose |
|
|
273
|
+
| --------------- | --------------------------------------------- | ----------------------------- |
|
|
274
|
+
| **Speed** | `@fast`, `@slow` | Execution time classification |
|
|
275
|
+
| **Priority** | `@critical`, `@p0`, `@p1`, `@p2` | Business importance |
|
|
276
|
+
| **Type** | `@smoke`, `@regression`, `@e2e` | Test suite categorization |
|
|
277
|
+
| **Feature** | `@auth`, `@payments`, `@settings` | Feature area grouping |
|
|
278
|
+
| **Pipeline** | `@pr`, `@nightly`, `@release` | CI/CD execution timing |
|
|
279
|
+
| **Status** | `@flaky`, `@wip`, `@quarantine` | Test health tracking |
|
|
280
|
+
| **Environment** | `@local`, `@staging`, `@prod` | Target environment |
|
|
281
|
+
| **Team** | `@team-frontend`, `@team-backend`, `@team-qa` | Team assignment |
|
|
282
|
+
|
|
283
|
+
## Anti-Patterns to Avoid
|
|
284
|
+
|
|
285
|
+
| Anti-Pattern | Problem | Solution |
|
|
286
|
+
| ------------------------ | ------------------------ | ---------------------------------------------- |
|
|
287
|
+
| Too many tags per test | Hard to maintain | Limit to 2-3 relevant tags |
|
|
288
|
+
| Inconsistent naming | Confusing filtering | Establish naming conventions |
|
|
289
|
+
| Missing `@` prefix | Tags won't match filters | Always prefix with `@` |
|
|
290
|
+
| Overlapping tag meanings | Ambiguous categorization | Define clear tag semantics |
|
|
291
|
+
| Not using tags | Can't selectively run | Tag by type, priority, or feature |
|
|
292
|
+
| Tags in test title | Hard to parse/filter | Use the details object for tags, not the title |
|
|
293
|
+
|
|
294
|
+
## Related References
|
|
295
|
+
|
|
296
|
+
- **Test Organization**: See [test-suite-structure.md](test-suite-structure.md) for structuring tests
|
|
297
|
+
- **Annotations**: See [annotations.md](annotations.md) for skip, fixme, fail, slow
|
|
298
|
+
- **CI/CD Integration**: See [ci-cd.md](../infrastructure-ci-cd/ci-cd.md) for pipeline setup
|