@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.
Files changed (126) hide show
  1. package/dist/clock.d.ts +30 -0
  2. package/dist/clock.d.ts.map +1 -0
  3. package/dist/clock.js +99 -0
  4. package/dist/clock.js.map +1 -0
  5. package/dist/coverage.d.ts +25 -0
  6. package/dist/coverage.d.ts.map +1 -0
  7. package/dist/coverage.js +92 -0
  8. package/dist/coverage.js.map +1 -0
  9. package/dist/deadline.d.ts +82 -0
  10. package/dist/deadline.d.ts.map +1 -0
  11. package/dist/deadline.js +184 -0
  12. package/dist/deadline.js.map +1 -0
  13. package/dist/dialogs.d.ts +28 -0
  14. package/dist/dialogs.d.ts.map +1 -0
  15. package/dist/dialogs.js +74 -0
  16. package/dist/dialogs.js.map +1 -0
  17. package/dist/equal.d.ts +28 -0
  18. package/dist/equal.d.ts.map +1 -0
  19. package/dist/equal.js +149 -0
  20. package/dist/equal.js.map +1 -0
  21. package/dist/errors.d.ts +8 -0
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/errors.js +37 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/expect.d.ts +35 -7
  26. package/dist/expect.d.ts.map +1 -1
  27. package/dist/expect.js +216 -68
  28. package/dist/expect.js.map +1 -1
  29. package/dist/fixture.d.ts +201 -23
  30. package/dist/fixture.d.ts.map +1 -1
  31. package/dist/fixture.js +1127 -157
  32. package/dist/fixture.js.map +1 -1
  33. package/dist/format.d.ts +2 -0
  34. package/dist/format.d.ts.map +1 -1
  35. package/dist/format.js +78 -0
  36. package/dist/format.js.map +1 -1
  37. package/dist/host-types.d.ts +65 -0
  38. package/dist/host-types.d.ts.map +1 -0
  39. package/dist/host-types.js +2 -0
  40. package/dist/host-types.js.map +1 -0
  41. package/dist/host.d.ts +20 -0
  42. package/dist/host.d.ts.map +1 -1
  43. package/dist/host.js +33 -1
  44. package/dist/host.js.map +1 -1
  45. package/dist/ids.d.ts +14 -0
  46. package/dist/ids.d.ts.map +1 -1
  47. package/dist/ids.js +37 -2
  48. package/dist/ids.js.map +1 -1
  49. package/dist/index.d.ts +5 -7
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +3 -5
  52. package/dist/index.js.map +1 -1
  53. package/dist/json-result.d.ts +3 -0
  54. package/dist/json-result.d.ts.map +1 -0
  55. package/dist/json-result.js +62 -0
  56. package/dist/json-result.js.map +1 -0
  57. package/dist/junit.d.ts +1 -1
  58. package/dist/junit.d.ts.map +1 -1
  59. package/dist/junit.js +32 -4
  60. package/dist/junit.js.map +1 -1
  61. package/dist/locator.d.ts +87 -9
  62. package/dist/locator.d.ts.map +1 -1
  63. package/dist/locator.js +413 -86
  64. package/dist/locator.js.map +1 -1
  65. package/dist/mock.d.ts +43 -0
  66. package/dist/mock.d.ts.map +1 -0
  67. package/dist/mock.js +162 -0
  68. package/dist/mock.js.map +1 -0
  69. package/dist/network.d.ts +68 -0
  70. package/dist/network.d.ts.map +1 -0
  71. package/dist/network.js +287 -0
  72. package/dist/network.js.map +1 -0
  73. package/dist/openapi.d.ts +127 -0
  74. package/dist/openapi.d.ts.map +1 -0
  75. package/dist/openapi.js +414 -0
  76. package/dist/openapi.js.map +1 -0
  77. package/dist/pending.d.ts +84 -0
  78. package/dist/pending.d.ts.map +1 -0
  79. package/dist/pending.js +311 -0
  80. package/dist/pending.js.map +1 -0
  81. package/dist/redact.d.ts +41 -0
  82. package/dist/redact.d.ts.map +1 -0
  83. package/dist/redact.js +168 -0
  84. package/dist/redact.js.map +1 -0
  85. package/dist/remote.d.ts +32 -0
  86. package/dist/remote.d.ts.map +1 -0
  87. package/dist/remote.js +117 -0
  88. package/dist/remote.js.map +1 -0
  89. package/dist/report-extras.d.ts +16 -0
  90. package/dist/report-extras.d.ts.map +1 -0
  91. package/dist/report-extras.js +125 -0
  92. package/dist/report-extras.js.map +1 -0
  93. package/dist/report-types.d.ts +428 -0
  94. package/dist/report-types.d.ts.map +1 -0
  95. package/dist/report-types.js +6 -0
  96. package/dist/report-types.js.map +1 -0
  97. package/dist/report.d.ts +15 -1
  98. package/dist/report.d.ts.map +1 -1
  99. package/dist/report.js +195 -19
  100. package/dist/report.js.map +1 -1
  101. package/dist/runner.d.ts +13 -0
  102. package/dist/runner.d.ts.map +1 -0
  103. package/dist/runner.js +11 -0
  104. package/dist/runner.js.map +1 -0
  105. package/dist/runtime.d.ts +54 -4
  106. package/dist/runtime.d.ts.map +1 -1
  107. package/dist/runtime.js +1375 -97
  108. package/dist/runtime.js.map +1 -1
  109. package/dist/schema.d.ts +29 -0
  110. package/dist/schema.d.ts.map +1 -0
  111. package/dist/schema.js +463 -0
  112. package/dist/schema.js.map +1 -0
  113. package/dist/spec-api.d.ts +7 -2
  114. package/dist/spec-api.d.ts.map +1 -1
  115. package/dist/tags.d.ts +26 -0
  116. package/dist/tags.d.ts.map +1 -0
  117. package/dist/tags.js +78 -0
  118. package/dist/tags.js.map +1 -0
  119. package/dist/types.d.ts +852 -165
  120. package/dist/types.d.ts.map +1 -1
  121. package/dist/version.d.ts +1 -1
  122. package/dist/version.js +1 -1
  123. package/package.json +18 -5
  124. package/schemas/lxdev.schema.json +50 -0
  125. package/schemas/mock-config.schema.json +21 -0
  126. package/schemas/scenario.schema.json +180 -0
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Asynchronous work that spec code started in the test context, so a spec
3
+ * that times out without settling can name what it left behind.
4
+ *
5
+ * While a run is active the runtime wraps the test context's `setTimeout`,
6
+ * `setInterval` and `fetch`, and `rawAutomation()` hands out a driver that
7
+ * does the same for its calls; each call made while a spec owns the context is
8
+ * recorded under that spec until it fires, is cleared, or settles. The
9
+ * runner's own timers go through `runnerSetTimeout` / `runnerClearTimeout`,
10
+ * which are never recorded.
11
+ */
12
+ export type PendingKind = "timer" | "interval" | "fetch" | "eval" | "action";
13
+ export interface PendingWork {
14
+ kind: PendingKind;
15
+ /** What it is: `setTimeout 60000ms`, `GET https://…`, `t.app.logic.eval`. */
16
+ detail: string;
17
+ /** The spec that started it (its full name). */
18
+ owner: string;
19
+ /** Milliseconds since the owning spec started, when it was started. */
20
+ at_ms?: number;
21
+ }
22
+ /**
23
+ * Raw driver authority handed to spec code, one grant per spec. Every proxy
24
+ * `rawAutomation()` hands out keeps the grant it was made under: a spec the
25
+ * run abandons has its grant revoked, so a handle it still holds refuses its
26
+ * next call while the next spec's own handles keep working. Setup code that
27
+ * runs before the first spec has a grant of its own; between specs there is
28
+ * none, so a continuation of an ended spec cannot take a fresh handle then.
29
+ * Revoking the run (`revokeRawAuthority`) refuses every grant.
30
+ */
31
+ export interface Grant {
32
+ revoked?: string;
33
+ /** Host tiers read under this grant: native objects it cannot fence. */
34
+ readonly unfenced: Set<string>;
35
+ }
36
+ /** Stop spec code driving the app through `rawAutomation()` for the rest of the run. */
37
+ export declare function revokeRawAuthority(reason: string): void;
38
+ /** A new run: `rawAutomation()` works again (earlier proxies stay dead). */
39
+ export declare function restoreRawAuthority(): void;
40
+ /** Why spec code may no longer drive the app, or `undefined`. */
41
+ export declare function rawAuthorityRevoked(): string | undefined;
42
+ /** The grant of the spec whose code runs now. */
43
+ export declare function currentSpecGrant(): Grant | undefined;
44
+ /** The spec holding `grant` was abandoned: its handles refuse from now on. */
45
+ export declare function revokeGrant(grant: Grant | undefined, reason: string): void;
46
+ /** A runner timer: never recorded as spec work, never cancelled with it. */
47
+ export declare function runnerSetTimeout(callback: () => void, ms: number): unknown;
48
+ export declare function runnerClearTimeout(handle: unknown): void;
49
+ /** Start recording spec work in the test context. Idempotent. */
50
+ export declare function installPendingTracker(): void;
51
+ /**
52
+ * `root` with every promise-returning call recorded as pending work of the
53
+ * spec that made it (`eval` calls as `eval`), so a raw driver call a
54
+ * timed-out spec still awaits can be named. Getters and methods run against
55
+ * the original object, so native receivers keep working.
56
+ */
57
+ export declare function trackDriver<T extends object>(root: T, path: string, grant?: Grant): T;
58
+ /**
59
+ * The automation root with its lxapp drivers tracked (`trackDriver`). The
60
+ * host tiers (`lxapps`, `browser`, `shell`, `device`, `desktop`,
61
+ * `terminal`) are handed out as the native objects: the Rong host objects
62
+ * behind them lose their methods when read through a proxy.
63
+ */
64
+ export declare function trackAutomationRoot<T extends object>(root: T): T;
65
+ /** Put the test context's own timers and `fetch` back. */
66
+ export declare function uninstallPendingTracker(): void;
67
+ /** The spec whose code runs from now on, or `undefined` between specs. */
68
+ export declare function setPendingOwner(name: string | undefined): Grant | undefined;
69
+ /** Timers, fetches and raw driver calls `name` started that have not fired, been cleared or settled. */
70
+ export declare function pendingOf(name: string): PendingWork[];
71
+ /**
72
+ * Wait up to `ms` for the fetches and raw driver calls `name` left in flight
73
+ * to settle, including ones their continuations start meanwhile. Resolves
74
+ * what is still in flight (empty when all settled).
75
+ */
76
+ export declare function settleCallsOf(name: string, ms: number): Promise<PendingWork[]>;
77
+ /**
78
+ * Clear the timers and intervals `name` left: a timed-out spec is abandoned,
79
+ * and its polls must not fire into the specs after it. Returns how many.
80
+ */
81
+ export declare function cancelTimersOf(name: string): number;
82
+ /** `timer setTimeout 60000ms (at 12ms), fetch GET https://…` */
83
+ export declare function describePending(work: readonly PendingWork[]): string;
84
+ //# sourceMappingURL=pending.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../src/pending.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAkCD;;;;;;;;GAQG;AACH,MAAM,WAAW,KAAK;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAChC;AAOD,wFAAwF;AACxF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,IAAI,IAAI,CAM1C;AAED,iEAAiE;AACjE,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CAExD;AAED,iDAAiD;AACjD,wBAAgB,gBAAgB,IAAI,KAAK,GAAG,SAAS,CAEpD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAE1E;AAkBD,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE1E;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAExD;AAcD,iEAAiE;AACjE,wBAAgB,qBAAqB,IAAI,IAAI,CA0C5C;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,KAA+B,GAAG,CAAC,CAwB9G;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CA0ChE;AAWD,0DAA0D;AAC1D,wBAAgB,uBAAuB,IAAI,IAAI,CAY9C;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,CAS3E;AAED,wGAAwG;AACxG,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAErD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAepF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM,CAOpE"}
@@ -0,0 +1,311 @@
1
+ /**
2
+ * Asynchronous work that spec code started in the test context, so a spec
3
+ * that times out without settling can name what it left behind.
4
+ *
5
+ * While a run is active the runtime wraps the test context's `setTimeout`,
6
+ * `setInterval` and `fetch`, and `rawAutomation()` hands out a driver that
7
+ * does the same for its calls; each call made while a spec owns the context is
8
+ * recorded under that spec until it fires, is cleared, or settles. The
9
+ * runner's own timers go through `runnerSetTimeout` / `runnerClearTimeout`,
10
+ * which are never recorded.
11
+ */
12
+ const scope = globalThis;
13
+ function captureNatives() {
14
+ return {
15
+ setTimeout: scope.setTimeout,
16
+ clearTimeout: scope.clearTimeout,
17
+ setInterval: scope.setInterval,
18
+ clearInterval: scope.clearInterval,
19
+ fetch: typeof scope.fetch === "function" ? scope.fetch : undefined,
20
+ };
21
+ }
22
+ let natives = captureNatives();
23
+ let installed;
24
+ let owner;
25
+ const timers = new Map();
26
+ /** Fetches and raw driver calls in flight, with what settles them. */
27
+ const fetches = new Map();
28
+ const rawCalls = new Map();
29
+ let setupGrant = { unfenced: new Set() };
30
+ let currentGrant = setupGrant;
31
+ let specsStarted = false;
32
+ let revokedReason;
33
+ /** Stop spec code driving the app through `rawAutomation()` for the rest of the run. */
34
+ export function revokeRawAuthority(reason) {
35
+ revokedReason = reason;
36
+ }
37
+ /** A new run: `rawAutomation()` works again (earlier proxies stay dead). */
38
+ export function restoreRawAuthority() {
39
+ revokedReason = undefined;
40
+ if (setupGrant.revoked === undefined)
41
+ setupGrant.revoked = "it belongs to an earlier run";
42
+ setupGrant = { unfenced: new Set() };
43
+ currentGrant = setupGrant;
44
+ specsStarted = false;
45
+ }
46
+ /** Why spec code may no longer drive the app, or `undefined`. */
47
+ export function rawAuthorityRevoked() {
48
+ return revokedReason;
49
+ }
50
+ /** The grant of the spec whose code runs now. */
51
+ export function currentSpecGrant() {
52
+ return currentGrant;
53
+ }
54
+ /** The spec holding `grant` was abandoned: its handles refuse from now on. */
55
+ export function revokeGrant(grant, reason) {
56
+ if (grant && grant.revoked === undefined)
57
+ grant.revoked = reason;
58
+ }
59
+ function refused(reason) {
60
+ return Object.assign(new Error(`The run revoked spec code's automation authority: ${reason}`), {
61
+ code: "E_AUTOMATION_PRIVILEGE",
62
+ });
63
+ }
64
+ function checkGrant(grant) {
65
+ if (revokedReason !== undefined)
66
+ throw refused(revokedReason);
67
+ if (grant.revoked !== undefined)
68
+ throw refused(`this driver belongs to an abandoned spec: ${grant.revoked}`);
69
+ // A handle setup code took is shared by every spec, so no spec's grant
70
+ // fences it: the spec using it is one the run cannot fence.
71
+ if (grant !== currentGrant && currentGrant !== undefined && currentGrant !== setupGrant) {
72
+ currentGrant.unfenced.add("a rawAutomation() driver taken outside the spec");
73
+ }
74
+ }
75
+ /** A runner timer: never recorded as spec work, never cancelled with it. */
76
+ export function runnerSetTimeout(callback, ms) {
77
+ return (installed ?? natives).setTimeout.call(globalThis, callback, ms);
78
+ }
79
+ export function runnerClearTimeout(handle) {
80
+ (installed ?? natives).clearTimeout.call(globalThis, handle);
81
+ }
82
+ function entry(kind, detail) {
83
+ if (!owner)
84
+ return undefined;
85
+ return { kind, detail, owner: owner.name, at_ms: Date.now() - owner.started };
86
+ }
87
+ function describeRequest(input, init) {
88
+ const request = input;
89
+ const url = typeof input === "string" ? input : typeof request?.url === "string" ? request.url : String(input);
90
+ const method = init?.method ?? (typeof request?.method === "string" ? request.method : "GET");
91
+ return `${String(method).toUpperCase()} ${url.length > 120 ? `${url.slice(0, 117)}...` : url}`;
92
+ }
93
+ /** Start recording spec work in the test context. Idempotent. */
94
+ export function installPendingTracker() {
95
+ if (installed)
96
+ return;
97
+ natives = captureNatives();
98
+ const base = natives;
99
+ installed = base;
100
+ const trackedTimeout = function (callback, ms, ...args) {
101
+ const work = typeof callback === "function" ? entry("timer", `setTimeout ${Number(ms ?? 0)}ms`) : undefined;
102
+ if (!work)
103
+ return base.setTimeout.call(globalThis, callback, ms, ...args);
104
+ let handle;
105
+ handle = base.setTimeout.call(globalThis, (...fired) => {
106
+ timers.delete(handle);
107
+ return callback(...fired);
108
+ }, ms, ...args);
109
+ timers.set(handle, work);
110
+ return handle;
111
+ };
112
+ const trackedInterval = function (callback, ms, ...args) {
113
+ const handle = base.setInterval.call(globalThis, callback, ms, ...args);
114
+ const work = typeof callback === "function" ? entry("interval", `setInterval ${Number(ms ?? 0)}ms`) : undefined;
115
+ if (work)
116
+ timers.set(handle, work);
117
+ return handle;
118
+ };
119
+ const clear = (native) => function (handle) {
120
+ timers.delete(handle);
121
+ native.call(globalThis, handle);
122
+ };
123
+ scope.setTimeout = trackedTimeout;
124
+ scope.setInterval = trackedInterval;
125
+ scope.clearTimeout = clear(base.clearTimeout);
126
+ scope.clearInterval = clear(base.clearInterval);
127
+ if (base.fetch) {
128
+ const nativeFetch = base.fetch;
129
+ scope.fetch = function (input, init) {
130
+ const call = nativeFetch.call(globalThis, input, init);
131
+ const work = entry("fetch", describeRequest(input, init));
132
+ if (work) {
133
+ const done = () => { fetches.delete(work); };
134
+ fetches.set(work, Promise.resolve(call).then(done, done));
135
+ }
136
+ return call;
137
+ };
138
+ }
139
+ }
140
+ /**
141
+ * `root` with every promise-returning call recorded as pending work of the
142
+ * spec that made it (`eval` calls as `eval`), so a raw driver call a
143
+ * timed-out spec still awaits can be named. Getters and methods run against
144
+ * the original object, so native receivers keep working.
145
+ */
146
+ export function trackDriver(root, path, grant = { unfenced: new Set() }) {
147
+ return new Proxy(root, {
148
+ get(target, prop) {
149
+ const value = Reflect.get(target, prop, target);
150
+ if (typeof prop !== "string")
151
+ return value;
152
+ if (typeof value === "function") {
153
+ return (...args) => {
154
+ checkGrant(grant);
155
+ const result = value.apply(target, args);
156
+ const name = `${path}${prop}`;
157
+ if (result && typeof result.then === "function") {
158
+ const work = entry(prop === "eval" ? "eval" : "action", `${name}()`);
159
+ if (work) {
160
+ const done = () => { rawCalls.delete(work); };
161
+ rawCalls.set(work, Promise.resolve(result).then(done, done));
162
+ }
163
+ return result;
164
+ }
165
+ return result && typeof result === "object" ? trackDriver(result, `${name}().`, grant) : result;
166
+ };
167
+ }
168
+ return value && typeof value === "object" ? trackDriver(value, `${path}${prop}.`, grant) : value;
169
+ },
170
+ });
171
+ }
172
+ /**
173
+ * The automation root with its lxapp drivers tracked (`trackDriver`). The
174
+ * host tiers (`lxapps`, `browser`, `shell`, `device`, `desktop`,
175
+ * `terminal`) are handed out as the native objects: the Rong host objects
176
+ * behind them lose their methods when read through a proxy.
177
+ */
178
+ export function trackAutomationRoot(root) {
179
+ if (revokedReason !== undefined)
180
+ throw refused(revokedReason);
181
+ const grant = currentGrant;
182
+ if (!grant) {
183
+ throw refused("no spec is running; a spec that already ended cannot take a new driver");
184
+ }
185
+ checkGrant(grant);
186
+ return new Proxy(root, {
187
+ get(target, prop) {
188
+ checkGrant(grant);
189
+ const value = Reflect.get(target, prop, target);
190
+ if (isAccessor(target, prop) || (value !== null && typeof value === "object")) {
191
+ // A host tier (`shell`, `lxapps`, `desktop`, …) comes from a getter.
192
+ // It is handed out as the native object, whatever `typeof` says (a
193
+ // Rong host object can be callable): wrapping it hides the methods
194
+ // on its prototype. It cannot be fenced here once read, so the run
195
+ // notes it, and stops rather than continue past a spec abandoned
196
+ // while holding one.
197
+ if (value !== null && (typeof value === "object" || typeof value === "function")) {
198
+ grant.unfenced.add(String(prop));
199
+ }
200
+ return value;
201
+ }
202
+ if (typeof value !== "function")
203
+ return value;
204
+ if (prop !== "lxapp") {
205
+ return (...args) => {
206
+ checkGrant(grant);
207
+ const result = value.apply(target, args);
208
+ if (result && typeof result === "object" && typeof result.then !== "function") {
209
+ grant.unfenced.add(`${String(prop)}()`);
210
+ }
211
+ return result;
212
+ };
213
+ }
214
+ return (...args) => {
215
+ checkGrant(grant);
216
+ const driver = value.apply(target, args);
217
+ const path = `rawAutomation().lxapp(${args.length > 0 ? JSON.stringify(args[0]) : ""}).`;
218
+ return driver && typeof driver === "object" ? trackDriver(driver, path, grant) : driver;
219
+ };
220
+ },
221
+ });
222
+ }
223
+ /** Whether `prop` of `target` (or its prototype chain) is a getter. */
224
+ function isAccessor(target, prop) {
225
+ for (let owner = target; owner; owner = Object.getPrototypeOf(owner)) {
226
+ const descriptor = Object.getOwnPropertyDescriptor(owner, prop);
227
+ if (descriptor)
228
+ return typeof descriptor.get === "function";
229
+ }
230
+ return false;
231
+ }
232
+ /** Put the test context's own timers and `fetch` back. */
233
+ export function uninstallPendingTracker() {
234
+ if (!installed)
235
+ return;
236
+ scope.setTimeout = installed.setTimeout;
237
+ scope.clearTimeout = installed.clearTimeout;
238
+ scope.setInterval = installed.setInterval;
239
+ scope.clearInterval = installed.clearInterval;
240
+ if (installed.fetch)
241
+ scope.fetch = installed.fetch;
242
+ installed = undefined;
243
+ owner = undefined;
244
+ timers.clear();
245
+ fetches.clear();
246
+ rawCalls.clear();
247
+ }
248
+ /** The spec whose code runs from now on, or `undefined` between specs. */
249
+ export function setPendingOwner(name) {
250
+ owner = name === undefined ? undefined : { name, started: Date.now() };
251
+ if (name !== undefined) {
252
+ specsStarted = true;
253
+ currentGrant = { unfenced: new Set() };
254
+ }
255
+ else {
256
+ currentGrant = specsStarted ? undefined : setupGrant;
257
+ }
258
+ return currentGrant;
259
+ }
260
+ /** Timers, fetches and raw driver calls `name` started that have not fired, been cleared or settled. */
261
+ export function pendingOf(name) {
262
+ return [...rawCalls.keys(), ...fetches.keys(), ...timers.values()].filter((work) => work.owner === name);
263
+ }
264
+ /**
265
+ * Wait up to `ms` for the fetches and raw driver calls `name` left in flight
266
+ * to settle, including ones their continuations start meanwhile. Resolves
267
+ * what is still in flight (empty when all settled).
268
+ */
269
+ export async function settleCallsOf(name, ms) {
270
+ const deadline = Date.now() + ms;
271
+ for (;;) {
272
+ const open = [...rawCalls, ...fetches].filter(([work]) => work.owner === name);
273
+ const left = deadline - Date.now();
274
+ if (open.length === 0 || left <= 0)
275
+ return open.map(([work]) => work);
276
+ let handle;
277
+ await Promise.race([
278
+ Promise.all(open.map(([, settled]) => settled)),
279
+ new Promise((resolve) => { handle = runnerSetTimeout(resolve, left); }),
280
+ ]);
281
+ runnerClearTimeout(handle);
282
+ // Continuations of what settled run before the next look.
283
+ await new Promise((resolve) => { runnerSetTimeout(resolve, 0); });
284
+ }
285
+ }
286
+ /**
287
+ * Clear the timers and intervals `name` left: a timed-out spec is abandoned,
288
+ * and its polls must not fire into the specs after it. Returns how many.
289
+ */
290
+ export function cancelTimersOf(name) {
291
+ let cancelled = 0;
292
+ for (const [handle, work] of [...timers]) {
293
+ if (work.owner !== name)
294
+ continue;
295
+ timers.delete(handle);
296
+ const native = installed ?? natives;
297
+ (work.kind === "interval" ? native.clearInterval : native.clearTimeout).call(globalThis, handle);
298
+ cancelled += 1;
299
+ }
300
+ return cancelled;
301
+ }
302
+ /** `timer setTimeout 60000ms (at 12ms), fetch GET https://…` */
303
+ export function describePending(work) {
304
+ if (work.length === 0) {
305
+ return "an awaited promise that no timer, fetch or fixture call of the spec backs (e.g. `new Promise(() => {})`, or a raw driver call)";
306
+ }
307
+ return work
308
+ .map((item) => `${item.kind} ${item.detail}${item.at_ms !== undefined ? ` (started ${item.at_ms}ms into the spec)` : ""}`)
309
+ .join(", ");
310
+ }
311
+ //# sourceMappingURL=pending.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../src/pending.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `--arg` values end up in every report, and reports get shared.
3
+ *
4
+ * Two different guarantees, on purpose:
5
+ * - An arg passed with `lxdev test --secret-arg` is a declared secret. Its
6
+ * value is masked wherever it appears: `meta.args`, events, case records and
7
+ * text attachments.
8
+ * - An ordinary `--arg` whose key is named like a credential (`password`,
9
+ * `apiKey`, `DB_TOKEN`) only has its entry in `meta.args` shown as `***`. Its
10
+ * value is not searched for elsewhere: a guess from the name must not blank
11
+ * every `1000` in a report because someone passed `maxTokens=1000`.
12
+ *
13
+ * The spec always reads the real value with `t.arg()`.
14
+ */
15
+ export declare const REDACTED = "***";
16
+ /**
17
+ * Split a key into lower-case words at `_`, `-`, `.`, spaces and camelCase
18
+ * boundaries: `DB_PASSWORD` → db password, `apiKey` → api key,
19
+ * `APIKey` → api key, `passWithNoTests` → pass with no tests.
20
+ */
21
+ export declare function keyWords(key: string): string[];
22
+ /**
23
+ * Whether an arg key names a credential. Only the key's last word counts, as a
24
+ * whole word: `authToken` and `DB_PASSWORD` do; `tokenCount`, `maxTokens`,
25
+ * `bypassCache`, `passport` and `passWithNoTests` do not.
26
+ */
27
+ export declare function looksSecretKey(key: string): boolean;
28
+ export interface Redactor {
29
+ /** Args for `meta.args`: declared secrets and credential-named keys as `***`. */
30
+ args(args: Record<string, string>): Record<string, string>;
31
+ /** Deep copy with every declared secret value masked inside strings. */
32
+ deep<T>(value: T): T;
33
+ /** An attachment payload with declared secret values masked in its text. */
34
+ attachment(data: unknown): unknown;
35
+ }
36
+ /**
37
+ * @param args the user args (`t.arg()`)
38
+ * @param secretKeys keys passed with `--secret-arg`
39
+ */
40
+ export declare function createRedactor(args: Record<string, string>, secretKeys?: Iterable<string>): Redactor;
41
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAqB9B;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAO9C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED,MAAM,WAAW,QAAQ;IACvB,iFAAiF;IACjF,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3D,wEAAwE;IACxE,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC;CACpC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC5B,UAAU,GAAE,QAAQ,CAAC,MAAM,CAAM,GAChC,QAAQ,CA2DV"}
package/dist/redact.js ADDED
@@ -0,0 +1,168 @@
1
+ /**
2
+ * `--arg` values end up in every report, and reports get shared.
3
+ *
4
+ * Two different guarantees, on purpose:
5
+ * - An arg passed with `lxdev test --secret-arg` is a declared secret. Its
6
+ * value is masked wherever it appears: `meta.args`, events, case records and
7
+ * text attachments.
8
+ * - An ordinary `--arg` whose key is named like a credential (`password`,
9
+ * `apiKey`, `DB_TOKEN`) only has its entry in `meta.args` shown as `***`. Its
10
+ * value is not searched for elsewhere: a guess from the name must not blank
11
+ * every `1000` in a report because someone passed `maxTokens=1000`.
12
+ *
13
+ * The spec always reads the real value with `t.arg()`.
14
+ */
15
+ import { bytesToBase64 } from "./format.js";
16
+ export const REDACTED = "***";
17
+ /** Shorter values are too likely to collide with ordinary report text. */
18
+ const MIN_SCRUB_LENGTH = 4;
19
+ /** A key whose last word is one of these names a credential. */
20
+ const SECRET_WORDS = new Set([
21
+ "password",
22
+ "passwd",
23
+ "pwd",
24
+ "passphrase",
25
+ "secret",
26
+ "token",
27
+ "credential",
28
+ "credentials",
29
+ "apikey",
30
+ ]);
31
+ /** Two-word endings that name a credential (`apiKey`, `PRIVATE_KEY`). */
32
+ const SECRET_PAIRS = new Set(["api key", "private key"]);
33
+ /**
34
+ * Split a key into lower-case words at `_`, `-`, `.`, spaces and camelCase
35
+ * boundaries: `DB_PASSWORD` → db password, `apiKey` → api key,
36
+ * `APIKey` → api key, `passWithNoTests` → pass with no tests.
37
+ */
38
+ export function keyWords(key) {
39
+ return key
40
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
41
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
42
+ .split(/[^A-Za-z0-9]+/)
43
+ .filter((word) => word.length > 0)
44
+ .map((word) => word.toLowerCase());
45
+ }
46
+ /**
47
+ * Whether an arg key names a credential. Only the key's last word counts, as a
48
+ * whole word: `authToken` and `DB_PASSWORD` do; `tokenCount`, `maxTokens`,
49
+ * `bypassCache`, `passport` and `passWithNoTests` do not.
50
+ */
51
+ export function looksSecretKey(key) {
52
+ const words = keyWords(key);
53
+ const last = words[words.length - 1];
54
+ if (last === undefined)
55
+ return false;
56
+ if (SECRET_WORDS.has(last))
57
+ return true;
58
+ const pair = words.length >= 2 ? `${words[words.length - 2]} ${last}` : "";
59
+ return SECRET_PAIRS.has(pair);
60
+ }
61
+ /**
62
+ * @param args the user args (`t.arg()`)
63
+ * @param secretKeys keys passed with `--secret-arg`
64
+ */
65
+ export function createRedactor(args, secretKeys = []) {
66
+ const declared = new Set(secretKeys);
67
+ const values = Object.entries(args)
68
+ .filter(([key, value]) => declared.has(key) && value.length >= MIN_SCRUB_LENGTH)
69
+ .map(([, value]) => value)
70
+ // Longest first, so a secret containing another is masked whole.
71
+ .sort((a, b) => b.length - a.length);
72
+ const scrub = (text) => {
73
+ let out = text;
74
+ for (const value of values)
75
+ if (out.includes(value))
76
+ out = out.split(value).join(REDACTED);
77
+ return out;
78
+ };
79
+ const walk = (value, seen) => {
80
+ if (typeof value === "string")
81
+ return scrub(value);
82
+ if (!value || typeof value !== "object")
83
+ return value;
84
+ if (value instanceof Uint8Array)
85
+ return value;
86
+ if (seen.has(value))
87
+ return seen.get(value);
88
+ if (Array.isArray(value)) {
89
+ const out = [];
90
+ seen.set(value, out);
91
+ for (const item of value)
92
+ out.push(walk(item, seen));
93
+ return out;
94
+ }
95
+ const out = {};
96
+ seen.set(value, out);
97
+ for (const [key, item] of Object.entries(value))
98
+ out[key] = walk(item, seen);
99
+ return out;
100
+ };
101
+ return {
102
+ args(input) {
103
+ const out = {};
104
+ for (const [key, value] of Object.entries(input)) {
105
+ out[key] = declared.has(key) || looksSecretKey(key) ? REDACTED : value;
106
+ }
107
+ return out;
108
+ },
109
+ deep(value) {
110
+ return values.length === 0 ? value : walk(value, new WeakMap());
111
+ },
112
+ attachment(data) {
113
+ if (values.length === 0)
114
+ return data;
115
+ if (data && typeof data === "object" && !(data instanceof Uint8Array)) {
116
+ const record = data;
117
+ // A pre-encoded payload: only text is searched; images stay byte-exact.
118
+ if (typeof record.base64 === "string") {
119
+ const mimeType = typeof record.mimeType === "string" ? record.mimeType : "";
120
+ if (!isText(mimeType))
121
+ return data;
122
+ const text = decodeUtf8(record.base64);
123
+ if (text === undefined)
124
+ return data;
125
+ const scrubbed = scrub(text);
126
+ if (scrubbed === text)
127
+ return data;
128
+ return { ...record, base64: bytesToBase64(new TextEncoder().encode(scrubbed)) };
129
+ }
130
+ }
131
+ return walk(data, new WeakMap());
132
+ },
133
+ };
134
+ }
135
+ function isText(mimeType) {
136
+ return (mimeType.startsWith("text/") ||
137
+ mimeType.startsWith("application/json") ||
138
+ mimeType.startsWith("application/xml") ||
139
+ /\+(json|xml)\b/.test(mimeType));
140
+ }
141
+ const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
142
+ function decodeUtf8(base64) {
143
+ if (typeof TextDecoder === "undefined")
144
+ return undefined;
145
+ const clean = base64.replace(/[\s=]/g, "");
146
+ const bytes = new Uint8Array(Math.floor((clean.length * 3) / 4));
147
+ let buffer = 0;
148
+ let bits = 0;
149
+ let index = 0;
150
+ for (const char of clean) {
151
+ const value = BASE64_ALPHABET.indexOf(char);
152
+ if (value < 0)
153
+ return undefined;
154
+ buffer = (buffer << 6) | value;
155
+ bits += 6;
156
+ if (bits >= 8) {
157
+ bits -= 8;
158
+ bytes[index++] = (buffer >> bits) & 0xff;
159
+ }
160
+ }
161
+ try {
162
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes.subarray(0, index));
163
+ }
164
+ catch {
165
+ return undefined;
166
+ }
167
+ }
168
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"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"}