@gate-forge/pack-playwright 0.7.0 → 0.8.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 (200) hide show
  1. package/README.md +31 -0
  2. package/dist/constants.d.ts +13 -140
  3. package/dist/constants.d.ts.map +1 -1
  4. package/dist/constants.js +13 -148
  5. package/dist/constants.js.map +1 -1
  6. package/dist/cypress/plugin.d.ts +53 -0
  7. package/dist/cypress/plugin.d.ts.map +1 -0
  8. package/dist/cypress/plugin.js +369 -0
  9. package/dist/cypress/plugin.js.map +1 -0
  10. package/dist/cypress/spec-scan.d.ts +39 -0
  11. package/dist/cypress/spec-scan.d.ts.map +1 -0
  12. package/dist/cypress/spec-scan.js +301 -0
  13. package/dist/cypress/spec-scan.js.map +1 -0
  14. package/dist/diagnosis.d.ts +39 -0
  15. package/dist/diagnosis.d.ts.map +1 -0
  16. package/dist/diagnosis.js +63 -0
  17. package/dist/diagnosis.js.map +1 -0
  18. package/dist/discovery/adapter-projection.d.ts +13 -0
  19. package/dist/discovery/adapter-projection.d.ts.map +1 -0
  20. package/dist/discovery/adapter-projection.js +84 -0
  21. package/dist/discovery/adapter-projection.js.map +1 -0
  22. package/dist/discovery/config-locations.d.ts +5 -0
  23. package/dist/discovery/config-locations.d.ts.map +1 -0
  24. package/dist/discovery/config-locations.js +19 -0
  25. package/dist/discovery/config-locations.js.map +1 -0
  26. package/dist/discovery/cypress-runner-adapter.d.ts +112 -0
  27. package/dist/discovery/cypress-runner-adapter.d.ts.map +1 -0
  28. package/dist/discovery/cypress-runner-adapter.js +501 -0
  29. package/dist/discovery/cypress-runner-adapter.js.map +1 -0
  30. package/dist/discovery/discover.d.ts +53 -1
  31. package/dist/discovery/discover.d.ts.map +1 -1
  32. package/dist/discovery/discover.js +100 -3
  33. package/dist/discovery/discover.js.map +1 -1
  34. package/dist/discovery/git-ignore.d.ts +13 -0
  35. package/dist/discovery/git-ignore.d.ts.map +1 -0
  36. package/dist/discovery/git-ignore.js +62 -0
  37. package/dist/discovery/git-ignore.js.map +1 -0
  38. package/dist/discovery/index.d.ts +9 -0
  39. package/dist/discovery/index.d.ts.map +1 -1
  40. package/dist/discovery/index.js +9 -0
  41. package/dist/discovery/index.js.map +1 -1
  42. package/dist/discovery/playwright-runner-adapter.d.ts +108 -0
  43. package/dist/discovery/playwright-runner-adapter.d.ts.map +1 -0
  44. package/dist/discovery/playwright-runner-adapter.js +185 -0
  45. package/dist/discovery/playwright-runner-adapter.js.map +1 -0
  46. package/dist/discovery/prepare-barrier.d.ts +522 -0
  47. package/dist/discovery/prepare-barrier.d.ts.map +1 -0
  48. package/dist/discovery/prepare-barrier.js +739 -0
  49. package/dist/discovery/prepare-barrier.js.map +1 -0
  50. package/dist/discovery/pytest-adapter.d.ts.map +1 -1
  51. package/dist/discovery/pytest-adapter.js +6 -2
  52. package/dist/discovery/pytest-adapter.js.map +1 -1
  53. package/dist/discovery/pytest-runner-adapter.d.ts +124 -0
  54. package/dist/discovery/pytest-runner-adapter.d.ts.map +1 -0
  55. package/dist/discovery/pytest-runner-adapter.js +454 -0
  56. package/dist/discovery/pytest-runner-adapter.js.map +1 -0
  57. package/dist/discovery/reconcile.d.ts +80 -11
  58. package/dist/discovery/reconcile.d.ts.map +1 -1
  59. package/dist/discovery/reconcile.js +395 -78
  60. package/dist/discovery/reconcile.js.map +1 -1
  61. package/dist/discovery/runner-env.d.ts +88 -2
  62. package/dist/discovery/runner-env.d.ts.map +1 -1
  63. package/dist/discovery/runner-env.js +142 -4
  64. package/dist/discovery/runner-env.js.map +1 -1
  65. package/dist/discovery/static-discovery.d.ts +38 -3
  66. package/dist/discovery/static-discovery.d.ts.map +1 -1
  67. package/dist/discovery/static-discovery.js +454 -15
  68. package/dist/discovery/static-discovery.js.map +1 -1
  69. package/dist/discovery/supervised-run.d.ts +199 -10
  70. package/dist/discovery/supervised-run.d.ts.map +1 -1
  71. package/dist/discovery/supervised-run.js +350 -39
  72. package/dist/discovery/supervised-run.js.map +1 -1
  73. package/dist/discovery/trusted-config.d.ts +180 -6
  74. package/dist/discovery/trusted-config.d.ts.map +1 -1
  75. package/dist/discovery/trusted-config.js +279 -10
  76. package/dist/discovery/trusted-config.js.map +1 -1
  77. package/dist/discovery/vitest-runner-adapter.d.ts +172 -0
  78. package/dist/discovery/vitest-runner-adapter.d.ts.map +1 -0
  79. package/dist/discovery/vitest-runner-adapter.js +607 -0
  80. package/dist/discovery/vitest-runner-adapter.js.map +1 -0
  81. package/dist/fixture/consumer-runner.d.ts +4 -0
  82. package/dist/fixture/consumer-runner.d.ts.map +1 -0
  83. package/dist/fixture/consumer-runner.js +38 -0
  84. package/dist/fixture/consumer-runner.js.map +1 -0
  85. package/dist/fixture/evidence.d.ts +27 -0
  86. package/dist/fixture/evidence.d.ts.map +1 -1
  87. package/dist/fixture/evidence.js +12 -0
  88. package/dist/fixture/evidence.js.map +1 -1
  89. package/dist/fixture/fixture.d.ts +2 -1
  90. package/dist/fixture/fixture.d.ts.map +1 -1
  91. package/dist/fixture/fixture.js +1 -17
  92. package/dist/fixture/fixture.js.map +1 -1
  93. package/dist/fixture/witness-client.d.ts +6 -174
  94. package/dist/fixture/witness-client.d.ts.map +1 -1
  95. package/dist/fixture/witness-client.js +6 -267
  96. package/dist/fixture/witness-client.js.map +1 -1
  97. package/dist/index.d.ts +9 -6
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +5 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/json.d.ts +6 -12
  102. package/dist/json.d.ts.map +1 -1
  103. package/dist/json.js +6 -17
  104. package/dist/json.js.map +1 -1
  105. package/dist/reporter/project-graph-reporter.d.ts +92 -0
  106. package/dist/reporter/project-graph-reporter.d.ts.map +1 -0
  107. package/dist/reporter/project-graph-reporter.js +92 -0
  108. package/dist/reporter/project-graph-reporter.js.map +1 -0
  109. package/dist/reporter/reporter.cjs.map +1 -1
  110. package/dist/reporter/reporter.d.ts +93 -4
  111. package/dist/reporter/reporter.d.ts.map +1 -1
  112. package/dist/reporter/reporter.js +174 -18
  113. package/dist/reporter/reporter.js.map +1 -1
  114. package/dist/runner-claims.d.ts +13 -0
  115. package/dist/runner-claims.d.ts.map +1 -0
  116. package/dist/runner-claims.js +46 -0
  117. package/dist/runner-claims.js.map +1 -0
  118. package/dist/runner-resolution.d.ts +3 -0
  119. package/dist/runner-resolution.d.ts.map +1 -0
  120. package/dist/runner-resolution.js +14 -0
  121. package/dist/runner-resolution.js.map +1 -0
  122. package/dist/supervisor/client.d.ts +23 -1
  123. package/dist/supervisor/client.d.ts.map +1 -1
  124. package/dist/supervisor/client.js +49 -0
  125. package/dist/supervisor/client.js.map +1 -1
  126. package/dist/supervisor/drain.d.ts +65 -0
  127. package/dist/supervisor/drain.d.ts.map +1 -1
  128. package/dist/supervisor/drain.js +353 -9
  129. package/dist/supervisor/drain.js.map +1 -1
  130. package/dist/supervisor/index.d.ts +7 -3
  131. package/dist/supervisor/index.d.ts.map +1 -1
  132. package/dist/supervisor/index.js +7 -3
  133. package/dist/supervisor/index.js.map +1 -1
  134. package/dist/supervisor/spool.d.ts +65 -2
  135. package/dist/supervisor/spool.d.ts.map +1 -1
  136. package/dist/supervisor/spool.js +47 -0
  137. package/dist/supervisor/spool.js.map +1 -1
  138. package/dist/surface.d.ts +6 -207
  139. package/dist/surface.d.ts.map +1 -1
  140. package/dist/surface.js +6 -264
  141. package/dist/surface.js.map +1 -1
  142. package/dist/vitest/index.d.ts +23 -0
  143. package/dist/vitest/index.d.ts.map +1 -0
  144. package/dist/vitest/index.js +356 -0
  145. package/dist/vitest/index.js.map +1 -0
  146. package/dist/vitest/reporter.d.ts +83 -0
  147. package/dist/vitest/reporter.d.ts.map +1 -0
  148. package/dist/vitest/reporter.js +211 -0
  149. package/dist/vitest/reporter.js.map +1 -0
  150. package/dist/vitest/worker-slot.d.ts +36 -0
  151. package/dist/vitest/worker-slot.d.ts.map +1 -0
  152. package/dist/vitest/worker-slot.js +51 -0
  153. package/dist/vitest/worker-slot.js.map +1 -0
  154. package/dist/witness/adapter-registry.d.ts +6 -50
  155. package/dist/witness/adapter-registry.d.ts.map +1 -1
  156. package/dist/witness/adapter-registry.js +6 -257
  157. package/dist/witness/adapter-registry.js.map +1 -1
  158. package/dist/witness/behavior-request.d.ts +6 -76
  159. package/dist/witness/behavior-request.d.ts.map +1 -1
  160. package/dist/witness/behavior-request.js +6 -273
  161. package/dist/witness/behavior-request.js.map +1 -1
  162. package/dist/witness/behavior.d.ts +6 -48
  163. package/dist/witness/behavior.d.ts.map +1 -1
  164. package/dist/witness/behavior.js +6 -114
  165. package/dist/witness/behavior.js.map +1 -1
  166. package/dist/witness/bin.d.ts +6 -17
  167. package/dist/witness/bin.d.ts.map +1 -1
  168. package/dist/witness/bin.js +6 -168
  169. package/dist/witness/bin.js.map +1 -1
  170. package/dist/witness/browser.d.ts +14 -206
  171. package/dist/witness/browser.d.ts.map +1 -1
  172. package/dist/witness/browser.js +15 -654
  173. package/dist/witness/browser.js.map +1 -1
  174. package/dist/witness/classifications.d.ts +6 -38
  175. package/dist/witness/classifications.d.ts.map +1 -1
  176. package/dist/witness/classifications.js +6 -83
  177. package/dist/witness/classifications.js.map +1 -1
  178. package/dist/witness/env-attestation.d.ts +6 -94
  179. package/dist/witness/env-attestation.d.ts.map +1 -1
  180. package/dist/witness/env-attestation.js +6 -198
  181. package/dist/witness/env-attestation.js.map +1 -1
  182. package/dist/witness/fixture-provider.d.ts +6 -82
  183. package/dist/witness/fixture-provider.d.ts.map +1 -1
  184. package/dist/witness/fixture-provider.js +6 -105
  185. package/dist/witness/fixture-provider.js.map +1 -1
  186. package/dist/witness/loopback-pins.d.ts +6 -75
  187. package/dist/witness/loopback-pins.d.ts.map +1 -1
  188. package/dist/witness/loopback-pins.js +6 -240
  189. package/dist/witness/loopback-pins.js.map +1 -1
  190. package/dist/witness/server.d.ts +8 -26
  191. package/dist/witness/server.d.ts.map +1 -1
  192. package/dist/witness/server.js +24 -3761
  193. package/dist/witness/server.js.map +1 -1
  194. package/dist/witness/types.d.ts +6 -882
  195. package/dist/witness/types.d.ts.map +1 -1
  196. package/dist/witness/types.js +9 -1
  197. package/dist/witness/types.js.map +1 -1
  198. package/examples/overlay-proof.spec.js +75 -0
  199. package/package.json +8 -2
  200. package/python/gateforge_pytest_plugin.py +462 -0
