@remix-run/test 0.1.0 → 0.3.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 (159) hide show
  1. package/README.md +161 -50
  2. package/dist/app/client/entry.d.ts +2 -0
  3. package/dist/app/client/entry.d.ts.map +1 -0
  4. package/dist/app/client/entry.js +328 -0
  5. package/dist/app/client/iframe.d.ts +2 -0
  6. package/dist/app/client/iframe.d.ts.map +1 -0
  7. package/dist/app/client/iframe.js +22 -0
  8. package/dist/app/server.d.ts +6 -0
  9. package/dist/app/server.d.ts.map +1 -0
  10. package/dist/app/server.js +303 -0
  11. package/dist/cli-entry.d.ts +3 -0
  12. package/dist/cli-entry.d.ts.map +1 -0
  13. package/dist/cli-entry.js +14 -0
  14. package/dist/cli.d.ts +7 -2
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +319 -140
  17. package/dist/index.d.ts +2 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/lib/colors.d.ts +2 -0
  20. package/dist/lib/colors.d.ts.map +1 -0
  21. package/dist/lib/colors.js +2 -0
  22. package/dist/lib/config.d.ts +59 -14
  23. package/dist/lib/config.d.ts.map +1 -1
  24. package/dist/lib/config.js +181 -38
  25. package/dist/lib/context.d.ts +37 -13
  26. package/dist/lib/context.d.ts.map +1 -1
  27. package/dist/lib/context.js +19 -3
  28. package/dist/lib/coverage-loader.d.ts +16 -0
  29. package/dist/lib/coverage-loader.d.ts.map +1 -0
  30. package/dist/lib/coverage-loader.js +20 -0
  31. package/dist/lib/coverage.d.ts +28 -0
  32. package/dist/lib/coverage.d.ts.map +1 -0
  33. package/dist/lib/coverage.js +212 -0
  34. package/dist/lib/executor.d.ts +3 -26
  35. package/dist/lib/executor.d.ts.map +1 -1
  36. package/dist/lib/executor.js +11 -6
  37. package/dist/lib/fake-timers.d.ts +13 -0
  38. package/dist/lib/fake-timers.d.ts.map +1 -0
  39. package/dist/lib/fake-timers.js +64 -0
  40. package/dist/lib/import-module.d.ts +2 -0
  41. package/dist/lib/import-module.d.ts.map +1 -0
  42. package/dist/lib/import-module.js +38 -0
  43. package/dist/lib/normalize.d.ts +2 -0
  44. package/dist/lib/normalize.d.ts.map +1 -0
  45. package/dist/lib/{utils.js → normalize.js} +0 -9
  46. package/dist/lib/playwright.d.ts +1 -1
  47. package/dist/lib/playwright.d.ts.map +1 -1
  48. package/dist/lib/playwright.js +5 -8
  49. package/dist/lib/reporters/dot.d.ts +1 -2
  50. package/dist/lib/reporters/dot.d.ts.map +1 -1
  51. package/dist/lib/reporters/dot.js +12 -1
  52. package/dist/lib/reporters/files.d.ts +1 -2
  53. package/dist/lib/reporters/files.d.ts.map +1 -1
  54. package/dist/lib/reporters/files.js +12 -1
  55. package/dist/lib/reporters/index.d.ts +4 -5
  56. package/dist/lib/reporters/index.d.ts.map +1 -1
  57. package/dist/lib/reporters/index.js +3 -3
  58. package/dist/lib/reporters/results.d.ts +30 -0
  59. package/dist/lib/reporters/results.d.ts.map +1 -0
  60. package/dist/lib/reporters/results.js +1 -0
  61. package/dist/lib/reporters/spec.d.ts +1 -2
  62. package/dist/lib/reporters/spec.d.ts.map +1 -1
  63. package/dist/lib/reporters/spec.js +12 -1
  64. package/dist/lib/reporters/tap.d.ts +1 -2
  65. package/dist/lib/reporters/tap.d.ts.map +1 -1
  66. package/dist/lib/reporters/tap.js +11 -1
  67. package/dist/lib/runner-browser.d.ts +21 -0
  68. package/dist/lib/runner-browser.d.ts.map +1 -0
  69. package/dist/lib/runner-browser.js +123 -0
  70. package/dist/lib/runner.d.ts +24 -2
  71. package/dist/lib/runner.d.ts.map +1 -1
  72. package/dist/lib/runner.js +216 -38
  73. package/dist/lib/runtime.d.ts +2 -0
  74. package/dist/lib/runtime.d.ts.map +1 -0
  75. package/dist/lib/runtime.js +2 -0
  76. package/dist/lib/ts-transform.d.ts +4 -0
  77. package/dist/lib/ts-transform.d.ts.map +1 -0
  78. package/dist/lib/ts-transform.js +29 -0
  79. package/dist/lib/worker-e2e-file.d.ts +11 -0
  80. package/dist/lib/worker-e2e-file.d.ts.map +1 -0
  81. package/dist/lib/worker-e2e-file.js +69 -0
  82. package/dist/lib/worker-e2e.js +11 -46
  83. package/dist/lib/worker-process.d.ts +2 -0
  84. package/dist/lib/worker-process.d.ts.map +1 -0
  85. package/dist/lib/worker-process.js +55 -0
  86. package/dist/lib/worker-results.d.ts +3 -0
  87. package/dist/lib/worker-results.d.ts.map +1 -0
  88. package/dist/lib/worker-results.js +20 -0
  89. package/dist/lib/worker-server.d.ts +10 -0
  90. package/dist/lib/worker-server.d.ts.map +1 -0
  91. package/dist/lib/worker-server.js +113 -0
  92. package/dist/lib/worker.js +7 -28
  93. package/dist/test/coverage/fixture.d.ts +5 -0
  94. package/dist/test/coverage/fixture.d.ts.map +1 -0
  95. package/dist/test/coverage/fixture.js +32 -0
  96. package/dist/test/coverage/test-browser.d.ts +2 -0
  97. package/dist/test/coverage/test-browser.d.ts.map +1 -0
  98. package/dist/test/coverage/test-browser.js +24 -0
  99. package/dist/test/coverage/test-e2e.d.ts +2 -0
  100. package/dist/test/coverage/test-e2e.d.ts.map +1 -0
  101. package/dist/test/coverage/test-e2e.js +60 -0
  102. package/dist/test/coverage/test-unit.d.ts +2 -0
  103. package/dist/test/coverage/test-unit.d.ts.map +1 -0
  104. package/dist/test/coverage/test-unit.js +27 -0
  105. package/dist/test/framework.test.browser.d.ts +2 -0
  106. package/dist/test/framework.test.browser.d.ts.map +1 -0
  107. package/dist/test/framework.test.browser.js +107 -0
  108. package/dist/test/framework.test.e2e.d.ts.map +1 -0
  109. package/dist/test/framework.test.e2e.js +34 -0
  110. package/package.json +30 -9
  111. package/src/app/client/entry.ts +357 -0
  112. package/src/app/client/iframe.ts +18 -0
  113. package/src/app/server.ts +336 -0
  114. package/src/cli-entry.ts +15 -0
  115. package/src/cli.ts +382 -145
  116. package/src/index.ts +2 -1
  117. package/src/lib/colors.ts +3 -0
  118. package/src/lib/config.ts +266 -54
  119. package/src/lib/context.ts +59 -17
  120. package/src/lib/coverage-loader.ts +31 -0
  121. package/src/lib/coverage.ts +320 -0
  122. package/src/lib/executor.ts +18 -35
  123. package/src/lib/fake-timers.ts +89 -0
  124. package/src/lib/import-module.ts +39 -0
  125. package/src/lib/{utils.ts → normalize.ts} +0 -18
  126. package/src/lib/playwright.ts +5 -7
  127. package/src/lib/reporters/dot.ts +12 -2
  128. package/src/lib/reporters/files.ts +12 -2
  129. package/src/lib/reporters/index.ts +4 -5
  130. package/src/lib/reporters/results.ts +29 -0
  131. package/src/lib/reporters/spec.ts +12 -2
  132. package/src/lib/reporters/tap.ts +11 -2
  133. package/src/lib/runner-browser.ts +171 -0
  134. package/src/lib/runner.ts +308 -53
  135. package/src/lib/runtime.ts +2 -0
  136. package/src/lib/ts-transform.ts +36 -0
  137. package/src/lib/worker-e2e-file.ts +98 -0
  138. package/src/lib/worker-e2e.ts +14 -49
  139. package/src/lib/worker-process.ts +69 -0
  140. package/src/lib/worker-results.ts +22 -0
  141. package/src/lib/worker-server.ts +123 -0
  142. package/src/lib/worker.ts +8 -28
  143. package/src/test/coverage/fixture.ts +34 -0
  144. package/src/test/coverage/test-browser.ts +29 -0
  145. package/src/test/coverage/test-e2e.ts +70 -0
  146. package/src/test/coverage/test-unit.ts +32 -0
  147. package/tsconfig.json +3 -1
  148. package/dist/lib/e2e-server.d.ts +0 -11
  149. package/dist/lib/e2e-server.d.ts.map +0 -1
  150. package/dist/lib/e2e-server.js +0 -15
  151. package/dist/lib/framework.test.d.ts +0 -2
  152. package/dist/lib/framework.test.d.ts.map +0 -1
  153. package/dist/lib/framework.test.e2e.d.ts.map +0 -1
  154. package/dist/lib/framework.test.e2e.js +0 -29
  155. package/dist/lib/framework.test.js +0 -283
  156. package/dist/lib/utils.d.ts +0 -16
  157. package/dist/lib/utils.d.ts.map +0 -1
  158. package/src/lib/e2e-server.ts +0 -28
  159. /package/dist/{lib → test}/framework.test.e2e.d.ts +0 -0
