@arcadialdev/arcality 2.4.28 → 2.4.30

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 (83) hide show
  1. package/README.md +2 -2
  2. package/package.json +3 -7
  3. package/scripts/gen-and-run.mjs +5 -18
  4. package/src/KnowledgeService.ts +256 -0
  5. package/src/arcalityClient.mjs +2 -1
  6. package/src/consoleBanner.ts +32 -0
  7. package/src/envSetup.ts +205 -0
  8. package/src/index.ts +25 -0
  9. package/src/projectInspector.ts +42 -0
  10. package/src/services/collectiveMemoryService.ts +178 -0
  11. package/src/services/securityScanner.ts +128 -0
  12. package/src/testRunner.ts +201 -0
  13. package/tests/_helpers/agentic-runner.bundle.spec.js +2912 -83
  14. package/.agents/skills/e2e-testing-expert/SKILL.md +0 -28
  15. package/.agents/skills/frontend-design/LICENSE.txt +0 -177
  16. package/.agents/skills/frontend-design/SKILL.md +0 -42
  17. package/.agents/skills/nodejs-backend-patterns/SKILL.md +0 -639
  18. package/.agents/skills/nodejs-backend-patterns/references/advanced-patterns.md +0 -430
  19. package/.agents/skills/playwright-best-practices/LICENSE.md +0 -7
  20. package/.agents/skills/playwright-best-practices/README.md +0 -147
  21. package/.agents/skills/playwright-best-practices/SKILL.md +0 -303
  22. package/.agents/skills/playwright-best-practices/advanced/authentication-flows.md +0 -360
  23. package/.agents/skills/playwright-best-practices/advanced/authentication.md +0 -871
  24. package/.agents/skills/playwright-best-practices/advanced/clock-mocking.md +0 -364
  25. package/.agents/skills/playwright-best-practices/advanced/mobile-testing.md +0 -409
  26. package/.agents/skills/playwright-best-practices/advanced/multi-context.md +0 -288
  27. package/.agents/skills/playwright-best-practices/advanced/multi-user.md +0 -393
  28. package/.agents/skills/playwright-best-practices/advanced/network-advanced.md +0 -452
  29. package/.agents/skills/playwright-best-practices/advanced/third-party.md +0 -464
  30. package/.agents/skills/playwright-best-practices/architecture/pom-vs-fixtures.md +0 -363
  31. package/.agents/skills/playwright-best-practices/architecture/test-architecture.md +0 -369
  32. package/.agents/skills/playwright-best-practices/architecture/when-to-mock.md +0 -383
  33. package/.agents/skills/playwright-best-practices/browser-apis/browser-apis.md +0 -391
  34. package/.agents/skills/playwright-best-practices/browser-apis/iframes.md +0 -403
  35. package/.agents/skills/playwright-best-practices/browser-apis/service-workers.md +0 -504
  36. package/.agents/skills/playwright-best-practices/browser-apis/websockets.md +0 -403
  37. package/.agents/skills/playwright-best-practices/core/annotations.md +0 -424
  38. package/.agents/skills/playwright-best-practices/core/assertions-waiting.md +0 -361
  39. package/.agents/skills/playwright-best-practices/core/configuration.md +0 -452
  40. package/.agents/skills/playwright-best-practices/core/fixtures-hooks.md +0 -417
  41. package/.agents/skills/playwright-best-practices/core/global-setup.md +0 -434
  42. package/.agents/skills/playwright-best-practices/core/locators.md +0 -242
  43. package/.agents/skills/playwright-best-practices/core/page-object-model.md +0 -315
  44. package/.agents/skills/playwright-best-practices/core/projects-dependencies.md +0 -453
  45. package/.agents/skills/playwright-best-practices/core/test-data.md +0 -492
  46. package/.agents/skills/playwright-best-practices/core/test-suite-structure.md +0 -361
  47. package/.agents/skills/playwright-best-practices/core/test-tags.md +0 -298
  48. package/.agents/skills/playwright-best-practices/debugging/console-errors.md +0 -420
  49. package/.agents/skills/playwright-best-practices/debugging/debugging.md +0 -504
  50. package/.agents/skills/playwright-best-practices/debugging/error-testing.md +0 -360
  51. package/.agents/skills/playwright-best-practices/debugging/flaky-tests.md +0 -496
  52. package/.agents/skills/playwright-best-practices/frameworks/angular.md +0 -530
  53. package/.agents/skills/playwright-best-practices/frameworks/nextjs.md +0 -469
  54. package/.agents/skills/playwright-best-practices/frameworks/react.md +0 -531
  55. package/.agents/skills/playwright-best-practices/frameworks/vue.md +0 -574
  56. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/ci-cd.md +0 -468
  57. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/docker.md +0 -283
  58. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/github-actions.md +0 -546
  59. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/gitlab.md +0 -397
  60. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/other-providers.md +0 -521
  61. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/parallel-sharding.md +0 -371
  62. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/performance.md +0 -453
  63. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/reporting.md +0 -424
  64. package/.agents/skills/playwright-best-practices/infrastructure-ci-cd/test-coverage.md +0 -497
  65. package/.agents/skills/playwright-best-practices/testing-patterns/accessibility.md +0 -359
  66. package/.agents/skills/playwright-best-practices/testing-patterns/api-testing.md +0 -719
  67. package/.agents/skills/playwright-best-practices/testing-patterns/browser-extensions.md +0 -506
  68. package/.agents/skills/playwright-best-practices/testing-patterns/canvas-webgl.md +0 -493
  69. package/.agents/skills/playwright-best-practices/testing-patterns/component-testing.md +0 -500
  70. package/.agents/skills/playwright-best-practices/testing-patterns/drag-drop.md +0 -576
  71. package/.agents/skills/playwright-best-practices/testing-patterns/electron.md +0 -509
  72. package/.agents/skills/playwright-best-practices/testing-patterns/file-operations.md +0 -377
  73. package/.agents/skills/playwright-best-practices/testing-patterns/file-upload-download.md +0 -562
  74. package/.agents/skills/playwright-best-practices/testing-patterns/forms-validation.md +0 -561
  75. package/.agents/skills/playwright-best-practices/testing-patterns/graphql-testing.md +0 -331
  76. package/.agents/skills/playwright-best-practices/testing-patterns/i18n.md +0 -508
  77. package/.agents/skills/playwright-best-practices/testing-patterns/performance-testing.md +0 -476
  78. package/.agents/skills/playwright-best-practices/testing-patterns/security-testing.md +0 -430
  79. package/.agents/skills/playwright-best-practices/testing-patterns/visual-regression.md +0 -634
  80. package/.agents/skills/security-qa/SKILL.md +0 -254
  81. package/public/ArcalityImagen.png +0 -0
  82. package/public/logo-arcadial-blanco.png +0 -0
  83. package/public/logo.png +0 -0
