@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.
Files changed (97) hide show
  1. package/.agents/skills/e2e-testing-expert/SKILL.md +28 -0
  2. package/.agents/skills/frontend-design/LICENSE.txt +177 -0
  3. package/.agents/skills/frontend-design/SKILL.md +42 -0
  4. package/.agents/skills/nodejs-backend-patterns/SKILL.md +639 -0
  5. package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +430 -0
  6. package/.agents/skills/playwright-best-practices/LICENSE.md +7 -0
  7. package/.agents/skills/playwright-best-practices/README.md +147 -0
  8. package/.agents/skills/playwright-best-practices/SKILL.md +303 -0
  9. package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +360 -0
  10. package/.agents/skills/playwright-best-practices/advanced/authentication.md +871 -0
  11. package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +364 -0
  12. package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +409 -0
  13. package/.agents/skills/playwright-best-practices/advanced/multi-context.md +288 -0
  14. package/.agents/skills/playwright-best-practices/advanced/multi-user.md +393 -0
  15. package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +452 -0
  16. package/.agents/skills/playwright-best-practices/advanced/third-party.md +464 -0
  17. package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +363 -0
  18. package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +369 -0
  19. package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +383 -0
  20. package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +391 -0
  21. package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +403 -0
  22. package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +504 -0
  23. package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +403 -0
  24. package/.agents/skills/playwright-best-practices/core/annotations.md +424 -0
  25. package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +361 -0
  26. package/.agents/skills/playwright-best-practices/core/configuration.md +452 -0
  27. package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +417 -0
  28. package/.agents/skills/playwright-best-practices/core/global-setup.md +434 -0
  29. package/.agents/skills/playwright-best-practices/core/locators.md +242 -0
  30. package/.agents/skills/playwright-best-practices/core/page-object-model.md +315 -0
  31. package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +453 -0
  32. package/.agents/skills/playwright-best-practices/core/test-data.md +492 -0
  33. package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +361 -0
  34. package/.agents/skills/playwright-best-practices/core/test-tags.md +298 -0
  35. package/.agents/skills/playwright-best-practices/debugging/console-errors.md +420 -0
  36. package/.agents/skills/playwright-best-practices/debugging/debugging.md +504 -0
  37. package/.agents/skills/playwright-best-practices/debugging/error-testing.md +360 -0
  38. package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +496 -0
  39. package/.agents/skills/playwright-best-practices/frameworks/angular.md +530 -0
  40. package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +469 -0
  41. package/.agents/skills/playwright-best-practices/frameworks/react.md +531 -0
  42. package/.agents/skills/playwright-best-practices/frameworks/vue.md +574 -0
  43. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +468 -0
  44. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +283 -0
  45. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +546 -0
  46. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +397 -0
  47. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +521 -0
  48. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +371 -0
  49. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +453 -0
  50. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +424 -0
  51. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +497 -0
  52. package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +359 -0
  53. package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +719 -0
  54. package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +506 -0
  55. package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +493 -0
  56. package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +500 -0
  57. package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +576 -0
  58. package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +509 -0
  59. package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +377 -0
  60. package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +562 -0
  61. package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +561 -0
  62. package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +331 -0
  63. package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +508 -0
  64. package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +476 -0
  65. package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +430 -0
  66. package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +634 -0
  67. package/.env.example +21 -0
  68. package/README.md +30 -0
  69. package/bin/arcality.mjs +86 -0
  70. package/package.json +66 -0
  71. package/playwright.config.ts +12 -0
  72. package/scripts/cleanup-qmsdev.mjs +63 -0
  73. package/scripts/discover-view.mjs +52 -0
  74. package/scripts/extract-view.mjs +64 -0
  75. package/scripts/gen-and-run.mjs +838 -0
  76. package/scripts/init.mjs +290 -0
  77. package/scripts/migrate-to-central-out.mjs +157 -0
  78. package/scripts/postinstall.mjs +63 -0
  79. package/scripts/rebrand-report.mjs +241 -0
  80. package/scripts/setup.mjs +166 -0
  81. package/src/KnowledgeService.ts +239 -0
  82. package/src/arcalityClient.mjs +266 -0
  83. package/src/configLoader.mjs +179 -0
  84. package/src/configManager.mjs +172 -0
  85. package/src/consoleBanner.ts +32 -0
  86. package/src/envSetup.ts +205 -0
  87. package/src/index.ts +25 -0
  88. package/src/projectInspector.ts +42 -0
  89. package/src/services/collectiveMemoryService.ts +178 -0
  90. package/src/testRunner.ts +201 -0
  91. package/tests/_helpers/ArcalityReporter.ts +490 -0
  92. package/tests/_helpers/agentic-runner.spec.ts +741 -0
  93. package/tests/_helpers/ai-agent-helper.ts +1573 -0
  94. package/tests/_helpers/discover-view.spec.ts +238 -0
  95. package/tests/_helpers/extract-view.spec.ts +118 -0
  96. package/tests/_helpers/qa-tools.ts +333 -0
  97. package/tests/_helpers/smart-action.spec.ts +1458 -0
