@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,377 @@
1
+ # File Upload & Download Testing
2
+
3
+ > For advanced patterns (progress tracking, cancellation, retry logic), see [file-upload-download.md](./file-upload-download.md)
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [File Downloads](#file-downloads)
8
+ 2. [File Uploads](#file-uploads)
9
+ 3. [Drag and Drop](#drag-and-drop)
10
+ 4. [File Content Verification](#file-content-verification)
11
+
12
+ ## File Downloads
13
+
14
+ ### Basic Download
15
+
16
+ ```typescript
17
+ test("download PDF report", async ({ page }) => {
18
+ await page.goto("/reports");
19
+
20
+ // Start waiting for download before clicking
21
+ const downloadPromise = page.waitForEvent("download");
22
+ await page.getByRole("button", { name: "Download PDF" }).click();
23
+ const download = await downloadPromise;
24
+
25
+ // Verify filename
26
+ expect(download.suggestedFilename()).toBe("report.pdf");
27
+
28
+ // Save to specific path
29
+ await download.saveAs("./downloads/report.pdf");
30
+ });
31
+ ```
32
+
33
+ ### Download with Custom Path
34
+
35
+ ```typescript
36
+ test("download to temp directory", async ({ page }, testInfo) => {
37
+ await page.goto("/exports");
38
+
39
+ const downloadPromise = page.waitForEvent("download");
40
+ await page.getByRole("link", { name: "Export CSV" }).click();
41
+ const download = await downloadPromise;
42
+
43
+ // Save to test output directory
44
+ const path = testInfo.outputPath(download.suggestedFilename());
45
+ await download.saveAs(path);
46
+
47
+ // Attach to test report
48
+ await testInfo.attach("downloaded-file", { path });
49
+ });
50
+ ```
51
+
52
+ ### Verify Download Content
53
+
54
+ ```typescript
55
+ import fs from "fs";
56
+ import path from "path";
57
+
58
+ test("verify CSV content", async ({ page }, testInfo) => {
59
+ await page.goto("/data");
60
+
61
+ const downloadPromise = page.waitForEvent("download");
62
+ await page.getByRole("button", { name: "Export" }).click();
63
+ const download = await downloadPromise;
64
+
65
+ const filePath = testInfo.outputPath("export.csv");
66
+ await download.saveAs(filePath);
67
+
68
+ // Read and verify content
69
+ const content = fs.readFileSync(filePath, "utf-8");
70
+ expect(content).toContain("Name,Email,Status");
71
+ expect(content).toContain("John Doe");
72
+
73
+ // Verify row count
74
+ const rows = content.trim().split("\n");
75
+ expect(rows.length).toBeGreaterThan(1);
76
+ });
77
+ ```
78
+
79
+ ### Multiple Downloads
80
+
81
+ ```typescript
82
+ test("download multiple files", async ({ page }) => {
83
+ await page.goto("/batch-export");
84
+
85
+ await page.getByRole("checkbox", { name: "Select All" }).check();
86
+
87
+ // Collect all downloads
88
+ const downloads: Download[] = [];
89
+ page.on("download", (download) => downloads.push(download));
90
+
91
+ await page.getByRole("button", { name: "Download Selected" }).click();
92
+
93
+ // Wait for all downloads
94
+ await expect.poll(() => downloads.length, { timeout: 30000 }).toBe(5);
95
+
96
+ // Verify each download
97
+ for (const download of downloads) {
98
+ expect(download.suggestedFilename()).toMatch(/\.pdf$/);
99
+ }
100
+ });
101
+ ```
102
+
103
+ ### Download Fixture
104
+
105
+ ```typescript
106
+ // fixtures/download.fixture.ts
107
+ import { test as base, Download } from "@playwright/test";
108
+ import fs from "fs";
109
+ import path from "path";
110
+
111
+ type DownloadFixtures = {
112
+ downloadDir: string;
113
+ downloadAndVerify: (
114
+ trigger: () => Promise<void>,
115
+ expectedFilename: string,
116
+ ) => Promise<string>;
117
+ };
118
+
119
+ export const test = base.extend<DownloadFixtures>({
120
+ downloadDir: async ({}, use, testInfo) => {
121
+ const dir = testInfo.outputPath("downloads");
122
+ fs.mkdirSync(dir, { recursive: true });
123
+ await use(dir);
124
+ },
125
+
126
+ downloadAndVerify: async ({ page, downloadDir }, use) => {
127
+ await use(async (trigger, expectedFilename) => {
128
+ const downloadPromise = page.waitForEvent("download");
129
+ await trigger();
130
+ const download = await downloadPromise;
131
+
132
+ expect(download.suggestedFilename()).toBe(expectedFilename);
133
+
134
+ const filePath = path.join(downloadDir, expectedFilename);
135
+ await download.saveAs(filePath);
136
+ return filePath;
137
+ });
138
+ },
139
+ });
140
+ ```
141
+
142
+ ## File Uploads
143
+
144
+ ### Basic Upload
145
+
146
+ ```typescript
147
+ test("upload profile picture", async ({ page }) => {
148
+ await page.goto("/settings/profile");
149
+
150
+ // Upload file
151
+ await page
152
+ .getByLabel("Profile Picture")
153
+ .setInputFiles("./fixtures/avatar.png");
154
+
155
+ // Verify preview
156
+ await expect(page.getByAltText("Profile preview")).toBeVisible();
157
+
158
+ await page.getByRole("button", { name: "Save" }).click();
159
+ await expect(page.getByText("Profile updated")).toBeVisible();
160
+ });
161
+ ```
162
+
163
+ ### Multiple File Upload
164
+
165
+ ```typescript
166
+ test("upload multiple documents", async ({ page }) => {
167
+ await page.goto("/documents/upload");
168
+
169
+ await page
170
+ .getByLabel("Documents")
171
+ .setInputFiles([
172
+ "./fixtures/doc1.pdf",
173
+ "./fixtures/doc2.pdf",
174
+ "./fixtures/doc3.pdf",
175
+ ]);
176
+
177
+ // Verify all files listed
178
+ await expect(page.getByText("doc1.pdf")).toBeVisible();
179
+ await expect(page.getByText("doc2.pdf")).toBeVisible();
180
+ await expect(page.getByText("doc3.pdf")).toBeVisible();
181
+
182
+ await page.getByRole("button", { name: "Upload All" }).click();
183
+ await expect(page.getByText("3 files uploaded")).toBeVisible();
184
+ });
185
+ ```
186
+
187
+ ### Upload with File Chooser
188
+
189
+ ```typescript
190
+ test("upload via file chooser dialog", async ({ page }) => {
191
+ await page.goto("/upload");
192
+
193
+ // Handle file chooser
194
+ const fileChooserPromise = page.waitForEvent("filechooser");
195
+ await page.getByRole("button", { name: "Choose File" }).click();
196
+ const fileChooser = await fileChooserPromise;
197
+
198
+ await fileChooser.setFiles("./fixtures/document.pdf");
199
+
200
+ await expect(page.getByText("document.pdf")).toBeVisible();
201
+ });
202
+ ```
203
+
204
+ ### Clear and Re-upload
205
+
206
+ ```typescript
207
+ test("replace uploaded file", async ({ page }) => {
208
+ await page.goto("/upload");
209
+
210
+ const input = page.getByLabel("Document");
211
+
212
+ // Upload first file
213
+ await input.setInputFiles("./fixtures/old.pdf");
214
+ await expect(page.getByText("old.pdf")).toBeVisible();
215
+
216
+ // Clear selection
217
+ await input.setInputFiles([]);
218
+
219
+ // Upload new file
220
+ await input.setInputFiles("./fixtures/new.pdf");
221
+ await expect(page.getByText("new.pdf")).toBeVisible();
222
+ await expect(page.getByText("old.pdf")).toBeHidden();
223
+ });
224
+ ```
225
+
226
+ ### Upload from Buffer
227
+
228
+ ```typescript
229
+ test("upload generated file", async ({ page }) => {
230
+ await page.goto("/upload");
231
+
232
+ // Create file content dynamically
233
+ const content = "Name,Email\nJohn,john@example.com";
234
+
235
+ await page.getByLabel("CSV File").setInputFiles({
236
+ name: "users.csv",
237
+ mimeType: "text/csv",
238
+ buffer: Buffer.from(content),
239
+ });
240
+
241
+ await expect(page.getByText("users.csv")).toBeVisible();
242
+ });
243
+ ```
244
+
245
+ ## Drag and Drop
246
+
247
+ ### Drag and Drop Upload
248
+
249
+ ```typescript
250
+ test("drag and drop file upload", async ({ page }) => {
251
+ await page.goto("/upload");
252
+
253
+ const dropzone = page.getByTestId("dropzone");
254
+
255
+ // Create a DataTransfer with the file
256
+ const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
257
+
258
+ // Read file and add to DataTransfer
259
+ const buffer = fs.readFileSync("./fixtures/image.png");
260
+ await page.evaluate(
261
+ async ([dataTransfer, data]) => {
262
+ const file = new File([new Uint8Array(data)], "image.png", {
263
+ type: "image/png",
264
+ });
265
+ dataTransfer.items.add(file);
266
+ },
267
+ [dataTransfer, [...buffer]] as const,
268
+ );
269
+
270
+ // Dispatch drop event
271
+ await dropzone.dispatchEvent("drop", { dataTransfer });
272
+
273
+ await expect(page.getByText("image.png uploaded")).toBeVisible();
274
+ });
275
+ ```
276
+
277
+ ### Simpler Drag and Drop
278
+
279
+ ```typescript
280
+ test("drag and drop with setInputFiles", async ({ page }) => {
281
+ await page.goto("/upload");
282
+
283
+ // Most dropzones have a hidden file input
284
+ const input = page.locator('input[type="file"]');
285
+
286
+ // This works even if the input is hidden
287
+ await input.setInputFiles("./fixtures/document.pdf");
288
+
289
+ await expect(page.getByText("document.pdf")).toBeVisible();
290
+ });
291
+ ```
292
+
293
+ ## File Content Verification
294
+
295
+ ### Verify PDF Content
296
+
297
+ ```typescript
298
+ import pdf from "pdf-parse";
299
+
300
+ test("verify PDF content", async ({ page }, testInfo) => {
301
+ await page.goto("/invoice/123");
302
+
303
+ const downloadPromise = page.waitForEvent("download");
304
+ await page.getByRole("button", { name: "Download Invoice" }).click();
305
+ const download = await downloadPromise;
306
+
307
+ const path = testInfo.outputPath("invoice.pdf");
308
+ await download.saveAs(path);
309
+
310
+ // Parse PDF
311
+ const dataBuffer = fs.readFileSync(path);
312
+ const data = await pdf(dataBuffer);
313
+
314
+ expect(data.text).toContain("Invoice #123");
315
+ expect(data.text).toContain("Total: $99.99");
316
+ });
317
+ ```
318
+
319
+ ### Verify Excel Content
320
+
321
+ ```typescript
322
+ import XLSX from "xlsx";
323
+
324
+ test("verify Excel export", async ({ page }, testInfo) => {
325
+ await page.goto("/reports");
326
+
327
+ const downloadPromise = page.waitForEvent("download");
328
+ await page.getByRole("button", { name: "Export Excel" }).click();
329
+ const download = await downloadPromise;
330
+
331
+ const path = testInfo.outputPath("report.xlsx");
332
+ await download.saveAs(path);
333
+
334
+ // Parse Excel
335
+ const workbook = XLSX.readFile(path);
336
+ const sheet = workbook.Sheets[workbook.SheetNames[0]];
337
+ const data = XLSX.utils.sheet_to_json(sheet);
338
+
339
+ expect(data).toHaveLength(10);
340
+ expect(data[0]).toHaveProperty("Name");
341
+ expect(data[0]).toHaveProperty("Email");
342
+ });
343
+ ```
344
+
345
+ ### Verify JSON Download
346
+
347
+ ```typescript
348
+ test("verify JSON export", async ({ page }, testInfo) => {
349
+ await page.goto("/api-data");
350
+
351
+ const downloadPromise = page.waitForEvent("download");
352
+ await page.getByRole("button", { name: "Export JSON" }).click();
353
+ const download = await downloadPromise;
354
+
355
+ const path = testInfo.outputPath("data.json");
356
+ await download.saveAs(path);
357
+
358
+ const content = JSON.parse(fs.readFileSync(path, "utf-8"));
359
+
360
+ expect(content.users).toHaveLength(5);
361
+ expect(content.exportDate).toBeDefined();
362
+ });
363
+ ```
364
+
365
+ ## Anti-Patterns to Avoid
366
+
367
+ | Anti-Pattern | Problem | Solution |
368
+ | ------------------------------------- | ------------------------------- | --------------------------------------------- |
369
+ | Not waiting for download | Race condition, test fails | Always use `waitForEvent("download")` |
370
+ | Hardcoded download paths | Conflicts in parallel runs | Use `testInfo.outputPath()` |
371
+ | Skipping content verification | Download might be empty/corrupt | Verify file content when possible |
372
+ | Using `force: true` for hidden inputs | May not trigger proper events | Use `setInputFiles` on hidden inputs directly |
373
+
374
+ ## Related References
375
+
376
+ - **Fixtures**: See [fixtures-hooks.md](../core/fixtures-hooks.md) for download fixture patterns
377
+ - **Debugging**: See [debugging.md](../debugging/debugging.md) for troubleshooting download issues