@gate-forge/pack-playwright 0.1.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 (140) hide show
  1. package/LICENSE +202 -0
  2. package/bin/gateforge-witness.js +40 -0
  3. package/dist/attestation/proxy.d.ts +40 -0
  4. package/dist/attestation/proxy.d.ts.map +1 -0
  5. package/dist/attestation/proxy.js +78 -0
  6. package/dist/attestation/proxy.js.map +1 -0
  7. package/dist/constants.d.ts +130 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +138 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/discovery/adapters.d.ts +167 -0
  12. package/dist/discovery/adapters.d.ts.map +1 -0
  13. package/dist/discovery/adapters.js +276 -0
  14. package/dist/discovery/adapters.js.map +1 -0
  15. package/dist/discovery/discover.d.ts +57 -0
  16. package/dist/discovery/discover.d.ts.map +1 -0
  17. package/dist/discovery/discover.js +544 -0
  18. package/dist/discovery/discover.js.map +1 -0
  19. package/dist/discovery/index.d.ts +15 -0
  20. package/dist/discovery/index.d.ts.map +1 -0
  21. package/dist/discovery/index.js +15 -0
  22. package/dist/discovery/index.js.map +1 -0
  23. package/dist/discovery/inference.d.ts +63 -0
  24. package/dist/discovery/inference.d.ts.map +1 -0
  25. package/dist/discovery/inference.js +173 -0
  26. package/dist/discovery/inference.js.map +1 -0
  27. package/dist/discovery/pytest-adapter.d.ts +205 -0
  28. package/dist/discovery/pytest-adapter.d.ts.map +1 -0
  29. package/dist/discovery/pytest-adapter.js +548 -0
  30. package/dist/discovery/pytest-adapter.js.map +1 -0
  31. package/dist/discovery/reconcile.d.ts +106 -0
  32. package/dist/discovery/reconcile.d.ts.map +1 -0
  33. package/dist/discovery/reconcile.js +268 -0
  34. package/dist/discovery/reconcile.js.map +1 -0
  35. package/dist/discovery/runner-env.d.ts +80 -0
  36. package/dist/discovery/runner-env.d.ts.map +1 -0
  37. package/dist/discovery/runner-env.js +139 -0
  38. package/dist/discovery/runner-env.js.map +1 -0
  39. package/dist/discovery/static-discovery.d.ts +121 -0
  40. package/dist/discovery/static-discovery.d.ts.map +1 -0
  41. package/dist/discovery/static-discovery.js +1028 -0
  42. package/dist/discovery/static-discovery.js.map +1 -0
  43. package/dist/discovery/supervised-run.d.ts +110 -0
  44. package/dist/discovery/supervised-run.d.ts.map +1 -0
  45. package/dist/discovery/supervised-run.js +328 -0
  46. package/dist/discovery/supervised-run.js.map +1 -0
  47. package/dist/discovery/trusted-config.d.ts +103 -0
  48. package/dist/discovery/trusted-config.d.ts.map +1 -0
  49. package/dist/discovery/trusted-config.js +117 -0
  50. package/dist/discovery/trusted-config.js.map +1 -0
  51. package/dist/fixture/evidence.d.ts +191 -0
  52. package/dist/fixture/evidence.d.ts.map +1 -0
  53. package/dist/fixture/evidence.js +366 -0
  54. package/dist/fixture/evidence.js.map +1 -0
  55. package/dist/fixture/fixture.d.ts +37 -0
  56. package/dist/fixture/fixture.d.ts.map +1 -0
  57. package/dist/fixture/fixture.js +38 -0
  58. package/dist/fixture/fixture.js.map +1 -0
  59. package/dist/fixture/witness-client.d.ts +164 -0
  60. package/dist/fixture/witness-client.d.ts.map +1 -0
  61. package/dist/fixture/witness-client.js +253 -0
  62. package/dist/fixture/witness-client.js.map +1 -0
  63. package/dist/index.d.ts +64 -0
  64. package/dist/index.d.ts.map +1 -0
  65. package/dist/index.js +55 -0
  66. package/dist/index.js.map +1 -0
  67. package/dist/json.d.ts +16 -0
  68. package/dist/json.d.ts.map +1 -0
  69. package/dist/json.js +21 -0
  70. package/dist/json.js.map +1 -0
  71. package/dist/reporter/ledger.d.ts +105 -0
  72. package/dist/reporter/ledger.d.ts.map +1 -0
  73. package/dist/reporter/ledger.js +197 -0
  74. package/dist/reporter/ledger.js.map +1 -0
  75. package/dist/reporter/reporter.cjs +105 -0
  76. package/dist/reporter/reporter.cjs.map +1 -0
  77. package/dist/reporter/reporter.d.cts +35 -0
  78. package/dist/reporter/reporter.d.cts.map +1 -0
  79. package/dist/reporter/reporter.d.ts +167 -0
  80. package/dist/reporter/reporter.d.ts.map +1 -0
  81. package/dist/reporter/reporter.js +673 -0
  82. package/dist/reporter/reporter.js.map +1 -0
  83. package/dist/setup.d.ts +49 -0
  84. package/dist/setup.d.ts.map +1 -0
  85. package/dist/setup.js +167 -0
  86. package/dist/setup.js.map +1 -0
  87. package/dist/supervisor/client.d.ts +73 -0
  88. package/dist/supervisor/client.d.ts.map +1 -0
  89. package/dist/supervisor/client.js +164 -0
  90. package/dist/supervisor/client.js.map +1 -0
  91. package/dist/supervisor/drain.d.ts +45 -0
  92. package/dist/supervisor/drain.d.ts.map +1 -0
  93. package/dist/supervisor/drain.js +235 -0
  94. package/dist/supervisor/drain.js.map +1 -0
  95. package/dist/supervisor/index.d.ts +16 -0
  96. package/dist/supervisor/index.d.ts.map +1 -0
  97. package/dist/supervisor/index.js +13 -0
  98. package/dist/supervisor/index.js.map +1 -0
  99. package/dist/supervisor/spool.d.ts +137 -0
  100. package/dist/supervisor/spool.d.ts.map +1 -0
  101. package/dist/supervisor/spool.js +263 -0
  102. package/dist/supervisor/spool.js.map +1 -0
  103. package/dist/surface.d.ts +134 -0
  104. package/dist/surface.d.ts.map +1 -0
  105. package/dist/surface.js +139 -0
  106. package/dist/surface.js.map +1 -0
  107. package/dist/witness/adapter-registry.d.ts +38 -0
  108. package/dist/witness/adapter-registry.d.ts.map +1 -0
  109. package/dist/witness/adapter-registry.js +158 -0
  110. package/dist/witness/adapter-registry.js.map +1 -0
  111. package/dist/witness/bin.d.ts +21 -0
  112. package/dist/witness/bin.d.ts.map +1 -0
  113. package/dist/witness/bin.js +172 -0
  114. package/dist/witness/bin.js.map +1 -0
  115. package/dist/witness/browser.d.ts +173 -0
  116. package/dist/witness/browser.d.ts.map +1 -0
  117. package/dist/witness/browser.js +580 -0
  118. package/dist/witness/browser.js.map +1 -0
  119. package/dist/witness/classifications.d.ts +42 -0
  120. package/dist/witness/classifications.d.ts.map +1 -0
  121. package/dist/witness/classifications.js +87 -0
  122. package/dist/witness/classifications.js.map +1 -0
  123. package/dist/witness/env-attestation.d.ts +98 -0
  124. package/dist/witness/env-attestation.d.ts.map +1 -0
  125. package/dist/witness/env-attestation.js +202 -0
  126. package/dist/witness/env-attestation.js.map +1 -0
  127. package/dist/witness/loopback-pins.d.ts +79 -0
  128. package/dist/witness/loopback-pins.d.ts.map +1 -0
  129. package/dist/witness/loopback-pins.js +244 -0
  130. package/dist/witness/loopback-pins.js.map +1 -0
  131. package/dist/witness/server.d.ts +34 -0
  132. package/dist/witness/server.d.ts.map +1 -0
  133. package/dist/witness/server.js +2539 -0
  134. package/dist/witness/server.js.map +1 -0
  135. package/dist/witness/types.d.ts +643 -0
  136. package/dist/witness/types.d.ts.map +1 -0
  137. package/dist/witness/types.js +2 -0
  138. package/dist/witness/types.js.map +1 -0
  139. package/package.json +64 -0
  140. package/python/gateforge_persistence_intents.py +100 -0
