@descryy/runtime-test-runner 0.0.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/dist/collector-version.d.ts +10 -0
- package/dist/collector-version.d.ts.map +1 -0
- package/dist/collector-version.js +12 -0
- package/dist/collector-version.js.map +1 -0
- package/dist/go-test.d.ts +81 -0
- package/dist/go-test.d.ts.map +1 -0
- package/dist/go-test.js +224 -0
- package/dist/go-test.js.map +1 -0
- package/dist/graph-mapping.d.ts +44 -0
- package/dist/graph-mapping.d.ts.map +1 -0
- package/dist/graph-mapping.js +72 -0
- package/dist/graph-mapping.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/jest-reporter.d.ts +72 -0
- package/dist/jest-reporter.d.ts.map +1 -0
- package/dist/jest-reporter.js +110 -0
- package/dist/jest-reporter.js.map +1 -0
- package/dist/playwright-reporter.d.ts +67 -0
- package/dist/playwright-reporter.d.ts.map +1 -0
- package/dist/playwright-reporter.js +93 -0
- package/dist/playwright-reporter.js.map +1 -0
- package/dist/reporter.d.ts +35 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +74 -0
- package/dist/reporter.js.map +1 -0
- package/dist/swift-xctest.d.ts +138 -0
- package/dist/swift-xctest.d.ts.map +1 -0
- package/dist/swift-xctest.js +384 -0
- package/dist/swift-xctest.js.map +1 -0
- package/dist/test-runner-collector.d.ts +370 -0
- package/dist/test-runner-collector.d.ts.map +1 -0
- package/dist/test-runner-collector.js +1014 -0
- package/dist/test-runner-collector.js.map +1 -0
- package/dist/vitest-reporter.d.ts +76 -0
- package/dist/vitest-reporter.d.ts.map +1 -0
- package/dist/vitest-reporter.js +131 -0
- package/dist/vitest-reporter.js.map +1 -0
- package/package.json +33 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A **Jest** custom reporter (`--reporters=<path to this file's compiled
|
|
3
|
+
* output>`), emitting the same NDJSON envelope `reporter.ts` emits for
|
|
4
|
+
* `node:test`.
|
|
5
|
+
*
|
|
6
|
+
* ## Why one envelope and three reporters, rather than three collectors
|
|
7
|
+
*
|
|
8
|
+
* The per-runner knowledge is *what its own structured API calls things*,
|
|
9
|
+
* and that knowledge only exists inside the runner's own process, where the
|
|
10
|
+
* API is. So each runner gets a reporter that speaks its API and writes the
|
|
11
|
+
* one shape `test-runner-collector.ts` already reads —
|
|
12
|
+
* `{type: "test:start"|"test:pass"|"test:fail", data: {...}}`, node:test's
|
|
13
|
+
* own event names, kept as the envelope because it was first and renaming
|
|
14
|
+
* them would churn a working translator for nothing.
|
|
15
|
+
*
|
|
16
|
+
* `createEventTranslator` therefore needed **no per-runner branch**: no
|
|
17
|
+
* `if (runner === "jest")` anywhere above this file, which is the same
|
|
18
|
+
* boundary rule the IR has. Everything Jest-specific is here.
|
|
19
|
+
*
|
|
20
|
+
* ## What Jest gives that node:test does not, and vice versa
|
|
21
|
+
*
|
|
22
|
+
* `testCaseResult.ancestorTitles` is the real `describe()` chain, so
|
|
23
|
+
* `qualifiedName` is exact rather than reconstructed — node:test forced
|
|
24
|
+
* `SuiteStack` to rebuild it from `nesting` because its events carry only
|
|
25
|
+
* the innermost title (RT-076). Emitting it directly is why the translator
|
|
26
|
+
* prefers a supplied `qualifiedName` over its own reconstruction.
|
|
27
|
+
*
|
|
28
|
+
* **Jest's own `fullName` is the same space-joined string** and is used
|
|
29
|
+
* here in preference to re-joining, since it is what Jest itself
|
|
30
|
+
* considers the test's full name. It matches `adapter-typescript`'s
|
|
31
|
+
* TEST_CASE convention (`[...suite, title].join(" ")`) exactly — verified
|
|
32
|
+
* against a real run, not assumed. Vitest's `fullName` does **not** (it
|
|
33
|
+
* joins with `" > "`), which is why `vitest-reporter.ts` rebuilds it and
|
|
34
|
+
* this one does not.
|
|
35
|
+
*
|
|
36
|
+
* **`onTestCaseStart` carries no location** — measured. Only
|
|
37
|
+
* `onTestCaseResult` does, and only when `--testLocationInResults` is
|
|
38
|
+
* passed. So TEST_STARTED for Jest has a `file` but null `line`/`column`,
|
|
39
|
+
* where node:test's has all three. Disclosed rather than filled in.
|
|
40
|
+
*
|
|
41
|
+
* ## `--testLocationInResults` is load-bearing, and its absence is silent
|
|
42
|
+
*
|
|
43
|
+
* Measured directly: without it, `testCaseResult.location` is `undefined`
|
|
44
|
+
* on every result. The collector still runs, still emits every event, and
|
|
45
|
+
* every one silently has no line or column — the same shape as RT-073's
|
|
46
|
+
* reporter-flag ordering bug, where the failure was "no error, wrong
|
|
47
|
+
* output". `withReporterFlags` injects it; it is not left to the caller.
|
|
48
|
+
*/
|
|
49
|
+
function write(type, data) {
|
|
50
|
+
// stdout, one JSON value per line — the collector ignores any line that
|
|
51
|
+
// is not JSON, so Jest's own progress output (which goes to stderr
|
|
52
|
+
// anyway) can never be mistaken for an event.
|
|
53
|
+
process.stdout.write(JSON.stringify({ type, data }) + "\n");
|
|
54
|
+
}
|
|
55
|
+
// **The envelope declaration, emitted at module load** — before any test
|
|
56
|
+
// runs, because the runner imports this reporter during its own start-up.
|
|
57
|
+
// A stdout write is correct here (unlike node:test's reporter, which is a
|
|
58
|
+
// stream transform and must yield instead), since this reporter already
|
|
59
|
+
// writes every event the same way (RT-130).
|
|
60
|
+
write("descry:envelope", { version: 1 });
|
|
61
|
+
export default class DescryJestReporter {
|
|
62
|
+
onTestCaseStart(test, info) {
|
|
63
|
+
write("test:start", {
|
|
64
|
+
name: info.title,
|
|
65
|
+
qualifiedName: info.fullName,
|
|
66
|
+
file: test.path,
|
|
67
|
+
line: null,
|
|
68
|
+
column: null,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
onTestCaseResult(test, result) {
|
|
72
|
+
// **`skipped` and `todo` are not results and must not be reported as
|
|
73
|
+
// passes.** Jest reports a `test.todo` with `status: "todo"` and omits
|
|
74
|
+
// a `test.skip` from `onTestCaseResult` entirely (both measured), so
|
|
75
|
+
// the `skip` flag below is set for statuses Jest *can* report and a
|
|
76
|
+
// `.skip`'d test produces no event from this reporter at all. That is
|
|
77
|
+
// Jest's own coverage limit, not this reporter declining to look: it
|
|
78
|
+
// is why `traceCoverage().notRun` is a floor rather than a total for
|
|
79
|
+
// Jest, and why the tests assert a bound rather than an equality.
|
|
80
|
+
//
|
|
81
|
+
// The translator turns these into `TEST_SKIPPED` (RT-124) — its own
|
|
82
|
+
// event, carrying this location and qualified name, not a counter.
|
|
83
|
+
write(result.status === "failed" ? "test:fail" : "test:pass", {
|
|
84
|
+
name: result.title,
|
|
85
|
+
qualifiedName: result.fullName,
|
|
86
|
+
file: test.path,
|
|
87
|
+
line: result.location?.line ?? null,
|
|
88
|
+
column: result.location?.column ?? null,
|
|
89
|
+
skip: result.status === "skipped" || result.status === "pending" || result.status === "disabled",
|
|
90
|
+
todo: result.status === "todo",
|
|
91
|
+
// Jest names the one it can report: `todo` is a declared absence.
|
|
92
|
+
// The `skipped`/`pending`/`disabled` statuses are switched-off tests,
|
|
93
|
+
// and a `.skip`'d one never reaches this callback at all (measured),
|
|
94
|
+
// so no value here is a guess about a test Jest declined to describe.
|
|
95
|
+
...(result.status === "todo" ? { skipReason: "not-implemented" } : { skipReason: "disabled" }),
|
|
96
|
+
details: {
|
|
97
|
+
duration_ms: result.duration ?? null,
|
|
98
|
+
// Jest hands failures over as formatted strings, not as the live
|
|
99
|
+
// Error objects node:test's reporter carries. `failureDetails` is
|
|
100
|
+
// the structured half when the matcher provided one; both are
|
|
101
|
+
// passed through verbatim rather than parsed, because parsing a
|
|
102
|
+
// matcher's prose is exactly what this seam exists to avoid.
|
|
103
|
+
error: result.status === "failed"
|
|
104
|
+
? { failureType: "test", messages: result.failureMessages, details: result.failureDetails ?? null }
|
|
105
|
+
: null,
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=jest-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jest-reporter.js","sourceRoot":"","sources":["../src/jest-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAoBH,SAAS,KAAK,CAAC,IAAY,EAAE,IAAa;IACxC,wEAAwE;IACxE,mEAAmE;IACnE,8CAA8C;IAC9C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,yEAAyE;AACzE,0EAA0E;AAC1E,0EAA0E;AAC1E,wEAAwE;AACxE,4CAA4C;AAC5C,KAAK,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AAEzC,MAAM,CAAC,OAAO,OAAO,kBAAkB;IACrC,eAAe,CAAC,IAAc,EAAE,IAA2B;QACzD,KAAK,CAAC,YAAY,EAAE;YAClB,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,aAAa,EAAE,IAAI,CAAC,QAAQ;YAC5B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;IACL,CAAC;IAED,gBAAgB,CAAC,IAAc,EAAE,MAA0B;QACzD,qEAAqE;QACrE,uEAAuE;QACvE,qEAAqE;QACrE,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,qEAAqE;QACrE,kEAAkE;QAClE,EAAE;QACF,oEAAoE;QACpE,mEAAmE;QACnE,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;YAC5D,IAAI,EAAE,MAAM,CAAC,KAAK;YAClB,aAAa,EAAE,MAAM,CAAC,QAAQ;YAC9B,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE,IAAI,IAAI,IAAI;YACnC,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,IAAI,IAAI;YACvC,IAAI,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;YAChG,IAAI,EAAE,MAAM,CAAC,MAAM,KAAK,MAAM;YAC9B,kEAAkE;YAClE,sEAAsE;YACtE,qEAAqE;YACrE,sEAAsE;YACtE,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAE,EAAE,UAAU,EAAE,iBAAiB,EAAY,CAAC,CAAC,CAAE,EAAE,UAAU,EAAE,UAAU,EAAY,CAAC;YACpH,OAAO,EAAE;gBACP,WAAW,EAAE,MAAM,CAAC,QAAQ,IAAI,IAAI;gBACpC,iEAAiE;gBACjE,kEAAkE;gBAClE,8DAA8D;gBAC9D,gEAAgE;gBAChE,6DAA6D;gBAC7D,KAAK,EACH,MAAM,CAAC,MAAM,KAAK,QAAQ;oBACxB,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,eAAe,EAAE,OAAO,EAAE,MAAM,CAAC,cAAc,IAAI,IAAI,EAAE;oBACnG,CAAC,CAAC,IAAI;aACX;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Test's reporter, the fifth runner on this seam (RT-184).
|
|
3
|
+
*
|
|
4
|
+
* Playwright is the **only** runner measured here that supplies source
|
|
5
|
+
* locations with no flag at all. Jest needs `--testLocationInResults`,
|
|
6
|
+
* Vitest `--includeTaskLocation`, .NET
|
|
7
|
+
* `RunConfiguration.CollectSourceInformation=true`; `go test` and
|
|
8
|
+
* `swift test --xunit-output` cannot supply them under any flag (RT-136,
|
|
9
|
+
* RT-141). `TestCase.location` is `{file, line, column}` and is always
|
|
10
|
+
* populated. So this profile injects a reporter and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* ## Two shapes no other runner on this seam has
|
|
13
|
+
*
|
|
14
|
+
* **1. A test may declare the outcome it expects.** `test.fail()` runs the
|
|
15
|
+
* body and its *failure* is the declared outcome — measured:
|
|
16
|
+
* `status: "failed"`, `expectedStatus: "failed"`. Mapping status alone
|
|
17
|
+
* would report a working, deliberately-failing test as a problem, which is
|
|
18
|
+
* the false-positive direction and the more expensive one. The rule is a
|
|
19
|
+
* comparison, not a lookup: **the outcome matched what was declared, or it
|
|
20
|
+
* did not.**
|
|
21
|
+
*
|
|
22
|
+
* **2. `skip` and `fixme` are distinguishable; a declared skip and a
|
|
23
|
+
* runtime one are not.** `test.annotations` carries `{type: "fixme"}` for
|
|
24
|
+
* `test.fixme()` — unambiguous, a developer switched it off. But
|
|
25
|
+
* `{type: "skip"}` is emitted *identically* for a declared `test.skip(...)`
|
|
26
|
+
* and for a `test.skip(condition)` evaluated inside a running body
|
|
27
|
+
* (measured, both `ann: ["skip"]`). Those are different facts about
|
|
28
|
+
* coverage — switched off versus ran and hit a precondition — and this
|
|
29
|
+
* runner cannot separate them.
|
|
30
|
+
*
|
|
31
|
+
* So `fixme` reports `disabled` and `skip` reports **`unspecified`**. That
|
|
32
|
+
* value now has three independent producers — Vitest (RT-129), .NET's
|
|
33
|
+
* `TestOutcome.Skipped` (Lane A's RT-099) and this — each arriving because
|
|
34
|
+
* a runner collapses two facts rather than because the vocabulary lacked a
|
|
35
|
+
* word. Reading `disabled` off an annotation *named* skip would have been
|
|
36
|
+
* the plausible mistake here, and it would state that a developer turned
|
|
37
|
+
* off a test that ran real code.
|
|
38
|
+
*/
|
|
39
|
+
interface PlaywrightLocation {
|
|
40
|
+
readonly file: string;
|
|
41
|
+
readonly line: number;
|
|
42
|
+
readonly column: number;
|
|
43
|
+
}
|
|
44
|
+
interface PlaywrightSuite {
|
|
45
|
+
readonly type: string;
|
|
46
|
+
readonly title: string;
|
|
47
|
+
readonly parent?: PlaywrightSuite;
|
|
48
|
+
}
|
|
49
|
+
interface PlaywrightTestCase {
|
|
50
|
+
readonly title: string;
|
|
51
|
+
readonly location: PlaywrightLocation;
|
|
52
|
+
readonly expectedStatus: string;
|
|
53
|
+
readonly annotations: readonly {
|
|
54
|
+
readonly type: string;
|
|
55
|
+
}[];
|
|
56
|
+
readonly parent?: PlaywrightSuite;
|
|
57
|
+
}
|
|
58
|
+
interface PlaywrightResult {
|
|
59
|
+
readonly status: string;
|
|
60
|
+
readonly duration: number;
|
|
61
|
+
readonly errors: readonly unknown[];
|
|
62
|
+
}
|
|
63
|
+
export default class DescryPlaywrightReporter {
|
|
64
|
+
onTestEnd(test: PlaywrightTestCase, result: PlaywrightResult): void;
|
|
65
|
+
}
|
|
66
|
+
export {};
|
|
67
|
+
//# sourceMappingURL=playwright-reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-reporter.d.ts","sourceRoot":"","sources":["../src/playwright-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAIH,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,UAAU,kBAAkB;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3D,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;CACnC;AAED,UAAU,gBAAgB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,CAAC;CACrC;AA+BD,MAAM,CAAC,OAAO,OAAO,wBAAwB;IAC3C,SAAS,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,gBAAgB,GAAG,IAAI;CA0BpE"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Test's reporter, the fifth runner on this seam (RT-184).
|
|
3
|
+
*
|
|
4
|
+
* Playwright is the **only** runner measured here that supplies source
|
|
5
|
+
* locations with no flag at all. Jest needs `--testLocationInResults`,
|
|
6
|
+
* Vitest `--includeTaskLocation`, .NET
|
|
7
|
+
* `RunConfiguration.CollectSourceInformation=true`; `go test` and
|
|
8
|
+
* `swift test --xunit-output` cannot supply them under any flag (RT-136,
|
|
9
|
+
* RT-141). `TestCase.location` is `{file, line, column}` and is always
|
|
10
|
+
* populated. So this profile injects a reporter and nothing else.
|
|
11
|
+
*
|
|
12
|
+
* ## Two shapes no other runner on this seam has
|
|
13
|
+
*
|
|
14
|
+
* **1. A test may declare the outcome it expects.** `test.fail()` runs the
|
|
15
|
+
* body and its *failure* is the declared outcome — measured:
|
|
16
|
+
* `status: "failed"`, `expectedStatus: "failed"`. Mapping status alone
|
|
17
|
+
* would report a working, deliberately-failing test as a problem, which is
|
|
18
|
+
* the false-positive direction and the more expensive one. The rule is a
|
|
19
|
+
* comparison, not a lookup: **the outcome matched what was declared, or it
|
|
20
|
+
* did not.**
|
|
21
|
+
*
|
|
22
|
+
* **2. `skip` and `fixme` are distinguishable; a declared skip and a
|
|
23
|
+
* runtime one are not.** `test.annotations` carries `{type: "fixme"}` for
|
|
24
|
+
* `test.fixme()` — unambiguous, a developer switched it off. But
|
|
25
|
+
* `{type: "skip"}` is emitted *identically* for a declared `test.skip(...)`
|
|
26
|
+
* and for a `test.skip(condition)` evaluated inside a running body
|
|
27
|
+
* (measured, both `ann: ["skip"]`). Those are different facts about
|
|
28
|
+
* coverage — switched off versus ran and hit a precondition — and this
|
|
29
|
+
* runner cannot separate them.
|
|
30
|
+
*
|
|
31
|
+
* So `fixme` reports `disabled` and `skip` reports **`unspecified`**. That
|
|
32
|
+
* value now has three independent producers — Vitest (RT-129), .NET's
|
|
33
|
+
* `TestOutcome.Skipped` (Lane A's RT-099) and this — each arriving because
|
|
34
|
+
* a runner collapses two facts rather than because the vocabulary lacked a
|
|
35
|
+
* word. Reading `disabled` off an annotation *named* skip would have been
|
|
36
|
+
* the plausible mistake here, and it would state that a developer turned
|
|
37
|
+
* off a test that ran real code.
|
|
38
|
+
*/
|
|
39
|
+
const ENVELOPE_VERSION = 1;
|
|
40
|
+
function write(type, data) {
|
|
41
|
+
process.stdout.write(JSON.stringify({ type, data }) + "\n");
|
|
42
|
+
}
|
|
43
|
+
write("descry:envelope", { version: ENVELOPE_VERSION });
|
|
44
|
+
/**
|
|
45
|
+
* The `describe()` chain, and **only** that chain.
|
|
46
|
+
*
|
|
47
|
+
* `titlePath()` returns `["", "invoices.spec.js", "invoice deletion", "runs
|
|
48
|
+
* normally"]` — the project name (empty unless projects are configured) and
|
|
49
|
+
* the file title sit in front of it. Slicing a fixed number of entries off
|
|
50
|
+
* would silently take the first `describe` instead once a project is named.
|
|
51
|
+
* `suite.type` is Playwright's own discriminator (`root`/`project`/`file`/
|
|
52
|
+
* `describe`, measured), so the walk stops on a type rather than a count.
|
|
53
|
+
*/
|
|
54
|
+
function qualify(test) {
|
|
55
|
+
const groups = [];
|
|
56
|
+
for (let suite = test.parent; suite !== undefined; suite = suite.parent) {
|
|
57
|
+
if (suite.type !== "describe")
|
|
58
|
+
break;
|
|
59
|
+
groups.unshift(suite.title);
|
|
60
|
+
}
|
|
61
|
+
return [...groups, test.title].join(" ");
|
|
62
|
+
}
|
|
63
|
+
function skipReasonOf(test) {
|
|
64
|
+
return test.annotations.some((a) => a.type === "fixme") ? "disabled" : "unspecified";
|
|
65
|
+
}
|
|
66
|
+
export default class DescryPlaywrightReporter {
|
|
67
|
+
onTestEnd(test, result) {
|
|
68
|
+
const skipped = result.status === "skipped";
|
|
69
|
+
// The comparison, not a lookup: `test.fail()` declares failure as the
|
|
70
|
+
// expected outcome, and a run that matches its declaration is not a
|
|
71
|
+
// problem to report.
|
|
72
|
+
const asDeclared = result.status === test.expectedStatus;
|
|
73
|
+
write(skipped || asDeclared ? "test:pass" : "test:fail", {
|
|
74
|
+
name: test.title,
|
|
75
|
+
qualifiedName: qualify(test),
|
|
76
|
+
file: test.location.file,
|
|
77
|
+
line: test.location.line,
|
|
78
|
+
column: test.location.column,
|
|
79
|
+
skip: skipped,
|
|
80
|
+
todo: false,
|
|
81
|
+
...(skipped ? { skipReason: skipReasonOf(test) } : {}),
|
|
82
|
+
details: {
|
|
83
|
+
duration_ms: result.duration,
|
|
84
|
+
// Passed through verbatim, like Vitest's: Playwright's errors are
|
|
85
|
+
// already plain serialisable objects carrying `message`, `stack`
|
|
86
|
+
// and a matcher's `snippet`, and copying named fields would discard
|
|
87
|
+
// whichever ones this code did not think to name (RT-123).
|
|
88
|
+
error: asDeclared || skipped ? null : { failureType: "test", errors: result.errors },
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=playwright-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-reporter.js","sourceRoot":"","sources":["../src/playwright-reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,MAAM,gBAAgB,GAAG,CAAC,CAAC;AA4B3B,SAAS,KAAK,CAAC,IAAY,EAAE,IAAa;IACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,KAAK,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAExD;;;;;;;;;GASG;AACH,SAAS,OAAO,CAAC,IAAwB;IACvC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,KAAK,SAAS,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;YAAE,MAAM;QACrC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,YAAY,CAAC,IAAwB;IAC5C,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,OAAO,OAAO,wBAAwB;IAC3C,SAAS,CAAC,IAAwB,EAAE,MAAwB;QAC1D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC;QAC5C,sEAAsE;QACtE,oEAAoE;QACpE,qBAAqB;QACrB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,KAAK,IAAI,CAAC,cAAc,CAAC;QAEzD,KAAK,CAAC,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE;YACvD,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,aAAa,EAAE,OAAO,CAAC,IAAI,CAAC;YAC5B,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACxB,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACxB,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM;YAC5B,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,KAAK;YACX,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtD,OAAO,EAAE;gBACP,WAAW,EAAE,MAAM,CAAC,QAAQ;gBAC5B,kEAAkE;gBAClE,iEAAiE;gBACjE,oEAAoE;gBACpE,2DAA2D;gBAC3D,KAAK,EAAE,UAAU,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE;aACrF;SACF,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `node:test` custom reporter (Node's own reporter API — loaded via
|
|
3
|
+
* `--test-reporter=<path to this file's compiled output>`), never TAP.
|
|
4
|
+
*
|
|
5
|
+
* TAP is a text format meant for a human or a line-oriented parser to read;
|
|
6
|
+
* scraping it would mean re-deriving structure (which line is a test name,
|
|
7
|
+
* which is a diagnostic, which YAML block belongs to which result) that
|
|
8
|
+
* Node's own reporter stream already hands over as real objects —
|
|
9
|
+
* `test:start` / `test:pass` / `test:fail`, each with `name`, `file`,
|
|
10
|
+
* `line`, `column`, and for a failure the real `error` (assertion message,
|
|
11
|
+
* `code`, `cause`), never printed prose to re-parse. This reporter's only
|
|
12
|
+
* job is turning that object stream into one JSON value per line on
|
|
13
|
+
* stdout, so `test-runner-collector.ts` can `JSON.parse` each line instead
|
|
14
|
+
* of pattern-matching text — the same reason RT-072's own benchmark lesson
|
|
15
|
+
* exists ("scraping prose measures the prose").
|
|
16
|
+
*
|
|
17
|
+
* Loaded as a standalone file by a *spawned* `node --test` process, whose
|
|
18
|
+
* own cwd may be anywhere — `test-runner-collector.ts` references this
|
|
19
|
+
* module's compiled path absolutely (`new URL("./reporter.js",
|
|
20
|
+
* import.meta.url)`), never by bare specifier, so it resolves regardless of
|
|
21
|
+
* the target application's own `node_modules`.
|
|
22
|
+
*/
|
|
23
|
+
interface ReporterEvent {
|
|
24
|
+
readonly type: string;
|
|
25
|
+
readonly data: {
|
|
26
|
+
readonly details?: {
|
|
27
|
+
readonly type?: string;
|
|
28
|
+
};
|
|
29
|
+
readonly skip?: boolean;
|
|
30
|
+
readonly todo?: boolean;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export default function ndjsonReporter(source: AsyncIterable<ReporterEvent>): AsyncGenerator<string>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=reporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,UAAU,aAAa;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE;YAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACpH;AAqCD,wBAA+B,cAAc,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,cAAc,CAAC,MAAM,CAAC,CAe1G"}
|
package/dist/reporter.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `node:test` custom reporter (Node's own reporter API — loaded via
|
|
3
|
+
* `--test-reporter=<path to this file's compiled output>`), never TAP.
|
|
4
|
+
*
|
|
5
|
+
* TAP is a text format meant for a human or a line-oriented parser to read;
|
|
6
|
+
* scraping it would mean re-deriving structure (which line is a test name,
|
|
7
|
+
* which is a diagnostic, which YAML block belongs to which result) that
|
|
8
|
+
* Node's own reporter stream already hands over as real objects —
|
|
9
|
+
* `test:start` / `test:pass` / `test:fail`, each with `name`, `file`,
|
|
10
|
+
* `line`, `column`, and for a failure the real `error` (assertion message,
|
|
11
|
+
* `code`, `cause`), never printed prose to re-parse. This reporter's only
|
|
12
|
+
* job is turning that object stream into one JSON value per line on
|
|
13
|
+
* stdout, so `test-runner-collector.ts` can `JSON.parse` each line instead
|
|
14
|
+
* of pattern-matching text — the same reason RT-072's own benchmark lesson
|
|
15
|
+
* exists ("scraping prose measures the prose").
|
|
16
|
+
*
|
|
17
|
+
* Loaded as a standalone file by a *spawned* `node --test` process, whose
|
|
18
|
+
* own cwd may be anywhere — `test-runner-collector.ts` references this
|
|
19
|
+
* module's compiled path absolutely (`new URL("./reporter.js",
|
|
20
|
+
* import.meta.url)`), never by bare specifier, so it resolves regardless of
|
|
21
|
+
* the target application's own `node_modules`.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* **`describe()` blocks emit their own `test:pass`, and node:test says so
|
|
25
|
+
* itself** — `data.details.type` is `"suite"` for a container and `"test"`
|
|
26
|
+
* for a real test case (measured; the field's presence is the
|
|
27
|
+
* discriminator, not a heuristic on nesting or naming).
|
|
28
|
+
*
|
|
29
|
+
* That distinction has to survive into the envelope, because it is
|
|
30
|
+
* node:test-specific and Jest's and Vitest's reporters never see a
|
|
31
|
+
* container at all — their per-test callbacks only fire for test cases. So
|
|
32
|
+
* the flag is set here, where the runner-specific knowledge is, and the
|
|
33
|
+
* translator applies one runner-agnostic rule to it.
|
|
34
|
+
*
|
|
35
|
+
* The event itself is still forwarded whole: a suite's `test:fail` is a
|
|
36
|
+
* real failure (a `before`/`after` hook threw) and dropping it here would
|
|
37
|
+
* lose the only signal that a whole block never ran. Which of the two the
|
|
38
|
+
* translator emits is its decision, not this reporter's.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* **node:test tells `skip` and `todo` apart, and RT-124 threw that away.**
|
|
42
|
+
* Both became one `TEST_SKIPPED` with no way to recover which — "switched
|
|
43
|
+
* off" and "never written" are different facts about coverage, and the
|
|
44
|
+
* distinction was dropped silently by the change whose subject was not
|
|
45
|
+
* dropping distinctions silently. `skipReason` is set here rather than
|
|
46
|
+
* derived in the translator because only a reporter knows what its runner
|
|
47
|
+
* can distinguish (RT-129).
|
|
48
|
+
*
|
|
49
|
+
* `todo` wins when both flags are set: `test.todo()` is the stronger claim
|
|
50
|
+
* (there is nothing to run) and node marks a todo as skipped as well.
|
|
51
|
+
*/
|
|
52
|
+
function skipReasonOf(data) {
|
|
53
|
+
if (data?.todo === true)
|
|
54
|
+
return "not-implemented";
|
|
55
|
+
if (data?.skip === true)
|
|
56
|
+
return "disabled";
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
export default async function* ndjsonReporter(source) {
|
|
60
|
+
// **Declared before the first event, not written to stdout.** This
|
|
61
|
+
// reporter is a stream transform: its yielded values *are* the output, so
|
|
62
|
+
// a `process.stdout.write` here would race the stream it is supposed to
|
|
63
|
+
// precede. Yielding first is the same guarantee by construction (RT-130).
|
|
64
|
+
yield JSON.stringify({ type: "descry:envelope", data: { version: 1 } }) + "\n";
|
|
65
|
+
for await (const event of source) {
|
|
66
|
+
const isSuite = event.data?.details?.type === "suite";
|
|
67
|
+
const skipReason = skipReasonOf(event.data);
|
|
68
|
+
const data = isSuite || skipReason !== undefined
|
|
69
|
+
? { ...event.data, ...(isSuite ? { isSuite: true } : {}), ...(skipReason === undefined ? {} : { skipReason }) }
|
|
70
|
+
: event.data;
|
|
71
|
+
yield JSON.stringify(data === event.data ? event : { ...event, data }) + "\n";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.js","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAOH;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;GAWG;AACH,SAAS,YAAY,CAAC,IAA2B;IAC/C,IAAI,IAAI,EAAE,IAAI,KAAK,IAAI;QAAE,OAAO,iBAAiB,CAAC;IAClD,IAAI,IAAI,EAAE,IAAI,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IAC3C,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAC,cAAc,CAAC,MAAoC;IAChF,mEAAmE;IACnE,0EAA0E;IAC1E,wEAAwE;IACxE,0EAA0E;IAC1E,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;IAC/E,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,KAAK,OAAO,CAAC;QACtD,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,IAAI,GACR,OAAO,IAAI,UAAU,KAAK,SAAS;YACjC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YAC/G,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QACjB,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IAChF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift's XCTest half of §17, observed through a custom `XCTestObservation`
|
|
3
|
+
* hooked directly into the test process, in-process and streaming — not
|
|
4
|
+
* `swift test --xunit-output`'s end-of-run artifact (RT-181), which on
|
|
5
|
+
* Swift 6.1.2/Linux covers swift-testing only and silently reports a
|
|
6
|
+
* smaller, clean-looking run for one where twice as many tests ran and half
|
|
7
|
+
* of them failed. This closes the "real path... a different piece of work
|
|
8
|
+
* from consuming an artifact" RT-181 named but did not build.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this is not a seventh `PROFILES` entry in `test-runner-collector.ts`
|
|
11
|
+
*
|
|
12
|
+
* Every runner on that seam is one spawn: inject a reporter flag, run the
|
|
13
|
+
* command as given. XCTest on Linux has no such flag. SwiftPM's generated
|
|
14
|
+
* test entry point (`runner.swift`, rebuilt fresh every build — not
|
|
15
|
+
* something a caller can edit) calls `XCTMain(__allDiscoveredTests())` with
|
|
16
|
+
* no `observers:` argument at all, even though the symbol accepts one and
|
|
17
|
+
* `swift test`'s own template privately builds — but never wires up — an
|
|
18
|
+
* `XCTestObservation` conformer of its own (`SwiftPMXCTestObserver`,
|
|
19
|
+
* confirmed dead: never instantiated, and its `testOutputPath` file never
|
|
20
|
+
* appears even under `--parallel`). So there is no flag to inject.
|
|
21
|
+
*
|
|
22
|
+
* What Linux *does* still honor is `Tests/LinuxMain.swift` — SwiftPM's
|
|
23
|
+
* pre-automatic-discovery entry point. Measured directly: when present, it
|
|
24
|
+
* replaces the generated runner outright (`swift test` skips building the
|
|
25
|
+
* `*PackageDiscoveredTests` module entirely when it exists), and a plain
|
|
26
|
+
* `XCTestObservationCenter.shared.addTestObserver(...)` call inside it
|
|
27
|
+
* genuinely receives every callback, streamed in real time, interleaved
|
|
28
|
+
* with the runner's own console output — not collected after the process
|
|
29
|
+
* exits.
|
|
30
|
+
*
|
|
31
|
+
* So this collector runs in two passes: build the tests once to discover
|
|
32
|
+
* them (`--dump-tests-json`, a real flag on the built `.xctest` binary,
|
|
33
|
+
* needing no `LinuxMain.swift` of its own — the discovery build uses
|
|
34
|
+
* SwiftPM's ordinary automatic discovery), generate a `LinuxMain.swift`
|
|
35
|
+
* naming every discovered class and method, then spawn `swift test` for
|
|
36
|
+
* real, which rebuilds against the generated file and runs it.
|
|
37
|
+
*
|
|
38
|
+
* ## The trade-off this creates, disclosed rather than hidden
|
|
39
|
+
*
|
|
40
|
+
* `Tests/LinuxMain.swift`'s presence does not just replace the XCTest
|
|
41
|
+
* dispatch, it removes the swift-testing one too. Measured directly: a
|
|
42
|
+
* package with both an XCTest method and a swift-testing `@Test` function,
|
|
43
|
+
* with no `LinuxMain.swift`, runs both — `swift test` invokes the built
|
|
44
|
+
* binary twice, once per `--testing-library` value. With a
|
|
45
|
+
* `LinuxMain.swift` present — ours or anyone's — the `@Test` function does
|
|
46
|
+
* not run at all: not skipped, not reported, simply never invoked; not
|
|
47
|
+
* even its banner line prints. So this collector observes the XCTest half
|
|
48
|
+
* in real time and *stops covering swift-testing while it is active* — the
|
|
49
|
+
* mirror image of RT-181's gap, not a fix for both halves at once.
|
|
50
|
+
* `stop()` removes the generated file afterward so an unattended
|
|
51
|
+
* `swift test` reverts to normal dual-framework discovery once this
|
|
52
|
+
* collector is done.
|
|
53
|
+
*
|
|
54
|
+
* ## The generated file is never a guess at the user's code
|
|
55
|
+
*
|
|
56
|
+
* Every class and method name comes from `--dump-tests-json` against a real
|
|
57
|
+
* build of the real target — the same build-time-derived source SwiftPM's
|
|
58
|
+
* own automatic discovery already trusts, not a scrape of source text. No
|
|
59
|
+
* `allTests` needs to exist anywhere in the user's own code; the generated
|
|
60
|
+
* file adds its own `__descryAllTests` extension per class instead, so a
|
|
61
|
+
* project that already declares a legacy `allTests` is never collided with.
|
|
62
|
+
*
|
|
63
|
+
* **Known limitation, disclosed rather than silently mishandled:** two test
|
|
64
|
+
* classes of the same bare name in two different modules of the same
|
|
65
|
+
* package produce two `extension <Name>` blocks that collide. Real, and not
|
|
66
|
+
* solved here — `discoverClasses` still returns both, and the generated
|
|
67
|
+
* file fails to compile rather than silently picking one, which is the
|
|
68
|
+
* refuse-rather-than-guess the rest of this codebase holds to.
|
|
69
|
+
*/
|
|
70
|
+
import type { Collector } from "@descryy/runtime-contracts";
|
|
71
|
+
import { type TraceCoverage } from "./test-runner-collector.ts";
|
|
72
|
+
export interface SwiftTestDump {
|
|
73
|
+
readonly name: string;
|
|
74
|
+
readonly tests?: readonly SwiftTestDump[];
|
|
75
|
+
}
|
|
76
|
+
export interface DiscoveredSwiftClass {
|
|
77
|
+
readonly module: string;
|
|
78
|
+
readonly className: string;
|
|
79
|
+
readonly methods: readonly string[];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* `--dump-tests-json`'s tree has no explicit node kind — a class is
|
|
83
|
+
* recognised structurally, as a node whose every child is itself a leaf (a
|
|
84
|
+
* bare `{"name": "testFoo"}` with no `tests` of its own, which is exactly
|
|
85
|
+
* the shape a test *method* has and a bundle/suite container never does).
|
|
86
|
+
* Anything else — the root, `"debug.xctest"`, a suite — is a container and
|
|
87
|
+
* is recursed into instead.
|
|
88
|
+
*
|
|
89
|
+
* A node whose name carries no `.` (so not `Module.Class`) is skipped
|
|
90
|
+
* rather than guessed at — `--dump-tests-json`'s own class names are always
|
|
91
|
+
* qualified this way in every build observed, and a bare name reaching here
|
|
92
|
+
* would mean this method's own structural assumption is wrong for that
|
|
93
|
+
* node, which is worth surfacing as a dropped class rather than papering
|
|
94
|
+
* over with an invented module.
|
|
95
|
+
*/
|
|
96
|
+
export declare function discoverClasses(dump: SwiftTestDump): DiscoveredSwiftClass[];
|
|
97
|
+
/** Present at the top of every file this module writes — never anything a human authored. `stop()` refuses to delete a `Tests/LinuxMain.swift` that lacks it. */
|
|
98
|
+
export declare const GENERATED_MARKER = "// Generated by @descryy/runtime-test-runner's swift-xctest observer -- safe to delete, regenerated on every observed run.";
|
|
99
|
+
/** Pure: builds `Tests/LinuxMain.swift`'s full text from the classes `discoverClasses` found. No filesystem access. */
|
|
100
|
+
export declare function generateLinuxMain(classes: readonly DiscoveredSwiftClass[]): string;
|
|
101
|
+
export type SwiftDiscoveryResult = {
|
|
102
|
+
readonly ok: true;
|
|
103
|
+
readonly classes: readonly DiscoveredSwiftClass[];
|
|
104
|
+
} | {
|
|
105
|
+
readonly ok: false;
|
|
106
|
+
readonly reason: string;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Builds the tests once (ordinary automatic discovery — no `LinuxMain.swift`
|
|
110
|
+
* involved yet) and reads back `--dump-tests-json` from the resulting
|
|
111
|
+
* binary. A pre-existing Descry-generated `LinuxMain.swift` is removed
|
|
112
|
+
* first: left in place, this build would use last run's stale class list
|
|
113
|
+
* rather than discovering fresh, and could fail outright if a module it
|
|
114
|
+
* names has since been removed.
|
|
115
|
+
*/
|
|
116
|
+
export declare function discoverSwiftTests(packageRoot: string): SwiftDiscoveryResult;
|
|
117
|
+
/** Writes the generated file. Refuses (rather than overwrites) if a non-Descry `Tests/LinuxMain.swift` has appeared since `discoverSwiftTests` ran. */
|
|
118
|
+
export declare function writeLinuxMain(packageRoot: string, classes: readonly DiscoveredSwiftClass[]): void;
|
|
119
|
+
/** Removes a Descry-generated `Tests/LinuxMain.swift`, and only one — never a file this module did not write. */
|
|
120
|
+
export declare function removeGeneratedLinuxMain(packageRoot: string): void;
|
|
121
|
+
export interface SwiftXCTestCollectorOptions {
|
|
122
|
+
readonly packageRoot: string;
|
|
123
|
+
/** Joins emitted Evidence back to a named service, same convention as every other collector. Omit for a standalone test run with no corresponding service. */
|
|
124
|
+
readonly service?: string;
|
|
125
|
+
}
|
|
126
|
+
export interface SwiftXCTestCollector extends Collector {
|
|
127
|
+
waitForCompletion(): Promise<void>;
|
|
128
|
+
traceCoverage(): TraceCoverage;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The two-pass XCTest collector. `start()` does the discover-then-generate
|
|
132
|
+
* work before spawning anything a caller would recognise as "the test run"
|
|
133
|
+
* — genuinely slower to become `available` than the single-spawn runners on
|
|
134
|
+
* this seam, and that latency is the cost of there being no reporter flag
|
|
135
|
+
* to inject instead.
|
|
136
|
+
*/
|
|
137
|
+
export declare function createSwiftXCTestCollector(options: SwiftXCTestCollectorOptions): SwiftXCTestCollector;
|
|
138
|
+
//# sourceMappingURL=swift-xctest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swift-xctest.d.ts","sourceRoot":"","sources":["../src/swift-xctest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AAOH,OAAO,KAAK,EAAE,SAAS,EAAiE,MAAM,4BAA4B,CAAC;AAE3H,OAAO,EAAyE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGvI,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,GAAG,oBAAoB,EAAE,CAkB3E;AAED,iKAAiK;AACjK,eAAO,MAAM,gBAAgB,+HAA+H,CAAC;AA6C7J,uHAAuH;AACvH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,GAAG,MAAM,CA2BlF;AAoBD,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAA;CAAE,GACxE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,oBAAoB,CAyC5E;AAED,uJAAuJ;AACvJ,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,oBAAoB,EAAE,GAAG,IAAI,CAMlG;AAED,iHAAiH;AACjH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAKlE;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8JAA8J;IAC9J,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAmBD,MAAM,WAAW,oBAAqB,SAAQ,SAAS;IACrD,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,IAAI,aAAa,CAAC;CAChC;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,2BAA2B,GAAG,oBAAoB,CAsGrG"}
|