@@ -0,0 +1,492 @@
1
+ # Test Data Factories & Generators
2
+
3
+ This file covers **reusable test data builders** (factories, Faker, data generators). For related topics:
4
+
5
+ - **Per-test database fixtures** (isolation, transaction rollback): See [fixtures-hooks.md](fixtures-hooks.md#database-fixtures)
6
+ - **One-time database setup** (migrations, snapshots): See [global-setup.md](global-setup.md#database-patterns)
7
+
8
+ ## Table of Contents
9
+
10
+ 1. [Factory Pattern](#factory-pattern)
11
+ 2. [Faker Integration](#faker-integration)
12
+ 3. [Data-Driven Testing](#data-driven-testing)
13
+ 4. [Test Data Fixtures](#test-data-fixtures)
14
+ 5. [Database Seeding](#database-seeding)
15
+
16
+ ## Factory Pattern
17
+
18
+ ### Basic Factory
19
+
20
+ ```typescript
21
+ // factories/user.factory.ts
22
+ interface User {
23
+ id: string;
24
+ email: string;
25
+ name: string;
26
+ role: "admin" | "user" | "guest";
27
+ createdAt: Date;
28
+ }
29
+
30
+ let userIdCounter = 0;
31
+
32
+ export function createUser(overrides: Partial<User> = {}): User {
33
+ userIdCounter++;
34
+ return {
35
+ id: `user-${userIdCounter}`,
36
+ email: `user${userIdCounter}@test.com`,
37
+ name: `Test User ${userIdCounter}`,
38
+ role: "user",
39
+ createdAt: new Date(),
40
+ ...overrides,
41
+ };
42
+ }
43
+
44
+ // Usage
45
+ const user = createUser();
46
+ const admin = createUser({ role: "admin", name: "Admin User" });
47
+ ```
48
+
49
+ ### Factory with Traits
50
+
51
+ ```typescript
52
+ // factories/product.factory.ts
53
+ interface Product {
54
+ id: string;
55
+ name: string;
56
+ price: number;
57
+ stock: number;
58
+ category: string;
59
+ featured: boolean;
60
+ }
61
+
62
+ type ProductTrait = "outOfStock" | "featured" | "expensive" | "sale";
63
+
64
+ const traits: Record<ProductTrait, Partial<Product>> = {
65
+ outOfStock: { stock: 0 },
66
+ featured: { featured: true },
67
+ expensive: { price: 999.99 },
68
+ sale: { price: 9.99 },
69
+ };
70
+
71
+ let productIdCounter = 0;
72
+
73
+ export function createProduct(
74
+ overrides: Partial<Product> = {},
75
+ ...traitNames: ProductTrait[]
76
+ ): Product {
77
+ productIdCounter++;
78
+
79
+ const appliedTraits = traitNames.reduce(
80
+ (acc, trait) => ({ ...acc, ...traits[trait] }),
81
+ {},
82
+ );
83
+
84
+ return {
85
+ id: `prod-${productIdCounter}`,
86
+ name: `Product ${productIdCounter}`,
87
+ price: 29.99,
88
+ stock: 100,
89
+ category: "General",
90
+ featured: false,
91
+ ...appliedTraits,
92
+ ...overrides,
93
+ };
94
+ }
95
+
96
+ // Usage
97
+ const product = createProduct();
98
+ const featuredProduct = createProduct({}, "featured");
99
+ const saleItem = createProduct({ name: "Sale Item" }, "sale", "featured");
100
+ const soldOut = createProduct({}, "outOfStock");
101
+ ```
102
+
103
+ ### Factory with Relationships
104
+
105
+ ```typescript
106
+ // factories/order.factory.ts
107
+ import { createUser, User } from "./user.factory";
108
+ import { createProduct, Product } from "./product.factory";
109
+
110
+ interface OrderItem {
111
+ product: Product;
112
+ quantity: number;
113
+ }
114
+
115
+ interface Order {
116
+ id: string;
117
+ user: User;
118
+ items: OrderItem[];
119
+ total: number;
120
+ status: "pending" | "paid" | "shipped" | "delivered";
121
+ }
122
+
123
+ let orderIdCounter = 0;
124
+
125
+ export function createOrder(overrides: Partial<Order> = {}): Order {
126
+ orderIdCounter++;
127
+
128
+ const user = overrides.user ?? createUser();
129
+ const items = overrides.items ?? [{ product: createProduct(), quantity: 1 }];
130
+ const total = items.reduce(
131
+ (sum, item) => sum + item.product.price * item.quantity,
132
+ 0,
133
+ );
134
+
135
+ return {
136
+ id: `order-${orderIdCounter}`,
137
+ user,
138
+ items,
139
+ total,
140
+ status: "pending",
141
+ ...overrides,
142
+ };
143
+ }
144
+
145
+ // Usage
146
+ const order = createOrder();
147
+ const bigOrder = createOrder({
148
+ items: [
149
+ { product: createProduct({ price: 100 }), quantity: 5 },
150
+ { product: createProduct({ price: 50 }), quantity: 2 },
151
+ ],
152
+ });
153
+ ```
154
+
155
+ ## Faker Integration
156
+
157
+ ### Setup Faker
158
+
159
+ ```bash
160
+ npm install -D @faker-js/faker
161
+ ```
162
+
163
+ ```typescript
164
+ // factories/faker-user.factory.ts
165
+ import { faker } from "@faker-js/faker";
166
+
167
+ interface User {
168
+ id: string;
169
+ email: string;
170
+ name: string;
171
+ avatar: string;
172
+ address: {
173
+ street: string;
174
+ city: string;
175
+ country: string;
176
+ zipCode: string;
177
+ };
178
+ }
179
+
180
+ export function createFakeUser(overrides: Partial<User> = {}): User {
181
+ return {
182
+ id: faker.string.uuid(),
183
+ email: faker.internet.email(),
184
+ name: faker.person.fullName(),
185
+ avatar: faker.image.avatar(),
186
+ address: {
187
+ street: faker.location.streetAddress(),
188
+ city: faker.location.city(),
189
+ country: faker.location.country(),
190
+ zipCode: faker.location.zipCode(),
191
+ },
192
+ ...overrides,
193
+ };
194
+ }
195
+ ```
196
+
197
+ ### Seeded Faker for Reproducibility
198
+
199
+ ```typescript
200
+ import { faker } from "@faker-js/faker";
201
+
202
+ // Set seed for reproducible data
203
+ faker.seed(12345);
204
+
205
+ export function createDeterministicUser(): User {
206
+ return {
207
+ id: faker.string.uuid(),
208
+ email: faker.internet.email(),
209
+ name: faker.person.fullName(),
210
+ // Same seed = same data every time
211
+ };
212
+ }
213
+
214
+ // Or seed per test
215
+ test("user profile", async ({ page }) => {
216
+ faker.seed(42); // Reset seed for this test
217
+ const user = createFakeUser();
218
+ // user will always have the same data
219
+ });
220
+ ```
221
+
222
+ ### Faker Fixture
223
+
224
+ ```typescript
225
+ // fixtures/faker.fixture.ts
226
+ import { test as base } from "@playwright/test";
227
+ import { faker } from "@faker-js/faker";
228
+
229
+ type FakerFixtures = {
230
+ fake: typeof faker;
231
+ };
232
+
233
+ export const test = base.extend<FakerFixtures>({
234
+ fake: async ({}, use, testInfo) => {
235
+ // Seed based on test name for reproducibility
236
+ faker.seed(testInfo.title.length);
237
+ await use(faker);
238
+ },
239
+ });
240
+
241
+ // Usage
242
+ test("create user with fake data", async ({ page, fake }) => {
243
+ await page.goto("/signup");
244
+
245
+ await page.getByLabel("Name").fill(fake.person.fullName());
246
+ await page.getByLabel("Email").fill(fake.internet.email());
247
+ await page.getByLabel("Password").fill(fake.internet.password());
248
+
249
+ await page.getByRole("button", { name: "Sign Up" }).click();
250
+ });
251
+ ```
252
+
253
+ ## Data-Driven Testing
254
+
255
+ ### test.each with Arrays
256
+
257
+ ```typescript
258
+ const loginScenarios = [
259
+ { email: "user@example.com", password: "pass123", expected: "Dashboard" },
260
+ { email: "admin@example.com", password: "admin123", expected: "Admin Panel" },
261
+ {
262
+ email: "invalid@example.com",
263
+ password: "wrong",
264
+ expected: "Invalid credentials",
265
+ },
266
+ ];
267
+
268
+ for (const { email, password, expected } of loginScenarios) {
269
+ test(`login with ${email}`, async ({ page }) => {
270
+ await page.goto("/login");
271
+ await page.getByLabel("Email").fill(email);
272
+ await page.getByLabel("Password").fill(password);
273
+ await page.getByRole("button", { name: "Sign In" }).click();
274
+
275
+ await expect(page.getByText(expected)).toBeVisible();
276
+ });
277
+ }
278
+ ```
279
+
280
+ ### Parameterized Tests
281
+
282
+ ```typescript
283
+ // data/checkout-scenarios.ts
284
+ export const checkoutScenarios = [
285
+ {
286
+ name: "standard shipping",
287
+ shipping: "standard",
288
+ expectedDays: "5-7 business days",
289
+ expectedCost: "$5.99",
290
+ },
291
+ {
292
+ name: "express shipping",
293
+ shipping: "express",
294
+ expectedDays: "2-3 business days",
295
+ expectedCost: "$14.99",
296
+ },
297
+ {
298
+ name: "overnight shipping",
299
+ shipping: "overnight",
300
+ expectedDays: "Next business day",
301
+ expectedCost: "$29.99",
302
+ },
303
+ ];
304
+ ```
305
+
306
+ ```typescript
307
+ import { checkoutScenarios } from "./data/checkout-scenarios";
308
+
309
+ test.describe("shipping options", () => {
310
+ for (const scenario of checkoutScenarios) {
311
+ test(`checkout with ${scenario.name}`, async ({ page }) => {
312
+ await page.goto("/checkout");
313
+
314
+ await page.getByLabel(scenario.shipping, { exact: false }).check();
315
+
316
+ await expect(page.getByText(scenario.expectedDays)).toBeVisible();
317
+ await expect(page.getByText(scenario.expectedCost)).toBeVisible();
318
+ });
319
+ }
320
+ });
321
+ ```
322
+
323
+ ### CSV/JSON Data Source
324
+
325
+ ```typescript
326
+ import fs from "fs";
327
+
328
+ interface TestCase {
329
+ input: string;
330
+ expected: string;
331
+ }
332
+
333
+ // Load test data from JSON
334
+ const testCases: TestCase[] = JSON.parse(
335
+ fs.readFileSync("./data/search-tests.json", "utf-8"),
336
+ );
337
+
338
+ test.describe("search functionality", () => {
339
+ for (const { input, expected } of testCases) {
340
+ test(`search for "${input}"`, async ({ page }) => {
341
+ await page.goto("/search");
342
+ await page.getByLabel("Search").fill(input);
343
+ await page.getByLabel("Search").press("Enter");
344
+
345
+ await expect(page.getByText(expected)).toBeVisible();
346
+ });
347
+ }
348
+ });
349
+ ```
350
+
351
+ ## Test Data Fixtures
352
+
353
+ ### Fixture with Factory
354
+
355
+ ```typescript
356
+ // fixtures/data.fixture.ts
357
+ import { test as base } from "@playwright/test";
358
+ import { createUser, User } from "../factories/user.factory";
359
+ import { createProduct, Product } from "../factories/product.factory";
360
+
361
+ type DataFixtures = {
362
+ testUser: User;
363
+ testProducts: Product[];
364
+ };
365
+
366
+ export const test = base.extend<DataFixtures>({
367
+ testUser: async ({}, use) => {
368
+ const user = createUser({ name: "E2E Test User" });
369
+ await use(user);
370
+ },
371
+
372
+ testProducts: async ({}, use) => {
373
+ const products = [
374
+ createProduct({ name: "Test Product 1" }),
375
+ createProduct({ name: "Test Product 2" }),
376
+ createProduct({ name: "Test Product 3" }),
377
+ ];
378
+ await use(products);
379
+ },
380
+ });
381
+
382
+ // Usage
383
+ test("add product to cart", async ({ page, testUser, testProducts }) => {
384
+ // Mock API with test data
385
+ await page.route("**/api/user", (route) => route.fulfill({ json: testUser }));
386
+ await page.route("**/api/products", (route) =>
387
+ route.fulfill({ json: testProducts }),
388
+ );
389
+
390
+ await page.goto("/products");
391
+ await expect(page.getByText(testProducts[0].name)).toBeVisible();
392
+ });
393
+ ```
394
+
395
+ ## Database Seeding
396
+
397
+ ### API-Based Seeding
398
+
399
+ ```typescript
400
+ // fixtures/seed.fixture.ts
401
+ import { test as base, APIRequestContext } from "@playwright/test";
402
+ import { createUser } from "../factories/user.factory";
403
+
404
+ type SeedFixtures = {
405
+ seedUser: (overrides?: Partial<User>) => Promise<User>;
406
+ cleanupUsers: string[];
407
+ };
408
+
409
+ export const test = base.extend<SeedFixtures>({
410
+ cleanupUsers: [],
411
+
412
+ seedUser: async ({ request, cleanupUsers }, use) => {
413
+ await use(async (overrides = {}) => {
414
+ const userData = createUser(overrides);
415
+
416
+ const response = await request.post("/api/test/users", {
417
+ data: userData,
418
+ });
419
+ const user = await response.json();
420
+
421
+ cleanupUsers.push(user.id);
422
+ return user;
423
+ });
424
+ },
425
+
426
+ // Cleanup after test
427
+ cleanupUsers: async ({ request }, use) => {
428
+ const userIds: string[] = [];
429
+ await use(userIds);
430
+
431
+ // Delete all created users
432
+ for (const id of userIds) {
433
+ await request.delete(`/api/test/users/${id}`);
434
+ }
435
+ },
436
+ });
437
+
438
+ // Usage
439
+ test("user profile page", async ({ page, seedUser }) => {
440
+ const user = await seedUser({ name: "John Doe" });
441
+
442
+ await page.goto(`/users/${user.id}`);
443
+ await expect(page.getByText("John Doe")).toBeVisible();
444
+ });
445
+ ```
446
+
447
+ ### Transaction Rollback Seeding
448
+
449
+ ```typescript
450
+ // fixtures/db.fixture.ts
451
+ export const test = base.extend<{}, { db: DbTransaction }>({
452
+ db: [
453
+ async ({}, use) => {
454
+ const client = await pool.connect();
455
+ await client.query("BEGIN");
456
+
457
+ await use({
458
+ query: (sql: string, params?: any[]) => client.query(sql, params),
459
+ seed: async (table: string, data: object) => {
460
+ const keys = Object.keys(data);
461
+ const values = Object.values(data);
462
+ const placeholders = keys.map((_, i) => `$${i + 1}`);
463
+
464
+ const result = await client.query(
465
+ `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders.join(", ")}) RETURNING *`,
466
+ values,
467
+ );
468
+ return result.rows[0];
469
+ },
470
+ });
471
+
472
+ await client.query("ROLLBACK");
473
+ client.release();
474
+ },
475
+ { scope: "test" },
476
+ ],
477
+ });
478
+ ```
479
+
480
+ ## Anti-Patterns to Avoid
481
+
482
+ | Anti-Pattern | Problem | Solution |
483
+ | ------------------------------- | ------------------------------- | -------------------------- |
484
+ | Hardcoded test data | Brittle, repetitive | Use factories |
485
+ | Random data without seed | Non-reproducible failures | Seed faker per test |
486
+ | Shared mutable test data | Tests interfere with each other | Create fresh data per test |
487
+ | Manual data creation everywhere | Duplication, maintenance burden | Centralize in factories |
488
+
489
+ ## Related References
490
+
491
+ - **Fixtures**: See [fixtures-hooks.md](fixtures-hooks.md) for fixture patterns
492
+ - **API Testing**: See [test-suite-structure.md](test-suite-structure.md) for API mocking