@@ -0,0 +1,212 @@
1
+ import * as fsp from 'node:fs/promises';
2
+ import { createRequire } from 'node:module';
3
+ import * as path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { colors } from "./colors.js";
6
+ import { transformTypeScript } from "./ts-transform.js";
7
+ // Istanbul packages are loaded lazily so that FORCE_COLOR can be set based on
8
+ // the actual TTY state before supports-color caches its detection result.
9
+ let _istanbul;
10
+ function getIstanbul() {
11
+ if (!_istanbul) {
12
+ process.env.FORCE_COLOR ??= process.stdout.isTTY ? '1' : '0';
13
+ let require = createRequire(import.meta.url);
14
+ _istanbul = {
15
+ V8ToIstanbul: require('v8-to-istanbul'),
16
+ createCoverageMap: require('istanbul-lib-coverage').createCoverageMap,
17
+ createContext: require('istanbul-lib-report')
18
+ .createContext,
19
+ reports: require('istanbul-reports'),
20
+ };
21
+ }
22
+ return _istanbul;
23
+ }
24
+ function matchesGlobs(filePath, globs) {
25
+ return globs.some((glob) => path.matchesGlob(filePath, glob));
26
+ }
27
+ function filterCoverageMap(coverageMap, cwd, config) {
28
+ let filtered = getIstanbul().createCoverageMap({});
29
+ for (let filePath of coverageMap.files()) {
30
+ let relative = path.relative(cwd, filePath);
31
+ if (config.include && config.include.length > 0) {
32
+ if (!matchesGlobs(relative, config.include))
33
+ continue;
34
+ }
35
+ if (config.exclude && config.exclude.length > 0) {
36
+ if (matchesGlobs(relative, config.exclude))
37
+ continue;
38
+ }
39
+ let fc = coverageMap.fileCoverageFor(filePath);
40
+ filtered.addFileCoverage({ ...fc.toJSON(), path: relative });
41
+ }
42
+ return filtered;
43
+ }
44
+ function checkThresholds(coverageMap, config) {
45
+ let { statements, lines, branches, functions } = config;
46
+ if (statements === undefined &&
47
+ lines === undefined &&
48
+ branches === undefined &&
49
+ functions === undefined)
50
+ return true;
51
+ let summary = coverageMap.getCoverageSummary();
52
+ let passed = true;
53
+ if (statements !== undefined) {
54
+ let pct = summary.statements.pct;
55
+ if (pct < statements) {
56
+ console.error(colors.red(`\nError: Coverage threshold not met (statements ${pct.toFixed(2)}% < ${statements}%)`));
57
+ passed = false;
58
+ }
59
+ }
60
+ if (lines !== undefined) {
61
+ let pct = summary.lines.pct;
62
+ if (pct < lines) {
63
+ console.error(colors.red(`\nError: Coverage threshold not met (lines ${pct.toFixed(2)}% < ${lines}%)`));
64
+ passed = false;
65
+ }
66
+ }
67
+ if (branches !== undefined) {
68
+ let pct = summary.branches.pct;
69
+ if (pct < branches) {
70
+ console.error(colors.red(`\nError: Coverage threshold not met (branches ${pct.toFixed(2)}% < ${branches}%)`));
71
+ passed = false;
72
+ }
73
+ }
74
+ if (functions !== undefined) {
75
+ let pct = summary.functions.pct;
76
+ if (pct < functions) {
77
+ console.error(colors.red(`\nError: Coverage threshold not met (functions ${pct.toFixed(2)}% < ${functions}%)`));
78
+ passed = false;
79
+ }
80
+ }
81
+ return passed;
82
+ }
83
+ async function writeIstanbulReports(coverageMap, cwd, outDir) {
84
+ await fsp.mkdir(outDir, { recursive: true });
85
+ let { createContext, reports } = getIstanbul();
86
+ let ctx = createContext({ coverageMap, dir: outDir });
87
+ console.log('\nCoverage report:');
88
+ reports.create('text').execute(ctx);
89
+ reports.create('lcovonly').execute(ctx);
90
+ console.log(`\nLCOV coverage written to ${path.relative(cwd, path.join(outDir, 'lcov.info'))}`);
91
+ }
92
+ // Convert a single V8 coverage entry to Istanbul format and merge it into the
93
+ // coverage map.
94
+ //
95
+ // V8 reports byte offsets against the JS bytes it actually instrumented. When
96
+ // the entry already carries that source (Playwright's `coverage.stopJSCoverage`
97
+ // returns it on each entry, including the inline source map), we hand it
98
+ // straight to v8-to-istanbul so the offsets line up exactly. The server path
99
+ // uses Node's `NODE_V8_COVERAGE` JSON, which doesn't include source — there we
100
+ // re-derive by re-running our esbuild transform on the original TS file.
101
+ async function addV8EntryToCoverageMap(coverageMap, filePath, functions, source) {
102
+ let { V8ToIstanbul } = getIstanbul();
103
+ let converter = new V8ToIstanbul(filePath, undefined, { source });
104
+ await converter.load();
105
+ converter.applyCoverage(functions);
106
+ coverageMap.merge(converter.toIstanbul());
107
+ return true;
108
+ }
109
+ function shouldExcludeFromCoverage(filePath, rootDir, testFiles) {
110
+ return (!filePath.startsWith(rootDir + path.sep) ||
111
+ filePath.includes(`${path.sep}node_modules${path.sep}`) ||
112
+ testFiles.has(filePath));
113
+ }
114
+ export async function collectServerCoverageMap(coverageDataDir, cwd, testFiles) {
115
+ let { createCoverageMap } = getIstanbul();
116
+ let coverageMap = createCoverageMap({});
117
+ let converted = 0;
118
+ let files;
119
+ try {
120
+ files = (await fsp.readdir(coverageDataDir)).filter((f) => f.startsWith('coverage-') && f.endsWith('.json'));
121
+ }
122
+ catch {
123
+ return null;
124
+ }
125
+ for (let file of files) {
126
+ let data = JSON.parse(await fsp.readFile(path.join(coverageDataDir, file), 'utf-8'));
127
+ let scriptCoverages = data.result ?? [];
128
+ for (let entry of scriptCoverages) {
129
+ if (!entry.url.startsWith('file://'))
130
+ continue;
131
+ let filePath;
132
+ try {
133
+ filePath = fileURLToPath(entry.url);
134
+ }
135
+ catch {
136
+ continue;
137
+ }
138
+ if (!filePath ||
139
+ !['.ts', '.tsx'].includes(path.extname(filePath)) ||
140
+ shouldExcludeFromCoverage(filePath, cwd, testFiles)) {
141
+ continue;
142
+ }
143
+ try {
144
+ // For server unit tests, we transform the TS with a module loader and V8 tracks
145
+ // coverage using byte offsets from the transformed JS. Re-transform with the
146
+ // same `esbuild` call here so offsets align, then pass the result with its
147
+ // inline source map to v8-to-istanbul.
148
+ let tsSource = await fsp.readFile(filePath, 'utf-8');
149
+ let { code } = await transformTypeScript(tsSource, filePath);
150
+ let success = await addV8EntryToCoverageMap(coverageMap, filePath, entry.functions, code);
151
+ if (success)
152
+ converted++;
153
+ }
154
+ catch (e) {
155
+ // Skip files that can't be converted
156
+ }
157
+ }
158
+ }
159
+ // Clean up raw V8 coverage JSON files now that we've processed them
160
+ //await Promise.all(files.map((f) => fsp.rm(path.join(coverageDataDir, f), { force: true })))
161
+ return converted > 0 ? coverageMap : null;
162
+ }
163
+ export async function collectCoverageMapFromPlaywright(entries, rootDir, testFiles, resolveRelativePath) {
164
+ let { createCoverageMap } = getIstanbul();
165
+ let coverageMap = createCoverageMap({});
166
+ let converted = 0;
167
+ for (let entry of entries) {
168
+ let filePath;
169
+ try {
170
+ let relativePath = await resolveRelativePath(new URL(entry.url).pathname);
171
+ if (!relativePath)
172
+ continue;
173
+ // Ignore entries outside the root dir, entries in node_modules, and test files
174
+ filePath = path.resolve(rootDir, relativePath);
175
+ if (shouldExcludeFromCoverage(filePath, rootDir, testFiles)) {
176
+ continue;
177
+ }
178
+ // Ensure file exists
179
+ await fsp.access(filePath);
180
+ }
181
+ catch {
182
+ continue;
183
+ }
184
+ if (!entry.source) {
185
+ throw new Error(`Entry for ${entry.url} is missing source, cannot convert coverage. Ensure the browser launched with Playwright's JS coverage enabled.`);
186
+ }
187
+ try {
188
+ let success = await addV8EntryToCoverageMap(coverageMap, filePath, entry.functions, entry.source);
189
+ if (success)
190
+ converted++;
191
+ }
192
+ catch {
193
+ // Skip files that can't be converted
194
+ }
195
+ }
196
+ return converted > 0 ? coverageMap : null;
197
+ }
198
+ export async function generateCombinedCoverageReport(maps, cwd, config) {
199
+ let { createCoverageMap } = getIstanbul();
200
+ let combined = createCoverageMap({});
201
+ for (let map of maps) {
202
+ if (map)
203
+ combined.merge(map);
204
+ }
205
+ if (combined.files().length === 0) {
206
+ console.log('No coverage data collected.');
207
+ return true;
208
+ }
209
+ let filtered = filterCoverageMap(combined, cwd, config);
210
+ await writeIstanbulReports(filtered, cwd, config.dir);
211
+ return checkThresholds(filtered, config);
212
+ }
@@ -1,27 +1,4 @@
1
- import type { Browser, BrowserContextOptions } from 'playwright';
2
- import type { CreateServerFunction } from './e2e-server.ts';
3
- export interface TestResult {
4
- name: string;
5
- suiteName: string;
6
- filePath?: string;
7
- status: 'passed' | 'failed' | 'skipped' | 'todo';
8
- error?: {
9
- message: string;
10
- stack?: string;
11
- };
12
- duration: number;
13
- }
14
- export interface TestResults {
15
- passed: number;
16
- failed: number;
17
- skipped: number;
18
- todo: number;
19
- tests: TestResult[];
20
- }
21
- export declare function runTests(options?: {
22
- createServer?: CreateServerFunction;
23
- browser?: Browser;
24
- open?: boolean;
25
- playwrightPageOptions?: BrowserContextOptions;
26
- }): Promise<TestResults>;
1
+ import { type CreateTestContextOptions } from './context.ts';
2
+ import type { TestResults } from './reporters/results.ts';
3
+ export declare function runTests(options?: Omit<CreateTestContextOptions, 'addE2ECoverageEntries'>): Promise<TestResults>;
27
4
  //# sourceMappingURL=executor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/lib/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAEhE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAE3D,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;CACpB;AAED,wBAAsB,QAAQ,CAAC,OAAO,CAAC,EAAE;IACvC,YAAY,CAAC,EAAE,oBAAoB,CAAA;IACnC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;CAC9C,GAAG,OAAO,CAAC,WAAW,CAAC,CAoIvB"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/lib/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAE/E,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAErE,wBAAsB,QAAQ,CAC5B,OAAO,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,uBAAuB,CAAC,GAChE,OAAO,CAAC,WAAW,CAAC,CA0ItB"}