@@ -1,497 +0,0 @@
1
- # Test Coverage
2
-
3
- ## Table of Contents
4
-
5
- 1. [Coverage Setup](#coverage-setup)
6
- 2. [Collecting Coverage](#collecting-coverage)
7
- 3. [Coverage Reports](#coverage-reports)
8
- 4. [Coverage Thresholds](#coverage-thresholds)
9
- 5. [Advanced Patterns](#advanced-patterns)
10
- 6. [CI Integration](#ci-integration)
11
-
12
- ## Coverage Setup
13
-
14
- ### Install Dependencies
15
-
16
- ```bash
17
- # For V8 coverage (built into Playwright)
18
- # No additional dependencies needed
19
-
20
- # For Istanbul-based coverage (more features)
21
- npm install -D nyc @istanbuljs/nyc-config-typescript
22
- ```
23
-
24
- ### Basic Configuration
25
-
26
- ```typescript
27
- // playwright.config.ts
28
- import { defineConfig } from "@playwright/test";
29
-
30
- export default defineConfig({
31
- use: {
32
- // Enable coverage collection
33
- contextOptions: {
34
- // V8 coverage is automatic with the API below
35
- },
36
- },
37
- });
38
- ```
39
-
40
- ### V8 Coverage Fixture
41
-
42
- ```typescript
43
- // fixtures/coverage.ts
44
- import { test as base, expect } from "@playwright/test";
45
- import fs from "fs";
46
- import path from "path";
47
- import { randomUUID } from "crypto";
48
-
49
- export const test = base.extend<{}, { collectCoverage: void }>({
50
- collectCoverage: [
51
- async ({ browser }, use) => {
52
- // Start coverage for all pages
53
- const context = await browser.newContext();
54
- const page = await context.newPage();
55
-
56
- await page.coverage.startJSCoverage();
57
- await page.coverage.startCSSCoverage();
58
-
59
- await use();
60
-
61
- // Collect coverage
62
- const [jsCoverage, cssCoverage] = await Promise.all([
63
- page.coverage.stopJSCoverage(),
64
- page.coverage.stopCSSCoverage(),
65
- ]);
66
-
67
- // Save coverage data
68
- const coverageDir = "./coverage";
69
- if (!fs.existsSync(coverageDir)) {
70
- fs.mkdirSync(coverageDir, { recursive: true });
71
- }
72
-
73
- fs.writeFileSync(
74
- path.join(coverageDir, `coverage-${randomUUID()}.json`),
75
- JSON.stringify([...jsCoverage, ...cssCoverage])
76
- );
77
-
78
- await context.close();
79
- },
80
- { scope: "worker", auto: true },
81
- ],
82
- });
83
- ```
84
-
85
- ## Collecting Coverage
86
-
87
- ### Per-Test Coverage
88
-
89
- ```typescript
90
- test("collect coverage for single test", async ({ page }) => {
91
- // Start coverage collection
92
- await page.coverage.startJSCoverage({
93
- resetOnNavigation: false,
94
- });
95
-
96
- // Run test
97
- await page.goto("/app");
98
- await page.getByRole("button", { name: "Submit" }).click();
99
- await expect(page.getByText("Success")).toBeVisible();
100
-
101
- // Stop and get coverage
102
- const coverage = await page.coverage.stopJSCoverage();
103
-
104
- // Filter to only your source files
105
- const appCoverage = coverage.filter((entry) => entry.url.includes("/src/"));
106
-
107
- console.log(`Covered ${appCoverage.length} source files`);
108
- });
109
- ```
110
-
111
- ### Coverage for Specific Files
112
-
113
- ```typescript
114
- test("track specific module coverage", async ({ page }) => {
115
- await page.coverage.startJSCoverage();
116
-
117
- await page.goto("/checkout");
118
- await page.getByRole("button", { name: "Pay" }).click();
119
-
120
- const coverage = await page.coverage.stopJSCoverage();
121
-
122
- // Find coverage for checkout module
123
- const checkoutCoverage = coverage.find((c) => c.url.includes("checkout.js"));
124
-
125
- if (checkoutCoverage) {
126
- const totalBytes = checkoutCoverage.text?.length || 0;
127
- const coveredBytes = checkoutCoverage.ranges.reduce(
128
- (sum, range) => sum + (range.end - range.start),
129
- 0
130
- );
131
- const percentage = (coveredBytes / totalBytes) * 100;
132
-
133
- console.log(`Checkout module: ${percentage.toFixed(1)}% covered`);
134
- expect(percentage).toBeGreaterThan(80);
135
- }
136
- });
137
- ```
138
-
139
- ### CSS Coverage
140
-
141
- ```typescript
142
- test("collect CSS coverage", async ({ page }) => {
143
- await page.coverage.startCSSCoverage();
144
-
145
- await page.goto("/app");
146
-
147
- // Interact to trigger different CSS states
148
- await page.getByRole("button").hover();
149
- await page.getByRole("dialog").waitFor();
150
-
151
- const cssCoverage = await page.coverage.stopCSSCoverage();
152
-
153
- // Find unused CSS
154
- for (const entry of cssCoverage) {
155
- const totalBytes = entry.text?.length || 0;
156
- const usedBytes = entry.ranges.reduce(
157
- (sum, range) => sum + (range.end - range.start),
158
- 0
159
- );
160
- const unusedPercentage = ((totalBytes - usedBytes) / totalBytes) * 100;
161
-
162
- if (unusedPercentage > 50) {
163
- console.warn(`${entry.url}: ${unusedPercentage.toFixed(1)}% unused CSS`);
164
- }
165
- }
166
- });
167
- ```
168
-
169
- ## Coverage Reports
170
-
171
- ### Converting to Istanbul Format
172
-
173
- ```typescript
174
- // scripts/convert-coverage.ts
175
- import { execSync } from "child_process";
176
- import fs from "fs";
177
- import path from "path";
178
- import v8ToIstanbul from "v8-to-istanbul";
179
-
180
- async function convertCoverage() {
181
- const coverageDir = "./coverage";
182
- const files = fs.readdirSync(coverageDir).filter((f) => f.endsWith(".json"));
183
-
184
- const istanbulCoverage: any = {};
185
-
186
- for (const file of files) {
187
- const coverageData = JSON.parse(
188
- fs.readFileSync(path.join(coverageDir, file), "utf-8")
189
- );
190
-
191
- for (const entry of coverageData) {
192
- if (!entry.url.startsWith("file://")) continue;
193
-
194
- const filePath = entry.url.replace("file://", "");
195
- const converter = v8ToIstanbul(filePath);
196
-
197
- await converter.load();
198
- converter.applyCoverage(entry.functions || []);
199
-
200
- const istanbul = converter.toIstanbul();
201
- Object.assign(istanbulCoverage, istanbul);
202
- }
203
- }
204
-
205
- fs.writeFileSync(
206
- path.join(coverageDir, "coverage-final.json"),
207
- JSON.stringify(istanbulCoverage)
208
- );
209
- }
210
-
211
- convertCoverage();
212
- ```
213
-
214
- ### Generating HTML Report
215
-
216
- ```bash
217
- # Using nyc to generate report
218
- npx nyc report --reporter=html --reporter=text --temp-dir=./coverage
219
- ```
220
-
221
- ```typescript
222
- // package.json scripts
223
- {
224
- "scripts": {
225
- "test": "playwright test",
226
- "test:coverage": "playwright test && npm run coverage:report",
227
- "coverage:report": "npx nyc report --reporter=html --reporter=lcov --temp-dir=./coverage"
228
- }
229
- }
230
- ```
231
-
232
- ### Custom Coverage Reporter
233
-
234
- ```typescript
235
- // reporters/coverage-reporter.ts
236
- import type { Reporter, FullResult } from "@playwright/test/reporter";
237
- import fs from "fs";
238
- import path from "path";
239
-
240
- class CoverageReporter implements Reporter {
241
- private coverageData: any[] = [];
242
-
243
- onEnd(result: FullResult) {
244
- // Aggregate all coverage files
245
- const coverageDir = "./coverage";
246
- const files = fs
247
- .readdirSync(coverageDir)
248
- .filter((f) => f.endsWith(".json"));
249
-
250
- for (const file of files) {
251
- const data = JSON.parse(
252
- fs.readFileSync(path.join(coverageDir, file), "utf-8")
253
- );
254
- this.coverageData.push(...data);
255
- }
256
-
257
- // Generate summary
258
- const summary = this.generateSummary();
259
- console.log("\n📊 Coverage Summary:");
260
- console.log(` Files: ${summary.totalFiles}`);
261
- console.log(` Lines: ${summary.lineCoverage.toFixed(1)}%`);
262
- console.log(` Bytes: ${summary.byteCoverage.toFixed(1)}%`);
263
-
264
- if (summary.lineCoverage < 80) {
265
- console.warn("⚠️ Coverage below 80% threshold!");
266
- }
267
- }
268
-
269
- private generateSummary() {
270
- let totalBytes = 0;
271
- let coveredBytes = 0;
272
- const files = new Set<string>();
273
-
274
- for (const entry of this.coverageData) {
275
- if (entry.url.includes("/src/")) {
276
- files.add(entry.url);
277
- totalBytes += entry.text?.length || 0;
278
- coveredBytes += entry.ranges.reduce(
279
- (sum: number, r: any) => sum + (r.end - r.start),
280
- 0
281
- );
282
- }
283
- }
284
-
285
- return {
286
- totalFiles: files.size,
287
- byteCoverage: (coveredBytes / totalBytes) * 100,
288
- lineCoverage: (coveredBytes / totalBytes) * 100, // Simplified
289
- };
290
- }
291
- }
292
-
293
- export default CoverageReporter;
294
- ```
295
-
296
- ## Coverage Thresholds
297
-
298
- ### Enforcing Minimum Coverage
299
-
300
- ```typescript
301
- // tests/coverage.spec.ts
302
- import { test, expect } from "@playwright/test";
303
- import fs from "fs";
304
- import path from "path";
305
-
306
- test.afterAll(async () => {
307
- const coverageDir = "./coverage";
308
- const files = fs.readdirSync(coverageDir).filter((f) => f.endsWith(".json"));
309
-
310
- let totalBytes = 0;
311
- let coveredBytes = 0;
312
-
313
- for (const file of files) {
314
- const coverage = JSON.parse(
315
- fs.readFileSync(path.join(coverageDir, file), "utf-8")
316
- );
317
-
318
- for (const entry of coverage) {
319
- if (!entry.url.includes("/src/")) continue;
320
- totalBytes += entry.text?.length || 0;
321
- coveredBytes += entry.ranges.reduce(
322
- (sum: number, r: any) => sum + (r.end - r.start),
323
- 0
324
- );
325
- }
326
- }
327
-
328
- const coveragePercent = (coveredBytes / totalBytes) * 100;
329
-
330
- // Enforce threshold
331
- expect(coveragePercent).toBeGreaterThan(80);
332
- });
333
- ```
334
-
335
- ### Per-Directory Thresholds
336
-
337
- ```typescript
338
- // coverage-check.ts
339
- interface CoverageThreshold {
340
- pattern: RegExp;
341
- minCoverage: number;
342
- }
343
-
344
- const thresholds: CoverageThreshold[] = [
345
- { pattern: /\/src\/core\//, minCoverage: 90 },
346
- { pattern: /\/src\/utils\//, minCoverage: 85 },
347
- { pattern: /\/src\/components\//, minCoverage: 70 },
348
- { pattern: /\/src\/pages\//, minCoverage: 60 },
349
- ];
350
-
351
- function checkThresholds(coverage: any[]): string[] {
352
- const violations: string[] = [];
353
-
354
- for (const threshold of thresholds) {
355
- const matchingFiles = coverage.filter((c) => threshold.pattern.test(c.url));
356
-
357
- let total = 0;
358
- let covered = 0;
359
-
360
- for (const file of matchingFiles) {
361
- total += file.text?.length || 0;
362
- covered += file.ranges.reduce(
363
- (sum: number, r: any) => sum + (r.end - r.start),
364
- 0
365
- );
366
- }
367
-
368
- const percent = total > 0 ? (covered / total) * 100 : 0;
369
-
370
- if (percent < threshold.minCoverage) {
371
- violations.push(
372
- `${threshold.pattern}: ${percent.toFixed(1)}% < ${
373
- threshold.minCoverage
374
- }%`
375
- );
376
- }
377
- }
378
-
379
- return violations;
380
- }
381
- ```
382
-
383
- ## Advanced Patterns
384
-
385
- ### Merging Coverage Across Shards
386
-
387
- ```typescript
388
- // scripts/merge-coverage.ts
389
- import fs from "fs";
390
- import { glob } from "glob";
391
-
392
- async function mergeCoverage() {
393
- const files = await glob("shard-*/coverage/*.json");
394
- const merged = new Map<string, any>();
395
-
396
- for (const file of files) {
397
- const data = JSON.parse(fs.readFileSync(file, "utf-8"));
398
- for (const entry of data) {
399
- if (merged.has(entry.url)) {
400
- const existing = merged.get(entry.url);
401
- existing.ranges.push(...entry.ranges);
402
- } else {
403
- merged.set(entry.url, { ...entry });
404
- }
405
- }
406
- }
407
-
408
- fs.writeFileSync(
409
- "./coverage/merged.json",
410
- JSON.stringify([...merged.values()])
411
- );
412
- }
413
-
414
- mergeCoverage();
415
- ```
416
-
417
- ### Incremental Coverage
418
-
419
- ```typescript
420
- // Check coverage only for changed files in CI
421
- import { execSync } from "child_process";
422
- import fs from "fs";
423
-
424
- const changedFiles = execSync("git diff --name-only HEAD~1")
425
- .toString()
426
- .split("\n")
427
- .filter((f) => f.endsWith(".ts"));
428
-
429
- const coverage = JSON.parse(fs.readFileSync("./coverage/merged.json", "utf-8"));
430
-
431
- for (const file of changedFiles) {
432
- const entry = coverage.find((c: any) => c.url.includes(file));
433
- if (entry) {
434
- const percent =
435
- (entry.ranges.reduce((s: number, r: any) => s + r.end - r.start, 0) /
436
- (entry.text?.length || 1)) *
437
- 100;
438
- console.log(`${file}: ${percent.toFixed(1)}%`);
439
- }
440
- }
441
- ```
442
-
443
- ## CI Integration
444
-
445
- ### GitHub Actions
446
-
447
- ```yaml
448
- # .github/workflows/test.yml
449
- name: Tests with Coverage
450
-
451
- on: [push, pull_request]
452
-
453
- jobs:
454
- test:
455
- runs-on: ubuntu-latest
456
- steps:
457
- - uses: actions/checkout@v4
458
-
459
- - uses: actions/setup-node@v4
460
- with:
461
- node-version: 22
462
-
463
- - run: npm ci
464
- - run: npx playwright install --with-deps
465
-
466
- - name: Run tests with coverage
467
- run: npm run test:coverage
468
-
469
- - name: Upload coverage to Codecov
470
- uses: codecov/codecov-action@v3
471
- with:
472
- files: ./coverage/lcov.info
473
- fail_ci_if_error: true
474
-
475
- - name: Check coverage threshold
476
- run: |
477
- COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
478
- if (( $(echo "$COVERAGE < 80" | bc -l) )); then
479
- echo "Coverage $COVERAGE% is below 80% threshold"
480
- exit 1
481
- fi
482
- ```
483
-
484
- ## Anti-Patterns to Avoid
485
-
486
- | Anti-Pattern | Problem | Solution |
487
- | ---------------------------- | -------------------------------------- | --------------------------- |
488
- | Coverage for coverage's sake | Gaming metrics | Focus on critical paths |
489
- | 100% coverage target | Diminishing returns, tests for getters | Set realistic thresholds |
490
- | Ignoring coverage drops | Technical debt | Enforce thresholds in CI |
491
- | No source map support | Wrong line numbers | Enable source maps in build |
492
- | Coverage only in CI | Late feedback | Run locally too |
493
-
494
- ## Related References
495
-
496
- - **CI/CD**: See [ci-cd.md](ci-cd.md) for pipeline configuration
497
- - **Performance**: See [performance.md](performance.md) for optimizing coverage collection