@@ -0,0 +1,548 @@
1
+ /**
2
+ * Bounded pytest diagnostic adapter (plan 2026-09-13 §3.5, phase 2 item
3
+ * 8 + Phase 4 item 9). pytest is a runner, not a test category: its
4
+ * suites power the advisory "red means inspect this" alarm and NEVER
5
+ * supply E2E proof.
6
+ *
7
+ * Hard bounds, all fail-closed:
8
+ * - The adapter only ever composes the CONFIGURED argv (interpreter +
9
+ * args from `diagnostics.suites[]`), appending collection/report
10
+ * flags. It never scans directories for executables and never runs a
11
+ * command it did not compose from config.
12
+ * - Every invocation carries a finite timeout (`timeoutMs` from the
13
+ * suite config); on expiry the child is killed and a typed timeout is
14
+ * reported — an incomplete/unavailable run, never a passing one.
15
+ * - Collection prefers structured output: `--collect-only -q` node ids;
16
+ * execution outcomes come from native junit XML ({@link parseJunitXml})
17
+ * written into the EXCLUDED run-state dir, never tracked inputs.
18
+ * - Diagnostic execution (Phase 4) runs each suite ONCE in an isolated
19
+ * process with every `GATEFORGE_*` variable stripped, and the result
20
+ * is DIAGNOSTIC data: it is never fed into claims, witness records,
21
+ * baselines, waivers, or E2E satisfaction (§3.5).
22
+ */
23
+ import { spawn } from 'node:child_process';
24
+ import { existsSync, readFileSync } from 'node:fs';
25
+ import { isAbsolute, join, relative } from 'node:path';
26
+ import { TestDiscoveryError, untrustedEnv } from './reconcile.js';
27
+ /**
28
+ * Composes the collection argv for a configured suite: the configured
29
+ * interpreter/args verbatim, then `--collect-only -q`, then the
30
+ * configured testPaths. Nothing else — no directory guessing, no extra
31
+ * commands beyond the configured argv + collection flags.
32
+ *
33
+ * Args:
34
+ * suite: the configured diagnostic suite.
35
+ *
36
+ * Returns:
37
+ * string[]: argv to spawn with cwd = repo root (the adapter passes the
38
+ * suite's own testPaths, which are repo-root-relative and resolved by
39
+ * the caller's cwd choice).
40
+ */
41
+ export function pytestCollectArgv(suite) {
42
+ return [...suite.argv, '--collect-only', '-q', ...suite.testPaths];
43
+ }
44
+ /**
45
+ * Composes the Phase 4 diagnostic EXECUTION argv (junit XML into the
46
+ * EXCLUDED run-state dir). Exported now so the composition is tested;
47
+ * invoking it is Phase 4 work.
48
+ *
49
+ * Args:
50
+ * suite: the configured diagnostic suite.
51
+ * stateDir: absolute run-state directory (excluded from inputs).
52
+ *
53
+ * Returns:
54
+ * string[]: argv running the suite with a junitxml report at
55
+ * `<stateDir>/diagnostics/<suite.name>.xml`.
56
+ */
57
+ export function pytestExecutionArgv(suite, stateDir) {
58
+ const reportPath = join(stateDir, 'diagnostics', `${suite.name}.xml`);
59
+ return [...suite.argv, `--junitxml=${reportPath}`, ...suite.testPaths];
60
+ }
61
+ /** Matches a `--collect-only -q` output line that is a pytest node id. */
62
+ function isNodeIdLine(line) {
63
+ return line.includes('::') && !line.startsWith('=') && !line.startsWith(' ') && !line.startsWith('\t');
64
+ }
65
+ /**
66
+ * Runs one bounded collection for a configured suite. The child runs as
67
+ * UNTRUSTED consumer code (all `GATEFORGE_*` env stripped — same trust
68
+ * boundary as playwright enumeration) with the suite's finite timeout.
69
+ *
70
+ * Args:
71
+ * suite: the configured suite (argv, testPaths, timeoutMs).
72
+ * cwd: absolute repo root the repo-relative testPaths resolve against.
73
+ *
74
+ * Returns:
75
+ * Promise<PytestCollectionResult>: collected node ids or an
76
+ * unavailable verdict — collection failure is data (§3.5: show
77
+ * incomplete status), never a fabricated empty success.
78
+ */
79
+ export async function collectPytestSuite(suite, cwd) {
80
+ const argv = pytestCollectArgv(suite);
81
+ const child = spawn(argv[0] ?? '', argv.slice(1), {
82
+ cwd,
83
+ env: untrustedEnv(process.env),
84
+ stdio: ['ignore', 'pipe', 'pipe'],
85
+ });
86
+ const outcome = await new Promise((settle) => {
87
+ let stdout = '';
88
+ let stderr = '';
89
+ let timedOut = false;
90
+ const timer = setTimeout(() => {
91
+ timedOut = true;
92
+ child.kill('SIGKILL');
93
+ }, suite.timeoutMs);
94
+ child.stdout?.on('data', (chunk) => {
95
+ stdout += chunk.toString('utf8');
96
+ });
97
+ child.stderr?.on('data', (chunk) => {
98
+ stderr += chunk.toString('utf8');
99
+ });
100
+ child.once('error', (error) => {
101
+ clearTimeout(timer);
102
+ settle({ code: null, stdout, stderr, timedOut: false, error });
103
+ });
104
+ child.once('exit', (code) => {
105
+ clearTimeout(timer);
106
+ settle({ code, stdout, stderr, timedOut, error: null });
107
+ });
108
+ });
109
+ if (outcome.timedOut) {
110
+ return {
111
+ status: 'unavailable',
112
+ detail: `suite '${suite.name}' collection exceeded its ${String(suite.timeoutMs)}ms timeout and was killed`,
113
+ cases: [],
114
+ collectionErrors: [],
115
+ exitCode: null,
116
+ };
117
+ }
118
+ if (outcome.error !== null) {
119
+ return {
120
+ status: 'unavailable',
121
+ detail: `suite '${suite.name}' collection failed to start (${suite.argv[0] ?? ''}): ${outcome.error.message}`,
122
+ cases: [],
123
+ collectionErrors: [],
124
+ exitCode: null,
125
+ };
126
+ }
127
+ const nodeIds = [...new Set(outcome.stdout
128
+ .split('\n')
129
+ .map((line) => line.trim())
130
+ .filter((line) => isNodeIdLine(line)))].sort();
131
+ const collectionErrors = outcome.code !== 0
132
+ ? [...new Set((outcome.stderr + '\n' + outcome.stdout)
133
+ .split('\n')
134
+ .filter((line) => /ERROR|error/i.test(line))
135
+ .map((line) => line.trim().slice(0, 300)))].sort()
136
+ : [];
137
+ if (nodeIds.length === 0 && (outcome.code !== 0 || collectionErrors.length > 0)) {
138
+ const firstError = collectionErrors[0];
139
+ return {
140
+ status: 'unavailable',
141
+ detail: `suite '${suite.name}' collected no tests (exit ${String(outcome.code)}): ` +
142
+ (firstError !== undefined ? `first error: ${firstError}` : 'no structured output'),
143
+ cases: [],
144
+ collectionErrors,
145
+ exitCode: outcome.code,
146
+ };
147
+ }
148
+ return {
149
+ status: 'discovered',
150
+ detail: `suite '${suite.name}' collection enumerated ${String(nodeIds.length)} case(s) via configured argv`,
151
+ cases: nodeIds.map((nodeId) => {
152
+ const segments = nodeId.split('::');
153
+ return {
154
+ nodeId,
155
+ file: (segments[0] ?? nodeId).split('\\').join('/'),
156
+ titlePath: segments.slice(1),
157
+ };
158
+ }),
159
+ collectionErrors,
160
+ exitCode: outcome.code,
161
+ };
162
+ }
163
+ /** Typed parser failure for malformed junit XML (fail closed). */
164
+ export class JunitParseError extends Error {
165
+ constructor(message) {
166
+ super(message);
167
+ this.name = 'JunitParseError';
168
+ }
169
+ }
170
+ /**
171
+ * Parses one attr="value" group into a record, tolerating the
172
+ * whitespace separators between attributes. Anything else (unterminated
173
+ * or malformed attributes) throws.
174
+ */
175
+ function parseAttributes(text, tagName) {
176
+ const attributes = {};
177
+ const pattern = /([A-Za-z_:][A-Za-z0-9_:.-]*)="([^"]*)"/g;
178
+ const whitespace = /\s*/gy;
179
+ let consumed = 0;
180
+ whitespace.lastIndex = consumed;
181
+ const spaceMatch = whitespace.exec(text);
182
+ if (spaceMatch !== null)
183
+ consumed = whitespace.lastIndex;
184
+ let match;
185
+ while ((match = pattern.exec(text)) !== null) {
186
+ if (match.index !== consumed) {
187
+ throw new JunitParseError(`malformed attribute text in <${tagName}>: '${text.slice(consumed, match.index)}'`);
188
+ }
189
+ attributes[match[1] ?? ''] = match[2] ?? '';
190
+ consumed = pattern.lastIndex;
191
+ whitespace.lastIndex = consumed;
192
+ const trailing = whitespace.exec(text);
193
+ if (trailing !== null)
194
+ consumed = whitespace.lastIndex;
195
+ }
196
+ if (consumed !== text.length) {
197
+ throw new JunitParseError(`malformed attribute text in <${tagName}>: '${text.slice(consumed)}'`);
198
+ }
199
+ return attributes;
200
+ }
201
+ /**
202
+ * Extracts the inner text of an element body up to the given end tag.
203
+ */
204
+ function innerText(xml, from, endTag) {
205
+ const end = xml.indexOf(endTag, from);
206
+ if (end < 0)
207
+ throw new JunitParseError(`missing ${endTag}`);
208
+ return xml.slice(from, end);
209
+ }
210
+ /**
211
+ * Parses a pytest junit-XML document into structured outcomes (plan
212
+ * phase 2 item 8: prefer structured results over parsing terminal
213
+ * colors). Bounded and strict: the parser understands the exact subset
214
+ * pytest emits (`<testsuite>` with `<testcase>` children carrying
215
+ * `<failure>`, `<error>`, or `<skipped type="...">` children) and THROWS
216
+ * (`JunitParseError`) on anything else — a malformed report is never
217
+ * silently read as a green run. xfail appears as `skipped` with
218
+ * `type="pytest.xfail"`; collection errors appear as testcases named
219
+ * `pytest_collection` with an `<error>` child.
220
+ *
221
+ * Args:
222
+ * xml: the junit-XML document text.
223
+ *
224
+ * Returns:
225
+ * JunitDocument: suite counters + one row per testcase.
226
+ *
227
+ * Throws:
228
+ * JunitParseError: on missing/malformed structure (fail closed).
229
+ */
230
+ export function parseJunitXml(xml) {
231
+ // The `<testsuite` literal must not match the `<testsuites>` wrapper
232
+ // pytest emits (the `(?![a-zA-Z])` boundary rejects the `s`), or every
233
+ // real document would fail attribute parsing and look "unparsable".
234
+ // Self-closing empty suite (zero tests) first — the open-tag pattern
235
+ // would otherwise swallow the closing slash into its attribute text.
236
+ const emptyMatch = /<testsuite(?![a-zA-Z])[^>]*?\/>/.exec(xml);
237
+ if (emptyMatch !== null) {
238
+ const attributes = parseAttributes((/<testsuite(?![a-zA-Z])([^>]*?)\/>/.exec(xml)?.[1]) ?? '', 'testsuite');
239
+ return {
240
+ suiteName: attributes['name'] ?? '',
241
+ tests: Number(attributes['tests'] ?? '0'),
242
+ failures: Number(attributes['failures'] ?? '0'),
243
+ errors: Number(attributes['errors'] ?? '0'),
244
+ skipped: Number(attributes['skipped'] ?? '0'),
245
+ cases: [],
246
+ };
247
+ }
248
+ const suiteMatch = /<testsuite(?![a-zA-Z])([^>]*)>/.exec(xml);
249
+ if (suiteMatch === null) {
250
+ throw new JunitParseError('no <testsuite> element found');
251
+ }
252
+ const suiteAttributes = parseAttributes(suiteMatch[1] ?? '', 'testsuite');
253
+ const bodyStart = (suiteMatch.index ?? 0) + suiteMatch[0].length;
254
+ const body = innerText(xml, bodyStart, '</testsuite>');
255
+ const cases = [];
256
+ const casePattern = /<testcase([^>]*?)(\/>|>([\s\S]*?)<\/testcase>)/g;
257
+ let match;
258
+ while ((match = casePattern.exec(body)) !== null) {
259
+ const attributes = parseAttributes(match[1] ?? '', 'testcase');
260
+ const childXml = match[3];
261
+ let outcome = 'passed';
262
+ let skipType;
263
+ let message;
264
+ if (childXml !== undefined) {
265
+ if (/<failure/.test(childXml)) {
266
+ outcome = 'failed';
267
+ message = firstLineOf(childXml, '<failure');
268
+ }
269
+ else if (/<error/.test(childXml)) {
270
+ outcome = 'error';
271
+ message = firstLineOf(childXml, '<error');
272
+ }
273
+ else if (/<skipped/.test(childXml)) {
274
+ outcome = 'skipped';
275
+ // Lazy capture + optional slash: pytest emits self-closing
276
+ // `<skipped type="..." message="" />`; a greedy `[^>]*` would
277
+ // swallow the trailing `/' and break attribute parsing (which
278
+ // would mark every xfail-bearing report unparsable).
279
+ const skipMatch = /<skipped\b([^>]*?)\/?>/.exec(childXml);
280
+ const skipAttributes = skipMatch === null ? {} : parseAttributes(skipMatch[1] ?? '', 'skipped');
281
+ skipType = skipAttributes['type'];
282
+ message = skipAttributes['message'];
283
+ }
284
+ else {
285
+ throw new JunitParseError(`unsupported <testcase> child content for '${attributes['name'] ?? ''}'`);
286
+ }
287
+ }
288
+ cases.push({
289
+ classname: attributes['classname'] ?? '',
290
+ name: attributes['name'] ?? '',
291
+ outcome,
292
+ ...(skipType !== undefined ? { skipType } : {}),
293
+ ...(message !== undefined ? { message } : {}),
294
+ ...(attributes['file'] !== undefined && attributes['file'] !== '' ? { file: attributes['file'] } : {}),
295
+ });
296
+ }
297
+ return {
298
+ suiteName: suiteAttributes['name'] ?? '',
299
+ tests: Number(suiteAttributes['tests'] ?? String(cases.length)),
300
+ failures: Number(suiteAttributes['failures'] ?? '0'),
301
+ errors: Number(suiteAttributes['errors'] ?? '0'),
302
+ skipped: Number(suiteAttributes['skipped'] ?? '0'),
303
+ cases,
304
+ };
305
+ }
306
+ /** First-line message of a failure/error child, tag attribute first. */
307
+ function firstLineOf(childXml, tag) {
308
+ const match = new RegExp(`${tag}([^>]*)>([\\s\\S]*?)<`).exec(childXml);
309
+ if (match === null)
310
+ return undefined;
311
+ const attributes = parseAttributes(match[1] ?? '', tag.slice(1));
312
+ const text = (attributes['message'] ?? match[2] ?? '').trim();
313
+ return text.length === 0 ? undefined : text.split('\n')[0];
314
+ }
315
+ /**
316
+ * Repo-relative form of `path` against `cwd` (absolute inputs only by
317
+ * contract; relative pass through normalized).
318
+ */
319
+ export function repoRelative(cwd, path) {
320
+ return (isAbsolute(path) ? relative(cwd, path) : path).split('\\').join('/');
321
+ }
322
+ /**
323
+ * Executes one configured diagnostic suite ONCE (plan Phase 4 item 9, §3.5):
324
+ * an isolated process (every `GATEFORGE_*` variable stripped), the
325
+ * configured argv + a junit-XML report into the EXCLUDED run-state dir,
326
+ * and a finite timeout. The result is advisory diagnostic data — it is
327
+ * never witness evidence and never satisfies an E2E obligation.
328
+ *
329
+ * Exit semantics (plan §3.5 / pytest exit codes):
330
+ * - `completed`: run finished, ≥1 passed, no unexpected failures;
331
+ * - `failures`: the run finished with test failures;
332
+ * - `incomplete`: collection/setup error, timeout, missing interpreter,
333
+ * interruption, zero tests, or a run of ONLY skipped/xfail cases —
334
+ * never displayed as a passing diagnostic run.
335
+ *
336
+ * Args:
337
+ * suite: the configured suite (argv, testPaths, timeoutMs).
338
+ * repoRoot: absolute repo root (suite.cwd resolves against it).
339
+ * stateDir: absolute run-state directory (excluded from inputs); the
340
+ * junit report lands at `<stateDir>/diagnostics/<suite.name>.xml`.
341
+ *
342
+ * Returns:
343
+ * Promise<DiagnosticRunResult>: the structured diagnostic result.
344
+ */
345
+ export async function executePytestSuite(suite, repoRoot, stateDir) {
346
+ const reportPath = join(stateDir, 'diagnostics', `${suite.name}.xml`);
347
+ const argv = pytestExecutionArgv(suite, stateDir);
348
+ const base = {
349
+ suite: suite.name,
350
+ status: 'incomplete',
351
+ exitCode: null,
352
+ timedOut: false,
353
+ spawnError: null,
354
+ collectionErrors: [],
355
+ selectedScope: [...suite.testPaths],
356
+ nodeIds: [],
357
+ cases: [],
358
+ counts: { passed: 0, failed: 0, errors: 0, skipped: 0, xfailed: 0 },
359
+ complete: false,
360
+ incompleteDetail: null,
361
+ causes: [],
362
+ reportPath,
363
+ reportExists: existsSync(reportPath),
364
+ reportUnparsable: false,
365
+ };
366
+ const child = spawn(argv[0] ?? '', argv.slice(1), {
367
+ cwd: join(repoRoot, suite.cwd),
368
+ env: untrustedEnv(process.env),
369
+ stdio: ['ignore', 'pipe', 'pipe'],
370
+ });
371
+ const outcome = await new Promise((settle) => {
372
+ let stdout = '';
373
+ let stderr = '';
374
+ let timedOut = false;
375
+ const timer = setTimeout(() => {
376
+ timedOut = true;
377
+ child.kill('SIGKILL');
378
+ }, suite.timeoutMs);
379
+ child.stdout?.on('data', (chunk) => {
380
+ stdout += chunk.toString('utf8');
381
+ });
382
+ child.stderr?.on('data', (chunk) => {
383
+ stderr += chunk.toString('utf8');
384
+ });
385
+ child.once('error', (error) => {
386
+ clearTimeout(timer);
387
+ settle({ code: null, signal: null, stdout, stderr, timedOut: false, error });
388
+ });
389
+ child.once('exit', (code, signal) => {
390
+ clearTimeout(timer);
391
+ settle({ code, signal, stdout, stderr, timedOut, error: null });
392
+ });
393
+ });
394
+ if (outcome.timedOut) {
395
+ return {
396
+ ...base,
397
+ timedOut: true,
398
+ incompleteDetail: `suite '${suite.name}' exceeded its ${String(suite.timeoutMs)}ms timeout and was killed — ` +
399
+ 'an incomplete diagnostic run never displays as passing',
400
+ causes: ['DIAGNOSTIC_RUN_INCOMPLETE'],
401
+ };
402
+ }
403
+ if (outcome.error !== null) {
404
+ return {
405
+ ...base,
406
+ spawnError: outcome.error.message,
407
+ incompleteDetail: `suite '${suite.name}' could not start (${suite.argv[0] ?? ''}): ${outcome.error.message} — ` +
408
+ 'repair the interpreter/configured argv',
409
+ causes: ['DIAGNOSTIC_RUN_INCOMPLETE'],
410
+ };
411
+ }
412
+ const collectionErrors = [...new Set((outcome.stderr + '\n' + outcome.stdout)
413
+ .split('\n')
414
+ .filter((line) => /ERROR|error/i.test(line))
415
+ .map((line) => line.trim().slice(0, 300)))].sort();
416
+ const reportExists = existsSync(reportPath);
417
+ let document = null;
418
+ let reportUnparsable = false;
419
+ if (reportExists) {
420
+ try {
421
+ document = parseJunitXml(readFileSync(reportPath, 'utf8'));
422
+ }
423
+ catch {
424
+ reportUnparsable = true; // fail closed: a malformed report is never a green run
425
+ }
426
+ }
427
+ const cases = [];
428
+ const counts = { passed: 0, failed: 0, errors: 0, skipped: 0, xfailed: 0 };
429
+ const nodeIds = [];
430
+ if (document !== null) {
431
+ for (const testCase of document.cases) {
432
+ const file = caseFileOf(testCase);
433
+ const nodeId = `${file}::${testCase.name}`;
434
+ nodeIds.push(nodeId);
435
+ if (testCase.outcome === 'passed')
436
+ counts.passed += 1;
437
+ else if (testCase.outcome === 'failed')
438
+ counts.failed += 1;
439
+ else if (testCase.outcome === 'error')
440
+ counts.errors += 1;
441
+ else {
442
+ counts.skipped += 1;
443
+ if (testCase.skipType === 'pytest.xfail' || testCase.skipType === 'xfail')
444
+ counts.xfailed += 1;
445
+ }
446
+ cases.push({
447
+ nodeId,
448
+ outcome: testCase.outcome,
449
+ ...(testCase.skipType !== undefined ? { skipType: testCase.skipType } : {}),
450
+ ...(testCase.message !== undefined ? { message: testCase.message } : {}),
451
+ // pytest junit: collection errors are testcases named
452
+ // `pytest_collection` with an <error> child.
453
+ phase: testCase.name === 'pytest_collection'
454
+ ? 'collection'
455
+ : testCase.outcome === 'error'
456
+ ? 'setup'
457
+ : testCase.outcome === 'failed'
458
+ ? 'call'
459
+ : 'unknown',
460
+ });
461
+ }
462
+ }
463
+ const incompleteDetail = diagnoseIncomplete({
464
+ suiteName: suite.name,
465
+ exitCode: outcome.code,
466
+ signal: outcome.signal,
467
+ document,
468
+ reportExists,
469
+ reportUnparsable,
470
+ collectionErrors,
471
+ });
472
+ const complete = incompleteDetail === null;
473
+ let status;
474
+ let causes = [];
475
+ if (!complete) {
476
+ status = 'incomplete';
477
+ causes = ['DIAGNOSTIC_RUN_INCOMPLETE'];
478
+ }
479
+ else if (counts.failed > 0 || counts.errors > 0) {
480
+ status = 'failures';
481
+ causes = ['DIAGNOSTIC_TEST_FAILURE'];
482
+ }
483
+ else {
484
+ status = 'completed';
485
+ }
486
+ return {
487
+ ...base,
488
+ exitCode: outcome.code,
489
+ collectionErrors,
490
+ nodeIds: [...new Set(nodeIds)].sort(),
491
+ cases,
492
+ counts,
493
+ complete,
494
+ incompleteDetail,
495
+ causes,
496
+ reportExists,
497
+ reportUnparsable,
498
+ status,
499
+ };
500
+ }
501
+ /**
502
+ * Decides whether a finished diagnostic run is INCOMPLETE (fail closed):
503
+ * unparsable/missing report, nonzero pytest status codes (2 interrupted,
504
+ * 3 internal, 4 usage), exit 5 (no tests collected), zero reported
505
+ * tests, or a run whose cases are ALL skipped/xfail. Returns null when
506
+ * the run honestly completed.
507
+ */
508
+ function diagnoseIncomplete(input) {
509
+ if (input.signal !== null) {
510
+ return `suite '${input.suiteName}' was interrupted (${input.signal}) — an unavailable run, never a passing one`;
511
+ }
512
+ if (!input.reportExists) {
513
+ return `suite '${input.suiteName}' produced no junit report — the run cannot be trusted as complete`;
514
+ }
515
+ if (input.reportUnparsable || input.document === null) {
516
+ return `suite '${input.suiteName}' produced an unparsable junit report — fail closed (never read as a green run)`;
517
+ }
518
+ if (input.exitCode === 5) {
519
+ return `suite '${input.suiteName}' collected no tests (pytest exit 5) — a zero-test run is incomplete`;
520
+ }
521
+ if (input.exitCode !== null && input.exitCode >= 2 && input.exitCode !== 5) {
522
+ return `suite '${input.suiteName}' ended with pytest status ${String(input.exitCode)} (interrupted/internal/usage error) — incomplete`;
523
+ }
524
+ if (input.exitCode === null) {
525
+ return `suite '${input.suiteName}' ended without an exit status — incomplete`;
526
+ }
527
+ if (input.document.tests === 0) {
528
+ return `suite '${input.suiteName}' reported zero tests — a zero-test run is incomplete`;
529
+ }
530
+ if (input.document.cases.length > 0 && input.document.cases.every((testCase) => testCase.outcome === 'skipped')) {
531
+ return `suite '${input.suiteName}' ran only skipped/expected-failure cases — nothing executed, so the run is incomplete`;
532
+ }
533
+ if (input.collectionErrors.length > 0 && input.exitCode !== 0 && input.document.cases.length === 0) {
534
+ return `suite '${input.suiteName}' reported collection errors: ${input.collectionErrors[0] ?? ''}`;
535
+ }
536
+ return null;
537
+ }
538
+ /** Best-effort file part of a junit testcase (file attr, then classname). */
539
+ function caseFileOf(testCase) {
540
+ if (testCase.file !== undefined && testCase.file.length > 0)
541
+ return testCase.file;
542
+ if (testCase.classname.length > 0)
543
+ return testCase.classname.split('.').join('/');
544
+ return '';
545
+ }
546
+ /** Re-export so the adapter module is the single pytest surface. */
547
+ export { TestDiscoveryError };
548
+ //# sourceMappingURL=pytest-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pytest-adapter.js","sourceRoot":"","sources":["../../src/discovery/pytest-adapter.ts"],"names":[],"mappings":"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"}