@remix-run/test 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -44
- package/dist/app/client/entry.js +4 -0
- package/dist/app/server.d.ts.map +1 -1
- package/dist/app/server.js +10 -10
- package/dist/cli.d.ts +30 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +87 -23
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/config.d.ts +55 -21
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +82 -33
- package/dist/lib/context.d.ts +5 -5
- package/dist/lib/coverage-loader.js +2 -2
- package/dist/lib/coverage.js +1 -1
- package/dist/lib/fake-timers.d.ts +39 -0
- package/dist/lib/fake-timers.d.ts.map +1 -1
- package/dist/lib/fake-timers.js +27 -8
- package/dist/lib/framework.d.ts +12 -6
- package/dist/lib/framework.d.ts.map +1 -1
- package/dist/lib/framework.js +24 -12
- package/dist/lib/import-module.d.ts.map +1 -1
- package/dist/lib/import-module.js +13 -3
- package/dist/lib/reporters/dot.d.ts.map +1 -1
- package/dist/lib/reporters/dot.js +10 -0
- package/dist/lib/reporters/files.d.ts.map +1 -1
- package/dist/lib/reporters/files.js +10 -0
- package/dist/lib/reporters/results.d.ts +1 -1
- package/dist/lib/reporters/results.d.ts.map +1 -1
- package/dist/lib/reporters/spec.d.ts.map +1 -1
- package/dist/lib/reporters/spec.js +10 -0
- package/dist/lib/reporters/tap.d.ts.map +1 -1
- package/dist/lib/reporters/tap.js +10 -0
- package/dist/lib/runner-browser.d.ts.map +1 -1
- package/dist/lib/runner-browser.js +40 -2
- package/dist/lib/runner.d.ts +18 -1
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +187 -38
- package/dist/lib/worker-e2e-file.d.ts +11 -0
- package/dist/lib/worker-e2e-file.d.ts.map +1 -0
- package/dist/lib/worker-e2e-file.js +69 -0
- package/dist/lib/worker-e2e.js +11 -47
- package/dist/lib/worker-process.d.ts +2 -0
- package/dist/lib/worker-process.d.ts.map +1 -0
- package/dist/lib/worker-process.js +55 -0
- package/dist/lib/worker-results.d.ts +3 -0
- package/dist/lib/worker-results.d.ts.map +1 -0
- package/dist/lib/worker-results.js +20 -0
- package/dist/lib/worker-server.d.ts +10 -0
- package/dist/lib/worker-server.d.ts.map +1 -0
- package/dist/lib/worker-server.js +112 -0
- package/dist/lib/worker.js +6 -55
- package/package.json +5 -5
- package/src/app/client/entry.ts +4 -0
- package/src/app/server.ts +11 -10
- package/src/cli.ts +121 -28
- package/src/index.ts +1 -1
- package/src/lib/config.ts +144 -58
- package/src/lib/context.ts +5 -5
- package/src/lib/coverage-loader.ts +2 -2
- package/src/lib/coverage.ts +1 -1
- package/src/lib/fake-timers.ts +65 -8
- package/src/lib/framework.ts +53 -36
- package/src/lib/import-module.ts +14 -3
- package/src/lib/reporters/dot.ts +9 -0
- package/src/lib/reporters/files.ts +9 -0
- package/src/lib/reporters/results.ts +1 -1
- package/src/lib/reporters/spec.ts +9 -0
- package/src/lib/reporters/tap.ts +9 -0
- package/src/lib/runner-browser.ts +46 -2
- package/src/lib/runner.ts +253 -50
- package/src/lib/ts-transform.ts +1 -1
- package/src/lib/worker-e2e-file.ts +98 -0
- package/src/lib/worker-e2e.ts +14 -51
- package/src/lib/worker-process.ts +69 -0
- package/src/lib/worker-results.ts +22 -0
- package/src/lib/worker-server.ts +123 -0
- package/src/lib/worker.ts +7 -47
- package/tsconfig.json +6 -3
package/dist/lib/config.js
CHANGED
|
@@ -40,19 +40,23 @@ const cliOptions = {
|
|
|
40
40
|
},
|
|
41
41
|
'glob.browser': {
|
|
42
42
|
type: 'string',
|
|
43
|
-
|
|
43
|
+
multiple: true,
|
|
44
|
+
description: 'Glob pattern(s) for browser test files',
|
|
44
45
|
},
|
|
45
46
|
'glob.e2e': {
|
|
46
47
|
type: 'string',
|
|
47
|
-
|
|
48
|
+
multiple: true,
|
|
49
|
+
description: 'Glob pattern(s) for E2E test files',
|
|
48
50
|
},
|
|
49
51
|
'glob.exclude': {
|
|
50
52
|
type: 'string',
|
|
51
|
-
|
|
53
|
+
multiple: true,
|
|
54
|
+
description: 'Glob pattern(s) for paths to exclude from discovery',
|
|
52
55
|
},
|
|
53
56
|
'glob.test': {
|
|
54
57
|
type: 'string',
|
|
55
|
-
|
|
58
|
+
multiple: true,
|
|
59
|
+
description: 'Glob pattern(s) for all test files',
|
|
56
60
|
},
|
|
57
61
|
concurrency: {
|
|
58
62
|
type: 'string',
|
|
@@ -109,7 +113,12 @@ const cliOptions = {
|
|
|
109
113
|
project: {
|
|
110
114
|
type: 'string',
|
|
111
115
|
short: 'p',
|
|
112
|
-
|
|
116
|
+
multiple: true,
|
|
117
|
+
description: 'Filter to specific Playwright project(s)',
|
|
118
|
+
},
|
|
119
|
+
pool: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
description: 'Pool used to run server and E2E test files: forks, threads (default: forks)',
|
|
113
122
|
},
|
|
114
123
|
reporter: {
|
|
115
124
|
type: 'string',
|
|
@@ -119,7 +128,8 @@ const cliOptions = {
|
|
|
119
128
|
type: {
|
|
120
129
|
type: 'string',
|
|
121
130
|
short: 't',
|
|
122
|
-
|
|
131
|
+
multiple: true,
|
|
132
|
+
description: 'Test types to run (default: server, browser, e2e)',
|
|
123
133
|
},
|
|
124
134
|
watch: {
|
|
125
135
|
type: 'boolean',
|
|
@@ -143,16 +153,17 @@ const defaultValues = {
|
|
|
143
153
|
functions: undefined,
|
|
144
154
|
},
|
|
145
155
|
glob: {
|
|
146
|
-
test: '**/*.test{,.e2e,.browser}.{ts,tsx}',
|
|
147
|
-
browser: '**/*.test.browser.{ts,tsx}',
|
|
148
|
-
e2e: '**/*.test.e2e.{ts,tsx}',
|
|
149
|
-
exclude: 'node_modules/**',
|
|
156
|
+
test: ['**/*.test{,.e2e,.browser}.{ts,tsx}'],
|
|
157
|
+
browser: ['**/*.test.browser.{ts,tsx}'],
|
|
158
|
+
e2e: ['**/*.test.e2e.{ts,tsx}'],
|
|
159
|
+
exclude: ['node_modules/**'],
|
|
150
160
|
},
|
|
151
|
-
|
|
152
|
-
type: 'server,browser,e2e',
|
|
153
|
-
setup: undefined,
|
|
161
|
+
pool: 'forks',
|
|
154
162
|
playwrightConfig: undefined,
|
|
155
163
|
project: undefined,
|
|
164
|
+
reporter: process.env.CI === 'true' ? 'files' : 'spec',
|
|
165
|
+
setup: undefined,
|
|
166
|
+
type: ['server', 'browser', 'e2e'],
|
|
156
167
|
watch: false,
|
|
157
168
|
};
|
|
158
169
|
export async function loadConfig(args = process.argv.slice(2), cwd = process.cwd()) {
|
|
@@ -161,12 +172,21 @@ export async function loadConfig(args = process.argv.slice(2), cwd = process.cwd
|
|
|
161
172
|
let config = resolveConfig(fileConfig, parsed);
|
|
162
173
|
return config;
|
|
163
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* Returns the formatted `remix-test --help` text. Useful for embedding the
|
|
177
|
+
* runner's CLI options in higher-level tooling.
|
|
178
|
+
*
|
|
179
|
+
* @param _target Output stream the help text will be written to. Reserved
|
|
180
|
+
* for future use (e.g. width-aware formatting); currently
|
|
181
|
+
* unused.
|
|
182
|
+
* @returns The help text as a single string ready to write to a stream.
|
|
183
|
+
*/
|
|
164
184
|
export function getRemixTestHelpText(_target = process.stdout) {
|
|
165
185
|
let lines = [
|
|
166
|
-
'Usage: remix-test [glob] [options]',
|
|
186
|
+
'Usage: remix-test [glob...] [options]',
|
|
167
187
|
'',
|
|
168
188
|
'Arguments:',
|
|
169
|
-
` glob Glob pattern for test files (default: "${defaultValues.glob.test}")`,
|
|
189
|
+
` glob Glob pattern(s) for test files (default: "${defaultValues.glob.test.join(', ')}")`,
|
|
170
190
|
'',
|
|
171
191
|
'Options:',
|
|
172
192
|
];
|
|
@@ -181,17 +201,25 @@ export function getRemixTestHelpText(_target = process.stdout) {
|
|
|
181
201
|
function parseCliArgs(args) {
|
|
182
202
|
return util.parseArgs({ args, options: cliOptions, allowPositionals: true });
|
|
183
203
|
}
|
|
204
|
+
function toArray(value) {
|
|
205
|
+
return Array.isArray(value) ? [...value] : [value];
|
|
206
|
+
}
|
|
207
|
+
function toCommaSeparatedArray(value) {
|
|
208
|
+
return toArray(value).flatMap((item) => item
|
|
209
|
+
.split(',')
|
|
210
|
+
.map((part) => part.trim())
|
|
211
|
+
.filter(Boolean));
|
|
212
|
+
}
|
|
184
213
|
function resolveConfig(fileConfig, { values: cliValues, positionals }) {
|
|
185
214
|
let fileCoverage = typeof fileConfig.coverage === 'boolean' ? {} : fileConfig.coverage || {};
|
|
186
215
|
return {
|
|
187
216
|
glob: {
|
|
188
|
-
test: positionals
|
|
189
|
-
|
|
190
|
-
fileConfig.glob?.test ??
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
exclude: cliValues['glob.exclude'] ?? fileConfig.glob?.exclude ?? defaultValues.glob.exclude,
|
|
217
|
+
test: toArray(positionals.length > 0
|
|
218
|
+
? positionals
|
|
219
|
+
: (cliValues['glob.test'] ?? fileConfig.glob?.test ?? defaultValues.glob.test)),
|
|
220
|
+
browser: toArray(cliValues['glob.browser'] ?? fileConfig.glob?.browser ?? defaultValues.glob.browser),
|
|
221
|
+
e2e: toArray(cliValues['glob.e2e'] ?? fileConfig.glob?.e2e ?? defaultValues.glob.e2e),
|
|
222
|
+
exclude: toArray(cliValues['glob.exclude'] ?? fileConfig.glob?.exclude ?? defaultValues.glob.exclude),
|
|
195
223
|
},
|
|
196
224
|
browser: {
|
|
197
225
|
echo: cliValues['browser.echo'] ?? fileConfig.browser?.echo ?? defaultValues.browser.echo,
|
|
@@ -201,12 +229,18 @@ function resolveConfig(fileConfig, { values: cliValues, positionals }) {
|
|
|
201
229
|
coverage: cliValues.coverage === true || !!fileConfig.coverage
|
|
202
230
|
? {
|
|
203
231
|
dir: cliValues['coverage.dir'] ?? fileCoverage.dir ?? defaultValues.coverage.dir,
|
|
204
|
-
include:
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
232
|
+
include: (() => {
|
|
233
|
+
let raw = cliValues['coverage.include'] ??
|
|
234
|
+
fileCoverage.include ??
|
|
235
|
+
defaultValues.coverage.include;
|
|
236
|
+
return raw === undefined ? undefined : toArray(raw);
|
|
237
|
+
})(),
|
|
238
|
+
exclude: (() => {
|
|
239
|
+
let raw = cliValues['coverage.exclude'] ??
|
|
240
|
+
fileCoverage.exclude ??
|
|
241
|
+
defaultValues.coverage.exclude;
|
|
242
|
+
return raw === undefined ? undefined : toArray(raw);
|
|
243
|
+
})(),
|
|
210
244
|
statements: cliValues['coverage.statements'] !== undefined
|
|
211
245
|
? Number(cliValues['coverage.statements'])
|
|
212
246
|
: fileCoverage.statements !== undefined
|
|
@@ -231,12 +265,22 @@ function resolveConfig(fileConfig, { values: cliValues, positionals }) {
|
|
|
231
265
|
: undefined,
|
|
232
266
|
setup: cliValues.setup ?? fileConfig.setup ?? defaultValues.setup,
|
|
233
267
|
playwrightConfig: cliValues.playwrightConfig ?? fileConfig.playwrightConfig ?? defaultValues.playwrightConfig,
|
|
234
|
-
|
|
268
|
+
pool: resolvePool(cliValues.pool ?? fileConfig.pool ?? defaultValues.pool),
|
|
269
|
+
project: (() => {
|
|
270
|
+
let raw = cliValues.project ?? fileConfig.project ?? defaultValues.project;
|
|
271
|
+
return raw === undefined ? undefined : toCommaSeparatedArray(raw);
|
|
272
|
+
})(),
|
|
235
273
|
reporter: cliValues.reporter ?? fileConfig.reporter ?? defaultValues.reporter,
|
|
236
|
-
type: cliValues.type ?? fileConfig.type ?? defaultValues.type,
|
|
274
|
+
type: toCommaSeparatedArray(cliValues.type ?? fileConfig.type ?? defaultValues.type),
|
|
237
275
|
watch: cliValues.watch ?? fileConfig.watch ?? defaultValues.watch,
|
|
238
276
|
};
|
|
239
277
|
}
|
|
278
|
+
function resolvePool(value) {
|
|
279
|
+
if (value === 'forks' || value === 'threads') {
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
throw new Error(`Unsupported test pool "${value}". Supported pools are: forks, threads`);
|
|
283
|
+
}
|
|
240
284
|
async function loadConfigFile(configPath, cwd) {
|
|
241
285
|
let candidates = configPath
|
|
242
286
|
? [path.resolve(cwd, configPath)]
|
|
@@ -244,12 +288,17 @@ async function loadConfigFile(configPath, cwd) {
|
|
|
244
288
|
for (let candidate of candidates) {
|
|
245
289
|
try {
|
|
246
290
|
await fsp.access(candidate);
|
|
247
|
-
let mod = await importModule(candidate, import.meta);
|
|
248
|
-
return mod.default ?? mod;
|
|
249
291
|
}
|
|
250
292
|
catch {
|
|
251
|
-
// not found
|
|
293
|
+
// not found — try the next candidate
|
|
294
|
+
continue;
|
|
252
295
|
}
|
|
296
|
+
// The file exists; let import errors propagate rather than silently
|
|
297
|
+
// falling through to defaults — that masking is what hid "Windows
|
|
298
|
+
// absolute paths aren't valid ESM specifiers" by classifying every
|
|
299
|
+
// browser test as a server test.
|
|
300
|
+
let mod = await importModule(candidate, import.meta);
|
|
301
|
+
return mod.default ?? mod;
|
|
253
302
|
}
|
|
254
303
|
return {};
|
|
255
304
|
}
|
package/dist/lib/context.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface TestServer {
|
|
|
13
13
|
close(): Promise<void>;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Test Context providing utilities for testing via remix-test
|
|
16
|
+
* Test Context providing utilities for testing via `remix-test`. The context is
|
|
17
17
|
* passed as the first argument to the {@link test}/{@link it} functions.
|
|
18
18
|
*
|
|
19
19
|
* @example
|
|
@@ -33,8 +33,8 @@ export interface TestContext {
|
|
|
33
33
|
*/
|
|
34
34
|
after(fn: () => void): void;
|
|
35
35
|
/**
|
|
36
|
-
* Mock tracker for the current test. Mirrors the shape of Node's
|
|
37
|
-
* `t.mock`. Method mocks created
|
|
36
|
+
* Mock tracker for the current test using {@link mock}. Mirrors the shape of Node's
|
|
37
|
+
* `t.mock`. Method mocks created via `t.mock` are auto-restored on test completion.
|
|
38
38
|
*/
|
|
39
39
|
mock: {
|
|
40
40
|
/**
|
|
@@ -67,8 +67,8 @@ export interface TestContext {
|
|
|
67
67
|
/**
|
|
68
68
|
* Wires a running test server up to a Playwright page so the test can drive
|
|
69
69
|
* it. The server is closed automatically when the test ends. Pair with
|
|
70
|
-
*
|
|
71
|
-
*
|
|
70
|
+
* {@link createTestServer} from `@remix-run/node-fetch-server/test` to spin
|
|
71
|
+
* up the server.
|
|
72
72
|
*
|
|
73
73
|
* @param server - The running server the page should target
|
|
74
74
|
* @returns A `Page` whose `baseURL` is set to `server.baseUrl`.
|
|
@@ -3,8 +3,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
import { transformTypeScript } from "./ts-transform.js";
|
|
4
4
|
// Custom ESM loader hook for TypeScript files.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// Applies an un-minified esbuild transform that preserves line structure.
|
|
7
|
+
// This ensures V8 coverage byte offsets map
|
|
8
8
|
// cleanly to TypeScript source lines via the inline source map, giving
|
|
9
9
|
// accurate per-line coverage rather than collapsing multiple statements onto
|
|
10
10
|
// a single minified line.
|
package/dist/lib/coverage.js
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handle returned by `mock.timers.enable()` for driving fake timers during a
|
|
3
|
+
* test. While enabled, `setTimeout`, `setInterval`, `clearTimeout`,
|
|
4
|
+
* `clearInterval`, and `Date.now` use the fake clock instead of the real one;
|
|
5
|
+
* timers fire only when the test calls `advance` (or `advanceAsync`).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* it('debounces save calls', (t) => {
|
|
10
|
+
* let timers = t.mock.timers.enable()
|
|
11
|
+
* let save = t.mock.fn()
|
|
12
|
+
* let debounced = debounce(save, 100)
|
|
13
|
+
* debounced(); debounced(); debounced()
|
|
14
|
+
* timers.advance(100)
|
|
15
|
+
* assert.equal(save.mock.calls.length, 1)
|
|
16
|
+
* })
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
1
19
|
export interface FakeTimers {
|
|
20
|
+
/**
|
|
21
|
+
* Advance the fake clock by `ms` milliseconds, synchronously firing every
|
|
22
|
+
* timer whose deadline is reached during the advance.
|
|
23
|
+
*
|
|
24
|
+
* @param ms Number of milliseconds to advance.
|
|
25
|
+
*/
|
|
2
26
|
advance(ms: number): void;
|
|
27
|
+
/**
|
|
28
|
+
* Like `advance`, but yields to microtasks between each timer firing so
|
|
29
|
+
* Promise continuations (and any timers they schedule) can settle before
|
|
30
|
+
* the next firing is processed. Use this when a callback awaits work that
|
|
31
|
+
* itself depends on the fake clock.
|
|
32
|
+
*
|
|
33
|
+
* @param ms Number of milliseconds to advance.
|
|
34
|
+
* @returns A promise that resolves once all reachable timers have fired.
|
|
35
|
+
*/
|
|
36
|
+
advanceAsync(ms: number): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Restore the original timer functions and the real clock. Called
|
|
39
|
+
* automatically after the test finishes; may also be called early to
|
|
40
|
+
* disable fake timers mid-test.
|
|
41
|
+
*/
|
|
3
42
|
restore(): void;
|
|
4
43
|
}
|
|
5
44
|
export declare function createFakeTimers(): FakeTimers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-timers.d.ts","sourceRoot":"","sources":["../../src/lib/fake-timers.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,gBAAgB,IAAI,UAAU,
|
|
1
|
+
{"version":3,"file":"fake-timers.d.ts","sourceRoot":"","sources":["../../src/lib/fake-timers.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CA0E7C"}
|
package/dist/lib/fake-timers.js
CHANGED
|
@@ -15,21 +15,40 @@ export function createFakeTimers() {
|
|
|
15
15
|
let clearTimeoutMock = mock.method(globalThis, 'clearTimeout', cancel);
|
|
16
16
|
let setIntervalMock = mock.method(globalThis, 'setInterval', ((fn, delay = 0) => schedule(fn, delay, Math.max(0, delay))));
|
|
17
17
|
let clearIntervalMock = mock.method(globalThis, 'clearInterval', cancel);
|
|
18
|
+
function takeNext(targetTime) {
|
|
19
|
+
let next = pending.filter((t) => t.time <= targetTime).sort((a, b) => a.time - b.time)[0];
|
|
20
|
+
if (!next)
|
|
21
|
+
return null;
|
|
22
|
+
currentTime = next.time;
|
|
23
|
+
pending = pending.filter((t) => t.id !== next.id);
|
|
24
|
+
// Requeue intervals before running the callback so that calling
|
|
25
|
+
// clearInterval(id) from inside the callback can cancel the next firing.
|
|
26
|
+
if (next.repeatMs !== undefined) {
|
|
27
|
+
pending.push({ ...next, time: next.time + Math.max(1, next.repeatMs) });
|
|
28
|
+
}
|
|
29
|
+
return next;
|
|
30
|
+
}
|
|
18
31
|
return {
|
|
19
32
|
advance(ms) {
|
|
20
33
|
let targetTime = currentTime + ms;
|
|
21
34
|
while (true) {
|
|
22
|
-
let next =
|
|
35
|
+
let next = takeNext(targetTime);
|
|
36
|
+
if (!next)
|
|
37
|
+
break;
|
|
38
|
+
next.fn();
|
|
39
|
+
}
|
|
40
|
+
currentTime = targetTime;
|
|
41
|
+
},
|
|
42
|
+
async advanceAsync(ms) {
|
|
43
|
+
let targetTime = currentTime + ms;
|
|
44
|
+
while (true) {
|
|
45
|
+
let next = takeNext(targetTime);
|
|
23
46
|
if (!next)
|
|
24
47
|
break;
|
|
25
|
-
currentTime = next.time;
|
|
26
|
-
pending = pending.filter((t) => t.id !== next.id);
|
|
27
|
-
// Requeue intervals before running the callback so that calling
|
|
28
|
-
// clearInterval(id) from inside the callback can cancel the next firing.
|
|
29
|
-
if (next.repeatMs !== undefined) {
|
|
30
|
-
pending.push({ ...next, time: next.time + Math.max(1, next.repeatMs) });
|
|
31
|
-
}
|
|
32
48
|
next.fn();
|
|
49
|
+
// Drain microtasks so Promise continuations (and any timers they
|
|
50
|
+
// schedule) can settle before we look for the next firing.
|
|
51
|
+
await Promise.resolve();
|
|
33
52
|
}
|
|
34
53
|
currentTime = targetTime;
|
|
35
54
|
},
|
package/dist/lib/framework.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { TestContext } from './context.ts';
|
|
2
|
+
declare function describeImpl(name: string, fn: () => void): void;
|
|
3
|
+
declare function describeImpl(name: string, meta: SuiteMeta, fn: () => void): void;
|
|
2
4
|
/**
|
|
3
|
-
* Groups related tests into a named suite. Suites can be nested
|
|
4
|
-
* as such
|
|
5
|
+
* Groups related tests into a named suite. Suites can be nested and will be displayed
|
|
6
|
+
* as such in reporter output. Lifecycle hooks registered inside
|
|
5
7
|
* a `describe` block apply only to tests within that block.
|
|
6
8
|
*
|
|
7
9
|
* @example
|
|
@@ -15,9 +17,10 @@ import type { TestContext } from './context.ts';
|
|
|
15
17
|
* describe.todo('planned suite')
|
|
16
18
|
*
|
|
17
19
|
* @param name - The suite name shown in reporter output.
|
|
20
|
+
* @param meta - Suite metadata such as `skip` or `only`.
|
|
18
21
|
* @param fn - A function that registers the tests and lifecycle hooks in this suite.
|
|
19
22
|
*/
|
|
20
|
-
export declare const describe:
|
|
23
|
+
export declare const describe: typeof describeImpl & {
|
|
21
24
|
skip: (name: string, fn: () => void) => void;
|
|
22
25
|
only: (name: string, fn: () => void) => void;
|
|
23
26
|
todo: (name: string) => void;
|
|
@@ -31,6 +34,8 @@ type TestMeta = {
|
|
|
31
34
|
only?: boolean;
|
|
32
35
|
};
|
|
33
36
|
type TestFn = (t: TestContext) => void | Promise<void>;
|
|
37
|
+
declare function itImpl(name: string, fn: TestFn): void;
|
|
38
|
+
declare function itImpl(name: string, meta: TestMeta, fn: TestFn): void;
|
|
34
39
|
/**
|
|
35
40
|
* Defines a single test case. The optional `TestContext` argument `t` provides
|
|
36
41
|
* mock helpers and per-test cleanup registration.
|
|
@@ -47,21 +52,22 @@ type TestFn = (t: TestContext) => void | Promise<void>;
|
|
|
47
52
|
* it.todo('coming soon')
|
|
48
53
|
*
|
|
49
54
|
* @param name - The test name shown in reporter output.
|
|
55
|
+
* @param meta - Test metadata such as `skip` or `only`.
|
|
50
56
|
* @param fn - The test body, receiving a {@link TestContext} as its first argument.
|
|
51
57
|
*/
|
|
52
|
-
export declare const it:
|
|
58
|
+
export declare const it: typeof itImpl & {
|
|
53
59
|
skip: (name: string, fn?: TestFn | undefined) => void;
|
|
54
60
|
only: (name: string, fn: TestFn) => void;
|
|
55
61
|
todo: (name: string) => void;
|
|
56
62
|
};
|
|
57
63
|
/** Alias for {@link describe}. */
|
|
58
|
-
export declare const suite:
|
|
64
|
+
export declare const suite: typeof describeImpl & {
|
|
59
65
|
skip: (name: string, fn: () => void) => void;
|
|
60
66
|
only: (name: string, fn: () => void) => void;
|
|
61
67
|
todo: (name: string) => void;
|
|
62
68
|
};
|
|
63
69
|
/** Alias for {@link it}. */
|
|
64
|
-
export declare const test:
|
|
70
|
+
export declare const test: typeof itImpl & {
|
|
65
71
|
skip: (name: string, fn?: TestFn | undefined) => void;
|
|
66
72
|
only: (name: string, fn: TestFn) => void;
|
|
67
73
|
todo: (name: string) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/lib/framework.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"framework.d.ts","sourceRoot":"","sources":["../../src/lib/framework.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AA4F/C,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;AACzD,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;AAO1E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ;;;;CAUnB,CAAA;AAEF,KAAK,SAAS,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AACnD,KAAK,QAAQ,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAClD,KAAK,MAAM,GAAG,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAatD,iBAAS,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;AAC/C,iBAAS,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;AAO/D;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,EAAE;;;;CAUb,CAAA;AAEF,kCAAkC;AAClC,eAAO,MAAM,KAAK;;;;CAAW,CAAA;AAC7B,4BAA4B;AAC5B,eAAO,MAAM,IAAI;;;;CAAK,CAAA;AA2BtB;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAGxD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAGvD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAGvD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAGtD;AAED,mEAAiE;AACjE,eAAO,MAAM,MAAM,kBAAY,CAAA;AAC/B,kEAAgE;AAChE,eAAO,MAAM,KAAK,iBAAW,CAAA"}
|
package/dist/lib/framework.js
CHANGED
|
@@ -26,6 +26,14 @@ function registerDescribe(name, fn, flags) {
|
|
|
26
26
|
throw new Error(`Duplicate suite name: "${fullName}"`);
|
|
27
27
|
}
|
|
28
28
|
let suite = { name: fullName, tests: [], ...flags };
|
|
29
|
+
// Children inherit `skip`/`only` from their parent so that
|
|
30
|
+
// `describe.skip('parent', () => describe('child', () => it(...)))` actually
|
|
31
|
+
// skips the child's tests. The executor walks `rootSuites` as a flat list and
|
|
32
|
+
// only inspects each suite's own flag, so the propagation has to happen here.
|
|
33
|
+
if (currentSuite?.skip)
|
|
34
|
+
suite.skip = true;
|
|
35
|
+
if (currentSuite?.only)
|
|
36
|
+
suite.only = true;
|
|
29
37
|
// Inherit lifecycle hooks from parent suite (or root hooks if at top level)
|
|
30
38
|
let parent = currentSuite ?? rootHooks;
|
|
31
39
|
if (parent.beforeEach)
|
|
@@ -53,9 +61,14 @@ function registerDescribe(name, fn, flags) {
|
|
|
53
61
|
currentSuite = prevSuite;
|
|
54
62
|
}
|
|
55
63
|
}
|
|
64
|
+
function describeImpl(name, metaOrFn, fn) {
|
|
65
|
+
let meta = typeof metaOrFn === 'function' ? {} : metaOrFn;
|
|
66
|
+
let suiteFn = typeof metaOrFn === 'function' ? metaOrFn : fn;
|
|
67
|
+
registerDescribe(name, suiteFn, meta);
|
|
68
|
+
}
|
|
56
69
|
/**
|
|
57
|
-
* Groups related tests into a named suite. Suites can be nested
|
|
58
|
-
* as such
|
|
70
|
+
* Groups related tests into a named suite. Suites can be nested and will be displayed
|
|
71
|
+
* as such in reporter output. Lifecycle hooks registered inside
|
|
59
72
|
* a `describe` block apply only to tests within that block.
|
|
60
73
|
*
|
|
61
74
|
* @example
|
|
@@ -69,13 +82,10 @@ function registerDescribe(name, fn, flags) {
|
|
|
69
82
|
* describe.todo('planned suite')
|
|
70
83
|
*
|
|
71
84
|
* @param name - The suite name shown in reporter output.
|
|
85
|
+
* @param meta - Suite metadata such as `skip` or `only`.
|
|
72
86
|
* @param fn - A function that registers the tests and lifecycle hooks in this suite.
|
|
73
87
|
*/
|
|
74
|
-
export const describe = Object.assign(
|
|
75
|
-
let meta = typeof metaOrFn === 'function' ? {} : metaOrFn;
|
|
76
|
-
let suiteFn = typeof metaOrFn === 'function' ? metaOrFn : fn;
|
|
77
|
-
registerDescribe(name, suiteFn, meta);
|
|
78
|
-
}, {
|
|
88
|
+
export const describe = Object.assign(describeImpl, {
|
|
79
89
|
skip: (name, fn) => registerDescribe(name, fn, { skip: true }),
|
|
80
90
|
only: (name, fn) => registerDescribe(name, fn, { only: true }),
|
|
81
91
|
todo: (name) => {
|
|
@@ -93,6 +103,11 @@ function registerIt(name, fn, flags) {
|
|
|
93
103
|
}
|
|
94
104
|
suite.tests.push({ name, fn, suite, ...flags });
|
|
95
105
|
}
|
|
106
|
+
function itImpl(name, metaOrFn, fn) {
|
|
107
|
+
let meta = typeof metaOrFn === 'function' ? {} : metaOrFn;
|
|
108
|
+
let testFn = typeof metaOrFn === 'function' ? metaOrFn : fn;
|
|
109
|
+
registerIt(name, testFn, meta);
|
|
110
|
+
}
|
|
96
111
|
/**
|
|
97
112
|
* Defines a single test case. The optional `TestContext` argument `t` provides
|
|
98
113
|
* mock helpers and per-test cleanup registration.
|
|
@@ -109,13 +124,10 @@ function registerIt(name, fn, flags) {
|
|
|
109
124
|
* it.todo('coming soon')
|
|
110
125
|
*
|
|
111
126
|
* @param name - The test name shown in reporter output.
|
|
127
|
+
* @param meta - Test metadata such as `skip` or `only`.
|
|
112
128
|
* @param fn - The test body, receiving a {@link TestContext} as its first argument.
|
|
113
129
|
*/
|
|
114
|
-
export const it = Object.assign(
|
|
115
|
-
let meta = typeof metaOrFn === 'function' ? {} : metaOrFn;
|
|
116
|
-
let testFn = typeof metaOrFn === 'function' ? metaOrFn : fn;
|
|
117
|
-
registerIt(name, testFn, meta);
|
|
118
|
-
}, {
|
|
130
|
+
export const it = Object.assign(itImpl, {
|
|
119
131
|
skip: (name, fn) => registerIt(name, fn ?? (() => { }), { skip: true }),
|
|
120
132
|
only: (name, fn) => registerIt(name, fn, { only: true }),
|
|
121
133
|
todo: (name) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-module.d.ts","sourceRoot":"","sources":["../../src/lib/import-module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"import-module.d.ts","sourceRoot":"","sources":["../../src/lib/import-module.ts"],"names":[],"mappings":"AAmBA,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAoBpF"}
|
|
@@ -6,7 +6,8 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
6
6
|
}
|
|
7
7
|
return path;
|
|
8
8
|
};
|
|
9
|
-
import
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import { pathToFileURL } from 'node:url';
|
|
10
11
|
import { IS_BUN } from "./runtime.js";
|
|
11
12
|
function hasImportMetaResolve(meta) {
|
|
12
13
|
return 'resolve' in meta && typeof meta.resolve === 'function';
|
|
@@ -19,11 +20,20 @@ function hasImportMetaResolve(meta) {
|
|
|
19
20
|
* @returns The imported module namespace.
|
|
20
21
|
*/
|
|
21
22
|
export async function importModule(specifier, meta) {
|
|
23
|
+
// Absolute Windows paths (`C:\foo\bar.ts`) aren't valid ESM specifiers — only
|
|
24
|
+
// `file:///C:/foo/bar.ts` URLs, relative specifiers, or POSIX absolute paths
|
|
25
|
+
// are. Convert any absolute filesystem path to its `file:` URL so module
|
|
26
|
+
// loaders and `import()` accept it on every platform. POSIX absolute paths
|
|
27
|
+
// happen to work as specifiers without conversion, but going through
|
|
28
|
+
// `pathToFileURL` is safe and platform-agnostic.
|
|
29
|
+
let resolvedSpecifier = path.isAbsolute(specifier) ? pathToFileURL(specifier).href : specifier;
|
|
22
30
|
if (IS_BUN) {
|
|
23
31
|
if (!hasImportMetaResolve(meta)) {
|
|
24
32
|
throw new Error('importModule() requires import.meta.resolve() in Bun');
|
|
25
33
|
}
|
|
26
|
-
return import(__rewriteRelativeImportExtension(meta.resolve(
|
|
34
|
+
return import(__rewriteRelativeImportExtension(meta.resolve(resolvedSpecifier, meta.url)));
|
|
27
35
|
}
|
|
28
|
-
|
|
36
|
+
// node-tsx uses Node APIs that fail in Bun if statically imported
|
|
37
|
+
let { loadModule } = await import('@remix-run/node-tsx/load-module');
|
|
38
|
+
return loadModule(resolvedSpecifier, meta.url);
|
|
29
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/dot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,WAAY,YAAW,QAAQ;;
|
|
1
|
+
{"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/dot.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,WAAY,YAAW,QAAQ;;IAM1C,cAAc,CAAC,MAAM,EAAE,MAAM,QAAI;IAEjC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,QAmB3C;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QA+B3C;CACF"}
|
|
@@ -3,8 +3,16 @@ import { normalizeLine } from "../normalize.js";
|
|
|
3
3
|
export class DotReporter {
|
|
4
4
|
#failures = [];
|
|
5
5
|
#dotCount = 0;
|
|
6
|
+
#files = new Set();
|
|
7
|
+
#suites = new Set();
|
|
6
8
|
onSectionStart(_label) { }
|
|
7
9
|
onResult(results, _env) {
|
|
10
|
+
for (let test of results.tests) {
|
|
11
|
+
if (test.filePath)
|
|
12
|
+
this.#files.add(test.filePath);
|
|
13
|
+
if (test.suiteName)
|
|
14
|
+
this.#suites.add(test.suiteName);
|
|
15
|
+
}
|
|
8
16
|
for (let test of results.tests) {
|
|
9
17
|
if (test.status === 'passed') {
|
|
10
18
|
process.stdout.write(colors.green('.'));
|
|
@@ -43,6 +51,8 @@ export class DotReporter {
|
|
|
43
51
|
let { passed, failed, skipped, todo } = counts;
|
|
44
52
|
let info = colors.cyan('ℹ');
|
|
45
53
|
console.log();
|
|
54
|
+
console.log(`${info} files ${this.#files.size}`);
|
|
55
|
+
console.log(`${info} suites ${this.#suites.size}`);
|
|
46
56
|
console.log(`${info} tests ${passed + failed + skipped + todo}`);
|
|
47
57
|
console.log(`${info} pass ${passed}`);
|
|
48
58
|
console.log(`${info} fail ${failed}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/files.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,aAAc,YAAW,QAAQ;;
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/files.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,aAAc,YAAW,QAAQ;;IAK5C,cAAc,CAAC,MAAM,EAAE,MAAM,QAAI;IAEjC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,QAmC1C;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAkC3C;CACF"}
|
|
@@ -3,8 +3,16 @@ import { colors } from "../colors.js";
|
|
|
3
3
|
import { normalizeLine } from "../normalize.js";
|
|
4
4
|
export class FilesReporter {
|
|
5
5
|
#failures = [];
|
|
6
|
+
#files = new Set();
|
|
7
|
+
#suites = new Set();
|
|
6
8
|
onSectionStart(_label) { }
|
|
7
9
|
onResult(results, env) {
|
|
10
|
+
for (let test of results.tests) {
|
|
11
|
+
if (test.filePath)
|
|
12
|
+
this.#files.add(test.filePath);
|
|
13
|
+
if (test.suiteName)
|
|
14
|
+
this.#suites.add(test.suiteName);
|
|
15
|
+
}
|
|
8
16
|
let filePath = results.tests[0]?.filePath;
|
|
9
17
|
let fileName = filePath ? path.relative(process.cwd(), filePath) : '(unknown)';
|
|
10
18
|
let envLabel = env ? ` ${colors.dim(`[${env}]`)}` : '';
|
|
@@ -58,6 +66,8 @@ export class FilesReporter {
|
|
|
58
66
|
let { passed, failed, skipped, todo } = counts;
|
|
59
67
|
let info = colors.cyan('ℹ');
|
|
60
68
|
console.log();
|
|
69
|
+
console.log(`${info} files ${this.#files.size}`);
|
|
70
|
+
console.log(`${info} suites ${this.#suites.size}`);
|
|
61
71
|
console.log(`${info} tests ${passed + failed + skipped + todo}`);
|
|
62
72
|
console.log(`${info} pass ${passed}`);
|
|
63
73
|
console.log(`${info} fail ${failed}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAErD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAA;IAChD,KAAK,CAAC,EAAE;QACN,OAAO,EAAE,MAAM,CAAA;QACf,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;IACD,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,yBAAyB,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,eAAe,EAAE,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnF;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/spec.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,YAAa,YAAW,QAAQ;;
|
|
1
|
+
{"version":3,"file":"spec.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/spec.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAc,WAAW,EAAE,MAAM,cAAc,CAAA;AAEnE,qBAAa,YAAa,YAAW,QAAQ;;IAK3C,cAAc,CAAC,KAAK,EAAE,MAAM,QAE3B;IAED,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,QAmI1C;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAkC3C;CACF"}
|