@@ -0,0 +1,369 @@
1
+ /**
2
+ * The Cypress side of the witness channel (plan 2026-09-25 phase 2).
3
+ *
4
+ * Cypress exposes exactly two runner-side seams, and this module uses
5
+ * both — nothing else about a Cypress run is trusted:
6
+ *
7
+ * - `setupNodeEvents` (`on('task')` + `on('after:run')`) runs in the
8
+ * Cypress PROCESS. The pack registers the lifecycle tasks the
9
+ * generated support file calls (`gateforge:test-begin` /
10
+ * `gateforge:test-end`): each appends the same lifecycle spool event
11
+ * the Playwright reporter writes (testBegin with the obligation
12
+ * claims, testEnd with the outcome and attempt), and `test-begin`
13
+ * additionally resolves the supervisor-issued session for the
14
+ * running test and hands its proxy origin to the browser. That
15
+ * process holds no verifier key and no supervisor rights — the
16
+ * TRUSTED CLI drain reads the spool and performs the witness calls.
17
+ * - `on('after:run')` receives mocha's own results. The plugin writes
18
+ * them to the run's report document in the pack's fixed shape
19
+ * (`<stateDir>/cypress/<runId>/report.json`): per spec, per test the
20
+ * title path, the state, and the ATTEMPT COUNT. A runner-assisted
21
+ * retry (Cypress `retries`) is therefore visible in the report and
22
+ * blocks the run — required retries are zero.
23
+ *
24
+ * Everything is INERT without supervised wiring: with no
25
+ * `GATEFORGE_STATE_DIR`/`GATEFORGE_RUN_ID` in the environment the tasks
26
+ * are not registered, the support file's calls fail loudly, and a
27
+ * plain `cypress run` behaves exactly as without the pack.
28
+ */
29
+ import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
30
+ import { failureDiagnosisOf } from '../diagnosis.js';
31
+ import { dirname, join } from 'node:path';
32
+ import { canonicalOf } from '../json.js';
33
+ import { claimInjectionsFor } from '../runner-claims.js';
34
+ /** The Cypress task the support file calls when a test starts. */
35
+ const TASK_TEST_BEGIN = 'gateforge:test-begin';
36
+ /** The Cypress task the support file calls when a test ends. */
37
+ const TASK_TEST_END = 'gateforge:test-end';
38
+ /** Header the run token travels in (the same name the fixture uses). */
39
+ const RUN_HEADER = 'x-gateforge-run';
40
+ /** How long a started test waits for the drain to open its session. */
41
+ const SESSION_RESOLVE_TIMEOUT_MS = 10_000;
42
+ /** Poll cadence for the session resolve (supervisor → witness latency). */
43
+ const SESSION_RESOLVE_POLL_MS = 50;
44
+ /** The mocha error the support file reports for a failing test. */
45
+ function errorOf(payload) {
46
+ if (typeof payload !== 'object' || payload === null || !('error' in payload))
47
+ return undefined;
48
+ const error = payload.error;
49
+ if (typeof error !== 'object' || error === null)
50
+ return undefined;
51
+ return [error];
52
+ }
53
+ /** The run-scoped wiring read from the environment, once. */
54
+ function pluginEnv() {
55
+ const stateDir = process.env['GATEFORGE_STATE_DIR'] ?? '';
56
+ const runId = process.env['GATEFORGE_RUN_ID'] ?? '';
57
+ const witnessUrl = process.env['GATEFORGE_WITNESS_URL'] ?? '';
58
+ const runToken = process.env['GATEFORGE_RUN_TOKEN'] ?? '';
59
+ const spooled = stateDir !== '' && runId !== '';
60
+ return {
61
+ stateDir: spooled ? stateDir : null,
62
+ runId: spooled ? runId : null,
63
+ witnessUrl: witnessUrl === '' ? null : witnessUrl,
64
+ runToken: runToken === '' ? null : runToken,
65
+ appBaseUrl: process.env['GATEFORGE_APP_BASE_URL'] ?? '',
66
+ };
67
+ }
68
+ /**
69
+ * Registers the gateforge Cypress tasks and the run report writer.
70
+ *
71
+ * Args:
72
+ * on: Cypress's `setupNodeEvents(on, config)` registrar.
73
+ *
74
+ * Returns:
75
+ * void
76
+ */
77
+ export function registerGateforgeCypressPlugin(on) {
78
+ const env = pluginEnv();
79
+ if (env.stateDir === null || env.runId === null)
80
+ return;
81
+ // With a run-scoped state dir the tasks ARE registered even when no
82
+ // witness is wired: the lifecycle spool is the runner's own record,
83
+ // and a test that then addresses a configured app without an open
84
+ // session is refused rather than passing untagged.
85
+ const spoolFile = join(env.stateDir, 'spool', env.runId, 'events.jsonl');
86
+ const reportFile = join(env.stateDir, 'cypress', env.runId, 'report.json');
87
+ on('task', {
88
+ [TASK_TEST_BEGIN]: async (payload) => {
89
+ const identity = identityOf(payload);
90
+ appendEvent(spoolFile, {
91
+ kind: 'testBegin',
92
+ testId: identity.testId,
93
+ workerIndex: 0,
94
+ file: identity.file,
95
+ titlePath: identity.titlePath,
96
+ project: null,
97
+ ...claimsFor(env.stateDir, identity.testId),
98
+ });
99
+ const credential = env.witnessUrl === null || env.runToken === null
100
+ ? { sessionId: '', sessionToken: '', proxyUrl: null }
101
+ : await resolveSession(env, identity);
102
+ return { ...credential, appBaseUrl: env.appBaseUrl };
103
+ },
104
+ [TASK_TEST_END]: (payload) => {
105
+ const identity = identityOf(payload);
106
+ const state = stateOf(payload);
107
+ appendEvent(spoolFile, {
108
+ kind: 'testEnd',
109
+ testId: identity.testId,
110
+ workerIndex: 0,
111
+ file: identity.file,
112
+ titlePath: identity.titlePath,
113
+ project: null,
114
+ outcome: state === 'passed' ? 'passed' : state === 'pending' ? 'skipped' : 'failed',
115
+ attempt: attemptOf(payload),
116
+ // Additive diagnosis for a non-passing test (mocha's own
117
+ // `err`): the CI progress stream and the failures artifact are
118
+ // the only readers, and the CLI screens the message first.
119
+ ...(state === 'passed' ? {} : (failureDiagnosisOf(errorOf(payload)) ?? {})),
120
+ });
121
+ return null;
122
+ },
123
+ });
124
+ on('after:run', (results) => {
125
+ writeRunReport(reportFile, results);
126
+ });
127
+ }
128
+ /**
129
+ * Normalizes the identity the support file reports, or refuses it: a
130
+ * task payload with no file and no title is never attributed to a test.
131
+ *
132
+ * Args:
133
+ * payload: the raw `cy.task` payload.
134
+ *
135
+ * Returns:
136
+ * { testId: string; file: string | null; titlePath: string[] }: the
137
+ * reconciliation identity (`<file>#<title path>`).
138
+ *
139
+ * Throws:
140
+ * Error: when the payload carries no file and no title path.
141
+ */
142
+ function identityOf(payload) {
143
+ const record = (typeof payload === 'object' && payload !== null ? payload : {});
144
+ const file = typeof record.file === 'string' && record.file !== '' ? record.file : null;
145
+ const titlePath = Array.isArray(record.titlePath)
146
+ ? record.titlePath.filter((title) => typeof title === 'string')
147
+ : typeof record.testId === 'string' && record.testId.includes('#')
148
+ ? [record.testId.split('#')[1]]
149
+ : [];
150
+ if (file === null && titlePath.length === 0) {
151
+ throw new Error('gateforge: the Cypress support file reported a test with no file and no title — ' +
152
+ 'such a test can never be attributed to a session');
153
+ }
154
+ const key = `${file ?? '-'}>${titlePath.join('>')}`;
155
+ return { testId: typeof record.testId === 'string' && record.testId !== '' ? record.testId : key, file, titlePath };
156
+ }
157
+ /** The observed state the support file reports (default: failed). */
158
+ function stateOf(payload) {
159
+ const record = (typeof payload === 'object' && payload !== null ? payload : {});
160
+ return typeof record.state === 'string' ? record.state : 'failed';
161
+ }
162
+ /** The 1-based attempt the support file reports (default: 1). */
163
+ function attemptOf(payload) {
164
+ const record = (typeof payload === 'object' && payload !== null ? payload : {});
165
+ return typeof record.attempt === 'number' && record.attempt >= 1 ? Math.trunc(record.attempt) : 1;
166
+ }
167
+ /** The claims a spooled `testBegin` carries for one key. */
168
+ function claimsFor(stateDir, testId) {
169
+ const claims = claimInjectionsFor(stateDir, testId);
170
+ return claims.length > 0 ? { claims } : {};
171
+ }
172
+ /** Appends one lifecycle event (never crashes the run on failure). */
173
+ function appendEvent(spoolFile, event) {
174
+ try {
175
+ mkdirSync(dirname(spoolFile), { recursive: true });
176
+ appendFileSync(spoolFile, `${canonicalOf(event)}\n`, 'utf8');
177
+ }
178
+ catch (error) {
179
+ console.warn(`[gateforge] cannot append to the lifecycle spool: ${error.message}`);
180
+ }
181
+ }
182
+ /**
183
+ * Resolves the supervisor-issued session for a started test by asking
184
+ * the witness, exactly like the Playwright fixture and the pytest
185
+ * plugin. The drain opens the session from the spooled `testBegin`, so
186
+ * the first attempts race it and are retried briefly.
187
+ *
188
+ * Args:
189
+ * env: the run-scoped wiring.
190
+ * identity: the started test's reconciliation identity.
191
+ *
192
+ * Returns:
193
+ * Promise<CypressSessionCredential>: the open session's credential.
194
+ *
195
+ * Throws:
196
+ * Error: when no open session answers within the bound — an
197
+ * unattributable test fails loudly instead of running untagged.
198
+ */
199
+ async function resolveSession(env, identity) {
200
+ const witnessUrl = env.witnessUrl;
201
+ const runToken = env.runToken;
202
+ const deadline = Date.now() + SESSION_RESOLVE_TIMEOUT_MS;
203
+ let lastDetail = 'no answer';
204
+ while (Date.now() < deadline) {
205
+ try {
206
+ const response = await fetch(`${witnessUrl.replace(/\/$/, '')}/sessions/resolve`, {
207
+ method: 'POST',
208
+ headers: { 'content-type': 'application/json', [RUN_HEADER]: runToken },
209
+ body: JSON.stringify({ testId: identity.testId, workerIndex: 0 }),
210
+ });
211
+ if (response.ok) {
212
+ const body = (await response.json());
213
+ if (typeof body.sessionId === 'string' && body.sessionId !== '') {
214
+ return {
215
+ sessionId: body.sessionId,
216
+ sessionToken: typeof body.sessionToken === 'string' ? body.sessionToken : '',
217
+ proxyUrl: typeof body.proxyUrl === 'string' && body.proxyUrl !== '' ? body.proxyUrl : null,
218
+ };
219
+ }
220
+ lastDetail = 'malformed resolve response';
221
+ }
222
+ else if (response.status !== 404) {
223
+ lastDetail = `HTTP ${String(response.status)} from /sessions/resolve`;
224
+ }
225
+ }
226
+ catch (error) {
227
+ lastDetail = error.message;
228
+ }
229
+ await new Promise((resolveSleep) => {
230
+ setTimeout(resolveSleep, SESSION_RESOLVE_POLL_MS);
231
+ });
232
+ }
233
+ throw new Error(`[gateforge] no open witness session answered for Cypress test '${identity.testId}' within ` +
234
+ `${String(SESSION_RESOLVE_TIMEOUT_MS)}ms (${lastDetail}) — a test whose traffic cannot be ` +
235
+ 'attributed is never allowed to pass');
236
+ }
237
+ /**
238
+ * Writes the run's report document from mocha's own `after:run`
239
+ * results: per spec, per test the title path, the state, and the
240
+ * attempt count. A test with more than one attempt is a
241
+ * runner-assisted retry, which blocks the run.
242
+ *
243
+ * Args:
244
+ * reportFile: the run-scoped report path.
245
+ * results: Cypress's `after:run` payload.
246
+ */
247
+ function writeRunReport(reportFile, results) {
248
+ const specs = [];
249
+ let retriesDetected = false;
250
+ for (const run of results.runs ?? []) {
251
+ const file = typeof run.spec?.relative === 'string' ? run.spec.relative : '';
252
+ const tests = (run.tests ?? []).map((test) => {
253
+ const titlePath = Array.isArray(test.title)
254
+ ? test.title.filter((title) => typeof title === 'string')
255
+ : [];
256
+ const attempts = Array.isArray(test.attempts) ? test.attempts.length : 1;
257
+ if (attempts > 1)
258
+ retriesDetected = true;
259
+ return {
260
+ titlePath,
261
+ state: typeof test.state === 'string' ? test.state : 'failed',
262
+ attempts: Math.max(1, attempts),
263
+ };
264
+ });
265
+ specs.push({ file, tests });
266
+ }
267
+ try {
268
+ mkdirSync(dirname(reportFile), { recursive: true });
269
+ const report = { schemaVersion: 1, retriesDetected, specs };
270
+ writeFileSync(reportFile, `${canonicalOf(report)}\n`, 'utf8');
271
+ }
272
+ catch (error) {
273
+ console.warn(`[gateforge] cannot write the Cypress run report: ${error.message}`);
274
+ }
275
+ }
276
+ /**
277
+ * The generated Cypress support file: the in-browser half of the
278
+ * channel. It opens each test's session through the plugin task, and
279
+ * rewrites `cy.request` traffic addressed at the app origin onto that
280
+ * session's proxy origin, so every exchange is attributed to the test
281
+ * that issued it. Traffic addressed anywhere else (a raw browser
282
+ * `fetch` to the app, a third-party origin) is left ALONE and therefore
283
+ * stays unattributed — the witness credits it to nothing.
284
+ *
285
+ * Args:
286
+ * projectSupportFile: the project's own support file (required first,
287
+ * so its hooks and commands keep working), or null.
288
+ *
289
+ * Returns:
290
+ * string: CommonJS support-file source.
291
+ */
292
+ export function cypressSupportSource(projectSupportFile) {
293
+ const chained = projectSupportFile === null
294
+ ? ''
295
+ : `require(${JSON.stringify(projectSupportFile)});\n`;
296
+ return `// Generated by gateforge (plan 2026-09-25 phase 2). Do not edit.
297
+ 'use strict';
298
+ ${chained}
299
+ const gateforgeSession = { proxyUrl: null, appBaseUrl: '' };
300
+
301
+ beforeEach(function () {
302
+ const current = this.currentTest;
303
+ if (!current || typeof current.titlePath !== 'function') return;
304
+ const file = (Cypress.spec && Cypress.spec.relative) || '';
305
+ const titlePath = current.titlePath();
306
+ const attempt = (typeof this.test._currentRetry === 'number' ? this.test._currentRetry : 0) + 1;
307
+ cy.task('gateforge:test-begin', { testId: file + '#' + titlePath.join('>'), file: file, titlePath: titlePath, attempt: attempt })
308
+ .then((session) => {
309
+ gateforgeSession.proxyUrl = session && typeof session.proxyUrl === 'string' ? session.proxyUrl : null;
310
+ gateforgeSession.appBaseUrl = session && typeof session.appBaseUrl === 'string' ? session.appBaseUrl : '';
311
+ });
312
+ });
313
+
314
+ afterEach(function () {
315
+ const current = this.currentTest;
316
+ gateforgeSession.proxyUrl = null;
317
+ if (!current || typeof current.titlePath !== 'function') return;
318
+ const file = (Cypress.spec && Cypress.spec.relative) || '';
319
+ const titlePath = current.titlePath();
320
+ const attempt = (typeof this.test._currentRetry === 'number' ? this.test._currentRetry : 0) + 1;
321
+ cy.task('gateforge:test-end', {
322
+ testId: file + '#' + titlePath.join('>'),
323
+ file: file,
324
+ titlePath: titlePath,
325
+ state: current.state,
326
+ attempt: attempt,
327
+ error: current.err ? { message: String(current.err.message || ''), stack: String(current.err.stack || '') } : null,
328
+ });
329
+ });
330
+
331
+ // Job 2: cy.request traffic at the app origin crosses THIS test's
332
+ // session proxy. Without an open session the request is refused: an
333
+ // untagged request can never be witnessed evidence, so it must not
334
+ // pass quietly.
335
+ Cypress.Commands.overwrite('request', function (originalFn, ...args) {
336
+ const gateforgeRewrite = (value) => {
337
+ if (typeof value !== 'string' || gateforgeSession.appBaseUrl === '') return value;
338
+ let target;
339
+ try {
340
+ target = new URL(value, gateforgeSession.appBaseUrl);
341
+ } catch (error) {
342
+ return value;
343
+ }
344
+ let app;
345
+ try {
346
+ app = new URL(gateforgeSession.appBaseUrl);
347
+ } catch (error) {
348
+ return value;
349
+ }
350
+ if (target.origin !== app.origin) return value;
351
+ if (gateforgeSession.proxyUrl === null || gateforgeSession.proxyUrl === '') {
352
+ throw new Error(
353
+ 'gateforge: this cy.request has no open witness session for the running test, so it could ' +
354
+ 'never be witnessed evidence — run under gateforge test-gates (or the CypressRunnerAdapter) ' +
355
+ 'and use cy.request (not a raw fetch) for app traffic. [GATEFORGE_WITNESS_SESSION_MISSING]'
356
+ );
357
+ }
358
+ return gateforgeSession.proxyUrl + target.pathname + target.search + target.hash;
359
+ };
360
+ const rewritten = args.map((arg) =>
361
+ arg !== null && typeof arg === 'object' && typeof arg.url === 'string'
362
+ ? Object.assign({}, arg, { url: gateforgeRewrite(arg.url) })
363
+ : gateforgeRewrite(arg)
364
+ );
365
+ return originalFn.apply(this, rewritten);
366
+ });
367
+ `;
368
+ }
369
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/cypress/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /** One statically enumerated Cypress test. */
2
+ export interface ScannedCypressTest {
3
+ /** Repo-relative posix spec path. */
4
+ readonly file: string;
5
+ /** Suite chain titles, then the leaf test title. */
6
+ readonly titlePath: readonly string[];
7
+ }
8
+ /** The outcome of scanning one project's spec tree. */
9
+ export type SpecScanResult = {
10
+ readonly status: 'scanned';
11
+ readonly tests: readonly ScannedCypressTest[];
12
+ } | {
13
+ readonly status: 'unavailable';
14
+ readonly detail: string;
15
+ };
16
+ /**
17
+ * Collects the spec files of a project (repo-relative posix paths,
18
+ * sorted). Only the default `cypress/` spec tree is walked.
19
+ *
20
+ * Args:
21
+ * root: absolute project root.
22
+ *
23
+ * Returns:
24
+ * string[]: the spec files, sorted; [] when the project has none.
25
+ */
26
+ export declare function cypressSpecFiles(root: string): string[];
27
+ /**
28
+ * Statically enumerates every test a project's specs declare.
29
+ *
30
+ * Args:
31
+ * root: absolute project root.
32
+ *
33
+ * Returns:
34
+ * SpecScanResult: the declared tests, or `unavailable` with a single
35
+ * cause when a spec uses a non-literal title or declares no test
36
+ * (never a partial set, never a faked empty success).
37
+ */
38
+ export declare function scanCypressSpecs(root: string): SpecScanResult;
39
+ //# sourceMappingURL=spec-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-scan.d.ts","sourceRoot":"","sources":["../../src/cypress/spec-scan.ts"],"names":[],"mappings":"AAoBA,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,uDAAuD;AACvD,MAAM,MAAM,cAAc,GACtB;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,kBAAkB,EAAE,CAAA;CAAE,GAC7E;IAAE,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAkDhE;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAqC7D"}