@rstest/browser 0.8.4 → 0.9.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/LICENSE-APACHE-2.0 +202 -0
- package/NOTICE +11 -0
- package/dist/361.js +8 -0
- package/dist/augmentExpect.d.ts +73 -0
- package/dist/browser-container/container-static/css/index.5c72297783.css +1 -0
- package/dist/browser-container/container-static/js/{392.28f9a733.js → 101.36a8ccdf84.js} +4068 -3904
- package/dist/browser-container/container-static/js/101.36a8ccdf84.js.LICENSE.txt +1 -0
- package/dist/browser-container/container-static/js/{index.129eaf9c.js → index.0687a8142a.js} +742 -692
- package/dist/browser-container/container-static/js/{lib-react.97ee79b0.js → lib-react.dcf2a5e57a.js} +10 -10
- package/dist/browser-container/container-static/js/lib-react.dcf2a5e57a.js.LICENSE.txt +1 -0
- package/dist/browser-container/index.html +1 -1
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +583 -0
- package/dist/browserRpcRegistry.d.ts +18 -0
- package/dist/client/api.d.ts +3 -0
- package/dist/client/browserRpc.d.ts +2 -0
- package/dist/client/dispatchTransport.d.ts +11 -0
- package/dist/client/entry.d.ts +1 -5
- package/dist/client/locator.d.ts +125 -0
- package/dist/client/snapshot.d.ts +0 -6
- package/dist/concurrency.d.ts +12 -0
- package/dist/dispatchCapabilities.d.ts +34 -0
- package/dist/dispatchRouter.d.ts +20 -0
- package/dist/headlessLatestRerunScheduler.d.ts +19 -0
- package/dist/headlessTransport.d.ts +12 -0
- package/dist/index.js +1608 -296
- package/dist/protocol.d.ts +44 -33
- package/dist/providers/index.d.ts +79 -0
- package/dist/providers/playwright/compileLocator.d.ts +3 -0
- package/dist/providers/playwright/dispatchBrowserRpc.d.ts +13 -0
- package/dist/providers/playwright/expectUtils.d.ts +24 -0
- package/dist/providers/playwright/implementation.d.ts +2 -0
- package/dist/providers/playwright/index.d.ts +1 -0
- package/dist/providers/playwright/runtime.d.ts +5 -0
- package/dist/providers/playwright/textMatcher.d.ts +8 -0
- package/dist/rpcProtocol.d.ts +145 -0
- package/dist/runSession.d.ts +33 -0
- package/dist/sessionRegistry.d.ts +34 -0
- package/dist/sourceMap/sourceMapLoader.d.ts +14 -0
- package/dist/watchRerunPlanner.d.ts +21 -0
- package/package.json +16 -11
- package/src/AGENTS.md +128 -0
- package/src/augmentExpect.ts +62 -0
- package/src/browser.ts +3 -0
- package/src/browserRpcRegistry.ts +57 -0
- package/src/client/AGENTS.md +82 -0
- package/src/client/api.ts +213 -0
- package/src/client/browserRpc.ts +86 -0
- package/src/client/dispatchTransport.ts +178 -0
- package/src/client/entry.ts +109 -39
- package/src/client/locator.ts +452 -0
- package/src/client/snapshot.ts +32 -97
- package/src/client/sourceMapSupport.ts +26 -37
- package/src/concurrency.ts +62 -0
- package/src/dispatchCapabilities.ts +162 -0
- package/src/dispatchRouter.ts +82 -0
- package/src/env.d.ts +8 -1
- package/src/headlessLatestRerunScheduler.ts +76 -0
- package/src/headlessTransport.ts +28 -0
- package/src/hostController.ts +1292 -367
- package/src/protocol.ts +66 -31
- package/src/providers/index.ts +103 -0
- package/src/providers/playwright/compileLocator.ts +130 -0
- package/src/providers/playwright/dispatchBrowserRpc.ts +372 -0
- package/src/providers/playwright/expectUtils.ts +57 -0
- package/src/providers/playwright/implementation.ts +33 -0
- package/src/providers/playwright/index.ts +1 -0
- package/src/providers/playwright/runtime.ts +32 -0
- package/src/providers/playwright/textMatcher.ts +10 -0
- package/src/rpcProtocol.ts +220 -0
- package/src/runSession.ts +110 -0
- package/src/sessionRegistry.ts +89 -0
- package/src/sourceMap/sourceMapLoader.ts +96 -0
- package/src/watchRerunPlanner.ts +77 -0
- package/dist/browser-container/container-static/css/index.5a71c757.css +0 -1
- package/dist/browser-container/container-static/js/392.28f9a733.js.LICENSE.txt +0 -1
- package/dist/browser-container/container-static/js/lib-react.97ee79b0.js.LICENSE.txt +0 -1
- package/dist/browser-container/container-static/js/scheduler.6976de44.js +0 -411
- package/dist/browser-container/scheduler.html +0 -19
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BrowserDispatchRequest,
|
|
3
|
+
BrowserDispatchResponse,
|
|
4
|
+
} from '../protocol';
|
|
5
|
+
import {
|
|
6
|
+
DISPATCH_MESSAGE_TYPE,
|
|
7
|
+
DISPATCH_RESPONSE_TYPE,
|
|
8
|
+
DISPATCH_RPC_REQUEST_TYPE,
|
|
9
|
+
} from '../protocol';
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_RPC_TIMEOUT_MS = 30_000;
|
|
12
|
+
|
|
13
|
+
export const getRpcTimeout = (): number => {
|
|
14
|
+
return (
|
|
15
|
+
window.__RSTEST_BROWSER_OPTIONS__?.rpcTimeout ?? DEFAULT_RPC_TIMEOUT_MS
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const pendingRequests = new Map<
|
|
20
|
+
string,
|
|
21
|
+
{
|
|
22
|
+
resolve: (value: unknown) => void;
|
|
23
|
+
reject: (error: Error) => void;
|
|
24
|
+
staleMessage: string;
|
|
25
|
+
}
|
|
26
|
+
>();
|
|
27
|
+
|
|
28
|
+
let requestIdCounter = 0;
|
|
29
|
+
let messageListenerInitialized = false;
|
|
30
|
+
|
|
31
|
+
export const createRequestId = (prefix: string): string => {
|
|
32
|
+
if (typeof globalThis.crypto?.randomUUID === 'function') {
|
|
33
|
+
return globalThis.crypto.randomUUID();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
requestIdCounter += 1;
|
|
37
|
+
return `${prefix}-${Date.now().toString(36)}-${requestIdCounter.toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const isDispatchResponse = (
|
|
41
|
+
value: unknown,
|
|
42
|
+
): value is BrowserDispatchResponse => {
|
|
43
|
+
return (
|
|
44
|
+
typeof value === 'object' &&
|
|
45
|
+
value !== null &&
|
|
46
|
+
'requestId' in value &&
|
|
47
|
+
typeof (value as { requestId: unknown }).requestId === 'string'
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const settlePendingRequest = (response: BrowserDispatchResponse): void => {
|
|
52
|
+
const pending = pendingRequests.get(response.requestId);
|
|
53
|
+
if (!pending) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
pendingRequests.delete(response.requestId);
|
|
58
|
+
if (response.stale) {
|
|
59
|
+
pending.reject(new Error(pending.staleMessage));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (response.error) {
|
|
63
|
+
pending.reject(new Error(response.error));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
pending.resolve(response.result);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const initMessageListener = (): void => {
|
|
70
|
+
if (messageListenerInitialized) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
messageListenerInitialized = true;
|
|
74
|
+
|
|
75
|
+
window.addEventListener('message', (event: MessageEvent) => {
|
|
76
|
+
if (event.data?.type === DISPATCH_RESPONSE_TYPE) {
|
|
77
|
+
settlePendingRequest(event.data.payload as BrowserDispatchResponse);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const unwrapDispatchBridgeResult = <T>(
|
|
83
|
+
requestId: string,
|
|
84
|
+
result: unknown,
|
|
85
|
+
staleMessage: string,
|
|
86
|
+
): T => {
|
|
87
|
+
if (!isDispatchResponse(result)) {
|
|
88
|
+
throw new Error('Invalid dispatch bridge response payload.');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (result.requestId !== requestId) {
|
|
92
|
+
throw new Error(
|
|
93
|
+
`Mismatched dispatch response id: expected ${requestId}, got ${result.requestId}`,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (result.stale) {
|
|
97
|
+
throw new Error(staleMessage);
|
|
98
|
+
}
|
|
99
|
+
if (result.error) {
|
|
100
|
+
throw new Error(result.error);
|
|
101
|
+
}
|
|
102
|
+
return result.result as T;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const dispatchRpc = <T>({
|
|
106
|
+
requestId,
|
|
107
|
+
request,
|
|
108
|
+
timeoutMs,
|
|
109
|
+
timeoutMessage,
|
|
110
|
+
staleMessage,
|
|
111
|
+
}: {
|
|
112
|
+
requestId: string;
|
|
113
|
+
request: BrowserDispatchRequest;
|
|
114
|
+
timeoutMs: number;
|
|
115
|
+
timeoutMessage: string;
|
|
116
|
+
staleMessage: string;
|
|
117
|
+
}): Promise<T> => {
|
|
118
|
+
if (window.parent === window) {
|
|
119
|
+
const dispatchBridge = window.__rstest_dispatch_rpc__;
|
|
120
|
+
if (!dispatchBridge) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
'Dispatch RPC bridge is not available in top-level runner.',
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return new Promise<T>((resolve, reject) => {
|
|
127
|
+
const timeoutId = setTimeout(() => {
|
|
128
|
+
reject(new Error(timeoutMessage));
|
|
129
|
+
}, timeoutMs);
|
|
130
|
+
|
|
131
|
+
const call = Promise.resolve(dispatchBridge(request)).then((result) =>
|
|
132
|
+
unwrapDispatchBridgeResult<T>(requestId, result, staleMessage),
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
call
|
|
136
|
+
.then((result) => {
|
|
137
|
+
clearTimeout(timeoutId);
|
|
138
|
+
resolve(result);
|
|
139
|
+
})
|
|
140
|
+
.catch((error) => {
|
|
141
|
+
clearTimeout(timeoutId);
|
|
142
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
initMessageListener();
|
|
148
|
+
|
|
149
|
+
return new Promise<T>((resolve, reject) => {
|
|
150
|
+
const timeoutId = setTimeout(() => {
|
|
151
|
+
pendingRequests.delete(requestId);
|
|
152
|
+
reject(new Error(timeoutMessage));
|
|
153
|
+
}, timeoutMs);
|
|
154
|
+
|
|
155
|
+
pendingRequests.set(requestId, {
|
|
156
|
+
staleMessage,
|
|
157
|
+
resolve: (value) => {
|
|
158
|
+
clearTimeout(timeoutId);
|
|
159
|
+
resolve(value as T);
|
|
160
|
+
},
|
|
161
|
+
reject: (error) => {
|
|
162
|
+
clearTimeout(timeoutId);
|
|
163
|
+
reject(error);
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
window.parent.postMessage(
|
|
168
|
+
{
|
|
169
|
+
type: DISPATCH_MESSAGE_TYPE,
|
|
170
|
+
payload: {
|
|
171
|
+
type: DISPATCH_RPC_REQUEST_TYPE,
|
|
172
|
+
payload: request,
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
'*',
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
};
|
package/src/client/entry.ts
CHANGED
|
@@ -20,9 +20,15 @@ import {
|
|
|
20
20
|
import { normalize } from 'pathe';
|
|
21
21
|
import type {
|
|
22
22
|
BrowserClientMessage,
|
|
23
|
-
|
|
23
|
+
BrowserDispatchRequest,
|
|
24
24
|
BrowserProjectRuntime,
|
|
25
25
|
} from '../protocol';
|
|
26
|
+
import {
|
|
27
|
+
DISPATCH_MESSAGE_TYPE,
|
|
28
|
+
DISPATCH_NAMESPACE_RUNNER,
|
|
29
|
+
DISPATCH_RPC_REQUEST_TYPE,
|
|
30
|
+
RSTEST_CONFIG_MESSAGE_TYPE,
|
|
31
|
+
} from '../protocol';
|
|
26
32
|
import { BrowserSnapshotEnvironment } from './snapshot';
|
|
27
33
|
import {
|
|
28
34
|
findNewScriptUrl,
|
|
@@ -32,14 +38,18 @@ import {
|
|
|
32
38
|
} from './sourceMapSupport';
|
|
33
39
|
|
|
34
40
|
declare global {
|
|
35
|
-
interface Window {
|
|
36
|
-
__RSTEST_BROWSER_OPTIONS__?: BrowserHostConfig;
|
|
37
|
-
__rstest_dispatch__?: (message: BrowserClientMessage) => void;
|
|
38
|
-
}
|
|
39
41
|
// eslint-disable-next-line no-var
|
|
40
42
|
var __coverage__: Record<string, unknown> | undefined;
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
type RunnerLifecycleMethod =
|
|
46
|
+
| 'file-ready'
|
|
47
|
+
| 'suite-start'
|
|
48
|
+
| 'suite-result'
|
|
49
|
+
| 'case-start';
|
|
50
|
+
|
|
51
|
+
let runnerDispatchRequestId = 0;
|
|
52
|
+
|
|
43
53
|
/**
|
|
44
54
|
* Debug logger for browser client.
|
|
45
55
|
* Only logs when debug mode is enabled (DEBUG=rstest on server side).
|
|
@@ -50,10 +60,13 @@ const debugLog = (...args: unknown[]): void => {
|
|
|
50
60
|
}
|
|
51
61
|
};
|
|
52
62
|
|
|
53
|
-
type
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
63
|
+
type RuntimeEnvStore = Record<string, string | undefined>;
|
|
64
|
+
const RSTEST_ENV_SYMBOL = Symbol.for('rstest.env');
|
|
65
|
+
|
|
66
|
+
type GlobalWithRuntimeEnv = typeof globalThis &
|
|
67
|
+
Record<symbol, unknown> & {
|
|
68
|
+
global?: typeof globalThis;
|
|
69
|
+
};
|
|
57
70
|
|
|
58
71
|
const REGEXP_FLAG_PREFIX = 'RSTEST_REGEXP:';
|
|
59
72
|
|
|
@@ -82,36 +95,34 @@ const restoreRuntimeConfig = (
|
|
|
82
95
|
};
|
|
83
96
|
};
|
|
84
97
|
|
|
85
|
-
const
|
|
86
|
-
const globalRef = globalThis as
|
|
98
|
+
const ensureRuntimeEnv = (env: RuntimeConfig['env'] | undefined): void => {
|
|
99
|
+
const globalRef = globalThis as GlobalWithRuntimeEnv;
|
|
87
100
|
if (!globalRef.global) {
|
|
88
101
|
globalRef.global = globalRef;
|
|
89
102
|
}
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
cwd: () => '/',
|
|
99
|
-
platform: 'linux',
|
|
100
|
-
nextTick: (cb: (...args: unknown[]) => void, ...args: unknown[]) =>
|
|
101
|
-
queueMicrotask(() => cb(...args)),
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
globalRef.process = processShim as unknown as NodeJS.Process;
|
|
104
|
+
const existingEnv = globalRef[RSTEST_ENV_SYMBOL];
|
|
105
|
+
let runtimeEnv: RuntimeEnvStore;
|
|
106
|
+
if (existingEnv && typeof existingEnv === 'object') {
|
|
107
|
+
runtimeEnv = existingEnv as RuntimeEnvStore;
|
|
108
|
+
} else {
|
|
109
|
+
runtimeEnv = {};
|
|
110
|
+
globalRef[RSTEST_ENV_SYMBOL] = runtimeEnv;
|
|
105
111
|
}
|
|
106
112
|
|
|
107
|
-
globalRef.process.env ??= {};
|
|
108
|
-
|
|
109
113
|
if (env) {
|
|
110
114
|
for (const [key, value] of Object.entries(env)) {
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
const normalizedValue =
|
|
116
|
+
typeof value === 'string'
|
|
117
|
+
? value
|
|
118
|
+
: value == null
|
|
119
|
+
? undefined
|
|
120
|
+
: String(value);
|
|
121
|
+
|
|
122
|
+
if (normalizedValue === undefined) {
|
|
123
|
+
delete runtimeEnv[key];
|
|
113
124
|
} else {
|
|
114
|
-
|
|
125
|
+
runtimeEnv[key] = normalizedValue;
|
|
115
126
|
}
|
|
116
127
|
}
|
|
117
128
|
}
|
|
@@ -206,7 +217,7 @@ const send = (message: BrowserClientMessage): void => {
|
|
|
206
217
|
// If in iframe, send to parent window (container) which will forward to host via RPC
|
|
207
218
|
if (window.parent !== window) {
|
|
208
219
|
window.parent.postMessage(
|
|
209
|
-
{ type:
|
|
220
|
+
{ type: DISPATCH_MESSAGE_TYPE, payload: message },
|
|
210
221
|
'*',
|
|
211
222
|
);
|
|
212
223
|
return;
|
|
@@ -216,6 +227,38 @@ const send = (message: BrowserClientMessage): void => {
|
|
|
216
227
|
window.__rstest_dispatch__?.(message);
|
|
217
228
|
};
|
|
218
229
|
|
|
230
|
+
const dispatchRunnerLifecycle = (
|
|
231
|
+
method: RunnerLifecycleMethod,
|
|
232
|
+
payload: unknown,
|
|
233
|
+
): void => {
|
|
234
|
+
const request: BrowserDispatchRequest = {
|
|
235
|
+
requestId: `runner-lifecycle-${++runnerDispatchRequestId}`,
|
|
236
|
+
namespace: DISPATCH_NAMESPACE_RUNNER,
|
|
237
|
+
method,
|
|
238
|
+
args: payload,
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
if (window.parent === window) {
|
|
242
|
+
const dispatchBridge = window.__rstest_dispatch_rpc__;
|
|
243
|
+
if (!dispatchBridge) {
|
|
244
|
+
debugLog(
|
|
245
|
+
'[Runner] Missing dispatch bridge for lifecycle method:',
|
|
246
|
+
method,
|
|
247
|
+
);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
void Promise.resolve(dispatchBridge(request)).catch((error: unknown) => {
|
|
251
|
+
debugLog('[Runner] Failed to dispatch lifecycle method:', method, error);
|
|
252
|
+
});
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
send({
|
|
257
|
+
type: DISPATCH_RPC_REQUEST_TYPE,
|
|
258
|
+
payload: request,
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
|
|
219
262
|
/** Timeout for waiting for browser config from container (30 seconds) */
|
|
220
263
|
const CONFIG_WAIT_TIMEOUT_MS = 30_000;
|
|
221
264
|
|
|
@@ -231,7 +274,7 @@ const waitForConfig = (): Promise<void> => {
|
|
|
231
274
|
|
|
232
275
|
return new Promise((resolve, reject) => {
|
|
233
276
|
const handleMessage = (event: MessageEvent) => {
|
|
234
|
-
if (event.data?.type ===
|
|
277
|
+
if (event.data?.type === RSTEST_CONFIG_MESSAGE_TYPE) {
|
|
235
278
|
window.__RSTEST_BROWSER_OPTIONS__ = event.data.payload;
|
|
236
279
|
debugLog(
|
|
237
280
|
'[Runner] Received config from container:',
|
|
@@ -324,6 +367,7 @@ const run = async () => {
|
|
|
324
367
|
// Support reading testFile and testNamePattern from URL parameters
|
|
325
368
|
const urlParams = new URLSearchParams(window.location.search);
|
|
326
369
|
const urlTestFile = urlParams.get('testFile');
|
|
370
|
+
const urlRunId = urlParams.get('runId');
|
|
327
371
|
const urlTestNamePattern = urlParams.get('testNamePattern');
|
|
328
372
|
|
|
329
373
|
if (urlTestFile && options) {
|
|
@@ -334,6 +378,13 @@ const run = async () => {
|
|
|
334
378
|
};
|
|
335
379
|
}
|
|
336
380
|
|
|
381
|
+
if (urlRunId && options) {
|
|
382
|
+
options = {
|
|
383
|
+
...options,
|
|
384
|
+
runId: urlRunId,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
337
388
|
// Override testNamePattern from URL parameter if provided
|
|
338
389
|
if (urlTestNamePattern && options) {
|
|
339
390
|
options = {
|
|
@@ -404,7 +455,7 @@ const run = async () => {
|
|
|
404
455
|
}
|
|
405
456
|
|
|
406
457
|
const runtimeConfig = restoreRuntimeConfig(projectRuntime.runtimeConfig);
|
|
407
|
-
|
|
458
|
+
ensureRuntimeEnv(runtimeConfig.env);
|
|
408
459
|
|
|
409
460
|
// Get this project's setup loaders and test context
|
|
410
461
|
const currentSetupLoaders =
|
|
@@ -426,12 +477,13 @@ const run = async () => {
|
|
|
426
477
|
return;
|
|
427
478
|
}
|
|
428
479
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
480
|
+
const loadSetupFiles = async (): Promise<void> => {
|
|
481
|
+
for (const loadSetup of currentSetupLoaders) {
|
|
482
|
+
await loadSetup();
|
|
483
|
+
}
|
|
484
|
+
};
|
|
433
485
|
|
|
434
|
-
//
|
|
486
|
+
// 1. Determine which test files to run
|
|
435
487
|
let testKeysToRun: string[];
|
|
436
488
|
|
|
437
489
|
if (targetTestFile) {
|
|
@@ -478,6 +530,9 @@ const run = async () => {
|
|
|
478
530
|
}
|
|
479
531
|
|
|
480
532
|
try {
|
|
533
|
+
// Load setup files for this project after runtime is ready.
|
|
534
|
+
await loadSetupFiles();
|
|
535
|
+
|
|
481
536
|
// Load the test file dynamically (registers tests without running)
|
|
482
537
|
await currentTestContext.loadTest(key);
|
|
483
538
|
|
|
@@ -512,7 +567,7 @@ const run = async () => {
|
|
|
512
567
|
return;
|
|
513
568
|
}
|
|
514
569
|
|
|
515
|
-
//
|
|
570
|
+
// 2. Run tests for each file
|
|
516
571
|
for (const key of testKeysToRun) {
|
|
517
572
|
const testPath = toAbsolutePath(key, currentProject.projectRoot);
|
|
518
573
|
|
|
@@ -552,6 +607,18 @@ const run = async () => {
|
|
|
552
607
|
let failedTestsCount = 0;
|
|
553
608
|
|
|
554
609
|
const runnerHooks: RunnerHooks = {
|
|
610
|
+
onTestFileReady: async (test) => {
|
|
611
|
+
dispatchRunnerLifecycle('file-ready', test);
|
|
612
|
+
},
|
|
613
|
+
onTestSuiteStart: async (test) => {
|
|
614
|
+
dispatchRunnerLifecycle('suite-start', test);
|
|
615
|
+
},
|
|
616
|
+
onTestSuiteResult: async (result) => {
|
|
617
|
+
dispatchRunnerLifecycle('suite-result', result);
|
|
618
|
+
},
|
|
619
|
+
onTestCaseStart: async (test) => {
|
|
620
|
+
dispatchRunnerLifecycle('case-start', test);
|
|
621
|
+
},
|
|
555
622
|
onTestCaseResult: async (result) => {
|
|
556
623
|
if (result.status === 'fail') {
|
|
557
624
|
failedTestsCount++;
|
|
@@ -573,6 +640,9 @@ const run = async () => {
|
|
|
573
640
|
});
|
|
574
641
|
|
|
575
642
|
try {
|
|
643
|
+
// Load setup files for this project after runtime is ready.
|
|
644
|
+
await loadSetupFiles();
|
|
645
|
+
|
|
576
646
|
// Record script URLs before loading the test file
|
|
577
647
|
const beforeScripts = getScriptUrls();
|
|
578
648
|
|