@sungen/driver-ui 3.2.35 → 3.3.0-alpha.10

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 (92) hide show
  1. package/dist/app-profile-presets.d.ts +12 -0
  2. package/dist/app-profile-presets.d.ts.map +1 -0
  3. package/dist/app-profile-presets.js +85 -0
  4. package/dist/app-profile-presets.js.map +1 -0
  5. package/dist/index.d.ts +37 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +93 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/patterns/assertion-patterns.d.ts +13 -0
  10. package/dist/patterns/assertion-patterns.d.ts.map +1 -0
  11. package/dist/patterns/assertion-patterns.js +903 -0
  12. package/dist/patterns/assertion-patterns.js.map +1 -0
  13. package/dist/patterns/capture-patterns.d.ts +21 -0
  14. package/dist/patterns/capture-patterns.d.ts.map +1 -0
  15. package/dist/patterns/capture-patterns.js +174 -0
  16. package/dist/patterns/capture-patterns.js.map +1 -0
  17. package/dist/patterns/focus-patterns.d.ts +22 -0
  18. package/dist/patterns/focus-patterns.d.ts.map +1 -0
  19. package/dist/patterns/focus-patterns.js +79 -0
  20. package/dist/patterns/focus-patterns.js.map +1 -0
  21. package/dist/patterns/form-patterns.d.ts +6 -0
  22. package/dist/patterns/form-patterns.d.ts.map +1 -0
  23. package/dist/patterns/form-patterns.js +239 -0
  24. package/dist/patterns/form-patterns.js.map +1 -0
  25. package/dist/patterns/interaction-patterns.d.ts +20 -0
  26. package/dist/patterns/interaction-patterns.d.ts.map +1 -0
  27. package/dist/patterns/interaction-patterns.js +633 -0
  28. package/dist/patterns/interaction-patterns.js.map +1 -0
  29. package/dist/patterns/keyboard-patterns.d.ts +7 -0
  30. package/dist/patterns/keyboard-patterns.d.ts.map +1 -0
  31. package/dist/patterns/keyboard-patterns.js +57 -0
  32. package/dist/patterns/keyboard-patterns.js.map +1 -0
  33. package/dist/patterns/navigation-patterns.d.ts +6 -0
  34. package/dist/patterns/navigation-patterns.d.ts.map +1 -0
  35. package/dist/patterns/navigation-patterns.js +185 -0
  36. package/dist/patterns/navigation-patterns.js.map +1 -0
  37. package/dist/patterns/scope-patterns.d.ts +7 -0
  38. package/dist/patterns/scope-patterns.d.ts.map +1 -0
  39. package/dist/patterns/scope-patterns.js +36 -0
  40. package/dist/patterns/scope-patterns.js.map +1 -0
  41. package/dist/patterns/scroll-patterns.d.ts +7 -0
  42. package/dist/patterns/scroll-patterns.d.ts.map +1 -0
  43. package/dist/patterns/scroll-patterns.js +25 -0
  44. package/dist/patterns/scroll-patterns.js.map +1 -0
  45. package/dist/patterns/setup-patterns.d.ts +6 -0
  46. package/dist/patterns/setup-patterns.d.ts.map +1 -0
  47. package/dist/patterns/setup-patterns.js +75 -0
  48. package/dist/patterns/setup-patterns.js.map +1 -0
  49. package/dist/patterns/storage-patterns.d.ts +26 -0
  50. package/dist/patterns/storage-patterns.d.ts.map +1 -0
  51. package/dist/patterns/storage-patterns.js +142 -0
  52. package/dist/patterns/storage-patterns.js.map +1 -0
  53. package/dist/patterns/table-pagination-patterns.d.ts +42 -0
  54. package/dist/patterns/table-pagination-patterns.d.ts.map +1 -0
  55. package/dist/patterns/table-pagination-patterns.js +93 -0
  56. package/dist/patterns/table-pagination-patterns.js.map +1 -0
  57. package/dist/patterns/table-patterns.d.ts +19 -0
  58. package/dist/patterns/table-patterns.d.ts.map +1 -0
  59. package/dist/patterns/table-patterns.js +594 -0
  60. package/dist/patterns/table-patterns.js.map +1 -0
  61. package/dist/trace-identity/aria-snapshot-head.d.ts +23 -0
  62. package/dist/trace-identity/aria-snapshot-head.d.ts.map +1 -0
  63. package/dist/trace-identity/aria-snapshot-head.js +26 -0
  64. package/dist/trace-identity/aria-snapshot-head.js.map +1 -0
  65. package/dist/trace-identity/playwright-identity-resolver.d.ts +10 -0
  66. package/dist/trace-identity/playwright-identity-resolver.d.ts.map +1 -0
  67. package/dist/trace-identity/playwright-identity-resolver.js +130 -0
  68. package/dist/trace-identity/playwright-identity-resolver.js.map +1 -0
  69. package/dist/trace-identity/trace-run-record-reporter.d.ts +50 -0
  70. package/dist/trace-identity/trace-run-record-reporter.d.ts.map +1 -0
  71. package/dist/trace-identity/trace-run-record-reporter.js +146 -0
  72. package/dist/trace-identity/trace-run-record-reporter.js.map +1 -0
  73. package/dist/utils/column-header.d.ts +37 -0
  74. package/dist/utils/column-header.d.ts.map +1 -0
  75. package/dist/utils/column-header.js +46 -0
  76. package/dist/utils/column-header.js.map +1 -0
  77. package/dist/utils/row-index.d.ts +18 -0
  78. package/dist/utils/row-index.d.ts.map +1 -0
  79. package/dist/utils/row-index.js +39 -0
  80. package/dist/utils/row-index.js.map +1 -0
  81. package/dist/utils/url-path-regex.d.ts +45 -0
  82. package/dist/utils/url-path-regex.d.ts.map +1 -0
  83. package/dist/utils/url-path-regex.js +68 -0
  84. package/dist/utils/url-path-regex.js.map +1 -0
  85. package/package.json +9 -3
  86. package/src/index.ts +5 -0
  87. package/src/patterns/assertion-patterns.ts +10 -88
  88. package/src/patterns/form-patterns.ts +2 -47
  89. package/src/patterns/table-patterns.ts +3 -15
  90. package/src/trace-identity/aria-snapshot-head.ts +33 -0
  91. package/src/trace-identity/playwright-identity-resolver.ts +123 -0
  92. package/src/trace-identity/trace-run-record-reporter.ts +131 -0
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Playwright reporter that records sungen's own RUN RECORD for trace conformance (DOS-14.6, G5).
3
+ *
4
+ * A Playwright trace carries no run id and no hash of the code that produced it, so a good trace of
5
+ * another test — or of the same test before the code was weakened — could be swapped in. This
6
+ * reporter writes, next to the traces it vouches for (`<outputDir>/sungen-run-record[.shard-i-of-n].json`):
7
+ *
8
+ * runId SUNGEN_RUN_ID when set (one id across CI shards), else a fresh UUID
9
+ * specs sha256 of every test file at run START (the code that ran)
10
+ * contract sha256 of every `.feature` and `contracts.lock.yaml` under `qa/` at run START (schema 2,
11
+ * #967): the contract the run saw. A trace proves a contract only while those bytes still
12
+ * hold — compared by content, so a touch, a checkout or a fresh clone stales nothing
13
+ * attempts per test attempt: testId, retry, status, window, and the sha256 of its trace.zip
14
+ * report where the JSON reporter wrote its report — traces are mapped THROUGH that report
15
+ * (merge-reports renames trace files; their content, and so the sha256, stays)
16
+ *
17
+ * The outputDir is wiped at the start of every Playwright run, so a record and its traces always
18
+ * come from the same run. Enable it for free / impl:code tests together with `trace: 'on'`, in a
19
+ * config with its OWN outputDir — the compiled suite clears `test-results/` on every run (#941):
20
+ *
21
+ * outputDir: 'test-results-free',
22
+ * reporter: [['json', { outputFile: 'test-results-free/results.json' }],
23
+ * ['@sungen/driver-ui/dist/trace-identity/trace-run-record-reporter.js']],
24
+ * (the compiled file — Playwright does not transpile TypeScript inside node_modules; `prepack` builds it)
25
+ * use: { trace: 'on' },
26
+ */
27
+ import type { FullConfig, Reporter, Suite, TestCase, TestResult } from '@playwright/test/reporter';
28
+ import { createHash, randomUUID } from 'node:crypto';
29
+ import * as fs from 'node:fs';
30
+ import * as path from 'node:path';
31
+
32
+ interface AttemptRecord {
33
+ testId: string; file: string; title: string; retry: number; status: string;
34
+ startTime: string; duration: number; trace: { sha256: string } | null;
35
+ }
36
+
37
+ const sha256File = (file: string): string | null => {
38
+ try { return createHash('sha256').update(fs.readFileSync(file)).digest('hex'); } catch { return null; }
39
+ };
40
+ const posix = (p: string): string => p.split(path.sep).join('/');
41
+ const isContractFile = (name: string): boolean => name.endsWith('.feature') || name === 'contracts.lock.yaml';
42
+
43
+ /**
44
+ * sha256 of every contract file under `<root>/qa` — each `*.feature` and `contracts.lock.yaml` — keyed
45
+ * by its posix path from `root`, sorted. Dot-directories, node_modules and symlinks are not followed.
46
+ */
47
+ export function contractContent(root: string): Record<string, string> {
48
+ const found: Array<[string, string]> = [];
49
+ const walk = (dir: string): void => {
50
+ let entries: fs.Dirent[];
51
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
52
+ for (const e of entries) {
53
+ const full = path.join(dir, e.name);
54
+ if (e.isDirectory()) { if (!e.name.startsWith('.') && e.name !== 'node_modules') walk(full); continue; }
55
+ const sha = e.isFile() && isContractFile(e.name) ? sha256File(full) : null;
56
+ if (sha) found.push([posix(path.relative(root, full)), sha]);
57
+ }
58
+ };
59
+ walk(path.join(root, 'qa'));
60
+ return Object.fromEntries(found.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
61
+ }
62
+
63
+ class TraceRunRecordReporter implements Reporter {
64
+ private config?: FullConfig;
65
+ private root = process.cwd();
66
+ private runId = process.env.SUNGEN_RUN_ID || randomUUID();
67
+ private startedAt = new Date().toISOString();
68
+ private specs: Record<string, string> = {};
69
+ private contract: Record<string, string> = {};
70
+ private results: Array<{ test: TestCase; result: TestResult }> = [];
71
+
72
+ printsToStdio(): boolean { return false; }
73
+
74
+ onBegin(config: FullConfig, suite: Suite): void {
75
+ this.config = config;
76
+ if (config.configFile) this.root = path.dirname(config.configFile);
77
+ this.contract = contractContent(this.root);
78
+ for (const test of suite.allTests()) {
79
+ const rel = this.rel(test.location.file);
80
+ if (this.specs[rel] === undefined) this.specs[rel] = sha256File(test.location.file) ?? '';
81
+ }
82
+ }
83
+
84
+ onTestEnd(test: TestCase, result: TestResult): void {
85
+ this.results.push({ test, result });
86
+ }
87
+
88
+ async onEnd(): Promise<void> {
89
+ if (!this.config) return;
90
+ const attempts: AttemptRecord[] = this.results.map(({ test, result }) => {
91
+ const trace = result.attachments.find((a) => a.name === 'trace' && a.path);
92
+ const sha = trace?.path ? sha256File(trace.path) : null;
93
+ return {
94
+ testId: test.id, file: this.rel(test.location.file), title: test.title, retry: result.retry, status: result.status,
95
+ startTime: result.startTime.toISOString(), duration: result.duration, trace: sha ? { sha256: sha } : null,
96
+ };
97
+ });
98
+ const shard = this.config.shard;
99
+ const record = {
100
+ schema: 2, tool: 'sungen-trace-run-record', runId: this.runId, startedAt: this.startedAt,
101
+ playwrightVersion: this.config.version, shard: shard ? `${shard.current}/${shard.total}` : null,
102
+ report: this.jsonReportPath(), specs: this.specs, contract: this.contract, attempts,
103
+ };
104
+ const outDir = this.config.projects[0]?.outputDir ?? path.join(this.root, 'test-results');
105
+ const name = shard ? `sungen-run-record.shard-${shard.current}-of-${shard.total}.json` : 'sungen-run-record.json';
106
+ try {
107
+ fs.mkdirSync(outDir, { recursive: true });
108
+ fs.writeFileSync(path.join(outDir, name), JSON.stringify(record, null, 2));
109
+ } catch (e) {
110
+ // A missing record makes every free / impl:code test `unproven` — say so instead of hiding it.
111
+ console.error(`[sungen] could not write the trace run record: ${e instanceof Error ? e.message : String(e)}`);
112
+ }
113
+ }
114
+
115
+ /** The JSON reporter's output file, as the reporter itself resolves it (option, then env). */
116
+ private jsonReportPath(): string | null {
117
+ const json = this.config?.reporter.find(([name]) => name === 'json');
118
+ const opt = json && typeof (json[1] as { outputFile?: unknown })?.outputFile === 'string' ? (json[1] as { outputFile: string }).outputFile : undefined;
119
+ const fromEnv = process.env.PLAYWRIGHT_JSON_OUTPUT_FILE
120
+ ?? (process.env.PLAYWRIGHT_JSON_OUTPUT_NAME ? path.join(process.env.PLAYWRIGHT_JSON_OUTPUT_DIR ?? '', process.env.PLAYWRIGHT_JSON_OUTPUT_NAME) : undefined);
121
+ const chosen = opt ? path.resolve(this.root, opt) : fromEnv ? path.resolve(process.cwd(), fromEnv) : undefined;
122
+ return chosen ? this.rel(chosen) : null;
123
+ }
124
+
125
+ private rel(file: string): string {
126
+ const r = path.relative(this.root, file);
127
+ return posix(r.startsWith('..') || path.isAbsolute(r) ? path.basename(file) : r);
128
+ }
129
+ }
130
+
131
+ export default TraceRunRecordReporter;