@lingxia/test 0.18.0 → 0.20.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/clock.d.ts +30 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +99 -0
- package/dist/clock.js.map +1 -0
- package/dist/coverage.d.ts +25 -0
- package/dist/coverage.d.ts.map +1 -0
- package/dist/coverage.js +92 -0
- package/dist/coverage.js.map +1 -0
- package/dist/deadline.d.ts +82 -0
- package/dist/deadline.d.ts.map +1 -0
- package/dist/deadline.js +184 -0
- package/dist/deadline.js.map +1 -0
- package/dist/dialogs.d.ts +28 -0
- package/dist/dialogs.d.ts.map +1 -0
- package/dist/dialogs.js +74 -0
- package/dist/dialogs.js.map +1 -0
- package/dist/equal.d.ts +28 -0
- package/dist/equal.d.ts.map +1 -0
- package/dist/equal.js +149 -0
- package/dist/equal.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -0
- package/dist/expect.d.ts +35 -7
- package/dist/expect.d.ts.map +1 -1
- package/dist/expect.js +216 -68
- package/dist/expect.js.map +1 -1
- package/dist/fixture.d.ts +201 -23
- package/dist/fixture.d.ts.map +1 -1
- package/dist/fixture.js +1127 -157
- package/dist/fixture.js.map +1 -1
- package/dist/format.d.ts +2 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +78 -0
- package/dist/format.js.map +1 -1
- package/dist/host-types.d.ts +65 -0
- package/dist/host-types.d.ts.map +1 -0
- package/dist/host-types.js +2 -0
- package/dist/host-types.js.map +1 -0
- package/dist/host.d.ts +20 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +33 -1
- package/dist/host.js.map +1 -1
- package/dist/ids.d.ts +14 -0
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +37 -2
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/json-result.d.ts +3 -0
- package/dist/json-result.d.ts.map +1 -0
- package/dist/json-result.js +62 -0
- package/dist/json-result.js.map +1 -0
- package/dist/junit.d.ts +1 -1
- package/dist/junit.d.ts.map +1 -1
- package/dist/junit.js +32 -4
- package/dist/junit.js.map +1 -1
- package/dist/locator.d.ts +87 -9
- package/dist/locator.d.ts.map +1 -1
- package/dist/locator.js +413 -86
- package/dist/locator.js.map +1 -1
- package/dist/mock.d.ts +43 -0
- package/dist/mock.d.ts.map +1 -0
- package/dist/mock.js +162 -0
- package/dist/mock.js.map +1 -0
- package/dist/network.d.ts +68 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +287 -0
- package/dist/network.js.map +1 -0
- package/dist/openapi.d.ts +127 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +414 -0
- package/dist/openapi.js.map +1 -0
- package/dist/pending.d.ts +84 -0
- package/dist/pending.d.ts.map +1 -0
- package/dist/pending.js +311 -0
- package/dist/pending.js.map +1 -0
- package/dist/redact.d.ts +41 -0
- package/dist/redact.d.ts.map +1 -0
- package/dist/redact.js +168 -0
- package/dist/redact.js.map +1 -0
- package/dist/remote.d.ts +32 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +117 -0
- package/dist/remote.js.map +1 -0
- package/dist/report-extras.d.ts +16 -0
- package/dist/report-extras.d.ts.map +1 -0
- package/dist/report-extras.js +125 -0
- package/dist/report-extras.js.map +1 -0
- package/dist/report-types.d.ts +428 -0
- package/dist/report-types.d.ts.map +1 -0
- package/dist/report-types.js +6 -0
- package/dist/report-types.js.map +1 -0
- package/dist/report.d.ts +15 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +195 -19
- package/dist/report.js.map +1 -1
- package/dist/runner.d.ts +13 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +11 -0
- package/dist/runner.js.map +1 -0
- package/dist/runtime.d.ts +54 -4
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +1375 -97
- package/dist/runtime.js.map +1 -1
- package/dist/schema.d.ts +29 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +463 -0
- package/dist/schema.js.map +1 -0
- package/dist/spec-api.d.ts +7 -2
- package/dist/spec-api.d.ts.map +1 -1
- package/dist/tags.d.ts +26 -0
- package/dist/tags.d.ts.map +1 -0
- package/dist/tags.js +78 -0
- package/dist/tags.js.map +1 -0
- package/dist/types.d.ts +852 -165
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +18 -5
- package/schemas/lxdev.schema.json +50 -0
- package/schemas/mock-config.schema.json +21 -0
- package/schemas/scenario.schema.json +180 -0
package/dist/clock.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ClockDriver, HostRunAutomation } from "@lingxia/types/automation";
|
|
2
|
+
import type { TestClock } from "./types.js";
|
|
3
|
+
/** The fixture surface the clock wrapper needs. */
|
|
4
|
+
export interface ClockHost {
|
|
5
|
+
act<T>(name: string, detail: string, op: () => T | Promise<T>): Promise<T>;
|
|
6
|
+
diagnostic(phase: string, message: string, level?: "info"): void | Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Clocks one spec installed, by lxapp id. The runner uninstalls them when
|
|
10
|
+
* the spec ends, so the next spec starts on real time; an app that closed or
|
|
11
|
+
* reopened since is back on real time already.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ClockScope {
|
|
14
|
+
readonly apps: Set<string>;
|
|
15
|
+
/** Test timers still pending when the spec's clocks were uninstalled. */
|
|
16
|
+
dropped: number;
|
|
17
|
+
private automation;
|
|
18
|
+
track(appid: string, automation: () => HostRunAutomation): void;
|
|
19
|
+
/** Uninstall every tracked clock; rejects naming those that failed. */
|
|
20
|
+
reclaim(diagnostic: (phase: string, message: string, level?: "info") => void | Promise<void>): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* `resolve` reads the raw driver lazily, inside each traced call: a host
|
|
24
|
+
* without the test clock then fails that call, never the `t.app.clock` read.
|
|
25
|
+
*/
|
|
26
|
+
export declare function wrapClock(resolve: () => {
|
|
27
|
+
driver: ClockDriver | undefined;
|
|
28
|
+
appid: () => Promise<string>;
|
|
29
|
+
}, host: ClockHost, scope: ClockScope, automation: () => HostRunAutomation): TestClock;
|
|
30
|
+
//# sourceMappingURL=clock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,WAAW,EAMX,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAClF;AAeD;;;;GAIG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,IAAI,cAAqB;IAClC,yEAAyE;IACzE,OAAO,SAAK;IACZ,OAAO,CAAC,UAAU,CAAwC;IAE1D,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,GAAG,IAAI;IAK/D,uEAAuE;IACjE,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAqBnH;AAmBD;;;GAGG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM;IAAE,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,EAChF,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,iBAAiB,GAClC,SAAS,CA2BX"}
|
package/dist/clock.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/** The host's record, as a plain object of exactly these keys. */
|
|
2
|
+
function clockState({ now, pending }) {
|
|
3
|
+
return { now, pending };
|
|
4
|
+
}
|
|
5
|
+
function clockAdvance({ now, pending, fired }) {
|
|
6
|
+
return { now, pending, fired };
|
|
7
|
+
}
|
|
8
|
+
function droppedNote(dropped, when) {
|
|
9
|
+
return `${when} dropped ${dropped} pending test timer${dropped === 1 ? "" : "s"}; they never fired`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Clocks one spec installed, by lxapp id. The runner uninstalls them when
|
|
13
|
+
* the spec ends, so the next spec starts on real time; an app that closed or
|
|
14
|
+
* reopened since is back on real time already.
|
|
15
|
+
*/
|
|
16
|
+
export class ClockScope {
|
|
17
|
+
constructor() {
|
|
18
|
+
this.apps = new Set();
|
|
19
|
+
/** Test timers still pending when the spec's clocks were uninstalled. */
|
|
20
|
+
this.dropped = 0;
|
|
21
|
+
}
|
|
22
|
+
track(appid, automation) {
|
|
23
|
+
this.apps.add(appid);
|
|
24
|
+
this.automation = automation;
|
|
25
|
+
}
|
|
26
|
+
/** Uninstall every tracked clock; rejects naming those that failed. */
|
|
27
|
+
async reclaim(diagnostic) {
|
|
28
|
+
const automation = this.automation;
|
|
29
|
+
if (!automation)
|
|
30
|
+
return;
|
|
31
|
+
const failed = [];
|
|
32
|
+
for (const id of [...this.apps]) {
|
|
33
|
+
// Select the app again: a profile rollback may have reopened it.
|
|
34
|
+
// Raw driver: the fixture is closed by now.
|
|
35
|
+
try {
|
|
36
|
+
const result = await automation().lxapp(id).clock.uninstall();
|
|
37
|
+
this.dropped += result.dropped;
|
|
38
|
+
// The spec installed this clock: removing it is expected, not a warning.
|
|
39
|
+
if (result.dropped > 0)
|
|
40
|
+
await diagnostic("clock", droppedNote(result.dropped, `the spec's end uninstalled the test clock of ${id} and`), "info");
|
|
41
|
+
this.apps.delete(id);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// A closed app took its Logic, and the clock with it.
|
|
45
|
+
if (appGone(error)) {
|
|
46
|
+
this.apps.delete(id);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
failed.push(`${id}: ${String(error?.message ?? error)}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (failed.length > 0)
|
|
53
|
+
throw new Error(`test clocks were not uninstalled (${failed.join("; ")})`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The host's answer for an app that is not running. */
|
|
57
|
+
function appGone(error) {
|
|
58
|
+
return /lxapp is not active:/.test(String(error?.message ?? error));
|
|
59
|
+
}
|
|
60
|
+
/** `install({ now })` / `setSystemTime` detail for the trace. */
|
|
61
|
+
function describeTime(time) {
|
|
62
|
+
if (time === undefined)
|
|
63
|
+
return "";
|
|
64
|
+
if (time instanceof Date)
|
|
65
|
+
return Number.isNaN(time.getTime()) ? "Invalid Date" : time.toISOString();
|
|
66
|
+
return String(time);
|
|
67
|
+
}
|
|
68
|
+
/** A `Date` crosses to the host as epoch milliseconds. */
|
|
69
|
+
function toWire(time) {
|
|
70
|
+
return time instanceof Date ? time.getTime() : time;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* `resolve` reads the raw driver lazily, inside each traced call: a host
|
|
74
|
+
* without the test clock then fails that call, never the `t.app.clock` read.
|
|
75
|
+
*/
|
|
76
|
+
export function wrapClock(resolve, host, scope, automation) {
|
|
77
|
+
const driver = () => resolve().driver;
|
|
78
|
+
return {
|
|
79
|
+
install: (options) => host.act("clock.install", describeTime(options?.now), async () => {
|
|
80
|
+
const clock = driver();
|
|
81
|
+
const now = options?.now === undefined ? undefined : toWire(options.now);
|
|
82
|
+
// An explicit `undefined` argument is not "no options" to the host:
|
|
83
|
+
// omit it instead.
|
|
84
|
+
const result = await (now === undefined ? clock.install() : clock.install({ now }));
|
|
85
|
+
scope.track(await resolve().appid(), automation);
|
|
86
|
+
return clockState(result);
|
|
87
|
+
}),
|
|
88
|
+
tick: (ms) => host.act("clock.tick", `${ms}ms`, async () => clockAdvance(await driver().tick(ms))),
|
|
89
|
+
runAll: (options) => host.act("clock.runAll", options?.maxTimers === undefined ? "" : `max ${options.maxTimers}`, async () => clockAdvance(await (options === undefined ? driver().runAll() : driver().runAll(options)))),
|
|
90
|
+
setSystemTime: (time) => host.act("clock.setSystemTime", describeTime(time), async () => clockState(await driver().setSystemTime(toWire(time)))),
|
|
91
|
+
uninstall: () => host.act("clock.uninstall", "", async () => {
|
|
92
|
+
const result = await driver().uninstall();
|
|
93
|
+
scope.dropped += result.dropped;
|
|
94
|
+
if (result.dropped > 0)
|
|
95
|
+
await host.diagnostic("clock", droppedNote(result.dropped, "clock.uninstall"), "info");
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=clock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clock.js","sourceRoot":"","sources":["../src/clock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { CaseRecord, CoverageSummary } from "./report-types.js";
|
|
2
|
+
/** One requirement of a `--covers-manifest` file, as lxdev sends it. */
|
|
3
|
+
export interface ManifestEntry {
|
|
4
|
+
id: string;
|
|
5
|
+
title?: string;
|
|
6
|
+
}
|
|
7
|
+
/** A registered spec, whether or not this selection ran it. */
|
|
8
|
+
export interface RegisteredCover {
|
|
9
|
+
id: string;
|
|
10
|
+
title: string;
|
|
11
|
+
covers: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* `control.coversManifest` is a JSON list of `{ id, title? }`; lxdev has
|
|
15
|
+
* already read and checked the file. Anything else is a broken control.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseManifest(raw: string | undefined): ManifestEntry[] | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Which manifest ids the suite covers, by which specs and with what outcome;
|
|
20
|
+
* which have no spec at all; and which `covers` ids are not in the manifest.
|
|
21
|
+
* A spec registered but outside this selection still covers its ids, as
|
|
22
|
+
* `not_run`, so a filtered run never reports a false hole.
|
|
23
|
+
*/
|
|
24
|
+
export declare function coverageSummary(manifest: readonly ManifestEntry[], cases: readonly CaseRecord[], registered: readonly RegisteredCover[]): CoverageSummary;
|
|
25
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAgB,eAAe,EAAc,MAAM,mBAAmB,CAAC;AAE/F,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,EAAE,GAAG,SAAS,CAclF;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,UAAU,EAAE,SAAS,eAAe,EAAE,GACrC,eAAe,CAmCjB"}
|
package/dist/coverage.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `control.coversManifest` is a JSON list of `{ id, title? }`; lxdev has
|
|
3
|
+
* already read and checked the file. Anything else is a broken control.
|
|
4
|
+
*/
|
|
5
|
+
export function parseManifest(raw) {
|
|
6
|
+
if (raw === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (!Array.isArray(parsed))
|
|
10
|
+
throw new Error("coversManifest control must be a JSON list");
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
return parsed.map((entry, index) => {
|
|
13
|
+
const record = (entry && typeof entry === "object" ? entry : {});
|
|
14
|
+
if (typeof record.id !== "string" || record.id.length === 0) {
|
|
15
|
+
throw new Error(`coversManifest entry ${index} has no id`);
|
|
16
|
+
}
|
|
17
|
+
if (seen.has(record.id))
|
|
18
|
+
throw new Error(`coversManifest lists ${JSON.stringify(record.id)} twice`);
|
|
19
|
+
seen.add(record.id);
|
|
20
|
+
return typeof record.title === "string" ? { id: record.id, title: record.title } : { id: record.id };
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const BROKEN = new Set(["failed", "timeout", "xpass"]);
|
|
24
|
+
/**
|
|
25
|
+
* Which manifest ids the suite covers, by which specs and with what outcome;
|
|
26
|
+
* which have no spec at all; and which `covers` ids are not in the manifest.
|
|
27
|
+
* A spec registered but outside this selection still covers its ids, as
|
|
28
|
+
* `not_run`, so a filtered run never reports a false hole.
|
|
29
|
+
*/
|
|
30
|
+
export function coverageSummary(manifest, cases, registered) {
|
|
31
|
+
const ran = new Map();
|
|
32
|
+
for (const item of cases) {
|
|
33
|
+
const list = ran.get(item.id) ?? [];
|
|
34
|
+
list.push(item);
|
|
35
|
+
ran.set(item.id, list);
|
|
36
|
+
}
|
|
37
|
+
const specsFor = (id) => registered
|
|
38
|
+
.filter((spec) => spec.covers.includes(id))
|
|
39
|
+
.map((spec) => ({ id: spec.id, title: spec.title, status: outcome(ran.get(spec.id)) }));
|
|
40
|
+
const known = new Set(manifest.map((entry) => entry.id));
|
|
41
|
+
const ids = manifest.map((entry) => {
|
|
42
|
+
const specs = specsFor(entry.id);
|
|
43
|
+
return { ...entry, status: rollUp(specs), specs };
|
|
44
|
+
});
|
|
45
|
+
const unknown = new Map();
|
|
46
|
+
for (const spec of registered) {
|
|
47
|
+
for (const id of spec.covers) {
|
|
48
|
+
if (known.has(id))
|
|
49
|
+
continue;
|
|
50
|
+
const list = unknown.get(id) ?? [];
|
|
51
|
+
if (!list.includes(spec.id))
|
|
52
|
+
list.push(spec.id);
|
|
53
|
+
unknown.set(id, list);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const covered = ids.filter((entry) => entry.specs.length > 0);
|
|
57
|
+
return {
|
|
58
|
+
total: manifest.length,
|
|
59
|
+
covered: covered.length,
|
|
60
|
+
passing: covered.filter((entry) => entry.status === "passed").length,
|
|
61
|
+
failing: covered.filter((entry) => entry.status === "failed").length,
|
|
62
|
+
uncovered: ids.filter((entry) => entry.specs.length === 0).map(({ id, title }) => (title ? { id, title } : { id })),
|
|
63
|
+
unknown: [...unknown.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([id, specs]) => ({ id, specs })),
|
|
64
|
+
ids,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** A spec's outcome across its executions (repeats): any break wins. */
|
|
68
|
+
function outcome(executions) {
|
|
69
|
+
if (!executions || executions.length === 0)
|
|
70
|
+
return "not_run";
|
|
71
|
+
const broken = executions.find((item) => BROKEN.has(item.status));
|
|
72
|
+
if (broken)
|
|
73
|
+
return broken.status;
|
|
74
|
+
if (executions.some((item) => item.status === "passed"))
|
|
75
|
+
return "passed";
|
|
76
|
+
return executions[0].status;
|
|
77
|
+
}
|
|
78
|
+
/** An id is `failed` if any spec broke, `passed` if one passed, else what is left. */
|
|
79
|
+
function rollUp(specs) {
|
|
80
|
+
if (specs.length === 0)
|
|
81
|
+
return "uncovered";
|
|
82
|
+
if (specs.some((spec) => BROKEN.has(spec.status)))
|
|
83
|
+
return "failed";
|
|
84
|
+
if (specs.some((spec) => spec.status === "passed"))
|
|
85
|
+
return "passed";
|
|
86
|
+
if (specs.some((spec) => spec.status === "xfail"))
|
|
87
|
+
return "xfail";
|
|
88
|
+
if (specs.some((spec) => spec.status === "skipped"))
|
|
89
|
+
return "skipped";
|
|
90
|
+
return "not_run";
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../src/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixture call or budget ran out: `t.waitFor`, `waitForCall`, a driver
|
|
3
|
+
* call raced against an action budget or timing out itself (its own code is
|
|
4
|
+
* `cause.code` and `data.driverCode`), cleanup, or the spec itself.
|
|
5
|
+
*/
|
|
6
|
+
export declare class TimeoutError extends Error {
|
|
7
|
+
readonly name = "TimeoutError";
|
|
8
|
+
readonly code: "E_TIMEOUT";
|
|
9
|
+
data?: unknown;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One timeout code at the fixture boundary: a driver rejection that timed
|
|
13
|
+
* out becomes a `TimeoutError` whose `cause` is the driver's error; anything
|
|
14
|
+
* else passes through.
|
|
15
|
+
*/
|
|
16
|
+
export declare function asFixtureTimeout(error: unknown): unknown;
|
|
17
|
+
/**
|
|
18
|
+
* The budget of one retrying action or assertion. The requested timeout is
|
|
19
|
+
* clamped to what is left of the spec (or cleanup) budget, so an action never
|
|
20
|
+
* outlives the spec silently, and every driver call is raced against what is
|
|
21
|
+
* left of it, so a call that never returns fails the action by name instead of
|
|
22
|
+
* surfacing as an anonymous spec timeout.
|
|
23
|
+
*
|
|
24
|
+
* JS can only stop waiting: a native call that blocks the JS thread cannot be
|
|
25
|
+
* preempted, and a call abandoned here may still complete in the app.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ActionDeadline {
|
|
28
|
+
readonly started: number;
|
|
29
|
+
readonly timeout: number;
|
|
30
|
+
/** The timeout the caller asked for, when the spec budget cut it. */
|
|
31
|
+
readonly clampedFrom: number | undefined;
|
|
32
|
+
/** The budget's timer fired: a timer can fire a millisecond before `Date.now()` agrees. */
|
|
33
|
+
private lapsed;
|
|
34
|
+
constructor(requested: number, room?: number);
|
|
35
|
+
elapsed(): number;
|
|
36
|
+
remaining(): number;
|
|
37
|
+
expired(): boolean;
|
|
38
|
+
/** One line explaining a clamp, or `undefined` when the timeout is as asked. */
|
|
39
|
+
clampNote(): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Race `op` against the rest of this budget. On expiry the rejection names
|
|
42
|
+
* the call and `context()` (the action, its target and location); the
|
|
43
|
+
* abandoned promise is left to settle on its own.
|
|
44
|
+
*/
|
|
45
|
+
call<T>(label: string, op: () => T | Promise<T>, context: () => string): Promise<T>;
|
|
46
|
+
}
|
|
47
|
+
/** The stable `code` of a driver rejection, when it carries one. */
|
|
48
|
+
export declare function errorCode(error: unknown): string | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Errors the page drivers raise while a page is being replaced: the target is
|
|
51
|
+
* not the active instance yet, or its WebView is not attached. They occur
|
|
52
|
+
* before anything reaches the page, so retrying them is safe. Matched by code
|
|
53
|
+
* (`E_PAGE_NOT_ACTIVE`, `E_PAGE_NOT_READY`), plus WebView2's
|
|
54
|
+
* `ERROR_INVALID_STATE` (`0x8007139F`) while a navigation replaces the
|
|
55
|
+
* document, which carries no code of its own.
|
|
56
|
+
*/
|
|
57
|
+
export declare function isTransientPageError(error: unknown): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* The subset of transient errors that are raised while resolving the target
|
|
60
|
+
* page, before input dispatch. A WebView2 script error during dispatch is
|
|
61
|
+
* ambiguous (the input may have landed), so it is not in this set.
|
|
62
|
+
*/
|
|
63
|
+
export declare function isPreDispatchPageError(error: unknown): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* The element was missing or not interactable at dispatch: the native side
|
|
66
|
+
* refused before any input reached the page, so a retry is safe.
|
|
67
|
+
*/
|
|
68
|
+
export declare function isElementRefusal(error: unknown): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* The transport between the test runtime and the app dropped a call: the
|
|
71
|
+
* socket would block or was reset, or the channel closed under it. Only an
|
|
72
|
+
* idempotent read may be retried on it; for input it is ambiguous, since the
|
|
73
|
+
* call may have landed before the reply was lost.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isTransientTransportError(error: unknown): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Match the public error or a preserved cause, without changing either: an
|
|
78
|
+
* error's `cause`, or the `data.cause` a driver reports for what the app
|
|
79
|
+
* rejected with (a page action, an `lx.*` error thrown in `logic.eval`).
|
|
80
|
+
*/
|
|
81
|
+
export declare function matchesErrorCode(error: unknown, expected: string): boolean;
|
|
82
|
+
//# sourceMappingURL=deadline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadline.d.ts","sourceRoot":"","sources":["../src/deadline.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,SAAkB,IAAI,kBAAkB;IACxC,QAAQ,CAAC,IAAI,EAAG,WAAW,CAAU;IACrC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAKD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAQxD;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,QAAQ,CAAC,OAAO,SAAc;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,2FAA2F;IAC3F,OAAO,CAAC,MAAM,CAAS;gBAEX,SAAS,EAAE,MAAM,EAAE,IAAI,GAAE,MAAiC;IAMtE,OAAO,IAAI,MAAM;IAIjB,SAAS,IAAI,MAAM;IAInB,OAAO,IAAI,OAAO;IAIlB,gFAAgF;IAChF,SAAS,IAAI,MAAM,GAAG,SAAS;IAM/B;;;;OAIG;IACG,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CA8B1F;AAED,oEAAoE;AACpE,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAG5D;AAKD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI5D;AAOD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAG9D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAGxD;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAMjE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAa1E"}
|
package/dist/deadline.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { runnerClearTimeout, runnerSetTimeout } from "./pending.js";
|
|
2
|
+
/**
|
|
3
|
+
* A fixture call or budget ran out: `t.waitFor`, `waitForCall`, a driver
|
|
4
|
+
* call raced against an action budget or timing out itself (its own code is
|
|
5
|
+
* `cause.code` and `data.driverCode`), cleanup, or the spec itself.
|
|
6
|
+
*/
|
|
7
|
+
export class TimeoutError extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
this.name = "TimeoutError";
|
|
11
|
+
this.code = "E_TIMEOUT";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** The driver codes a fixture call reports as `E_TIMEOUT`. */
|
|
15
|
+
const DRIVER_TIMEOUT_CODES = new Set(["E_AUTOMATION_TIMEOUT", "E_EVAL_TIMEOUT", "E_DESKTOP_TIMEOUT"]);
|
|
16
|
+
/**
|
|
17
|
+
* One timeout code at the fixture boundary: a driver rejection that timed
|
|
18
|
+
* out becomes a `TimeoutError` whose `cause` is the driver's error; anything
|
|
19
|
+
* else passes through.
|
|
20
|
+
*/
|
|
21
|
+
export function asFixtureTimeout(error) {
|
|
22
|
+
const code = errorCode(error);
|
|
23
|
+
if (code === undefined || !DRIVER_TIMEOUT_CODES.has(code))
|
|
24
|
+
return error;
|
|
25
|
+
const timeout = new TimeoutError(error instanceof Error ? error.message : String(error));
|
|
26
|
+
const data = error.data;
|
|
27
|
+
timeout.data = data && typeof data === "object" ? { ...data, driverCode: code } : { driverCode: code };
|
|
28
|
+
timeout.cause = error;
|
|
29
|
+
return timeout;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The budget of one retrying action or assertion. The requested timeout is
|
|
33
|
+
* clamped to what is left of the spec (or cleanup) budget, so an action never
|
|
34
|
+
* outlives the spec silently, and every driver call is raced against what is
|
|
35
|
+
* left of it, so a call that never returns fails the action by name instead of
|
|
36
|
+
* surfacing as an anonymous spec timeout.
|
|
37
|
+
*
|
|
38
|
+
* JS can only stop waiting: a native call that blocks the JS thread cannot be
|
|
39
|
+
* preempted, and a call abandoned here may still complete in the app.
|
|
40
|
+
*/
|
|
41
|
+
export class ActionDeadline {
|
|
42
|
+
constructor(requested, room = Number.POSITIVE_INFINITY) {
|
|
43
|
+
this.started = Date.now();
|
|
44
|
+
/** The budget's timer fired: a timer can fire a millisecond before `Date.now()` agrees. */
|
|
45
|
+
this.lapsed = false;
|
|
46
|
+
const available = Math.max(1, Math.floor(room));
|
|
47
|
+
this.timeout = requested > available ? available : requested;
|
|
48
|
+
this.clampedFrom = requested > available ? requested : undefined;
|
|
49
|
+
}
|
|
50
|
+
elapsed() {
|
|
51
|
+
return Date.now() - this.started;
|
|
52
|
+
}
|
|
53
|
+
remaining() {
|
|
54
|
+
return this.timeout - this.elapsed();
|
|
55
|
+
}
|
|
56
|
+
expired() {
|
|
57
|
+
return this.lapsed || this.remaining() <= 0;
|
|
58
|
+
}
|
|
59
|
+
/** One line explaining a clamp, or `undefined` when the timeout is as asked. */
|
|
60
|
+
clampNote() {
|
|
61
|
+
return this.clampedFrom === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: `timeout ${this.clampedFrom}ms was clamped to ${this.timeout}ms, the time left in the spec's budget`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Race `op` against the rest of this budget. On expiry the rejection names
|
|
67
|
+
* the call and `context()` (the action, its target and location); the
|
|
68
|
+
* abandoned promise is left to settle on its own.
|
|
69
|
+
*/
|
|
70
|
+
async call(label, op, context) {
|
|
71
|
+
const ms = this.remaining();
|
|
72
|
+
const expired = () => new TimeoutError([
|
|
73
|
+
`${label} was not started because the ${this.timeout}ms action budget expired.`,
|
|
74
|
+
this.clampNote(),
|
|
75
|
+
context(),
|
|
76
|
+
].filter(Boolean).join("\n"));
|
|
77
|
+
if (ms <= 0)
|
|
78
|
+
throw expired();
|
|
79
|
+
const task = Promise.resolve().then(() => {
|
|
80
|
+
if (this.expired())
|
|
81
|
+
throw expired();
|
|
82
|
+
return op();
|
|
83
|
+
});
|
|
84
|
+
let handle;
|
|
85
|
+
const expiry = new Promise((_, reject) => {
|
|
86
|
+
handle = runnerSetTimeout(() => {
|
|
87
|
+
this.lapsed = true;
|
|
88
|
+
task.catch(() => { });
|
|
89
|
+
reject(new TimeoutError([
|
|
90
|
+
`${label} did not return within ${ms}ms, the rest of the ${this.timeout}ms action budget.`,
|
|
91
|
+
this.clampNote(),
|
|
92
|
+
context(),
|
|
93
|
+
].filter(Boolean).join("\n")));
|
|
94
|
+
}, ms);
|
|
95
|
+
});
|
|
96
|
+
try {
|
|
97
|
+
return await Promise.race([task, expiry]);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (handle !== undefined)
|
|
101
|
+
runnerClearTimeout(handle);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** The stable `code` of a driver rejection, when it carries one. */
|
|
106
|
+
export function errorCode(error) {
|
|
107
|
+
const code = error && typeof error === "object" ? error.code : undefined;
|
|
108
|
+
return typeof code === "string" ? code : undefined;
|
|
109
|
+
}
|
|
110
|
+
/** Page-readiness codes: the target was not reached, so a retry is safe. */
|
|
111
|
+
const PAGE_NOT_READY_CODES = new Set(["E_PAGE_NOT_ACTIVE", "E_PAGE_NOT_READY"]);
|
|
112
|
+
/**
|
|
113
|
+
* Errors the page drivers raise while a page is being replaced: the target is
|
|
114
|
+
* not the active instance yet, or its WebView is not attached. They occur
|
|
115
|
+
* before anything reaches the page, so retrying them is safe. Matched by code
|
|
116
|
+
* (`E_PAGE_NOT_ACTIVE`, `E_PAGE_NOT_READY`), plus WebView2's
|
|
117
|
+
* `ERROR_INVALID_STATE` (`0x8007139F`) while a navigation replaces the
|
|
118
|
+
* document, which carries no code of its own.
|
|
119
|
+
*/
|
|
120
|
+
export function isTransientPageError(error) {
|
|
121
|
+
const code = errorCode(error);
|
|
122
|
+
if (code !== undefined && PAGE_NOT_READY_CODES.has(code))
|
|
123
|
+
return true;
|
|
124
|
+
return isWebView2InvalidState(error);
|
|
125
|
+
}
|
|
126
|
+
function isWebView2InvalidState(error) {
|
|
127
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
128
|
+
return /0x8007139f/i.test(message);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* The subset of transient errors that are raised while resolving the target
|
|
132
|
+
* page, before input dispatch. A WebView2 script error during dispatch is
|
|
133
|
+
* ambiguous (the input may have landed), so it is not in this set.
|
|
134
|
+
*/
|
|
135
|
+
export function isPreDispatchPageError(error) {
|
|
136
|
+
const code = errorCode(error);
|
|
137
|
+
return code !== undefined && PAGE_NOT_READY_CODES.has(code);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The element was missing or not interactable at dispatch: the native side
|
|
141
|
+
* refused before any input reached the page, so a retry is safe.
|
|
142
|
+
*/
|
|
143
|
+
export function isElementRefusal(error) {
|
|
144
|
+
const code = errorCode(error);
|
|
145
|
+
return code === "E_ELEMENT_NOT_FOUND" || code === "E_ELEMENT_NOT_INTERACTABLE";
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The transport between the test runtime and the app dropped a call: the
|
|
149
|
+
* socket would block or was reset, or the channel closed under it. Only an
|
|
150
|
+
* idempotent read may be retried on it; for input it is ambiguous, since the
|
|
151
|
+
* call may have landed before the reply was lost.
|
|
152
|
+
*/
|
|
153
|
+
export function isTransientTransportError(error) {
|
|
154
|
+
if (errorCode(error) === "E_TRANSPORT")
|
|
155
|
+
return true;
|
|
156
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
157
|
+
if (!message)
|
|
158
|
+
return false;
|
|
159
|
+
return /os error (?:11|35|54|104)\b|resource temporarily unavailable|connection reset|broken pipe|channel closed|websocket (?:closed|disconnected|frame)/i
|
|
160
|
+
.test(message);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Match the public error or a preserved cause, without changing either: an
|
|
164
|
+
* error's `cause`, or the `data.cause` a driver reports for what the app
|
|
165
|
+
* rejected with (a page action, an `lx.*` error thrown in `logic.eval`).
|
|
166
|
+
*/
|
|
167
|
+
export function matchesErrorCode(error, expected) {
|
|
168
|
+
const seen = new Set();
|
|
169
|
+
const pending = [error];
|
|
170
|
+
while (pending.length > 0) {
|
|
171
|
+
const next = pending.pop();
|
|
172
|
+
if (next === null || typeof next !== "object" || seen.has(next))
|
|
173
|
+
continue;
|
|
174
|
+
if (errorCode(next) === expected)
|
|
175
|
+
return true;
|
|
176
|
+
seen.add(next);
|
|
177
|
+
pending.push(next.cause);
|
|
178
|
+
const data = next.data;
|
|
179
|
+
if (data && typeof data === "object")
|
|
180
|
+
pending.push(data.cause);
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=deadline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadline.js","sourceRoot":"","sources":["../src/deadline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DialogDriver, LxAppDriver } from "@lingxia/types/automation";
|
|
2
|
+
import type { TestDialogs } from "./types.js";
|
|
3
|
+
/** The fixture surface the dialogs wrapper needs. */
|
|
4
|
+
export interface DialogsHost {
|
|
5
|
+
act<T>(name: string, detail: string, op: () => T | Promise<T>): Promise<T>;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* `resolve` reads the raw driver lazily, inside each traced call: a host
|
|
9
|
+
* without dialog watching fails that call, never the `t.app.dialogs` read.
|
|
10
|
+
*/
|
|
11
|
+
export declare function wrapDialogs(resolve: () => DialogDriver, host: DialogsHost, ensure: () => Promise<void>): TestDialogs;
|
|
12
|
+
/** One spec's watch of the app under test's dialogs. */
|
|
13
|
+
export interface DialogWatch {
|
|
14
|
+
/** Resolves the first dialog that found no answer; never resolves otherwise. */
|
|
15
|
+
readonly unanswered: Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Stop watching, through `driver` (the app under test as selected now: a
|
|
18
|
+
* profile switch reopens it); what the spec queued and no dialog used, or
|
|
19
|
+
* `undefined` when nothing is left.
|
|
20
|
+
*/
|
|
21
|
+
end(driver: LxAppDriver): Promise<string | undefined>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Watch the app's dialogs for the spec that starts now. `undefined` on a
|
|
25
|
+
* host without dialog watching. A refused watch fails spec setup.
|
|
26
|
+
*/
|
|
27
|
+
export declare function watchDialogs(driver: LxAppDriver): DialogWatch | undefined;
|
|
28
|
+
//# sourceMappingURL=dialogs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogs.d.ts","sourceRoot":"","sources":["../src/dialogs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,YAAY,EAEZ,WAAW,EAEZ,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC5E;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,WAAW,CA8BpH;AAED,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC;;;;OAIG;IACH,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CACvD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,SAAS,CA6BzE"}
|