@gate-forge/pack-playwright 0.7.1 → 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.
- package/README.md +31 -0
- package/dist/constants.d.ts +13 -140
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +13 -148
- package/dist/constants.js.map +1 -1
- package/dist/cypress/plugin.d.ts +53 -0
- package/dist/cypress/plugin.d.ts.map +1 -0
- package/dist/cypress/plugin.js +369 -0
- package/dist/cypress/plugin.js.map +1 -0
- package/dist/cypress/spec-scan.d.ts +39 -0
- package/dist/cypress/spec-scan.d.ts.map +1 -0
- package/dist/cypress/spec-scan.js +301 -0
- package/dist/cypress/spec-scan.js.map +1 -0
- package/dist/diagnosis.d.ts +39 -0
- package/dist/diagnosis.d.ts.map +1 -0
- package/dist/diagnosis.js +63 -0
- package/dist/diagnosis.js.map +1 -0
- package/dist/discovery/adapter-projection.d.ts +13 -0
- package/dist/discovery/adapter-projection.d.ts.map +1 -0
- package/dist/discovery/adapter-projection.js +84 -0
- package/dist/discovery/adapter-projection.js.map +1 -0
- package/dist/discovery/config-locations.d.ts +5 -0
- package/dist/discovery/config-locations.d.ts.map +1 -0
- package/dist/discovery/config-locations.js +19 -0
- package/dist/discovery/config-locations.js.map +1 -0
- package/dist/discovery/cypress-runner-adapter.d.ts +112 -0
- package/dist/discovery/cypress-runner-adapter.d.ts.map +1 -0
- package/dist/discovery/cypress-runner-adapter.js +501 -0
- package/dist/discovery/cypress-runner-adapter.js.map +1 -0
- package/dist/discovery/discover.d.ts +53 -1
- package/dist/discovery/discover.d.ts.map +1 -1
- package/dist/discovery/discover.js +100 -3
- package/dist/discovery/discover.js.map +1 -1
- package/dist/discovery/git-ignore.d.ts +13 -0
- package/dist/discovery/git-ignore.d.ts.map +1 -0
- package/dist/discovery/git-ignore.js +62 -0
- package/dist/discovery/git-ignore.js.map +1 -0
- package/dist/discovery/index.d.ts +9 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +9 -0
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/playwright-runner-adapter.d.ts +108 -0
- package/dist/discovery/playwright-runner-adapter.d.ts.map +1 -0
- package/dist/discovery/playwright-runner-adapter.js +185 -0
- package/dist/discovery/playwright-runner-adapter.js.map +1 -0
- package/dist/discovery/prepare-barrier.d.ts +522 -0
- package/dist/discovery/prepare-barrier.d.ts.map +1 -0
- package/dist/discovery/prepare-barrier.js +739 -0
- package/dist/discovery/prepare-barrier.js.map +1 -0
- package/dist/discovery/pytest-adapter.d.ts.map +1 -1
- package/dist/discovery/pytest-adapter.js +6 -2
- package/dist/discovery/pytest-adapter.js.map +1 -1
- package/dist/discovery/pytest-runner-adapter.d.ts +124 -0
- package/dist/discovery/pytest-runner-adapter.d.ts.map +1 -0
- package/dist/discovery/pytest-runner-adapter.js +454 -0
- package/dist/discovery/pytest-runner-adapter.js.map +1 -0
- package/dist/discovery/reconcile.d.ts +80 -11
- package/dist/discovery/reconcile.d.ts.map +1 -1
- package/dist/discovery/reconcile.js +395 -78
- package/dist/discovery/reconcile.js.map +1 -1
- package/dist/discovery/runner-env.d.ts +88 -2
- package/dist/discovery/runner-env.d.ts.map +1 -1
- package/dist/discovery/runner-env.js +142 -4
- package/dist/discovery/runner-env.js.map +1 -1
- package/dist/discovery/static-discovery.d.ts +38 -3
- package/dist/discovery/static-discovery.d.ts.map +1 -1
- package/dist/discovery/static-discovery.js +454 -15
- package/dist/discovery/static-discovery.js.map +1 -1
- package/dist/discovery/supervised-run.d.ts +199 -10
- package/dist/discovery/supervised-run.d.ts.map +1 -1
- package/dist/discovery/supervised-run.js +350 -39
- package/dist/discovery/supervised-run.js.map +1 -1
- package/dist/discovery/trusted-config.d.ts +180 -6
- package/dist/discovery/trusted-config.d.ts.map +1 -1
- package/dist/discovery/trusted-config.js +279 -10
- package/dist/discovery/trusted-config.js.map +1 -1
- package/dist/discovery/vitest-runner-adapter.d.ts +172 -0
- package/dist/discovery/vitest-runner-adapter.d.ts.map +1 -0
- package/dist/discovery/vitest-runner-adapter.js +607 -0
- package/dist/discovery/vitest-runner-adapter.js.map +1 -0
- package/dist/fixture/consumer-runner.d.ts +4 -0
- package/dist/fixture/consumer-runner.d.ts.map +1 -0
- package/dist/fixture/consumer-runner.js +38 -0
- package/dist/fixture/consumer-runner.js.map +1 -0
- package/dist/fixture/evidence.d.ts +27 -0
- package/dist/fixture/evidence.d.ts.map +1 -1
- package/dist/fixture/evidence.js +12 -0
- package/dist/fixture/evidence.js.map +1 -1
- package/dist/fixture/fixture.d.ts +2 -1
- package/dist/fixture/fixture.d.ts.map +1 -1
- package/dist/fixture/fixture.js +1 -17
- package/dist/fixture/fixture.js.map +1 -1
- package/dist/fixture/witness-client.d.ts +6 -174
- package/dist/fixture/witness-client.d.ts.map +1 -1
- package/dist/fixture/witness-client.js +6 -267
- package/dist/fixture/witness-client.js.map +1 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +6 -12
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js +6 -17
- package/dist/json.js.map +1 -1
- package/dist/reporter/project-graph-reporter.d.ts +92 -0
- package/dist/reporter/project-graph-reporter.d.ts.map +1 -0
- package/dist/reporter/project-graph-reporter.js +92 -0
- package/dist/reporter/project-graph-reporter.js.map +1 -0
- package/dist/reporter/reporter.cjs.map +1 -1
- package/dist/reporter/reporter.d.ts +93 -4
- package/dist/reporter/reporter.d.ts.map +1 -1
- package/dist/reporter/reporter.js +174 -18
- package/dist/reporter/reporter.js.map +1 -1
- package/dist/runner-claims.d.ts +13 -0
- package/dist/runner-claims.d.ts.map +1 -0
- package/dist/runner-claims.js +46 -0
- package/dist/runner-claims.js.map +1 -0
- package/dist/runner-resolution.d.ts +3 -0
- package/dist/runner-resolution.d.ts.map +1 -0
- package/dist/runner-resolution.js +14 -0
- package/dist/runner-resolution.js.map +1 -0
- package/dist/supervisor/client.d.ts +23 -1
- package/dist/supervisor/client.d.ts.map +1 -1
- package/dist/supervisor/client.js +49 -0
- package/dist/supervisor/client.js.map +1 -1
- package/dist/supervisor/drain.d.ts +65 -0
- package/dist/supervisor/drain.d.ts.map +1 -1
- package/dist/supervisor/drain.js +353 -9
- package/dist/supervisor/drain.js.map +1 -1
- package/dist/supervisor/index.d.ts +7 -3
- package/dist/supervisor/index.d.ts.map +1 -1
- package/dist/supervisor/index.js +7 -3
- package/dist/supervisor/index.js.map +1 -1
- package/dist/supervisor/spool.d.ts +65 -2
- package/dist/supervisor/spool.d.ts.map +1 -1
- package/dist/supervisor/spool.js +47 -0
- package/dist/supervisor/spool.js.map +1 -1
- package/dist/surface.d.ts +6 -207
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +6 -264
- package/dist/surface.js.map +1 -1
- package/dist/vitest/index.d.ts +23 -0
- package/dist/vitest/index.d.ts.map +1 -0
- package/dist/vitest/index.js +356 -0
- package/dist/vitest/index.js.map +1 -0
- package/dist/vitest/reporter.d.ts +83 -0
- package/dist/vitest/reporter.d.ts.map +1 -0
- package/dist/vitest/reporter.js +211 -0
- package/dist/vitest/reporter.js.map +1 -0
- package/dist/vitest/worker-slot.d.ts +36 -0
- package/dist/vitest/worker-slot.d.ts.map +1 -0
- package/dist/vitest/worker-slot.js +51 -0
- package/dist/vitest/worker-slot.js.map +1 -0
- package/dist/witness/adapter-registry.d.ts +6 -50
- package/dist/witness/adapter-registry.d.ts.map +1 -1
- package/dist/witness/adapter-registry.js +6 -257
- package/dist/witness/adapter-registry.js.map +1 -1
- package/dist/witness/behavior-request.d.ts +6 -76
- package/dist/witness/behavior-request.d.ts.map +1 -1
- package/dist/witness/behavior-request.js +6 -273
- package/dist/witness/behavior-request.js.map +1 -1
- package/dist/witness/behavior.d.ts +6 -48
- package/dist/witness/behavior.d.ts.map +1 -1
- package/dist/witness/behavior.js +6 -114
- package/dist/witness/behavior.js.map +1 -1
- package/dist/witness/bin.d.ts +6 -17
- package/dist/witness/bin.d.ts.map +1 -1
- package/dist/witness/bin.js +6 -168
- package/dist/witness/bin.js.map +1 -1
- package/dist/witness/browser.d.ts +14 -206
- package/dist/witness/browser.d.ts.map +1 -1
- package/dist/witness/browser.js +15 -654
- package/dist/witness/browser.js.map +1 -1
- package/dist/witness/classifications.d.ts +6 -38
- package/dist/witness/classifications.d.ts.map +1 -1
- package/dist/witness/classifications.js +6 -83
- package/dist/witness/classifications.js.map +1 -1
- package/dist/witness/env-attestation.d.ts +6 -94
- package/dist/witness/env-attestation.d.ts.map +1 -1
- package/dist/witness/env-attestation.js +6 -198
- package/dist/witness/env-attestation.js.map +1 -1
- package/dist/witness/fixture-provider.d.ts +6 -82
- package/dist/witness/fixture-provider.d.ts.map +1 -1
- package/dist/witness/fixture-provider.js +6 -105
- package/dist/witness/fixture-provider.js.map +1 -1
- package/dist/witness/loopback-pins.d.ts +6 -75
- package/dist/witness/loopback-pins.d.ts.map +1 -1
- package/dist/witness/loopback-pins.js +6 -240
- package/dist/witness/loopback-pins.js.map +1 -1
- package/dist/witness/server.d.ts +8 -26
- package/dist/witness/server.d.ts.map +1 -1
- package/dist/witness/server.js +24 -3761
- package/dist/witness/server.js.map +1 -1
- package/dist/witness/types.d.ts +6 -882
- package/dist/witness/types.d.ts.map +1 -1
- package/dist/witness/types.js +9 -1
- package/dist/witness/types.js.map +1 -1
- package/examples/overlay-proof.spec.js +75 -0
- package/package.json +8 -2
- package/python/__pycache__/gateforge_persistence_intents.cpython-312.pyc +0 -0
- package/python/__pycache__/gateforge_persistence_intents.cpython-314.pyc +0 -0
- 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"}
|