@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
|
@@ -13,7 +13,23 @@
|
|
|
13
13
|
* (from the planned expected set), or the runner default when the
|
|
14
14
|
* caller selected nothing;
|
|
15
15
|
* - projects: bare names carried as data (identity only — per-project
|
|
16
|
-
* code options are NOT honored)
|
|
16
|
+
* code options are NOT honored), each with the files the plan
|
|
17
|
+
* attributed to it, the dependency EDGES the enumeration captured
|
|
18
|
+
* (names only), and the `use.storageState` PATH the enumeration
|
|
19
|
+
* captured for that project. The edges are what makes a `setup`-project
|
|
20
|
+
* config order correctly: Playwright runs a dependency project's tests
|
|
21
|
+
* before the dependent project, which is the only way the dependent
|
|
22
|
+
* test can read the artifact the setup test produced — and the state
|
|
23
|
+
* is what hands that project the session the setup test saved, while
|
|
24
|
+
* the setup project itself keeps running unauthenticated;
|
|
25
|
+
* - storage states: a declared path is resolved from the NATIVE CONFIG
|
|
26
|
+
* DIRECTORY the runner child runs from (so the dependent project reads
|
|
27
|
+
* the very file its own setup project wrote from that same cwd) and is
|
|
28
|
+
* honored only while it lands INSIDE the candidate root, which stays
|
|
29
|
+
* the containment boundary for a nested project too; an
|
|
30
|
+
* operator-provided whole-run state still outranks every project
|
|
31
|
+
* declaration and keeps its own candidate-root meaning (see
|
|
32
|
+
* {@link resolveProjectStorageState});
|
|
17
33
|
* - reporter: the engine's own reporter entry forced by absolute path
|
|
18
34
|
* with run-state paths as CONSTRUCTOR OPTIONS (never env — worker
|
|
19
35
|
* processes must not learn the spool/outcomes locations);
|
|
@@ -36,8 +52,21 @@
|
|
|
36
52
|
*
|
|
37
53
|
* Compatibility limits (honest, not transparent):
|
|
38
54
|
* - consumer `globalSetup`/`globalTeardown` are NOT executed;
|
|
39
|
-
* - consumer reporters, `webServer`, per-project `use` options
|
|
40
|
-
* `testDir`/`testIgnore`
|
|
55
|
+
* - consumer reporters, `webServer`, per-project `use` options other
|
|
56
|
+
* than the captured `storageState` PATH, `testDir`/`testIgnore`
|
|
57
|
+
* scoping, and sharding are NOT honored;
|
|
58
|
+
* - consumer `testMatch` scoping is NOT honored as CONSUMER CODE. What IS
|
|
59
|
+
* honored is the SUPERVISOR'S OWN per-project file selection
|
|
60
|
+
* (`projectScopes`): project identity is the join key the whole pipeline
|
|
61
|
+
* speaks — catalog rows, the registered expected set, session opens, and
|
|
62
|
+
* the execution trace — so file scoping must be per project too. A single
|
|
63
|
+
* global `testMatch` collects every selected file under EVERY project,
|
|
64
|
+
* which is how a `setup`-dependency config (`{ name: 'setup', testMatch:
|
|
65
|
+
* /.*\.setup\.ts/ }` plus a dependent project) ran the whole suite once
|
|
66
|
+
* per project: identities the registered expected set never bound, so
|
|
67
|
+
* their sessions were refused and they lost every piece of evidence.
|
|
68
|
+
* - per-project `teardown` is NOT honored; only `dependencies` is, as
|
|
69
|
+
* ordering data (names only).
|
|
41
70
|
* - tests must be self-contained (app provided externally via the
|
|
42
71
|
* app-base env, as the fixture already requires).
|
|
43
72
|
*/
|
|
@@ -55,11 +84,44 @@ export interface TrustedReporterOptions {
|
|
|
55
84
|
outcomesPath: string;
|
|
56
85
|
/** Absolute obligations document path (reporter ledger; empty when none). */
|
|
57
86
|
obligationsPath: string;
|
|
87
|
+
/**
|
|
88
|
+
* Absolute CANDIDATE ROOT the reporter anchors every file identity
|
|
89
|
+
* to. Handed as trusted CONSTRUCTOR DATA (never worker env): the
|
|
90
|
+
* runner child runs from the native config directory, while every
|
|
91
|
+
* identity the supervisor registered is repo-relative — the reporter
|
|
92
|
+
* must therefore relativize against the root, not against the cwd it
|
|
93
|
+
* happens to run in.
|
|
94
|
+
*/
|
|
95
|
+
candidateRoot: string;
|
|
96
|
+
/**
|
|
97
|
+
* ABSOLUTE path of the engine's own generated preparation-freeze
|
|
98
|
+
* controller spec, when this run armed the global native freeze.
|
|
99
|
+
*
|
|
100
|
+
* The controller is a real Playwright test inside the runner, so the
|
|
101
|
+
* reporter would otherwise report it as a native case: it would append
|
|
102
|
+
* a lifecycle event (opening a witness session for a test the
|
|
103
|
+
* registered expected set never contained), record an outcome row (so
|
|
104
|
+
* the run's native count carries a non-native case), and collect its
|
|
105
|
+
* claims. The exclusion is therefore by ABSOLUTE FILE IDENTITY — the
|
|
106
|
+
* exact control bytes the trusted CLI pinned — never by title, never
|
|
107
|
+
* by a project-name prefix, and never by anything the candidate
|
|
108
|
+
* controls.
|
|
109
|
+
*/
|
|
110
|
+
controlSpecPath?: string;
|
|
58
111
|
}
|
|
59
112
|
/** Inputs for one trusted config synthesis. */
|
|
60
113
|
export interface TrustedConfigInput {
|
|
61
|
-
/** Absolute repo root (the runner's testDir). */
|
|
114
|
+
/** Absolute repo root (the runner's testDir, and the identity root). */
|
|
62
115
|
cwd: string;
|
|
116
|
+
/**
|
|
117
|
+
* Absolute native config directory — the directory the runner child
|
|
118
|
+
* runs from (the same one `listNativePlaywrightTests` enumerates
|
|
119
|
+
* from). Relative per-project {@link ProjectScope.storageState}
|
|
120
|
+
* declarations resolve from here, because that is the cwd the
|
|
121
|
+
* project's own setup test wrote the file from. Undefined = the repo
|
|
122
|
+
* root, which is exactly the config directory of a root-level config.
|
|
123
|
+
*/
|
|
124
|
+
nativeConfigDir?: string;
|
|
63
125
|
/** Absolute run-state dir (receives the synthesized config). */
|
|
64
126
|
stateDir: string;
|
|
65
127
|
/** The run identity. */
|
|
@@ -68,15 +130,126 @@ export interface TrustedConfigInput {
|
|
|
68
130
|
reporterEntry: string;
|
|
69
131
|
/** Trusted operator-provided app proxy URL for relative browser navigation. */
|
|
70
132
|
appBaseUrl?: string;
|
|
71
|
-
/**
|
|
133
|
+
/**
|
|
134
|
+
* Operator-provided browser storage state, embedded only in trusted
|
|
135
|
+
* config. This is the WHOLE-RUN state: when it is set it applies to
|
|
136
|
+
* every project and outranks each project's declared
|
|
137
|
+
* {@link ProjectScope.storageState}, exactly as it always has. A
|
|
138
|
+
* relative value keeps its CANDIDATE-ROOT meaning — it is resolved
|
|
139
|
+
* against {@link TrustedConfigInput.cwd} here, so moving the native
|
|
140
|
+
* child's cwd can never re-point an operator's path.
|
|
141
|
+
*/
|
|
72
142
|
storageState?: string;
|
|
73
143
|
/** Exact repo-relative posix test files to run (undefined = default). */
|
|
74
144
|
testFiles?: readonly string[];
|
|
75
145
|
/** Bare project names to run (undefined = no project filter). */
|
|
76
146
|
projects?: readonly string[];
|
|
147
|
+
/**
|
|
148
|
+
* The supervisor's OWN per-project file selection: each named project
|
|
149
|
+
* carries exactly the files the plan attributed to it. A project with no
|
|
150
|
+
* files is omitted (it would execute nothing). Files no project scope
|
|
151
|
+
* claims (a project-less plan row) stay in the global `testMatch`, so
|
|
152
|
+
* they still run. Empty = one global `testMatch` over `testFiles`, which
|
|
153
|
+
* is byte-identical to the pre-scope behavior for a single-project run.
|
|
154
|
+
*/
|
|
155
|
+
projectScopes?: readonly ProjectScope[];
|
|
156
|
+
/**
|
|
157
|
+
* ABSOLUTE path of the generated preparation-freeze controller spec,
|
|
158
|
+
* when this run armed the global native freeze. It crosses to the
|
|
159
|
+
* engine reporter as TRUSTED CONSTRUCTOR DATA (never env, never a
|
|
160
|
+
* candidate-relative path) so the reporter can exclude exactly that one
|
|
161
|
+
* file from its outcome rows, claims and lifecycle events. Unarmed, the
|
|
162
|
+
* field is absent and the reporter records every test, exactly as
|
|
163
|
+
* before.
|
|
164
|
+
*/
|
|
165
|
+
controlSpecPath?: string;
|
|
77
166
|
/** Per-test timeout ms (default 60_000). */
|
|
78
167
|
testTimeoutMs?: number;
|
|
79
168
|
}
|
|
169
|
+
/** One named project and the repo-relative files the plan attributed to it. */
|
|
170
|
+
export interface ProjectScope {
|
|
171
|
+
/** The project name — identity only; no consumer code options. */
|
|
172
|
+
name: string;
|
|
173
|
+
/** Repo-relative posix test files this project runs. */
|
|
174
|
+
files: readonly string[];
|
|
175
|
+
/**
|
|
176
|
+
* Project names this project depends on, as the runner resolved them
|
|
177
|
+
* (names only — never the consumer's per-project options). The
|
|
178
|
+
* synthesized config emits them so Playwright runs a `setup` project's
|
|
179
|
+
* tests BEFORE the dependent project that reads their artifact; an
|
|
180
|
+
* edge naming a project the synthesized config omits is dropped,
|
|
181
|
+
* because Playwright refuses to load such a config at all.
|
|
182
|
+
*/
|
|
183
|
+
dependencies?: readonly string[];
|
|
184
|
+
/**
|
|
185
|
+
* The `use.storageState` PATH this project declared, as the runner
|
|
186
|
+
* resolved it (data, never consumer code). The synthesized config
|
|
187
|
+
* hands it to THIS project only, which is what lets a `setup` project
|
|
188
|
+
* sign in and save `playwright/.auth/user.json` for the dependent
|
|
189
|
+
* project that reads it while the setup project itself stays logged
|
|
190
|
+
* out. Relative paths resolve against the RUNNER's cwd — the native
|
|
191
|
+
* config directory the child runs from — exactly like the setup
|
|
192
|
+
* test's own relative write, which is the very cwd that write is
|
|
193
|
+
* resolved from. Containment stays the WHOLE candidate root, so a
|
|
194
|
+
* valid `../shared/state.json` that lands back inside the candidate
|
|
195
|
+
* is honored while anything reaching outside it is refused (see
|
|
196
|
+
* {@link resolveProjectStorageState}).
|
|
197
|
+
*
|
|
198
|
+
* An operator-provided whole-run state (GATEFORGE_SESSION_STATE)
|
|
199
|
+
* outranks every project declaration, so this field is not emitted at
|
|
200
|
+
* all in that case.
|
|
201
|
+
*/
|
|
202
|
+
storageState?: string;
|
|
203
|
+
/**
|
|
204
|
+
* This project's OWN `testDir` (absolute), when it collects files from
|
|
205
|
+
* somewhere other than the config's `testDir`. Only the engine's freeze
|
|
206
|
+
* controller uses it: its spec is GENERATED code in a private per-run
|
|
207
|
+
* directory OUTSIDE the repository, which the config's own repo-root
|
|
208
|
+
* `testDir` never covers and the consumer's own configuration can
|
|
209
|
+
* never collect. A consumer project never gets one — the files it runs
|
|
210
|
+
* are always repo-relative to the identity root.
|
|
211
|
+
*/
|
|
212
|
+
testDir?: string;
|
|
213
|
+
}
|
|
214
|
+
/** Thrown when a project-declared browser state may not be read. */
|
|
215
|
+
export declare class ProjectStorageStateError extends Error {
|
|
216
|
+
constructor(message: string);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Resolves one project-declared `use.storageState` and refuses anything
|
|
220
|
+
* a supervised run must not read.
|
|
221
|
+
*
|
|
222
|
+
* A relative path is resolved against the NATIVE CONFIG DIRECTORY —
|
|
223
|
+
* the directory the runner child runs from, exactly the directory
|
|
224
|
+
* `listNativePlaywrightTests` enumerated the suite from: the worker
|
|
225
|
+
* reads the file relative to the process it runs in, which is that very
|
|
226
|
+
* cwd, which is also where the project's own setup test wrote it from.
|
|
227
|
+
* The file itself need not exist yet — the setup project writes it
|
|
228
|
+
* during this run.
|
|
229
|
+
*
|
|
230
|
+
* Containment is the WHOLE CANDIDATE ROOT, not the config directory,
|
|
231
|
+
* and it is PHYSICAL rather than lexical: a symlink inside the
|
|
232
|
+
* candidate that points outside it is refused too, so the check follows
|
|
233
|
+
* the real filesystem from the nearest existing ancestor. A nested
|
|
234
|
+
* project's `../shared/state.json` therefore stays valid whenever it
|
|
235
|
+
* lands back inside the candidate.
|
|
236
|
+
*
|
|
237
|
+
* @param value: the `use.storageState` string the runner resolved.
|
|
238
|
+
* @param root: the candidate root (the containment boundary).
|
|
239
|
+
* @param project: the declaring project, named in the error.
|
|
240
|
+
* @param baseDir: the directory a relative declaration resolves from —
|
|
241
|
+
* the native config directory the runner child runs from.
|
|
242
|
+
*
|
|
243
|
+
* @returns
|
|
244
|
+
* string: the absolute path the declared state resolves to.
|
|
245
|
+
*
|
|
246
|
+
* @throws
|
|
247
|
+
* ProjectStorageStateError: when the value is empty, names a URL, or
|
|
248
|
+
* resolves outside the candidate root either directly or through a
|
|
249
|
+
* link. A requested state is never silently dropped — that would
|
|
250
|
+
* degrade into a logged-out run that looks green.
|
|
251
|
+
*/
|
|
252
|
+
export declare function resolveProjectStorageState(value: string, root: string, project: string, baseDir: string): string;
|
|
80
253
|
/**
|
|
81
254
|
* Resolves the engine reporter entry the trusted config forces: the
|
|
82
255
|
* pack's own BUILT reporter (the same class the consumer config would
|
|
@@ -94,7 +267,8 @@ export declare function trustedReporterEntry(fromModule?: string): string;
|
|
|
94
267
|
* Synthesizes the trusted Playwright config into the run-state dir.
|
|
95
268
|
*
|
|
96
269
|
* Args:
|
|
97
|
-
* input: repo root, run state, reporter
|
|
270
|
+
* input: repo root, native config directory, run state, reporter
|
|
271
|
+
* entry, file/project selection, and the operator's whole-run state.
|
|
98
272
|
*
|
|
99
273
|
* Returns:
|
|
100
274
|
* { configPath, reporterOptions }: absolute config path for
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-config.d.ts","sourceRoot":"","sources":["../../src/discovery/trusted-config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"trusted-config.d.ts","sourceRoot":"","sources":["../../src/discovery/trusted-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AAQH,4EAA4E;AAC5E,eAAO,MAAM,mBAAmB,kCAAkC,CAAC;AAEnE,4EAA4E;AAC5E,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAE7E,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,6EAA6E;IAC7E,eAAe,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;;;;;;;;;;;;OAaG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IACxC;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC;;;;;;;;;;;;;;;;;OAiBG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,oEAAoE;AACpE,qBAAa,wBAAyB,SAAQ,KAAK;gBACrC,OAAO,EAAE,MAAM;CAI5B;AAoBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAiDhH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,GAAE,MAAwB,GAAG,MAAM,CAKjF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,kBAAkB,GAAG;IAClE,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,sBAAsB,CAAC;CACzC,CA+KA"}
|
|
@@ -13,7 +13,23 @@
|
|
|
13
13
|
* (from the planned expected set), or the runner default when the
|
|
14
14
|
* caller selected nothing;
|
|
15
15
|
* - projects: bare names carried as data (identity only — per-project
|
|
16
|
-
* code options are NOT honored)
|
|
16
|
+
* code options are NOT honored), each with the files the plan
|
|
17
|
+
* attributed to it, the dependency EDGES the enumeration captured
|
|
18
|
+
* (names only), and the `use.storageState` PATH the enumeration
|
|
19
|
+
* captured for that project. The edges are what makes a `setup`-project
|
|
20
|
+
* config order correctly: Playwright runs a dependency project's tests
|
|
21
|
+
* before the dependent project, which is the only way the dependent
|
|
22
|
+
* test can read the artifact the setup test produced — and the state
|
|
23
|
+
* is what hands that project the session the setup test saved, while
|
|
24
|
+
* the setup project itself keeps running unauthenticated;
|
|
25
|
+
* - storage states: a declared path is resolved from the NATIVE CONFIG
|
|
26
|
+
* DIRECTORY the runner child runs from (so the dependent project reads
|
|
27
|
+
* the very file its own setup project wrote from that same cwd) and is
|
|
28
|
+
* honored only while it lands INSIDE the candidate root, which stays
|
|
29
|
+
* the containment boundary for a nested project too; an
|
|
30
|
+
* operator-provided whole-run state still outranks every project
|
|
31
|
+
* declaration and keeps its own candidate-root meaning (see
|
|
32
|
+
* {@link resolveProjectStorageState});
|
|
17
33
|
* - reporter: the engine's own reporter entry forced by absolute path
|
|
18
34
|
* with run-state paths as CONSTRUCTOR OPTIONS (never env — worker
|
|
19
35
|
* processes must not learn the spool/outcomes locations);
|
|
@@ -36,18 +52,143 @@
|
|
|
36
52
|
*
|
|
37
53
|
* Compatibility limits (honest, not transparent):
|
|
38
54
|
* - consumer `globalSetup`/`globalTeardown` are NOT executed;
|
|
39
|
-
* - consumer reporters, `webServer`, per-project `use` options
|
|
40
|
-
* `testDir`/`testIgnore`
|
|
55
|
+
* - consumer reporters, `webServer`, per-project `use` options other
|
|
56
|
+
* than the captured `storageState` PATH, `testDir`/`testIgnore`
|
|
57
|
+
* scoping, and sharding are NOT honored;
|
|
58
|
+
* - consumer `testMatch` scoping is NOT honored as CONSUMER CODE. What IS
|
|
59
|
+
* honored is the SUPERVISOR'S OWN per-project file selection
|
|
60
|
+
* (`projectScopes`): project identity is the join key the whole pipeline
|
|
61
|
+
* speaks — catalog rows, the registered expected set, session opens, and
|
|
62
|
+
* the execution trace — so file scoping must be per project too. A single
|
|
63
|
+
* global `testMatch` collects every selected file under EVERY project,
|
|
64
|
+
* which is how a `setup`-dependency config (`{ name: 'setup', testMatch:
|
|
65
|
+
* /.*\.setup\.ts/ }` plus a dependent project) ran the whole suite once
|
|
66
|
+
* per project: identities the registered expected set never bound, so
|
|
67
|
+
* their sessions were refused and they lost every piece of evidence.
|
|
68
|
+
* - per-project `teardown` is NOT honored; only `dependencies` is, as
|
|
69
|
+
* ordering data (names only).
|
|
41
70
|
* - tests must be self-contained (app provided externally via the
|
|
42
71
|
* app-base env, as the fixture already requires).
|
|
43
72
|
*/
|
|
44
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
45
|
-
import { join } from 'node:path';
|
|
73
|
+
import { lstatSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
|
|
74
|
+
import { dirname, join, relative, resolve, sep } from 'node:path';
|
|
46
75
|
import { fileURLToPath } from 'node:url';
|
|
76
|
+
import { FREEZE_CONTROLLER_PROJECT } from './prepare-barrier.js';
|
|
47
77
|
/** File name of the synthesized trusted config inside the run-state dir. */
|
|
48
78
|
export const TRUSTED_CONFIG_FILE = 'trusted.playwright.config.mjs';
|
|
49
79
|
/** File name of the forced reporter options (diagnostic mirror of argv). */
|
|
50
80
|
export const TRUSTED_REPORTER_OPTIONS_FILE = 'trusted-reporter-options.json';
|
|
81
|
+
/** Thrown when a project-declared browser state may not be read. */
|
|
82
|
+
export class ProjectStorageStateError extends Error {
|
|
83
|
+
constructor(message) {
|
|
84
|
+
super(message);
|
|
85
|
+
this.name = 'ProjectStorageStateError';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/** A declared state that names a URL scheme rather than a file path. */
|
|
89
|
+
const URL_LIKE = /^[a-zA-Z][a-zA-Z\d+.-]*:/;
|
|
90
|
+
/**
|
|
91
|
+
* True when a path exists as a directory entry — a file, a directory, or
|
|
92
|
+
* a symlink of its own, including one that leads nowhere. Deliberately
|
|
93
|
+
* not `existsSync`, which follows links and would report a dangling one
|
|
94
|
+
* as absent.
|
|
95
|
+
*/
|
|
96
|
+
function isDirectoryEntry(path) {
|
|
97
|
+
try {
|
|
98
|
+
lstatSync(path);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolves one project-declared `use.storageState` and refuses anything
|
|
107
|
+
* a supervised run must not read.
|
|
108
|
+
*
|
|
109
|
+
* A relative path is resolved against the NATIVE CONFIG DIRECTORY —
|
|
110
|
+
* the directory the runner child runs from, exactly the directory
|
|
111
|
+
* `listNativePlaywrightTests` enumerated the suite from: the worker
|
|
112
|
+
* reads the file relative to the process it runs in, which is that very
|
|
113
|
+
* cwd, which is also where the project's own setup test wrote it from.
|
|
114
|
+
* The file itself need not exist yet — the setup project writes it
|
|
115
|
+
* during this run.
|
|
116
|
+
*
|
|
117
|
+
* Containment is the WHOLE CANDIDATE ROOT, not the config directory,
|
|
118
|
+
* and it is PHYSICAL rather than lexical: a symlink inside the
|
|
119
|
+
* candidate that points outside it is refused too, so the check follows
|
|
120
|
+
* the real filesystem from the nearest existing ancestor. A nested
|
|
121
|
+
* project's `../shared/state.json` therefore stays valid whenever it
|
|
122
|
+
* lands back inside the candidate.
|
|
123
|
+
*
|
|
124
|
+
* @param value: the `use.storageState` string the runner resolved.
|
|
125
|
+
* @param root: the candidate root (the containment boundary).
|
|
126
|
+
* @param project: the declaring project, named in the error.
|
|
127
|
+
* @param baseDir: the directory a relative declaration resolves from —
|
|
128
|
+
* the native config directory the runner child runs from.
|
|
129
|
+
*
|
|
130
|
+
* @returns
|
|
131
|
+
* string: the absolute path the declared state resolves to.
|
|
132
|
+
*
|
|
133
|
+
* @throws
|
|
134
|
+
* ProjectStorageStateError: when the value is empty, names a URL, or
|
|
135
|
+
* resolves outside the candidate root either directly or through a
|
|
136
|
+
* link. A requested state is never silently dropped — that would
|
|
137
|
+
* degrade into a logged-out run that looks green.
|
|
138
|
+
*/
|
|
139
|
+
export function resolveProjectStorageState(value, root, project, baseDir) {
|
|
140
|
+
const base = resolve(root);
|
|
141
|
+
const from = resolve(base, baseDir);
|
|
142
|
+
const refuse = (why) => {
|
|
143
|
+
throw new ProjectStorageStateError(`project '${project}' declares use.storageState '${value}', which ${why}. A supervised run reads a ` +
|
|
144
|
+
`browser state only from inside the candidate (root '${base}'), resolving relative paths from the ` +
|
|
145
|
+
`project's config directory '${from}': point the project at a path under the candidate — the ` +
|
|
146
|
+
`standard pattern writes 'playwright/.auth/user.json' from its own setup project — or set ` +
|
|
147
|
+
`GATEFORGE_SESSION_STATE to a whole-run state instead.`);
|
|
148
|
+
};
|
|
149
|
+
if (value.length === 0)
|
|
150
|
+
return refuse('is empty');
|
|
151
|
+
if (URL_LIKE.test(value))
|
|
152
|
+
return refuse('is a URL, not a file path');
|
|
153
|
+
const resolvedPath = resolve(from, value);
|
|
154
|
+
if (resolvedPath !== base && !resolvedPath.startsWith(base + sep)) {
|
|
155
|
+
return refuse(`resolves outside the candidate root ('${resolvedPath}')`);
|
|
156
|
+
}
|
|
157
|
+
// A path that only LOOKS contained is not contained: a symlink inside
|
|
158
|
+
// the candidate can point anywhere on the host, and the worker would
|
|
159
|
+
// follow it. So the check follows the real filesystem from the nearest
|
|
160
|
+
// existing ancestor — the state file itself need not exist yet, the
|
|
161
|
+
// setup project writes it during this run — and compares against the
|
|
162
|
+
// real candidate root. Ancestor lookup uses lstat, NOT existsSync: a
|
|
163
|
+
// link that leads nowhere must be FOUND here and refused below, never
|
|
164
|
+
// stepped over as if it were absent.
|
|
165
|
+
let probe = resolvedPath;
|
|
166
|
+
while (!isDirectoryEntry(probe)) {
|
|
167
|
+
const parent = dirname(probe);
|
|
168
|
+
if (parent === probe)
|
|
169
|
+
return refuse('names no path this host can resolve');
|
|
170
|
+
probe = parent;
|
|
171
|
+
}
|
|
172
|
+
let realBase;
|
|
173
|
+
try {
|
|
174
|
+
realBase = realpathSync(base);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return refuse('cannot be resolved against this host\'s filesystem');
|
|
178
|
+
}
|
|
179
|
+
let realProbe;
|
|
180
|
+
try {
|
|
181
|
+
realProbe = realpathSync(probe);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return refuse('is a link this host cannot resolve');
|
|
185
|
+
}
|
|
186
|
+
const physical = resolve(realProbe, relative(probe, resolvedPath));
|
|
187
|
+
if (physical !== realBase && !physical.startsWith(realBase + sep)) {
|
|
188
|
+
return refuse(`reaches outside the candidate through a link ('${physical}')`);
|
|
189
|
+
}
|
|
190
|
+
return resolvedPath;
|
|
191
|
+
}
|
|
51
192
|
/**
|
|
52
193
|
* Resolves the engine reporter entry the trusted config forces: the
|
|
53
194
|
* pack's own BUILT reporter (the same class the consumer config would
|
|
@@ -70,7 +211,8 @@ export function trustedReporterEntry(fromModule = import.meta.url) {
|
|
|
70
211
|
* Synthesizes the trusted Playwright config into the run-state dir.
|
|
71
212
|
*
|
|
72
213
|
* Args:
|
|
73
|
-
* input: repo root, run state, reporter
|
|
214
|
+
* input: repo root, native config directory, run state, reporter
|
|
215
|
+
* entry, file/project selection, and the operator's whole-run state.
|
|
74
216
|
*
|
|
75
217
|
* Returns:
|
|
76
218
|
* { configPath, reporterOptions }: absolute config path for
|
|
@@ -82,9 +224,123 @@ export function synthesizeTrustedConfig(input) {
|
|
|
82
224
|
runId: input.runId,
|
|
83
225
|
outcomesPath: join(input.stateDir, 'runner-outcomes.json'),
|
|
84
226
|
obligationsPath: join(input.stateDir, 'obligations.json'),
|
|
227
|
+
candidateRoot: input.cwd,
|
|
228
|
+
// The engine's own freeze controller is excluded by ABSOLUTE FILE
|
|
229
|
+
// IDENTITY, handed here as trusted constructor data. Unarmed, the
|
|
230
|
+
// field is absent and the reporter records every test as before.
|
|
231
|
+
...(input.controlSpecPath !== undefined ? { controlSpecPath: input.controlSpecPath } : {}),
|
|
85
232
|
};
|
|
86
233
|
const testFiles = [...new Set(input.testFiles ?? [])].sort();
|
|
87
234
|
const projects = [...new Set(input.projects ?? [])].sort();
|
|
235
|
+
// An operator's whole-run state is resolved HERE, against the candidate
|
|
236
|
+
// root, and emitted absolute: a relative operator path keeps the
|
|
237
|
+
// candidate-root meaning it always had, whatever cwd the native child
|
|
238
|
+
// runs from. (An absolute value passes through unchanged — the
|
|
239
|
+
// operator's own path, never re-anchored.)
|
|
240
|
+
const operatorState = input.storageState === undefined ? undefined : resolve(input.cwd, input.storageState);
|
|
241
|
+
// Every project-declared storage state is resolved and checked BEFORE
|
|
242
|
+
// anything is written: a state a supervised run may not read refuses
|
|
243
|
+
// the run outright, because silently dropping it would leave the
|
|
244
|
+
// project logged out and still call the run green. Relative
|
|
245
|
+
// declarations resolve from the NATIVE CONFIG DIRECTORY (the child's
|
|
246
|
+
// cwd, where the setup test wrote the file), while containment stays
|
|
247
|
+
// the whole candidate root. Under an operator's whole-run state the
|
|
248
|
+
// declarations are not used at all, so they are neither read nor
|
|
249
|
+
// checked — precedence means the losing value never reaches the
|
|
250
|
+
// filesystem.
|
|
251
|
+
if (operatorState === undefined) {
|
|
252
|
+
for (const scope of input.projectScopes ?? []) {
|
|
253
|
+
if (scope.storageState !== undefined) {
|
|
254
|
+
resolveProjectStorageState(scope.storageState, input.cwd, scope.name, input.nativeConfigDir ?? input.cwd);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// Per-project file selection. Each project carries exactly the files the
|
|
259
|
+
// plan attributed to it, so a project-scoped consumer config (the standard
|
|
260
|
+
// `setup`-project auth pattern) does not have every selected file collected
|
|
261
|
+
// under every project. Files no project scope claims stay in the global
|
|
262
|
+
// `testMatch` — a project-less plan row must still execute. Scoping only
|
|
263
|
+
// changes what runs when TWO or more projects share the config: with one
|
|
264
|
+
// project the global `testMatch` selects the identical set, so a
|
|
265
|
+
// single-project run keeps exactly the old one-global-`testMatch` config.
|
|
266
|
+
// A project's declared state travels with it — except under an
|
|
267
|
+
// operator-provided WHOLE-RUN state, which has always outranked
|
|
268
|
+
// everything the config declared and keeps doing so: that state is
|
|
269
|
+
// emitted once as the global `use`, and no per-project state is emitted
|
|
270
|
+
// beside it. A project that declares nothing keeps no `use` at all and
|
|
271
|
+
// therefore runs logged out, which is exactly what the `setup` project
|
|
272
|
+
// of the standard pattern needs.
|
|
273
|
+
const scopedProjects = (input.projectScopes ?? [])
|
|
274
|
+
.map((scope) => ({
|
|
275
|
+
name: scope.name,
|
|
276
|
+
files: [...new Set(scope.files)].sort(),
|
|
277
|
+
// Carried through so the synthesized project can actually collect
|
|
278
|
+
// from it; a dropped field would make the engine's freeze controller
|
|
279
|
+
// look for its spec under the repo root and find nothing.
|
|
280
|
+
...(scope.testDir === undefined ? {} : { testDir: scope.testDir }),
|
|
281
|
+
dependencies: scope.dependencies ?? [],
|
|
282
|
+
...(operatorState === undefined && scope.storageState !== undefined
|
|
283
|
+
? { storageState: scope.storageState }
|
|
284
|
+
: {}),
|
|
285
|
+
}))
|
|
286
|
+
.filter((scope) => scope.name.length > 0 && scope.files.length > 0)
|
|
287
|
+
.sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));
|
|
288
|
+
const projectScopes = scopedProjects.length >= 2 ? scopedProjects : [];
|
|
289
|
+
// One surviving scope runs its files under that project alone — a named
|
|
290
|
+
// project that owns no file must not collect them a second time. Its
|
|
291
|
+
// declared state still rides along: that path emits no per-project
|
|
292
|
+
// `testMatch`, and dropping the state with it would log out the very
|
|
293
|
+
// project a narrowed run kept.
|
|
294
|
+
const loneScope = scopedProjects.length === 1 ? scopedProjects[0] : undefined;
|
|
295
|
+
const plainProjects = loneScope !== undefined ? [loneScope.name] : projects;
|
|
296
|
+
const scopedFiles = new Set(projectScopes.flatMap((scope) => scope.files));
|
|
297
|
+
const unscopedFiles = testFiles.filter((file) => !scopedFiles.has(file));
|
|
298
|
+
// Dependency edges are carried as the runner resolved them (names
|
|
299
|
+
// only) and filtered to the projects this config actually defines:
|
|
300
|
+
// Playwright REFUSES to load a config whose `dependencies` names a
|
|
301
|
+
// project it does not declare, so a dangling edge would fail the whole
|
|
302
|
+
// run instead of merely losing an ordering. An edge to a project with
|
|
303
|
+
// no files is dropped with it, for the same reason. Projects with no
|
|
304
|
+
// edges at all emit no `dependencies` key, so a single-project run
|
|
305
|
+
// stays byte-identical.
|
|
306
|
+
const scopedNames = new Set(projectScopes.map((scope) => scope.name));
|
|
307
|
+
// Whether this config carries the engine's preparation-freeze
|
|
308
|
+
// controller. Its presence is what makes the dependency emission below
|
|
309
|
+
// order-aware; every config without it emits exactly what it always did.
|
|
310
|
+
const freezeArmed = projectScopes.some((scope) => scope.name === FREEZE_CONTROLLER_PROJECT);
|
|
311
|
+
const synthesizedProjects = projectScopes.map((scope) => {
|
|
312
|
+
const captured = [
|
|
313
|
+
...new Set(scope.dependencies.filter((name) => scopedNames.has(name) && name !== scope.name)),
|
|
314
|
+
].sort();
|
|
315
|
+
// ARMED (the global preparation freeze is in this config): the
|
|
316
|
+
// controller is emitted FIRST, explicitly, and the project's own
|
|
317
|
+
// captured edges follow in their existing sorted order. Sorting the
|
|
318
|
+
// whole array instead would silently move the controller behind any
|
|
319
|
+
// prerequisite that sorts before it, and the extra-environment union
|
|
320
|
+
// the native scheduler builds over `project.deps` is positional with
|
|
321
|
+
// later entries winning — so where the controller lands decides which
|
|
322
|
+
// environment a body actually starts with. UNARMED keeps the exact
|
|
323
|
+
// pre-existing emission, so every run without the barrier stays
|
|
324
|
+
// byte-identical.
|
|
325
|
+
const edges = freezeArmed
|
|
326
|
+
? captured.includes(FREEZE_CONTROLLER_PROJECT)
|
|
327
|
+
? [FREEZE_CONTROLLER_PROJECT, ...captured.filter((name) => name !== FREEZE_CONTROLLER_PROJECT)]
|
|
328
|
+
: captured
|
|
329
|
+
: captured;
|
|
330
|
+
return {
|
|
331
|
+
name: scope.name,
|
|
332
|
+
testMatch: scope.files,
|
|
333
|
+
// A project with its OWN `testDir` (the engine's freeze controller)
|
|
334
|
+
// collects from there; every consumer project stays on the config's
|
|
335
|
+
// repo-root `testDir`, exactly as before.
|
|
336
|
+
...(scope.testDir === undefined ? {} : { testDir: scope.testDir }),
|
|
337
|
+
...(edges.length > 0 ? { dependencies: edges } : {}),
|
|
338
|
+
// The declared state, for THIS project only. It rides in `use`
|
|
339
|
+
// rather than at the top level so the `setup` project that writes
|
|
340
|
+
// the file keeps running with no session at all.
|
|
341
|
+
...(scope.storageState === undefined ? {} : { use: { storageState: scope.storageState } }),
|
|
342
|
+
};
|
|
343
|
+
});
|
|
88
344
|
const lines = [
|
|
89
345
|
'// GENERATED by gateforge trusted supervision — do not edit. The',
|
|
90
346
|
'// consumer config file is NEVER loaded for supervised runs: it is',
|
|
@@ -92,8 +348,21 @@ export function synthesizeTrustedConfig(input) {
|
|
|
92
348
|
'// spool and outcomes document this reporter writes.',
|
|
93
349
|
'export default {',
|
|
94
350
|
` testDir: ${JSON.stringify(input.cwd)},`,
|
|
95
|
-
...(
|
|
96
|
-
...(
|
|
351
|
+
...(unscopedFiles.length > 0 ? [` testMatch: ${JSON.stringify(unscopedFiles)},`] : []),
|
|
352
|
+
...(projectScopes.length > 0
|
|
353
|
+
? [
|
|
354
|
+
` projects: ${JSON.stringify(synthesizedProjects)},`,
|
|
355
|
+
]
|
|
356
|
+
: plainProjects.length > 0
|
|
357
|
+
? [
|
|
358
|
+
` projects: ${JSON.stringify(plainProjects.map((name) => ({
|
|
359
|
+
name,
|
|
360
|
+
...(loneScope?.name === name && loneScope.storageState !== undefined
|
|
361
|
+
? { use: { storageState: loneScope.storageState } }
|
|
362
|
+
: {}),
|
|
363
|
+
})))},`,
|
|
364
|
+
]
|
|
365
|
+
: []),
|
|
97
366
|
' workers: 1,',
|
|
98
367
|
' fullyParallel: false,',
|
|
99
368
|
' retries: 0,',
|
|
@@ -107,7 +376,7 @@ export function synthesizeTrustedConfig(input) {
|
|
|
107
376
|
headless: true,
|
|
108
377
|
trace: 'off',
|
|
109
378
|
...(input.appBaseUrl !== undefined ? { baseURL: input.appBaseUrl } : {}),
|
|
110
|
-
...(
|
|
379
|
+
...(operatorState !== undefined ? { storageState: operatorState } : {}),
|
|
111
380
|
})},`,
|
|
112
381
|
` outputDir: ${JSON.stringify(join(input.stateDir, 'playwright-artifacts'))},`,
|
|
113
382
|
'};',
|
|
@@ -116,7 +385,7 @@ export function synthesizeTrustedConfig(input) {
|
|
|
116
385
|
mkdirSync(input.stateDir, { recursive: true });
|
|
117
386
|
const configPath = join(input.stateDir, TRUSTED_CONFIG_FILE);
|
|
118
387
|
writeFileSync(configPath, `${lines.join('\n')}`, 'utf8');
|
|
119
|
-
writeFileSync(join(input.stateDir, TRUSTED_REPORTER_OPTIONS_FILE), `${JSON.stringify({ configPath, reporterEntry: input.reporterEntry, reporterOptions, testFiles, projects }, null, 2)}\n`, 'utf8');
|
|
388
|
+
writeFileSync(join(input.stateDir, TRUSTED_REPORTER_OPTIONS_FILE), `${JSON.stringify({ configPath, reporterEntry: input.reporterEntry, reporterOptions, testFiles, projects, projectScopes }, null, 2)}\n`, 'utf8');
|
|
120
389
|
return { configPath, reporterOptions };
|
|
121
390
|
}
|
|
122
391
|
//# sourceMappingURL=trusted-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"trusted-config.js","sourceRoot":"","sources":["../../src/discovery/trusted-config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"trusted-config.js","sourceRoot":"","sources":["../../src/discovery/trusted-config.ts"],"names":[],"mappings":"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"}
|