@@ -1,6 +1,7 @@
1
1
  import { createTestContext } from "./context.js";
2
2
  export async function runTests(options) {
3
3
  let suites = globalThis.__testSuites || [];
4
+ let e2eCoverageEntries = [];
4
5
  let results = {
5
6
  passed: 0,
6
7
  failed: 0,
@@ -71,12 +72,13 @@ export async function runTests(options) {
71
72
  status: 'passed',
72
73
  duration: 0,
73
74
  };
74
- let { testContext, cleanup } = createTestContext({
75
- createServer: options?.createServer,
76
- browser: options?.browser,
77
- open: options?.open,
78
- playwrightPageOptions: options?.playwrightPageOptions,
79
- });
75
+ let contextOpts = options
76
+ ? {
77
+ ...options,
78
+ addE2ECoverageEntries: (e) => e2eCoverageEntries.push(e),
79
+ }
80
+ : undefined;
81
+ let { testContext, cleanup } = createTestContext(contextOpts);
80
82
  try {
81
83
  if (suite.beforeEach) {
82
84
  await suite.beforeEach();
@@ -119,5 +121,8 @@ export async function runTests(options) {
119
121
  // Clear suites in-place so the shared framework module is reset
120
122
  // for the next test file (which reuses the same cached module instance)
121
123
  suites.length = 0;
124
+ if (e2eCoverageEntries.length > 0) {
125
+ results.e2eBrowserCoverageEntries = e2eCoverageEntries;
126
+ }
122
127
  return results;
123
128
  }
@@ -0,0 +1,13 @@
1
+ export interface FakeTimers {
2
+ advance(ms: number): void;
3
+ /**
4
+ * Like `advance`, but yields to microtasks between each timer firing so
5
+ * Promise continuations (and any timers they schedule) can settle before
6
+ * the next firing is processed. Use this when a callback awaits work that
7
+ * itself depends on the fake clock.
8
+ */
9
+ advanceAsync(ms: number): Promise<void>;
10
+ restore(): void;
11
+ }
12
+ export declare function createFakeTimers(): FakeTimers;
13
+ //# sourceMappingURL=fake-timers.d.ts.map
@@ -0,0 +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;;;;;OAKG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,OAAO,IAAI,IAAI,CAAA;CAChB;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CA0E7C"}
@@ -0,0 +1,64 @@
1
+ import { mock } from "./mock.js";
2
+ export function createFakeTimers() {
3
+ let currentTime = 0;
4
+ let nextId = 1;
5
+ let pending = [];
6
+ function schedule(fn, delay, repeatMs) {
7
+ let id = nextId++;
8
+ pending.push({ id, fn, time: currentTime + Math.max(0, delay), repeatMs });
9
+ return id;
10
+ }
11
+ function cancel(id) {
12
+ pending = pending.filter((t) => t.id !== id);
13
+ }
14
+ let setTimeoutMock = mock.method(globalThis, 'setTimeout', ((fn, delay = 0) => schedule(fn, delay)));
15
+ let clearTimeoutMock = mock.method(globalThis, 'clearTimeout', cancel);
16
+ let setIntervalMock = mock.method(globalThis, 'setInterval', ((fn, delay = 0) => schedule(fn, delay, Math.max(0, delay))));
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
+ }
31
+ return {
32
+ advance(ms) {
33
+ let targetTime = currentTime + ms;
34
+ while (true) {
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);
46
+ if (!next)
47
+ break;
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();
52
+ }
53
+ currentTime = targetTime;
54
+ },
55
+ restore() {
56
+ setTimeoutMock.mock.restore?.();
57
+ clearTimeoutMock.mock.restore?.();
58
+ setIntervalMock.mock.restore?.();
59
+ clearIntervalMock.mock.restore?.();
60
+ pending = [];
61
+ currentTime = 0;
62
+ },
63
+ };
64
+ }
@@ -0,0 +1,2 @@
1
+ export declare function importModule(specifier: string, meta: ImportMeta): Promise<any>;
2
+ //# sourceMappingURL=import-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-module.d.ts","sourceRoot":"","sources":["../../src/lib/import-module.ts"],"names":[],"mappings":"AAoBA,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAkBpF"}
@@ -0,0 +1,38 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import * as path from 'node:path';
10
+ import { pathToFileURL } from 'node:url';
11
+ import { tsImport } from 'tsx/esm/api';
12
+ import { IS_BUN } from "./runtime.js";
13
+ function hasImportMetaResolve(meta) {
14
+ return 'resolve' in meta && typeof meta.resolve === 'function';
15
+ }
16
+ /*
17
+ * Loads a module specifier relative to the caller's module context.
18
+ *
19
+ * @param specifier The module specifier or file path to load.
20
+ * @param meta The caller's `import.meta`, used as the context for resolution.
21
+ * @returns The imported module namespace.
22
+ */
23
+ export async function importModule(specifier, meta) {
24
+ // Absolute Windows paths (`C:\foo\bar.ts`) aren't valid ESM specifiers — only
25
+ // `file:///C:/foo/bar.ts` URLs, relative specifiers, or POSIX absolute paths
26
+ // are. Convert any absolute filesystem path to its `file:` URL so loaders like
27
+ // `tsImport` and `import()` accept it on every platform. POSIX absolute paths
28
+ // happen to work as specifiers without conversion, but going through
29
+ // `pathToFileURL` is safe and platform-agnostic.
30
+ let resolvedSpecifier = path.isAbsolute(specifier) ? pathToFileURL(specifier).href : specifier;
31
+ if (IS_BUN) {
32
+ if (!hasImportMetaResolve(meta)) {
33
+ throw new Error('importModule() requires import.meta.resolve() in Bun');
34
+ }
35
+ return import(__rewriteRelativeImportExtension(meta.resolve(resolvedSpecifier, meta.url)));
36
+ }
37
+ return tsImport(resolvedSpecifier, meta.url);
38
+ }
@@ -0,0 +1,2 @@
1
+ export declare function normalizeLine(line: string): string;
2
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/lib/normalize.ts"],"names":[],"mappings":"AAYA,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASlD"}
@@ -1,12 +1,3 @@
1
- const noColor = process.env.CI === 'true' || !!process.env.NO_COLOR;
2
- export const colors = {
3
- reset: noColor ? '' : '\x1b[0m',
4
- dim: noColor ? (s) => s : (s) => `\x1b[2m${s}\x1b[0m`,
5
- green: noColor ? (s) => s : (s) => `\x1b[32m${s}\x1b[0m`,
6
- red: noColor ? (s) => s : (s) => `\x1b[31m${s}\x1b[0m`,
7
- cyan: noColor ? (s) => s : (s) => `\x1b[36m${s}\x1b[0m`,
8
- yellow: noColor ? (s) => s : (s) => `\x1b[2m\x1b[33m${s}\x1b[0m`,
9
- };
10
1
  function normalizeFilePath(path) {
11
2
  let locSuffix = path.match(/(:\d+:\d+)$/)?.[0] || '';
12
3
  let normalized = path
@@ -1,7 +1,7 @@
1
1
  import type { BrowserContextOptions, LaunchOptions } from 'playwright';
2
2
  import type { PlaywrightTestConfig } from 'playwright/test';
3
3
  export type PlaywrightUseOpts = PlaywrightTestConfig['use'];
4
- export declare function loadPlaywrightConfig(input: string | undefined): Promise<PlaywrightTestConfig | undefined>;
4
+ export declare function loadPlaywrightConfig(input: string | undefined, cwd?: string): Promise<PlaywrightTestConfig | undefined>;
5
5
  export declare function getBrowserLauncher(playwrightUseOpts?: PlaywrightUseOpts): import("playwright").BrowserType<{}>;
6
6
  export declare function resolveProjects(config?: PlaywrightTestConfig): Array<{
7
7
  name?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/lib/playwright.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAG3D,MAAM,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;AAE3D,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAiB3C;AAQD,wBAAgB,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,wCAavE;AAED,wBAAgB,eAAe,CAC7B,MAAM,CAAC,EAAE,oBAAoB,GAC5B,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAahE;AAED,wBAAgB,0BAA0B,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAK/F;AAED,wBAAgB,wBAAwB,CACtC,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,qBAAqB,GAAG;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBhF"}
1
+ {"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/lib/playwright.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAA;AAG3D,MAAM,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;AAE3D,wBAAsB,oBAAoB,CACxC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,GAAG,SAAgB,GAClB,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAc3C;AAQD,wBAAgB,kBAAkB,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,wCAavE;AAED,wBAAgB,eAAe,CAC7B,MAAM,CAAC,EAAE,oBAAoB,GAC5B,KAAK,CAAC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAahE;AAED,wBAAgB,0BAA0B,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,aAAa,CAK/F;AAED,wBAAgB,wBAAwB,CACtC,iBAAiB,CAAC,EAAE,iBAAiB,GACpC,qBAAqB,GAAG;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAwBhF"}
@@ -1,18 +1,15 @@
1
1
  import * as path from 'node:path';
2
2
  import * as fs from 'node:fs/promises';
3
3
  import { chromium, firefox, webkit } from 'playwright';
4
- import { tsImport } from 'tsx/esm/api';
5
- export async function loadPlaywrightConfig(input) {
4
+ import { importModule } from "./import-module.js";
5
+ export async function loadPlaywrightConfig(input, cwd = process.cwd()) {
6
6
  let candidates = input
7
- ? [path.resolve(process.cwd(), input)]
8
- : [
9
- path.join(process.cwd(), 'playwright.config.ts'),
10
- path.join(process.cwd(), 'playwright.config.js'),
11
- ];
7
+ ? [path.resolve(cwd, input)]
8
+ : [path.join(cwd, 'playwright.config.ts'), path.join(cwd, 'playwright.config.js')];
12
9
  for (let configPath of candidates) {
13
10
  try {
14
11
  await fs.access(configPath);
15
- let mod = await tsImport(configPath, { parentURL: import.meta.url });
12
+ let mod = await importModule(configPath, import.meta);
16
13
  return mod.default ?? mod;
17
14
  }
18
15
  catch {
@@ -1,6 +1,5 @@
1
- import { type Counts } from '../utils.ts';
2
- import type { TestResults } from '../executor.ts';
3
1
  import type { Reporter } from './index.ts';
2
+ import type { Counts, TestResults } from './results.ts';
4
3
  export declare class DotReporter implements Reporter {
5
4
  #private;
6
5
  onSectionStart(_label: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"dot.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/dot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1C,qBAAa,WAAY,YAAW,QAAQ;;IAI1C,cAAc,CAAC,MAAM,EAAE,MAAM,QAAI;IAEjC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE,MAAM,QAc3C;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QA6B3C;CACF"}
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"}
@@ -1,9 +1,18 @@
1
- import { colors, normalizeLine } from "../utils.js";
1
+ import { colors } from "../colors.js";
2
+ import { normalizeLine } from "../normalize.js";
2
3
  export class DotReporter {
3
4
  #failures = [];
4
5
  #dotCount = 0;
6
+ #files = new Set();
7
+ #suites = new Set();
5
8
  onSectionStart(_label) { }
6
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
+ }
7
16
  for (let test of results.tests) {
8
17
  if (test.status === 'passed') {
9
18
  process.stdout.write(colors.green('.'));
@@ -42,6 +51,8 @@ export class DotReporter {
42
51
  let { passed, failed, skipped, todo } = counts;
43
52
  let info = colors.cyan('ℹ');
44
53
  console.log();
54
+ console.log(`${info} files ${this.#files.size}`);
55
+ console.log(`${info} suites ${this.#suites.size}`);
45
56
  console.log(`${info} tests ${passed + failed + skipped + todo}`);
46
57
  console.log(`${info} pass ${passed}`);
47
58
  console.log(`${info} fail ${failed}`);
@@ -1,6 +1,5 @@
1
- import { type Counts } from '../utils.ts';
2
- import type { TestResults } from '../executor.ts';
3
1
  import type { Reporter } from './index.ts';
2
+ import type { Counts, TestResults } from './results.ts';
4
3
  export declare class FilesReporter implements Reporter {
5
4
  #private;
6
5
  onSectionStart(_label: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/files.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1C,qBAAa,aAAc,YAAW,QAAQ;;IAG5C,cAAc,CAAC,MAAM,EAAE,MAAM,QAAI;IAEjC,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,QA8B1C;IAED,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAgC3C;CACF"}
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"}
@@ -1,9 +1,18 @@
1
1
  import * as path from 'node:path';
2
- import { colors, normalizeLine } from "../utils.js";
2
+ import { colors } from "../colors.js";
3
+ import { normalizeLine } from "../normalize.js";
3
4
  export class FilesReporter {
4
5
  #failures = [];
6
+ #files = new Set();
7
+ #suites = new Set();
5
8
  onSectionStart(_label) { }
6
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
+ }
7
16
  let filePath = results.tests[0]?.filePath;
8
17
  let fileName = filePath ? path.relative(process.cwd(), filePath) : '(unknown)';
9
18
  let envLabel = env ? ` ${colors.dim(`[${env}]`)}` : '';
@@ -57,6 +66,8 @@ export class FilesReporter {
57
66
  let { passed, failed, skipped, todo } = counts;
58
67
  let info = colors.cyan('ℹ');
59
68
  console.log();
69
+ console.log(`${info} files ${this.#files.size}`);
70
+ console.log(`${info} suites ${this.#suites.size}`);
60
71
  console.log(`${info} tests ${passed + failed + skipped + todo}`);
61
72
  console.log(`${info} pass ${passed}`);
62
73
  console.log(`${info} fail ${failed}`);
@@ -1,14 +1,13 @@
1
- import type { Counts } from '../utils.ts';
2
- import type { TestResults } from '../executor.ts';
3
- import { SpecReporter } from './spec.ts';
4
- import { TapReporter } from './tap.ts';
5
1
  import { DotReporter } from './dot.ts';
6
2
  import { FilesReporter } from './files.ts';
3
+ import type { Counts, TestResults } from './results.ts';
4
+ import { SpecReporter } from './spec.ts';
5
+ import { TapReporter } from './tap.ts';
7
6
  export interface Reporter {
8
7
  onResult(results: TestResults, env?: string): void;
9
8
  onSummary(counts: Counts, durationMs: number): void;
10
9
  onSectionStart(label: string): void;
11
10
  }
12
- export { SpecReporter, TapReporter, DotReporter, FilesReporter };
11
+ export { DotReporter, FilesReporter, SpecReporter, TapReporter };
13
12
  export declare function createReporter(type: string): Reporter;
14
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE1C,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,CAAA;AAEhE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClD,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACnD,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,CAAA;AAEhE,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAYrD"}
@@ -1,8 +1,8 @@
1
- import { SpecReporter } from "./spec.js";
2
- import { TapReporter } from "./tap.js";
3
1
  import { DotReporter } from "./dot.js";
4
2
  import { FilesReporter } from "./files.js";
5
- export { SpecReporter, TapReporter, DotReporter, FilesReporter };
3
+ import { SpecReporter } from "./spec.js";
4
+ import { TapReporter } from "./tap.js";
5
+ export { DotReporter, FilesReporter, SpecReporter, TapReporter };
6
6
  export function createReporter(type) {
7
7
  switch (type) {
8
8
  case 'tap':
@@ -0,0 +1,30 @@
1
+ import type { V8CoverageEntry } from '../coverage';
2
+ export interface TestResult {
3
+ name: string;
4
+ suiteName: string;
5
+ filePath?: string;
6
+ status: 'passed' | 'failed' | 'skipped' | 'todo';
7
+ error?: {
8
+ message: string;
9
+ stack?: string;
10
+ };
11
+ duration: number;
12
+ }
13
+ export interface TestResults {
14
+ passed: number;
15
+ failed: number;
16
+ skipped: number;
17
+ todo: number;
18
+ tests: TestResult[];
19
+ e2eBrowserCoverageEntries?: Array<{
20
+ entries: V8CoverageEntry[];
21
+ baseUrl: string;
22
+ }>;
23
+ }
24
+ export type Counts = {
25
+ passed: number;
26
+ failed: number;
27
+ skipped: number;
28
+ todo: number;
29
+ };
30
+ //# sourceMappingURL=results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/lib/reporters/results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,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"}
@@ -0,0 +1 @@
1
+ export {};