@sungen/driver-ui 3.3.0-alpha.1 → 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.
@@ -7,25 +7,36 @@
7
7
  *
8
8
  * runId SUNGEN_RUN_ID when set (one id across CI shards), else a fresh UUID
9
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
10
13
  * attempts per test attempt: testId, retry, status, window, and the sha256 of its trace.zip
11
14
  * report where the JSON reporter wrote its report — traces are mapped THROUGH that report
12
15
  * (merge-reports renames trace files; their content, and so the sha256, stays)
13
16
  *
14
17
  * The outputDir is wiped at the start of every Playwright run, so a record and its traces always
15
- * come from the same run. Enable it for free / impl:code tests together with `trace: 'on'`:
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):
16
20
  *
17
- * reporter: [['json', { outputFile: 'test-results/results.json' }],
21
+ * outputDir: 'test-results-free',
22
+ * reporter: [['json', { outputFile: 'test-results-free/results.json' }],
18
23
  * ['@sungen/driver-ui/dist/trace-identity/trace-run-record-reporter.js']],
19
24
  * (the compiled file — Playwright does not transpile TypeScript inside node_modules; `prepack` builds it)
20
25
  * use: { trace: 'on' },
21
26
  */
22
27
  import type { FullConfig, Reporter, Suite, TestCase, TestResult } from '@playwright/test/reporter';
28
+ /**
29
+ * sha256 of every contract file under `<root>/qa` — each `*.feature` and `contracts.lock.yaml` — keyed
30
+ * by its posix path from `root`, sorted. Dot-directories, node_modules and symlinks are not followed.
31
+ */
32
+ export declare function contractContent(root: string): Record<string, string>;
23
33
  declare class TraceRunRecordReporter implements Reporter {
24
34
  private config?;
25
35
  private root;
26
36
  private runId;
27
37
  private startedAt;
28
38
  private specs;
39
+ private contract;
29
40
  private results;
30
41
  printsToStdio(): boolean;
31
42
  onBegin(config: FullConfig, suite: Suite): void;
@@ -1 +1 @@
1
- {"version":3,"file":"trace-run-record-reporter.d.ts","sourceRoot":"","sources":["../../src/trace-identity/trace-run-record-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAenG,cAAM,sBAAuB,YAAW,QAAQ;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAa;IAC5B,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,OAAO,CAAqD;IAEpE,aAAa,IAAI,OAAO;IAExB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAS/C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAI7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B5B,8FAA8F;IAC9F,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,GAAG;CAIZ;AAED,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"trace-run-record-reporter.d.ts","sourceRoot":"","sources":["../../src/trace-identity/trace-run-record-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAgBnG;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcpE;AAED,cAAM,sBAAuB,YAAW,QAAQ;IAC9C,OAAO,CAAC,MAAM,CAAC,CAAa;IAC5B,OAAO,CAAC,IAAI,CAAiB;IAC7B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,OAAO,CAAqD;IAEpE,aAAa,IAAI,OAAO;IAExB,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAU/C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IAI7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B5B,8FAA8F;IAC9F,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,GAAG;CAIZ;AAED,eAAe,sBAAsB,CAAC"}
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.contractContent = contractContent;
36
37
  const node_crypto_1 = require("node:crypto");
37
38
  const fs = __importStar(require("node:fs"));
38
39
  const path = __importStar(require("node:path"));
@@ -45,12 +46,43 @@ const sha256File = (file) => {
45
46
  }
46
47
  };
47
48
  const posix = (p) => p.split(path.sep).join('/');
49
+ const isContractFile = (name) => name.endsWith('.feature') || name === 'contracts.lock.yaml';
50
+ /**
51
+ * sha256 of every contract file under `<root>/qa` — each `*.feature` and `contracts.lock.yaml` — keyed
52
+ * by its posix path from `root`, sorted. Dot-directories, node_modules and symlinks are not followed.
53
+ */
54
+ function contractContent(root) {
55
+ const found = [];
56
+ const walk = (dir) => {
57
+ let entries;
58
+ try {
59
+ entries = fs.readdirSync(dir, { withFileTypes: true });
60
+ }
61
+ catch {
62
+ return;
63
+ }
64
+ for (const e of entries) {
65
+ const full = path.join(dir, e.name);
66
+ if (e.isDirectory()) {
67
+ if (!e.name.startsWith('.') && e.name !== 'node_modules')
68
+ walk(full);
69
+ continue;
70
+ }
71
+ const sha = e.isFile() && isContractFile(e.name) ? sha256File(full) : null;
72
+ if (sha)
73
+ found.push([posix(path.relative(root, full)), sha]);
74
+ }
75
+ };
76
+ walk(path.join(root, 'qa'));
77
+ return Object.fromEntries(found.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)));
78
+ }
48
79
  class TraceRunRecordReporter {
49
80
  constructor() {
50
81
  this.root = process.cwd();
51
82
  this.runId = process.env.SUNGEN_RUN_ID || (0, node_crypto_1.randomUUID)();
52
83
  this.startedAt = new Date().toISOString();
53
84
  this.specs = {};
85
+ this.contract = {};
54
86
  this.results = [];
55
87
  }
56
88
  printsToStdio() { return false; }
@@ -58,6 +90,7 @@ class TraceRunRecordReporter {
58
90
  this.config = config;
59
91
  if (config.configFile)
60
92
  this.root = path.dirname(config.configFile);
93
+ this.contract = contractContent(this.root);
61
94
  for (const test of suite.allTests()) {
62
95
  const rel = this.rel(test.location.file);
63
96
  if (this.specs[rel] === undefined)
@@ -80,9 +113,9 @@ class TraceRunRecordReporter {
80
113
  });
81
114
  const shard = this.config.shard;
82
115
  const record = {
83
- schema: 1, tool: 'sungen-trace-run-record', runId: this.runId, startedAt: this.startedAt,
116
+ schema: 2, tool: 'sungen-trace-run-record', runId: this.runId, startedAt: this.startedAt,
84
117
  playwrightVersion: this.config.version, shard: shard ? `${shard.current}/${shard.total}` : null,
85
- report: this.jsonReportPath(), specs: this.specs, attempts,
118
+ report: this.jsonReportPath(), specs: this.specs, contract: this.contract, attempts,
86
119
  };
87
120
  const outDir = this.config.projects[0]?.outputDir ?? path.join(this.root, 'test-results');
88
121
  const name = shard ? `sungen-run-record.shard-${shard.current}-of-${shard.total}.json` : 'sungen-run-record.json';
@@ -1 +1 @@
1
- {"version":3,"file":"trace-run-record-reporter.js","sourceRoot":"","sources":["../../src/trace-identity/trace-run-record-reporter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"trace-run-record-reporter.js","sourceRoot":"","sources":["../../src/trace-identity/trace-run-record-reporter.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sungen/driver-ui",
3
- "version": "3.3.0-alpha.1",
3
+ "version": "3.3.0-alpha.10",
4
4
  "description": "Sungen UI capability (Playwright) — step patterns, viewpoint gate, and phase hooks. Plugs into @sun-asterisk/sungen via the capability SPI.",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -14,13 +14,15 @@
14
14
  "author": "eqe team (engineer & quality) — Sun Asterisk",
15
15
  "license": "MIT",
16
16
  "dependencies": {
17
- "@sun-asterisk/sungen": "3.3.0-alpha.1"
17
+ "@sun-asterisk/sungen": "3.3.0-alpha.10"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@playwright/test": "^1.57.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@playwright/test": "1.63.0"
23
+ "@playwright/test": "1.63.0",
24
+ "@types/node": "^20",
25
+ "typescript": "^5"
24
26
  },
25
27
  "files": [
26
28
  "dist",
@@ -7,14 +7,19 @@
7
7
  *
8
8
  * runId SUNGEN_RUN_ID when set (one id across CI shards), else a fresh UUID
9
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
10
13
  * attempts per test attempt: testId, retry, status, window, and the sha256 of its trace.zip
11
14
  * report where the JSON reporter wrote its report — traces are mapped THROUGH that report
12
15
  * (merge-reports renames trace files; their content, and so the sha256, stays)
13
16
  *
14
17
  * The outputDir is wiped at the start of every Playwright run, so a record and its traces always
15
- * come from the same run. Enable it for free / impl:code tests together with `trace: 'on'`:
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):
16
20
  *
17
- * reporter: [['json', { outputFile: 'test-results/results.json' }],
21
+ * outputDir: 'test-results-free',
22
+ * reporter: [['json', { outputFile: 'test-results-free/results.json' }],
18
23
  * ['@sungen/driver-ui/dist/trace-identity/trace-run-record-reporter.js']],
19
24
  * (the compiled file — Playwright does not transpile TypeScript inside node_modules; `prepack` builds it)
20
25
  * use: { trace: 'on' },
@@ -33,6 +38,27 @@ const sha256File = (file: string): string | null => {
33
38
  try { return createHash('sha256').update(fs.readFileSync(file)).digest('hex'); } catch { return null; }
34
39
  };
35
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
+ }
36
62
 
37
63
  class TraceRunRecordReporter implements Reporter {
38
64
  private config?: FullConfig;
@@ -40,6 +66,7 @@ class TraceRunRecordReporter implements Reporter {
40
66
  private runId = process.env.SUNGEN_RUN_ID || randomUUID();
41
67
  private startedAt = new Date().toISOString();
42
68
  private specs: Record<string, string> = {};
69
+ private contract: Record<string, string> = {};
43
70
  private results: Array<{ test: TestCase; result: TestResult }> = [];
44
71
 
45
72
  printsToStdio(): boolean { return false; }
@@ -47,6 +74,7 @@ class TraceRunRecordReporter implements Reporter {
47
74
  onBegin(config: FullConfig, suite: Suite): void {
48
75
  this.config = config;
49
76
  if (config.configFile) this.root = path.dirname(config.configFile);
77
+ this.contract = contractContent(this.root);
50
78
  for (const test of suite.allTests()) {
51
79
  const rel = this.rel(test.location.file);
52
80
  if (this.specs[rel] === undefined) this.specs[rel] = sha256File(test.location.file) ?? '';
@@ -69,9 +97,9 @@ class TraceRunRecordReporter implements Reporter {
69
97
  });
70
98
  const shard = this.config.shard;
71
99
  const record = {
72
- schema: 1, tool: 'sungen-trace-run-record', runId: this.runId, startedAt: this.startedAt,
100
+ schema: 2, tool: 'sungen-trace-run-record', runId: this.runId, startedAt: this.startedAt,
73
101
  playwrightVersion: this.config.version, shard: shard ? `${shard.current}/${shard.total}` : null,
74
- report: this.jsonReportPath(), specs: this.specs, attempts,
102
+ report: this.jsonReportPath(), specs: this.specs, contract: this.contract, attempts,
75
103
  };
76
104
  const outDir = this.config.projects[0]?.outputDir ?? path.join(this.root, 'test-results');
77
105
  const name = shard ? `sungen-run-record.shard-${shard.current}-of-${shard.total}.json` : 'sungen-run-record.json';