@rstest/core 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/0~85.js DELETED
@@ -1,1819 +0,0 @@
1
- import 'module';
2
- /*#__PURE__*/ import.meta.url;
3
- export const __webpack_id__ = "85";
4
- export const __webpack_ids__ = [
5
- "85"
6
- ];
7
- export const __webpack_modules__ = {
8
- "./src/runtime/api/index.ts": function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
9
- __webpack_require__.d(__webpack_exports__, {
10
- createRstestRuntime: ()=>createRstestRuntime
11
- });
12
- var dist = __webpack_require__("../../node_modules/.pnpm/@vitest+expect@3.2.4/node_modules/@vitest/expect/dist/index.js");
13
- var src_utils = __webpack_require__("./src/utils/index.ts");
14
- var node_modules_chai = __webpack_require__("../../node_modules/.pnpm/chai@5.3.3/node_modules/chai/index.js");
15
- var runtime_util = __webpack_require__("./src/runtime/util.ts");
16
- const unsupported = [
17
- 'matchSnapshot',
18
- 'toMatchSnapshot',
19
- 'toMatchInlineSnapshot',
20
- 'toThrowErrorMatchingSnapshot',
21
- 'toThrowErrorMatchingInlineSnapshot',
22
- 'throws',
23
- 'Throw',
24
- 'throw',
25
- 'toThrow',
26
- 'toThrowError'
27
- ];
28
- function createExpectPoll(expect) {
29
- return function poll(fn, options = {}) {
30
- const { interval = 50, timeout = 1000, message } = options;
31
- const assertion = expect(null, message).withContext({
32
- poll: true
33
- });
34
- fn = fn.bind(assertion);
35
- const test = node_modules_chai.ZS.flag(assertion, 'vitest-test');
36
- if (!test) throw new Error('expect.poll() must be called inside a test');
37
- const proxy = new Proxy(assertion, {
38
- get (target, key, receiver) {
39
- const assertionFunction = Reflect.get(target, key, receiver);
40
- if ('function' != typeof assertionFunction) return assertionFunction instanceof node_modules_chai.zo ? proxy : assertionFunction;
41
- if ('assert' === key) return assertionFunction;
42
- if ('string' == typeof key && unsupported.includes(key)) throw new SyntaxError(`expect.poll() is not supported in combination with .${key}(). Use rstest.waitFor() if your assertion condition is unstable.`);
43
- return function(...args) {
44
- const STACK_TRACE_ERROR = new Error('STACK_TRACE_ERROR');
45
- const promise = ()=>new Promise((resolve, reject)=>{
46
- let intervalId;
47
- let timeoutId;
48
- let lastError;
49
- const check = async ()=>{
50
- try {
51
- node_modules_chai.ZS.flag(assertion, '_name', key);
52
- const obj = await fn();
53
- node_modules_chai.ZS.flag(assertion, 'object', obj);
54
- resolve(await assertionFunction.call(assertion, ...args));
55
- clearTimeout(intervalId);
56
- clearTimeout(timeoutId);
57
- } catch (err) {
58
- lastError = err;
59
- if (!node_modules_chai.ZS.flag(assertion, '_isLastPollAttempt')) intervalId = (0, runtime_util.rZ)().setTimeout(check, interval);
60
- }
61
- };
62
- timeoutId = (0, runtime_util.rZ)().setTimeout(()=>{
63
- clearTimeout(intervalId);
64
- node_modules_chai.ZS.flag(assertion, '_isLastPollAttempt', true);
65
- const rejectWithCause = (cause)=>{
66
- reject(copyStackTrace(new Error(`Matcher did not succeed in ${timeout}ms`, {
67
- cause
68
- }), STACK_TRACE_ERROR));
69
- };
70
- check().then(()=>rejectWithCause(lastError)).catch((e)=>rejectWithCause(e));
71
- }, timeout);
72
- check();
73
- });
74
- let awaited = false;
75
- test.onFinished ??= [];
76
- test.onFinished.push(()=>{
77
- if (!awaited) {
78
- const negated = node_modules_chai.ZS.flag(assertion, 'negate') ? 'not.' : '';
79
- const name = node_modules_chai.ZS.flag(assertion, '_poll.element') ? 'element(locator)' : 'poll(assertion)';
80
- const assertionString = `expect.${name}.${negated}${String(key)}()`;
81
- const error = new Error(`${assertionString} was not awaited. This assertion is asynchronous and must be awaited; otherwise, it is not executed to avoid unhandled rejections:\n\nawait ${assertionString}\n`);
82
- throw copyStackTrace(error, STACK_TRACE_ERROR);
83
- }
84
- });
85
- let resultPromise;
86
- return {
87
- then (onFulfilled, onRejected) {
88
- awaited = true;
89
- resultPromise ||= promise();
90
- return resultPromise.then(onFulfilled, onRejected);
91
- },
92
- catch (onRejected) {
93
- resultPromise ||= promise();
94
- return resultPromise.catch(onRejected);
95
- },
96
- finally (onFinally) {
97
- resultPromise ||= promise();
98
- return resultPromise.finally(onFinally);
99
- },
100
- [Symbol.toStringTag]: 'Promise'
101
- };
102
- };
103
- }
104
- });
105
- return proxy;
106
- };
107
- }
108
- function copyStackTrace(target, source) {
109
- if (void 0 !== source.stack) target.stack = source.stack.replace(source.message, target.message);
110
- return target;
111
- }
112
- var snapshot_dist = __webpack_require__("../../node_modules/.pnpm/@vitest+snapshot@3.2.4/node_modules/@vitest/snapshot/dist/index.js");
113
- let _client;
114
- function getSnapshotClient() {
115
- if (!_client) _client = new snapshot_dist.s({
116
- isEqual: (received, expected)=>(0, dist.aI)(received, expected, [
117
- dist.D,
118
- dist.j2
119
- ])
120
- });
121
- return _client;
122
- }
123
- function recordAsyncExpect(_test, promise, assertion, error) {
124
- const test = _test;
125
- if (test && promise instanceof Promise) {
126
- promise = promise.finally(()=>{
127
- if (!test.promises) return;
128
- const index = test.promises.indexOf(promise);
129
- if (-1 !== index) test.promises.splice(index, 1);
130
- });
131
- if (!test.promises) test.promises = [];
132
- test.promises.push(promise);
133
- let resolved = false;
134
- test.onFinished ??= [];
135
- test.onFinished.push(()=>{
136
- if (!resolved) {
137
- const processor = globalThis.__vitest_worker__?.onFilterStackTrace || ((s)=>s || '');
138
- const stack = processor(error.stack);
139
- console.warn([
140
- `Promise returned by \`${assertion}\` was not awaited. `,
141
- 'Rstest currently auto-awaits hanging assertions at the end of the test.',
142
- 'Please remember to await the assertion.\n',
143
- stack
144
- ].join(''));
145
- }
146
- });
147
- return {
148
- then (onFulfilled, onRejected) {
149
- resolved = true;
150
- return promise.then(onFulfilled, onRejected);
151
- },
152
- catch (onRejected) {
153
- return promise.catch(onRejected);
154
- },
155
- finally (onFinally) {
156
- return promise.finally(onFinally);
157
- },
158
- [Symbol.toStringTag]: 'Promise'
159
- };
160
- }
161
- return promise;
162
- }
163
- function createAssertionMessage(util, assertion, hasArgs) {
164
- const not = util.flag(assertion, 'negate') ? 'not.' : '';
165
- const name = `${util.flag(assertion, '_name')}(${hasArgs ? 'expected' : ''})`;
166
- const promiseName = util.flag(assertion, 'promise');
167
- const promise = promiseName ? `.${promiseName}` : '';
168
- return `expect(actual)${promise}.${not}${name}`;
169
- }
170
- function getError(expected, promise) {
171
- if ('function' != typeof expected) {
172
- if (!promise) throw new Error(`expected must be a function, received ${typeof expected}`);
173
- return expected;
174
- }
175
- try {
176
- expected();
177
- } catch (e) {
178
- return e;
179
- }
180
- throw new Error("snapshot function didn't throw");
181
- }
182
- function getTestNames(test) {
183
- return {
184
- filepath: test.testPath,
185
- name: (0, src_utils.fN)(test)
186
- };
187
- }
188
- const SnapshotPlugin = (chai, utils)=>{
189
- function getTest(assertionName, obj) {
190
- const test = utils.flag(obj, 'vitest-test');
191
- if (!test) throw new Error(`'${assertionName}' cannot be used without test context`);
192
- return test;
193
- }
194
- for (const key of [
195
- 'matchSnapshot',
196
- 'toMatchSnapshot'
197
- ])utils.addMethod(chai.Assertion.prototype, key, function(properties, message) {
198
- utils.flag(this, '_name', key);
199
- const isNot = utils.flag(this, 'negate');
200
- if (isNot) throw new Error(`${key} cannot be used with "not"`);
201
- const expected = utils.flag(this, 'object');
202
- const test = getTest(key, this);
203
- if ('string' == typeof properties && void 0 === message) {
204
- message = properties;
205
- properties = void 0;
206
- }
207
- const errorMessage = utils.flag(this, 'message');
208
- getSnapshotClient().assert({
209
- received: expected,
210
- message,
211
- isInline: false,
212
- properties,
213
- errorMessage,
214
- ...getTestNames(test)
215
- });
216
- });
217
- utils.addMethod(chai.Assertion.prototype, 'toMatchFileSnapshot', function(file, message) {
218
- utils.flag(this, '_name', 'toMatchFileSnapshot');
219
- const isNot = utils.flag(this, 'negate');
220
- if (isNot) throw new Error('toMatchFileSnapshot cannot be used with "not"');
221
- const error = new Error('resolves');
222
- const expected = utils.flag(this, 'object');
223
- const test = getTest('toMatchFileSnapshot', this);
224
- const errorMessage = utils.flag(this, 'message');
225
- const promise = getSnapshotClient().assertRaw({
226
- received: expected,
227
- message,
228
- isInline: false,
229
- rawSnapshot: {
230
- file
231
- },
232
- errorMessage,
233
- ...getTestNames(test)
234
- });
235
- return recordAsyncExpect(test, promise, createAssertionMessage(utils, this, true), error);
236
- });
237
- utils.addMethod(chai.Assertion.prototype, 'toMatchInlineSnapshot', function __INLINE_SNAPSHOT__(properties, inlineSnapshot, message) {
238
- utils.flag(this, '_name', 'toMatchInlineSnapshot');
239
- const isNot = utils.flag(this, 'negate');
240
- if (isNot) throw new Error('toMatchInlineSnapshot cannot be used with "not"');
241
- const test = getTest('toMatchInlineSnapshot', this);
242
- const isInsideEach = test.each || test.inTestEach;
243
- if (isInsideEach) throw new Error('InlineSnapshot cannot be used inside of test.each or describe.each');
244
- const expected = utils.flag(this, 'object');
245
- const error = utils.flag(this, 'error');
246
- if ('string' == typeof properties) {
247
- message = inlineSnapshot;
248
- inlineSnapshot = properties;
249
- properties = void 0;
250
- }
251
- if (inlineSnapshot) inlineSnapshot = (0, snapshot_dist.cN)(inlineSnapshot);
252
- const errorMessage = utils.flag(this, 'message');
253
- getSnapshotClient().assert({
254
- received: expected,
255
- message,
256
- isInline: true,
257
- properties,
258
- inlineSnapshot,
259
- error,
260
- errorMessage,
261
- ...getTestNames(test)
262
- });
263
- });
264
- utils.addMethod(chai.Assertion.prototype, 'toThrowErrorMatchingSnapshot', function(message) {
265
- utils.flag(this, '_name', 'toThrowErrorMatchingSnapshot');
266
- const isNot = utils.flag(this, 'negate');
267
- if (isNot) throw new Error('toThrowErrorMatchingSnapshot cannot be used with "not"');
268
- const expected = utils.flag(this, 'object');
269
- const test = getTest('toThrowErrorMatchingSnapshot', this);
270
- const promise = utils.flag(this, 'promise');
271
- const errorMessage = utils.flag(this, 'message');
272
- getSnapshotClient().assert({
273
- received: getError(expected, promise),
274
- message,
275
- errorMessage,
276
- ...getTestNames(test)
277
- });
278
- });
279
- utils.addMethod(chai.Assertion.prototype, 'toThrowErrorMatchingInlineSnapshot', function __INLINE_SNAPSHOT__(inlineSnapshot, message) {
280
- const isNot = utils.flag(this, 'negate');
281
- if (isNot) throw new Error('toThrowErrorMatchingInlineSnapshot cannot be used with "not"');
282
- const test = getTest('toThrowErrorMatchingInlineSnapshot', this);
283
- const isInsideEach = test.each || test.inTestEach;
284
- if (isInsideEach) throw new Error('InlineSnapshot cannot be used inside of test.each or describe.each');
285
- const expected = utils.flag(this, 'object');
286
- const error = utils.flag(this, 'error');
287
- const promise = utils.flag(this, 'promise');
288
- const errorMessage = utils.flag(this, 'message');
289
- if (inlineSnapshot) inlineSnapshot = (0, snapshot_dist.cN)(inlineSnapshot);
290
- getSnapshotClient().assert({
291
- received: getError(expected, promise),
292
- message,
293
- inlineSnapshot,
294
- isInline: true,
295
- error,
296
- errorMessage,
297
- ...getTestNames(test)
298
- });
299
- });
300
- utils.addMethod(chai.expect, 'addSnapshotSerializer', snapshot_dist.U$);
301
- };
302
- node_modules_chai.Yx(dist.Xs);
303
- node_modules_chai.Yx(dist.dB);
304
- node_modules_chai.Yx(SnapshotPlugin);
305
- node_modules_chai.Yx(dist.Mc);
306
- function createExpect({ getCurrentTest, workerState }) {
307
- const expect = (value, message)=>{
308
- const { assertionCalls } = (0, dist.Gu)(expect);
309
- (0, dist.wb)({
310
- assertionCalls: assertionCalls + 1
311
- }, expect);
312
- const assert = node_modules_chai.E3(value, message);
313
- const _test = getCurrentTest();
314
- if (_test) return assert.withTest(_test);
315
- return assert;
316
- };
317
- Object.assign(expect, node_modules_chai.E3);
318
- Object.assign(expect, globalThis[dist.fs]);
319
- expect.getState = ()=>(0, dist.Gu)(expect);
320
- expect.setState = (state)=>(0, dist.wb)(state, expect);
321
- const globalState = (0, dist.Gu)(globalThis[dist.mZ]) || {};
322
- (0, dist.wb)({
323
- ...globalState,
324
- assertionCalls: 0,
325
- isExpectingAssertions: false,
326
- isExpectingAssertionsError: null,
327
- expectedAssertionsNumber: null,
328
- expectedAssertionsNumberErrorGen: null,
329
- get testPath () {
330
- return workerState.testPath;
331
- }
332
- }, expect);
333
- expect.extend = (matchers)=>node_modules_chai.E3.extend(expect, matchers);
334
- expect.addEqualityTesters = (customTesters)=>(0, dist.TB)(customTesters);
335
- expect.soft = (...args)=>expect(...args).withContext({
336
- soft: true
337
- });
338
- expect.poll = createExpectPoll(expect);
339
- expect.unreachable = (message)=>{
340
- node_modules_chai.vA.fail(`expected ${message ? `"${message}" ` : ''}not to be reached`);
341
- };
342
- function assertions(expected) {
343
- const errorGen = ()=>new Error(`expected number of assertions to be ${expected}, but got ${expect.getState().assertionCalls}`);
344
- if (Error.captureStackTrace) Error.captureStackTrace(errorGen(), assertions);
345
- expect.setState({
346
- expectedAssertionsNumber: expected,
347
- expectedAssertionsNumberErrorGen: errorGen
348
- });
349
- }
350
- function hasAssertions() {
351
- const error = new Error('expected any number of assertion, but got none');
352
- if (Error.captureStackTrace) Error.captureStackTrace(error, hasAssertions);
353
- expect.setState({
354
- isExpectingAssertions: true,
355
- isExpectingAssertionsError: error
356
- });
357
- }
358
- node_modules_chai.ZS.addMethod(expect, 'assertions', assertions);
359
- node_modules_chai.ZS.addMethod(expect, 'hasAssertions', hasAssertions);
360
- expect.extend(dist.Pf);
361
- return expect;
362
- }
363
- const normalizeFixtures = (fixtures = {}, extendFixtures = {})=>{
364
- const result = {};
365
- for(const key in fixtures){
366
- const fixtureOptionKeys = [
367
- 'auto'
368
- ];
369
- const value = fixtures[key];
370
- if (Array.isArray(value)) {
371
- if (1 === value.length && 'function' == typeof value[0]) {
372
- result[key] = {
373
- isFn: true,
374
- value: value[0]
375
- };
376
- continue;
377
- }
378
- if ((0, src_utils.Gv)(value[1]) && Object.keys(value[1]).some((key)=>fixtureOptionKeys.includes(key))) {
379
- result[key] = {
380
- isFn: 'function' == typeof value[0],
381
- value: value[0],
382
- options: value[1]
383
- };
384
- continue;
385
- }
386
- }
387
- result[key] = {
388
- isFn: 'function' == typeof value,
389
- value
390
- };
391
- }
392
- const formattedResult = Object.fromEntries(Object.entries(result).map(([key, value])=>{
393
- if (value.isFn) {
394
- const usedProps = getFixtureUsedProps(value.value);
395
- value.deps = usedProps.filter((p)=>p in result || p in extendFixtures);
396
- }
397
- return [
398
- key,
399
- value
400
- ];
401
- }));
402
- return {
403
- ...extendFixtures,
404
- ...formattedResult
405
- };
406
- };
407
- const handleFixtures = async (test, context)=>{
408
- const cleanups = [];
409
- if (!test.fixtures) return {
410
- cleanups
411
- };
412
- const doneMap = new Set();
413
- const pendingMap = new Set();
414
- const usedKeys = test.originalFn ? getFixtureUsedProps(test.originalFn) : [];
415
- const useFixture = async (name, NormalizedFixture)=>{
416
- if (doneMap.has(name)) return;
417
- if (pendingMap.has(name)) throw new Error(`Circular fixture dependency: ${name}`);
418
- const { isFn, deps, value: fixtureValue } = NormalizedFixture;
419
- if (!isFn) {
420
- context[name] = fixtureValue;
421
- doneMap.add(name);
422
- return;
423
- }
424
- pendingMap.add(name);
425
- if (deps?.length) for (const dep of deps)await useFixture(dep, test.fixtures[dep]);
426
- await new Promise((fixtureResolve)=>{
427
- let useDone;
428
- const block = fixtureValue(context, async (value)=>{
429
- context[name] = value;
430
- fixtureResolve();
431
- return new Promise((useFnResolve)=>{
432
- useDone = useFnResolve;
433
- });
434
- });
435
- cleanups.unshift(()=>{
436
- useDone?.();
437
- return block;
438
- });
439
- });
440
- doneMap.add(name);
441
- pendingMap.delete(name);
442
- };
443
- for (const [name, params] of Object.entries(test.fixtures)){
444
- const shouldAdd = params.options?.auto || usedKeys.includes(name);
445
- if (shouldAdd) await useFixture(name, params);
446
- }
447
- return {
448
- cleanups
449
- };
450
- };
451
- function splitByComma(s) {
452
- const result = [];
453
- const stack = [];
454
- let start = 0;
455
- for(let i = 0; i < s.length; i++)if ('{' === s[i] || '[' === s[i]) stack.push('{' === s[i] ? '}' : ']');
456
- else if (s[i] === stack[stack.length - 1]) stack.pop();
457
- else if (!stack.length && ',' === s[i]) {
458
- const token = s.substring(start, i).trim();
459
- if (token) result.push(token);
460
- start = i + 1;
461
- }
462
- const lastToken = s.substring(start).trim();
463
- if (lastToken) result.push(lastToken);
464
- return result;
465
- }
466
- function filterOutComments(s) {
467
- const result = [];
468
- let commentState = 'none';
469
- for(let i = 0; i < s.length; ++i)if ('singleline' === commentState) {
470
- if ('\n' === s[i]) commentState = 'none';
471
- } else if ('multiline' === commentState) {
472
- if ('*' === s[i - 1] && '/' === s[i]) commentState = 'none';
473
- } else if ('none' === commentState) if ('/' === s[i] && '/' === s[i + 1]) commentState = 'singleline';
474
- else if ('/' === s[i] && '*' === s[i + 1]) {
475
- commentState = 'multiline';
476
- i += 2;
477
- } else result.push(s[i]);
478
- return result.join('');
479
- }
480
- function getFixtureUsedProps(fn) {
481
- const text = filterOutComments(fn.toString());
482
- const match = text.match(/(?:async)?(?:\s+function)?[^(]*\(([^)]*)/);
483
- if (!match) return [];
484
- const trimmedParams = match[1].trim();
485
- if (!trimmedParams) return [];
486
- const [firstParam] = splitByComma(trimmedParams);
487
- if (firstParam?.[0] !== '{' || '}' !== firstParam[firstParam.length - 1]) {
488
- if (firstParam?.startsWith('_')) return [];
489
- throw new Error(`First argument must use the object destructuring pattern: ${firstParam}`);
490
- }
491
- const props = splitByComma(firstParam.substring(1, firstParam.length - 1)).map((prop)=>{
492
- const colon = prop.indexOf(':');
493
- return -1 === colon ? prop.trim() : prop.substring(0, colon).trim();
494
- });
495
- const restProperty = props.find((prop)=>prop.startsWith('...'));
496
- if (restProperty) throw new Error(`Rest property "${restProperty}" is not supported. List all used fixtures explicitly, separated by comma.`);
497
- return props;
498
- }
499
- const getTestStatus = (results, defaultStatus)=>{
500
- if (0 === results.length) return defaultStatus;
501
- return results.some((result)=>'fail' === result.status) ? 'fail' : results.every((result)=>'todo' === result.status) ? 'todo' : results.every((result)=>'skip' === result.status) ? 'skip' : 'pass';
502
- };
503
- function hasOnlyTest(test) {
504
- return test.some((t)=>'only' === t.runMode || 'suite' === t.type && hasOnlyTest(t.tests));
505
- }
506
- const shouldTestSkip = (test, runOnly, testNamePattern)=>{
507
- if (runOnly && 'only' !== test.runMode) return true;
508
- if (testNamePattern && !(0, src_utils.fN)(test, '').match(testNamePattern)) return true;
509
- return false;
510
- };
511
- const traverseUpdateTestRunMode = (testSuite, parentRunMode, runOnly, testNamePattern)=>{
512
- if (0 === testSuite.tests.length) return;
513
- if (runOnly && 'only' !== testSuite.runMode && !hasOnlyTest(testSuite.tests)) testSuite.runMode = 'skip';
514
- else if ([
515
- 'skip',
516
- 'todo'
517
- ].includes(parentRunMode)) testSuite.runMode = parentRunMode;
518
- const tests = testSuite.tests.map((test)=>{
519
- const runSubOnly = runOnly && 'only' !== testSuite.runMode ? runOnly : hasOnlyTest(testSuite.tests);
520
- if ('case' === test.type) {
521
- if ([
522
- 'skip',
523
- 'todo'
524
- ].includes(testSuite.runMode)) test.runMode = testSuite.runMode;
525
- if (shouldTestSkip(test, runSubOnly, testNamePattern)) test.runMode = 'skip';
526
- return test;
527
- }
528
- traverseUpdateTestRunMode(test, testSuite.runMode, runSubOnly, testNamePattern);
529
- return test;
530
- });
531
- if ('run' !== testSuite.runMode) return;
532
- const hasRunTest = tests.some((test)=>'run' === test.runMode || 'only' === test.runMode);
533
- if (hasRunTest) {
534
- testSuite.runMode = 'run';
535
- return;
536
- }
537
- const allTodoTest = tests.every((test)=>'todo' === test.runMode);
538
- testSuite.runMode = allTodoTest ? 'todo' : 'skip';
539
- };
540
- const updateTestModes = (tests, testNamePattern)=>{
541
- const hasOnly = hasOnlyTest(tests);
542
- for (const test of tests)if ('suite' === test.type) traverseUpdateTestRunMode(test, 'run', hasOnly, testNamePattern);
543
- else if (shouldTestSkip(test, hasOnly, testNamePattern)) test.runMode = 'skip';
544
- };
545
- const updateTestParents = (tests, parentNames = [])=>{
546
- for (const test of tests)if ('suite' === test.type) {
547
- const names = test.name === src_utils.q_ ? parentNames : parentNames.concat(test.name);
548
- updateTestParents(test.tests, names);
549
- } else test.parentNames = parentNames;
550
- };
551
- const traverseUpdateTest = (tests, testNamePattern)=>{
552
- updateTestParents(tests);
553
- updateTestModes(tests, testNamePattern);
554
- };
555
- const markAllTestAsSkipped = (test)=>{
556
- for (const t of test){
557
- t.runMode = 'skip';
558
- if ('suite' === t.type) markAllTestAsSkipped(t.tests);
559
- }
560
- };
561
- function registerTestSuiteListener(suite, key, fn) {
562
- const listenersKey = `${key}Listeners`;
563
- suite[listenersKey] ??= [];
564
- suite[listenersKey].push(fn);
565
- }
566
- function makeError(message, stackTraceError) {
567
- const error = new Error(message);
568
- if (stackTraceError?.stack) error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
569
- return error;
570
- }
571
- function wrapTimeout({ name, fn, timeout, stackTraceError }) {
572
- if (!timeout) return fn;
573
- return async (...args)=>{
574
- let timeoutId;
575
- const timeoutPromise = new Promise((_, reject)=>{
576
- timeoutId = (0, runtime_util.rZ)().setTimeout(()=>reject(makeError(`${name} timed out in ${timeout}ms`, stackTraceError)), timeout);
577
- });
578
- try {
579
- const result = await Promise.race([
580
- fn(...args),
581
- timeoutPromise
582
- ]);
583
- timeoutId && clearTimeout(timeoutId);
584
- return result;
585
- } catch (error) {
586
- timeoutId && clearTimeout(timeoutId);
587
- throw error;
588
- }
589
- };
590
- }
591
- function limitConcurrency(concurrency = 1 / 0) {
592
- let running = 0;
593
- const queue = [];
594
- const runNext = ()=>{
595
- if (queue.length > 0 && running < concurrency) {
596
- running++;
597
- const next = queue.shift();
598
- next();
599
- }
600
- };
601
- return (func, ...args)=>new Promise((resolve, reject)=>{
602
- const task = ()=>{
603
- Promise.resolve(func(...args)).then(resolve).catch(reject).finally(()=>{
604
- running--;
605
- runNext();
606
- });
607
- };
608
- if (running < concurrency) {
609
- running++;
610
- task();
611
- } else queue.push(task);
612
- });
613
- }
614
- const RealDate = Date;
615
- class TestRunner {
616
- _test;
617
- workerState;
618
- async runTests({ tests, testPath, state, hooks, api }) {
619
- this.workerState = state;
620
- const { runtimeConfig: { passWithNoTests, retry, maxConcurrency }, project, snapshotOptions } = state;
621
- const results = [];
622
- const errors = [];
623
- let defaultStatus = 'pass';
624
- const snapshotClient = getSnapshotClient();
625
- await snapshotClient.setup(testPath, snapshotOptions);
626
- const runTestsCase = async (test, parentHooks)=>{
627
- if ('skip' === test.runMode) {
628
- snapshotClient.skipTest(testPath, (0, src_utils.fN)(test));
629
- const result = {
630
- status: 'skip',
631
- parentNames: test.parentNames,
632
- name: test.name,
633
- testPath,
634
- project
635
- };
636
- return result;
637
- }
638
- if ('todo' === test.runMode) {
639
- const result = {
640
- status: 'todo',
641
- parentNames: test.parentNames,
642
- name: test.name,
643
- testPath,
644
- project
645
- };
646
- return result;
647
- }
648
- let result;
649
- this.beforeEach(test, state, api);
650
- const cleanups = [];
651
- try {
652
- for (const fn of parentHooks.beforeEachListeners){
653
- const cleanupFn = await fn();
654
- cleanupFn && cleanups.push(cleanupFn);
655
- }
656
- } catch (error) {
657
- result = {
658
- status: 'fail',
659
- parentNames: test.parentNames,
660
- name: test.name,
661
- errors: (0, runtime_util.o9)(error, test),
662
- testPath,
663
- project
664
- };
665
- }
666
- if (result?.status !== 'fail') if (test.fails) try {
667
- const fixtureCleanups = await this.beforeRunTest(test, snapshotClient.getSnapshotState(testPath));
668
- cleanups.push(...fixtureCleanups);
669
- await test.fn?.(test.context);
670
- this.afterRunTest(test);
671
- result = {
672
- status: 'fail',
673
- parentNames: test.parentNames,
674
- name: test.name,
675
- testPath,
676
- project,
677
- errors: [
678
- {
679
- message: 'Expect test to fail'
680
- }
681
- ]
682
- };
683
- } catch (_err) {
684
- result = {
685
- project,
686
- status: 'pass',
687
- parentNames: test.parentNames,
688
- name: test.name,
689
- testPath
690
- };
691
- }
692
- else try {
693
- const fixtureCleanups = await this.beforeRunTest(test, snapshotClient.getSnapshotState(testPath));
694
- cleanups.push(...fixtureCleanups);
695
- await test.fn?.(test.context);
696
- this.afterRunTest(test);
697
- result = {
698
- project,
699
- parentNames: test.parentNames,
700
- name: test.name,
701
- status: 'pass',
702
- testPath
703
- };
704
- } catch (error) {
705
- result = {
706
- project,
707
- status: 'fail',
708
- parentNames: test.parentNames,
709
- name: test.name,
710
- errors: (0, runtime_util.o9)(error, test),
711
- testPath
712
- };
713
- }
714
- const afterEachFns = [
715
- ...parentHooks.afterEachListeners || []
716
- ].reverse().concat(cleanups).concat(test.onFinished);
717
- try {
718
- for (const fn of afterEachFns)await fn({
719
- task: {
720
- result
721
- }
722
- });
723
- } catch (error) {
724
- result.status = 'fail';
725
- result.errors ??= [];
726
- result.errors.push(...(0, runtime_util.o9)(error));
727
- }
728
- if ('fail' === result.status) for (const fn of [
729
- ...test.onFailed
730
- ].reverse())try {
731
- await fn({
732
- task: {
733
- result
734
- }
735
- });
736
- } catch (error) {
737
- result.errors ??= [];
738
- result.errors.push(...(0, runtime_util.o9)(error));
739
- }
740
- this.resetCurrentTest();
741
- return result;
742
- };
743
- const limitMaxConcurrency = limitConcurrency(maxConcurrency);
744
- const runTests = async (allTest, parentHooks)=>{
745
- const tests = [
746
- ...allTest
747
- ];
748
- while(tests.length){
749
- const suite = tests.shift();
750
- if (suite.concurrent) {
751
- const cases = [
752
- suite
753
- ];
754
- while(tests[0]?.concurrent)cases.push(tests.shift());
755
- await Promise.all(cases.map((test)=>{
756
- if ('suite' === test.type) return runTest(test, parentHooks);
757
- return limitMaxConcurrency(()=>runTest(test, parentHooks));
758
- }));
759
- continue;
760
- }
761
- await runTest(suite, parentHooks);
762
- }
763
- };
764
- const runTest = async (test, parentHooks)=>{
765
- if ('suite' === test.type) {
766
- if (0 === test.tests.length) {
767
- if ([
768
- 'todo',
769
- 'skip'
770
- ].includes(test.runMode)) {
771
- defaultStatus = 'skip';
772
- return;
773
- }
774
- if (passWithNoTests) return;
775
- const noTestError = {
776
- message: `No test found in suite: ${test.name}`,
777
- name: 'No tests'
778
- };
779
- errors.push(noTestError);
780
- const result = {
781
- status: 'fail',
782
- parentNames: test.parentNames,
783
- name: test.name,
784
- testPath,
785
- errors: [
786
- noTestError
787
- ],
788
- project
789
- };
790
- hooks.onTestCaseResult?.(result);
791
- }
792
- const cleanups = [];
793
- let hasBeforeAllError = false;
794
- if ([
795
- 'run',
796
- 'only'
797
- ].includes(test.runMode) && test.beforeAllListeners) try {
798
- for (const fn of test.beforeAllListeners){
799
- const cleanupFn = await fn({
800
- filepath: testPath
801
- });
802
- cleanupFn && cleanups.push(cleanupFn);
803
- }
804
- } catch (error) {
805
- hasBeforeAllError = true;
806
- errors.push(...(0, runtime_util.o9)(error));
807
- }
808
- if (hasBeforeAllError) markAllTestAsSkipped(test.tests);
809
- await runTests(test.tests, {
810
- beforeEachListeners: parentHooks.beforeEachListeners.concat(test.beforeEachListeners || []),
811
- afterEachListeners: parentHooks.afterEachListeners.concat(test.afterEachListeners || [])
812
- });
813
- const afterAllFns = [
814
- ...test.afterAllListeners || []
815
- ].reverse().concat(cleanups);
816
- if ([
817
- 'run',
818
- 'only'
819
- ].includes(test.runMode) && afterAllFns.length) try {
820
- for (const fn of afterAllFns)await fn({
821
- filepath: testPath
822
- });
823
- } catch (error) {
824
- errors.push(...(0, runtime_util.o9)(error));
825
- }
826
- } else {
827
- const start = RealDate.now();
828
- let result;
829
- let retryCount = 0;
830
- do {
831
- const currentResult = await runTestsCase(test, parentHooks);
832
- result = {
833
- ...currentResult,
834
- errors: 'fail' === currentResult.status && result && result.errors ? result.errors.concat(...currentResult.errors || []) : currentResult.errors
835
- };
836
- retryCount++;
837
- }while (retryCount <= retry && 'fail' === result.status);
838
- result.duration = RealDate.now() - start;
839
- result.retryCount = retryCount - 1;
840
- hooks.onTestCaseResult?.(result);
841
- results.push(result);
842
- }
843
- };
844
- const start = RealDate.now();
845
- if (0 === tests.length) {
846
- if (passWithNoTests) return {
847
- project,
848
- testPath,
849
- name: '',
850
- status: 'pass',
851
- results
852
- };
853
- return {
854
- project,
855
- testPath,
856
- name: '',
857
- status: 'fail',
858
- results,
859
- errors: [
860
- {
861
- message: `No test suites found in file: ${testPath}`,
862
- name: 'No tests'
863
- }
864
- ]
865
- };
866
- }
867
- await runTests(tests, {
868
- beforeEachListeners: [],
869
- afterEachListeners: []
870
- });
871
- const snapshotResult = await snapshotClient.finish(testPath);
872
- return {
873
- project,
874
- testPath,
875
- name: '',
876
- status: errors.length ? 'fail' : getTestStatus(results, defaultStatus),
877
- results,
878
- snapshotResult,
879
- errors,
880
- duration: RealDate.now() - start
881
- };
882
- }
883
- resetCurrentTest() {
884
- this._test = void 0;
885
- }
886
- setCurrentTest(test) {
887
- this._test = test;
888
- }
889
- getCurrentTest() {
890
- return this._test;
891
- }
892
- beforeEach(test, state, api) {
893
- const { runtimeConfig: { clearMocks, resetMocks, restoreMocks, unstubEnvs, unstubGlobals } } = state;
894
- this.setCurrentTest(test);
895
- if (restoreMocks) api.rstest.restoreAllMocks();
896
- else if (resetMocks) api.rstest.resetAllMocks();
897
- else if (clearMocks) api.rstest.clearAllMocks();
898
- if (unstubEnvs) api.rstest.unstubAllEnvs();
899
- if (unstubGlobals) api.rstest.unstubAllGlobals();
900
- }
901
- createTestContext() {
902
- const context = ()=>{
903
- throw new Error('done() callback is deprecated, use promise instead');
904
- };
905
- let _expect;
906
- const current = this._test;
907
- Object.defineProperty(context, 'expect', {
908
- get: ()=>{
909
- if (!_expect) _expect = createExpect({
910
- workerState: this.workerState,
911
- getCurrentTest: ()=>current
912
- });
913
- return _expect;
914
- }
915
- });
916
- Object.defineProperty(context, '_useLocalExpect', {
917
- get () {
918
- return null != _expect;
919
- }
920
- });
921
- Object.defineProperty(context, 'onTestFinished', {
922
- get: ()=>(fn, timeout)=>{
923
- this.onTestFinished(current, fn, timeout);
924
- }
925
- });
926
- Object.defineProperty(context, 'onTestFailed', {
927
- get: ()=>(fn, timeout)=>{
928
- this.onTestFailed(current, fn, timeout);
929
- }
930
- });
931
- return context;
932
- }
933
- onTestFinished(test, fn, timeout) {
934
- if (!test) throw new Error('onTestFinished() can only be called inside a test');
935
- test.onFinished.push(wrapTimeout({
936
- name: 'onTestFinished hook',
937
- fn,
938
- timeout: timeout || this.workerState.runtimeConfig.hookTimeout,
939
- stackTraceError: new Error('STACK_TRACE_ERROR')
940
- }));
941
- }
942
- onTestFailed(test, fn, timeout) {
943
- if (!test) throw new Error('onTestFailed() can only be called inside a test');
944
- test.onFailed.push(wrapTimeout({
945
- name: 'onTestFailed hook',
946
- fn,
947
- timeout: timeout || this.workerState.runtimeConfig.hookTimeout,
948
- stackTraceError: new Error('STACK_TRACE_ERROR')
949
- }));
950
- }
951
- async beforeRunTest(test, snapshotState) {
952
- (0, dist.wb)({
953
- assertionCalls: 0,
954
- isExpectingAssertions: false,
955
- isExpectingAssertionsError: null,
956
- expectedAssertionsNumber: null,
957
- expectedAssertionsNumberErrorGen: null,
958
- testPath: test.testPath,
959
- snapshotState,
960
- currentTestName: (0, src_utils.fN)(test)
961
- }, globalThis[dist.mZ]);
962
- const context = this.createTestContext();
963
- const { cleanups } = await handleFixtures(test, context);
964
- Object.defineProperty(test, 'context', {
965
- value: context,
966
- enumerable: false
967
- });
968
- return cleanups;
969
- }
970
- afterRunTest(test) {
971
- const expect = test.context._useLocalExpect ? test.context.expect : globalThis[dist.mZ];
972
- const { assertionCalls, expectedAssertionsNumber, expectedAssertionsNumberErrorGen, isExpectingAssertions, isExpectingAssertionsError } = (0, dist.Gu)(expect);
973
- if (test.result?.state === 'fail') throw test.result.errors;
974
- if (null !== expectedAssertionsNumber && assertionCalls !== expectedAssertionsNumber) throw expectedAssertionsNumberErrorGen();
975
- if (true === isExpectingAssertions && 0 === assertionCalls) throw isExpectingAssertionsError;
976
- }
977
- }
978
- class RunnerRuntime {
979
- tests = [];
980
- _currentTest = [];
981
- testPath;
982
- status = 'collect';
983
- collectStatus = 'lazy';
984
- currentCollectList = [];
985
- runtimeConfig;
986
- project;
987
- constructor({ testPath, runtimeConfig, project }){
988
- this.project = project;
989
- this.testPath = testPath;
990
- this.runtimeConfig = runtimeConfig;
991
- }
992
- updateStatus(status) {
993
- this.status = status;
994
- }
995
- checkStatus(name, type) {
996
- if ('running' === this.status) {
997
- const error = new runtime_util.si(`${'case' === type ? 'Test' : 'Describe'} '${name}' cannot run`);
998
- throw error;
999
- }
1000
- }
1001
- afterAll(fn, timeout = this.runtimeConfig.hookTimeout) {
1002
- const currentSuite = this.getCurrentSuite();
1003
- registerTestSuiteListener(currentSuite, 'afterAll', wrapTimeout({
1004
- name: 'afterAll hook',
1005
- fn,
1006
- timeout,
1007
- stackTraceError: new Error('STACK_TRACE_ERROR')
1008
- }));
1009
- }
1010
- beforeAll(fn, timeout = this.runtimeConfig.hookTimeout) {
1011
- const currentSuite = this.getCurrentSuite();
1012
- registerTestSuiteListener(currentSuite, 'beforeAll', wrapTimeout({
1013
- name: 'beforeAll hook',
1014
- fn,
1015
- timeout,
1016
- stackTraceError: new Error('STACK_TRACE_ERROR')
1017
- }));
1018
- }
1019
- afterEach(fn, timeout = this.runtimeConfig.hookTimeout) {
1020
- const currentSuite = this.getCurrentSuite();
1021
- registerTestSuiteListener(currentSuite, 'afterEach', wrapTimeout({
1022
- name: 'afterEach hook',
1023
- fn,
1024
- timeout,
1025
- stackTraceError: new Error('STACK_TRACE_ERROR')
1026
- }));
1027
- }
1028
- beforeEach(fn, timeout = this.runtimeConfig.hookTimeout) {
1029
- const currentSuite = this.getCurrentSuite();
1030
- registerTestSuiteListener(currentSuite, 'beforeEach', wrapTimeout({
1031
- name: 'beforeEach hook',
1032
- fn,
1033
- timeout,
1034
- stackTraceError: new Error('STACK_TRACE_ERROR')
1035
- }));
1036
- }
1037
- getDefaultRootSuite() {
1038
- return {
1039
- project: this.project,
1040
- runMode: 'run',
1041
- testPath: this.testPath,
1042
- name: src_utils.q_,
1043
- tests: [],
1044
- type: 'suite'
1045
- };
1046
- }
1047
- describe({ name, fn, runMode = 'run', each = false, concurrent, sequential }) {
1048
- this.checkStatus(name, 'suite');
1049
- const currentSuite = {
1050
- project: this.project,
1051
- name,
1052
- runMode,
1053
- tests: [],
1054
- type: 'suite',
1055
- each,
1056
- testPath: this.testPath,
1057
- concurrent,
1058
- sequential
1059
- };
1060
- if (!fn) {
1061
- this.addTest(currentSuite);
1062
- this.resetCurrentTest();
1063
- return;
1064
- }
1065
- this.collectStatus = 'lazy';
1066
- this.currentCollectList.push(async ()=>{
1067
- this.addTest(currentSuite);
1068
- const result = fn();
1069
- if (result instanceof Promise) await result;
1070
- await this.collectCurrentTest();
1071
- this.resetCurrentTest();
1072
- });
1073
- }
1074
- resetCurrentTest() {
1075
- this._currentTest.pop();
1076
- }
1077
- addTest(test) {
1078
- if (0 === this._currentTest.length) this.tests.push(test);
1079
- else {
1080
- const current = this._currentTest[this._currentTest.length - 1];
1081
- if (current.each || current.inTestEach) test.inTestEach = true;
1082
- if (current.concurrent && true !== test.sequential) test.concurrent = true;
1083
- if (current.sequential && true !== test.concurrent) test.sequential = true;
1084
- if ('case' === current.type) throw new Error('Calling the test function inside another test function is not allowed. Please put it inside "describe" so it can be properly collected.');
1085
- current.tests.push(test);
1086
- }
1087
- this._currentTest.push(test);
1088
- }
1089
- async collectCurrentTest() {
1090
- const currentCollectList = this.currentCollectList;
1091
- this.currentCollectList = [];
1092
- while(currentCollectList.length > 0){
1093
- this.collectStatus = 'running';
1094
- const fn = currentCollectList.shift();
1095
- await fn();
1096
- }
1097
- }
1098
- async getTests() {
1099
- while(this.currentCollectList.length > 0)await this.collectCurrentTest();
1100
- return this.tests;
1101
- }
1102
- addTestCase(test) {
1103
- if ('lazy' === this.collectStatus) this.currentCollectList.push(()=>{
1104
- this.addTest({
1105
- ...test,
1106
- testPath: this.testPath,
1107
- context: void 0
1108
- });
1109
- this.resetCurrentTest();
1110
- });
1111
- else {
1112
- this.addTest({
1113
- ...test,
1114
- testPath: this.testPath,
1115
- context: void 0
1116
- });
1117
- this.resetCurrentTest();
1118
- }
1119
- }
1120
- ensureRootSuite() {
1121
- if (0 === this._currentTest.length) this.addTest(this.getDefaultRootSuite());
1122
- }
1123
- it({ name, fn, originalFn = fn, fixtures, timeout = this.runtimeConfig.testTimeout, runMode = 'run', fails = false, each = false, concurrent, sequential }) {
1124
- this.checkStatus(name, 'case');
1125
- this.addTestCase({
1126
- project: this.project,
1127
- name,
1128
- originalFn,
1129
- fn: fn ? wrapTimeout({
1130
- name: 'test',
1131
- fn,
1132
- timeout,
1133
- stackTraceError: new Error('STACK_TRACE_ERROR')
1134
- }) : fn,
1135
- runMode,
1136
- type: 'case',
1137
- timeout,
1138
- fixtures,
1139
- concurrent,
1140
- sequential,
1141
- each,
1142
- fails,
1143
- onFinished: [],
1144
- onFailed: []
1145
- });
1146
- }
1147
- describeEach({ cases, ...options }) {
1148
- return (name, fn)=>{
1149
- for(let i = 0; i < cases.length; i++){
1150
- const param = cases[i];
1151
- const params = (0, src_utils.bg)(param);
1152
- this.describe({
1153
- name: (0, runtime_util.nD)(name, param, i),
1154
- fn: ()=>fn?.(...params),
1155
- ...options,
1156
- each: true
1157
- });
1158
- }
1159
- };
1160
- }
1161
- describeFor({ cases, ...options }) {
1162
- return (name, fn)=>{
1163
- for(let i = 0; i < cases.length; i++){
1164
- const param = cases[i];
1165
- this.describe({
1166
- name: (0, runtime_util.nD)(name, param, i),
1167
- fn: ()=>fn?.(param),
1168
- ...options,
1169
- each: true
1170
- });
1171
- }
1172
- };
1173
- }
1174
- each({ cases, ...options }) {
1175
- return (name, fn, timeout = this.runtimeConfig.testTimeout)=>{
1176
- for(let i = 0; i < cases.length; i++){
1177
- const param = cases[i];
1178
- const params = (0, src_utils.bg)(param);
1179
- this.it({
1180
- name: (0, runtime_util.nD)(name, param, i),
1181
- originalFn: fn,
1182
- fn: ()=>fn?.(...params),
1183
- timeout,
1184
- ...options,
1185
- each: true
1186
- });
1187
- }
1188
- };
1189
- }
1190
- for({ cases, ...options }) {
1191
- return (name, fn, timeout = this.runtimeConfig.testTimeout)=>{
1192
- for(let i = 0; i < cases.length; i++){
1193
- const param = cases[i];
1194
- this.it({
1195
- name: (0, runtime_util.nD)(name, param, i),
1196
- originalFn: fn,
1197
- fn: (context)=>fn?.(param, context),
1198
- timeout,
1199
- ...options,
1200
- each: true
1201
- });
1202
- }
1203
- };
1204
- }
1205
- getCurrentSuite() {
1206
- this.ensureRootSuite();
1207
- for(let i = this._currentTest.length - 1; i >= 0; i--){
1208
- const test = this._currentTest[i];
1209
- if ('suite' === test.type) return test;
1210
- }
1211
- throw new Error('Expect to find a suite, but got undefined');
1212
- }
1213
- }
1214
- const createRuntimeAPI = ({ testPath, runtimeConfig, project })=>{
1215
- const runtimeInstance = new RunnerRuntime({
1216
- project,
1217
- testPath,
1218
- runtimeConfig
1219
- });
1220
- const createTestAPI = (options = {})=>{
1221
- const testFn = (name, fn, timeout)=>runtimeInstance.it({
1222
- name,
1223
- fn,
1224
- timeout,
1225
- ...options
1226
- });
1227
- for (const { name, overrides } of [
1228
- {
1229
- name: 'fails',
1230
- overrides: {
1231
- fails: true
1232
- }
1233
- },
1234
- {
1235
- name: 'concurrent',
1236
- overrides: {
1237
- concurrent: true
1238
- }
1239
- },
1240
- {
1241
- name: 'sequential',
1242
- overrides: {
1243
- sequential: true
1244
- }
1245
- },
1246
- {
1247
- name: 'skip',
1248
- overrides: {
1249
- runMode: 'skip'
1250
- }
1251
- },
1252
- {
1253
- name: 'todo',
1254
- overrides: {
1255
- runMode: 'todo'
1256
- }
1257
- },
1258
- {
1259
- name: 'only',
1260
- overrides: {
1261
- runMode: 'only'
1262
- }
1263
- }
1264
- ])Object.defineProperty(testFn, name, {
1265
- get: ()=>createTestAPI({
1266
- ...options,
1267
- ...overrides
1268
- }),
1269
- enumerable: true
1270
- });
1271
- testFn.runIf = (condition)=>condition ? testFn : testFn.skip;
1272
- testFn.skipIf = (condition)=>condition ? testFn.skip : testFn;
1273
- testFn.each = (cases)=>runtimeInstance.each({
1274
- cases,
1275
- ...options
1276
- });
1277
- testFn.for = (cases)=>runtimeInstance.for({
1278
- cases,
1279
- ...options
1280
- });
1281
- return testFn;
1282
- };
1283
- const it = createTestAPI();
1284
- it.extend = (fixtures)=>{
1285
- const extend = (fixtures, extendFixtures)=>{
1286
- const normalizedFixtures = normalizeFixtures(fixtures, extendFixtures);
1287
- const api = createTestAPI({
1288
- fixtures: normalizedFixtures
1289
- });
1290
- api.extend = (subFixtures)=>extend(subFixtures, normalizedFixtures);
1291
- return api;
1292
- };
1293
- return extend(fixtures);
1294
- };
1295
- const createDescribeAPI = (options = {})=>{
1296
- const describeFn = (name, fn)=>runtimeInstance.describe({
1297
- name,
1298
- fn,
1299
- ...options
1300
- });
1301
- for (const { name, overrides } of [
1302
- {
1303
- name: 'only',
1304
- overrides: {
1305
- runMode: 'only'
1306
- }
1307
- },
1308
- {
1309
- name: 'todo',
1310
- overrides: {
1311
- runMode: 'todo'
1312
- }
1313
- },
1314
- {
1315
- name: 'skip',
1316
- overrides: {
1317
- runMode: 'skip'
1318
- }
1319
- },
1320
- {
1321
- name: 'concurrent',
1322
- overrides: {
1323
- concurrent: true
1324
- }
1325
- },
1326
- {
1327
- name: 'sequential',
1328
- overrides: {
1329
- sequential: true
1330
- }
1331
- }
1332
- ])Object.defineProperty(describeFn, name, {
1333
- get: ()=>createDescribeAPI({
1334
- ...options,
1335
- ...overrides
1336
- }),
1337
- enumerable: true
1338
- });
1339
- describeFn.skipIf = (condition)=>condition ? describeFn.skip : describeFn;
1340
- describeFn.runIf = (condition)=>condition ? describeFn : describeFn.skip;
1341
- describeFn.each = (cases)=>runtimeInstance.describeEach({
1342
- cases,
1343
- ...options
1344
- });
1345
- describeFn.for = (cases)=>runtimeInstance.describeFor({
1346
- cases,
1347
- ...options
1348
- });
1349
- return describeFn;
1350
- };
1351
- const describe = createDescribeAPI();
1352
- return {
1353
- api: {
1354
- describe,
1355
- it,
1356
- test: it,
1357
- afterAll: runtimeInstance.afterAll.bind(runtimeInstance),
1358
- beforeAll: runtimeInstance.beforeAll.bind(runtimeInstance),
1359
- afterEach: runtimeInstance.afterEach.bind(runtimeInstance),
1360
- beforeEach: runtimeInstance.beforeEach.bind(runtimeInstance)
1361
- },
1362
- instance: runtimeInstance
1363
- };
1364
- };
1365
- function createRunner({ workerState }) {
1366
- const { testPath, project, runtimeConfig: { testNamePattern } } = workerState;
1367
- const runtime = createRuntimeAPI({
1368
- project,
1369
- testPath,
1370
- runtimeConfig: workerState.runtimeConfig
1371
- });
1372
- const testRunner = new TestRunner();
1373
- return {
1374
- api: {
1375
- ...runtime.api,
1376
- onTestFinished: (fn, timeout)=>{
1377
- testRunner.onTestFinished(testRunner.getCurrentTest(), fn, timeout);
1378
- },
1379
- onTestFailed: (fn, timeout)=>{
1380
- testRunner.onTestFailed(testRunner.getCurrentTest(), fn, timeout);
1381
- }
1382
- },
1383
- runner: {
1384
- runTests: async (testPath, hooks, api)=>{
1385
- const tests = await runtime.instance.getTests();
1386
- traverseUpdateTest(tests, testNamePattern);
1387
- runtime.instance.updateStatus('running');
1388
- const results = await testRunner.runTests({
1389
- tests,
1390
- testPath,
1391
- state: workerState,
1392
- hooks,
1393
- api
1394
- });
1395
- return results;
1396
- },
1397
- collectTests: async ()=>{
1398
- const tests = await runtime.instance.getTests();
1399
- traverseUpdateTest(tests, testNamePattern);
1400
- return tests;
1401
- },
1402
- getCurrentTest: ()=>testRunner.getCurrentTest()
1403
- }
1404
- };
1405
- }
1406
- var fake_timers_src = __webpack_require__("../../node_modules/.pnpm/@sinonjs+fake-timers@14.0.0/node_modules/@sinonjs/fake-timers/src/fake-timers-src.js");
1407
- const fakeTimers_RealDate = Date;
1408
- class FakeTimers {
1409
- _clock;
1410
- _config;
1411
- _fakingTime;
1412
- _fakeTimers;
1413
- constructor({ global, config = {} }){
1414
- this._config = config;
1415
- this._fakingTime = false;
1416
- this._fakeTimers = (0, fake_timers_src.withGlobal)(global);
1417
- }
1418
- clearAllTimers() {
1419
- if (this._fakingTime) this._clock.reset();
1420
- }
1421
- dispose() {
1422
- this.useRealTimers();
1423
- }
1424
- runAllTimers() {
1425
- if (this._checkFakeTimers()) this._clock.runAll();
1426
- }
1427
- async runAllTimersAsync() {
1428
- if (this._checkFakeTimers()) await this._clock.runAllAsync();
1429
- }
1430
- runOnlyPendingTimers() {
1431
- if (this._checkFakeTimers()) this._clock.runToLast();
1432
- }
1433
- async runOnlyPendingTimersAsync() {
1434
- if (this._checkFakeTimers()) await this._clock.runToLastAsync();
1435
- }
1436
- advanceTimersToNextTimer(steps = 1) {
1437
- if (this._checkFakeTimers()) for(let i = steps; i > 0; i--){
1438
- this._clock.next();
1439
- this._clock.tick(0);
1440
- if (0 === this._clock.countTimers()) break;
1441
- }
1442
- }
1443
- async advanceTimersToNextTimerAsync(steps = 1) {
1444
- if (this._checkFakeTimers()) for(let i = steps; i > 0; i--){
1445
- await this._clock.nextAsync();
1446
- await this._clock.tickAsync(0);
1447
- if (0 === this._clock.countTimers()) break;
1448
- }
1449
- }
1450
- advanceTimersByTime(msToRun) {
1451
- if (this._checkFakeTimers()) this._clock.tick(msToRun);
1452
- }
1453
- async advanceTimersByTimeAsync(msToRun) {
1454
- if (this._checkFakeTimers()) await this._clock.tickAsync(msToRun);
1455
- }
1456
- advanceTimersToNextFrame() {
1457
- if (this._checkFakeTimers()) this._clock.runToFrame();
1458
- }
1459
- runAllTicks() {
1460
- if (this._checkFakeTimers()) this._clock.runMicrotasks();
1461
- }
1462
- useRealTimers() {
1463
- if (this._fakingTime) {
1464
- this._clock.uninstall();
1465
- this._fakingTime = false;
1466
- }
1467
- }
1468
- useFakeTimers(fakeTimersConfig = {}) {
1469
- if (this._fakingTime) this._clock.uninstall();
1470
- const toFake = Object.keys(this._fakeTimers.timers).filter((timer)=>'nextTick' !== timer && 'queueMicrotask' !== timer);
1471
- const isChildProcess = 'undefined' != typeof process && !!process.send;
1472
- if (this._config?.toFake?.includes('nextTick') && isChildProcess) throw new Error('process.nextTick cannot be mocked inside child_process');
1473
- this._clock = this._fakeTimers.install({
1474
- loopLimit: 10000,
1475
- shouldClearNativeTimers: true,
1476
- now: Date.now(),
1477
- toFake: [
1478
- ...toFake
1479
- ],
1480
- ignoreMissingTimers: true,
1481
- ...fakeTimersConfig
1482
- });
1483
- this._fakingTime = true;
1484
- }
1485
- reset() {
1486
- if (this._checkFakeTimers()) {
1487
- const { now } = this._clock;
1488
- this._clock.reset();
1489
- this._clock.setSystemTime(now);
1490
- }
1491
- }
1492
- setSystemTime(now) {
1493
- if (this._checkFakeTimers()) this._clock.setSystemTime(now);
1494
- }
1495
- getRealSystemTime() {
1496
- return fakeTimers_RealDate.now();
1497
- }
1498
- now() {
1499
- if (this._fakingTime) return this._clock.now;
1500
- return Date.now();
1501
- }
1502
- getTimerCount() {
1503
- if (this._checkFakeTimers()) return this._clock.countTimers();
1504
- return 0;
1505
- }
1506
- _checkFakeTimers() {
1507
- if (!this._fakingTime) throw new Error('Timers are not mocked. Try calling "rstest.useFakeTimers()" first.');
1508
- return this._fakingTime;
1509
- }
1510
- isFakeTimers() {
1511
- return this._fakingTime;
1512
- }
1513
- }
1514
- var tinyspy_dist = __webpack_require__("../../node_modules/.pnpm/tinyspy@4.0.4/node_modules/tinyspy/dist/index.js");
1515
- let callOrder = 0;
1516
- const mocks = new Set();
1517
- const wrapSpy = (obj, methodName, mockFn)=>{
1518
- const spyImpl = (0, tinyspy_dist.jo)(obj, methodName, mockFn);
1519
- const spyFn = spyImpl;
1520
- let mockImplementationOnce = [];
1521
- let implementation = mockFn;
1522
- let mockName = mockFn?.name;
1523
- const initMockState = ()=>({
1524
- instances: [],
1525
- contexts: [],
1526
- invocationCallOrder: []
1527
- });
1528
- let mockState = initMockState();
1529
- const spyState = (0, tinyspy_dist.lf)(spyImpl);
1530
- spyFn.getMockName = ()=>mockName || methodName;
1531
- spyFn.mockName = (name)=>{
1532
- mockName = name;
1533
- return spyFn;
1534
- };
1535
- spyFn.getMockImplementation = ()=>mockImplementationOnce.length ? mockImplementationOnce[mockImplementationOnce.length - 1] : implementation;
1536
- function withImplementation(fn, cb) {
1537
- const originalImplementation = implementation;
1538
- const originalMockImplementationOnce = mockImplementationOnce;
1539
- implementation = fn;
1540
- mockImplementationOnce = [];
1541
- spyState.willCall(willCall);
1542
- const reset = ()=>{
1543
- implementation = originalImplementation;
1544
- mockImplementationOnce = originalMockImplementationOnce;
1545
- };
1546
- const result = cb();
1547
- if (result instanceof Promise) return result.then(()=>{
1548
- reset();
1549
- });
1550
- reset();
1551
- }
1552
- spyFn.withImplementation = withImplementation;
1553
- spyFn.mockImplementation = (fn)=>{
1554
- implementation = fn;
1555
- return spyFn;
1556
- };
1557
- spyFn.mockImplementationOnce = (fn)=>{
1558
- mockImplementationOnce.push(fn);
1559
- return spyFn;
1560
- };
1561
- spyFn.mockReturnValue = (value)=>spyFn.mockImplementation(()=>value);
1562
- spyFn.mockReturnValueOnce = (value)=>spyFn.mockImplementationOnce(()=>value);
1563
- spyFn.mockResolvedValue = (value)=>spyFn.mockImplementation(()=>Promise.resolve(value));
1564
- spyFn.mockResolvedValueOnce = (value)=>spyFn.mockImplementationOnce(()=>Promise.resolve(value));
1565
- spyFn.mockRejectedValue = (value)=>spyFn.mockImplementation(()=>Promise.reject(value));
1566
- spyFn.mockRejectedValueOnce = (value)=>spyFn.mockImplementationOnce(()=>Promise.reject(value));
1567
- spyFn.mockReturnThis = ()=>spyFn.mockImplementation(function() {
1568
- return this;
1569
- });
1570
- function willCall(...args) {
1571
- let impl = implementation || spyState.getOriginal();
1572
- mockState.instances.push(this);
1573
- mockState.contexts.push(this);
1574
- mockState.invocationCallOrder.push(++callOrder);
1575
- if (mockImplementationOnce.length) impl = mockImplementationOnce.shift();
1576
- return impl?.apply(this, args);
1577
- }
1578
- spyState.willCall(willCall);
1579
- Object.defineProperty(spyFn, 'mock', {
1580
- get: ()=>({
1581
- get calls () {
1582
- return spyState.calls;
1583
- },
1584
- get lastCall () {
1585
- return spyState.calls[spyState.callCount - 1];
1586
- },
1587
- get instances () {
1588
- return mockState.instances;
1589
- },
1590
- get contexts () {
1591
- return mockState.contexts;
1592
- },
1593
- get invocationCallOrder () {
1594
- return mockState.invocationCallOrder;
1595
- },
1596
- get results () {
1597
- return spyState.results.map(([resultType, value])=>{
1598
- const type = 'error' === resultType ? 'throw' : 'return';
1599
- return {
1600
- type: type,
1601
- value
1602
- };
1603
- });
1604
- },
1605
- get settledResults () {
1606
- return spyState.resolves.map(([resultType, value])=>{
1607
- const type = 'error' === resultType ? 'rejected' : 'fulfilled';
1608
- return {
1609
- type,
1610
- value
1611
- };
1612
- });
1613
- }
1614
- })
1615
- });
1616
- spyFn.mockClear = ()=>{
1617
- mockState = initMockState();
1618
- spyState.reset();
1619
- return spyFn;
1620
- };
1621
- spyFn.mockReset = ()=>{
1622
- spyFn.mockClear();
1623
- implementation = mockFn;
1624
- mockImplementationOnce = [];
1625
- return spyFn;
1626
- };
1627
- spyFn.mockRestore = ()=>{
1628
- spyFn.mockReset();
1629
- spyState.restore();
1630
- mockName = mockFn?.name;
1631
- };
1632
- mocks.add(spyFn);
1633
- return spyFn;
1634
- };
1635
- const spy_fn = (mockFn)=>{
1636
- const defaultName = 'rstest.fn()';
1637
- return wrapSpy({
1638
- [defaultName]: mockFn
1639
- }, defaultName, mockFn);
1640
- };
1641
- const spyOn = (obj, methodName, accessType)=>{
1642
- const accessTypeMap = {
1643
- get: 'getter',
1644
- set: 'setter'
1645
- };
1646
- const method = accessType ? {
1647
- [accessTypeMap[accessType]]: methodName
1648
- } : methodName;
1649
- return wrapSpy(obj, method);
1650
- };
1651
- const isMockFunction = (fn)=>'function' == typeof fn && '_isMockFunction' in fn && fn._isMockFunction;
1652
- const createRstestUtilities = (workerState)=>{
1653
- const originalEnvValues = new Map();
1654
- const originalGlobalValues = new Map();
1655
- let _timers;
1656
- let originalConfig;
1657
- const timers = ()=>{
1658
- if (!_timers) _timers = new FakeTimers({
1659
- global: globalThis
1660
- });
1661
- return _timers;
1662
- };
1663
- const rstest = {
1664
- fn: spy_fn,
1665
- spyOn: spyOn,
1666
- isMockFunction: isMockFunction,
1667
- clearAllMocks: ()=>{
1668
- for (const mock of mocks)mock.mockClear();
1669
- return rstest;
1670
- },
1671
- resetAllMocks: ()=>{
1672
- for (const mock of mocks)mock.mockReset();
1673
- return rstest;
1674
- },
1675
- restoreAllMocks: ()=>{
1676
- for (const mock of mocks)mock.mockRestore();
1677
- return rstest;
1678
- },
1679
- mock: ()=>{},
1680
- mockRequire: ()=>{},
1681
- doMock: ()=>{},
1682
- doMockRequire: ()=>{},
1683
- unmock: ()=>{},
1684
- doUnmock: ()=>{},
1685
- importMock: async ()=>({}),
1686
- requireMock: ()=>({}),
1687
- importActual: async ()=>({}),
1688
- requireActual: ()=>({}),
1689
- resetModules: ()=>rstest,
1690
- setConfig: (config)=>{
1691
- if (!originalConfig) originalConfig = {
1692
- ...workerState.runtimeConfig
1693
- };
1694
- Object.assign(workerState.runtimeConfig, config);
1695
- },
1696
- resetConfig: ()=>{
1697
- if (originalConfig) Object.assign(workerState.runtimeConfig, originalConfig);
1698
- },
1699
- stubEnv: (name, value)=>{
1700
- if (!originalEnvValues.has(name)) originalEnvValues.set(name, process.env[name]);
1701
- if (void 0 === value) delete process.env[name];
1702
- else process.env[name] = value;
1703
- return rstest;
1704
- },
1705
- unstubAllEnvs: ()=>{
1706
- for (const [name, value] of originalEnvValues)if (void 0 === value) delete process.env[name];
1707
- else process.env[name] = value;
1708
- originalEnvValues.clear();
1709
- return rstest;
1710
- },
1711
- stubGlobal: (name, value)=>{
1712
- if (!originalGlobalValues.has(name)) originalGlobalValues.set(name, Object.getOwnPropertyDescriptor(globalThis, name));
1713
- Object.defineProperty(globalThis, name, {
1714
- value,
1715
- writable: true,
1716
- configurable: true,
1717
- enumerable: true
1718
- });
1719
- return rstest;
1720
- },
1721
- unstubAllGlobals: ()=>{
1722
- originalGlobalValues.forEach((original, name)=>{
1723
- if (original) Object.defineProperty(globalThis, name, original);
1724
- else Reflect.deleteProperty(globalThis, name);
1725
- });
1726
- originalGlobalValues.clear();
1727
- return rstest;
1728
- },
1729
- useFakeTimers: (opts)=>{
1730
- timers().useFakeTimers(opts);
1731
- return rstest;
1732
- },
1733
- useRealTimers: ()=>{
1734
- timers().useRealTimers();
1735
- return rstest;
1736
- },
1737
- setSystemTime: (now)=>{
1738
- timers().setSystemTime(now);
1739
- return rstest;
1740
- },
1741
- getRealSystemTime: ()=>_timers ? timers().getRealSystemTime() : Date.now(),
1742
- isFakeTimers: ()=>_timers ? timers().isFakeTimers() : false,
1743
- runAllTimers: ()=>{
1744
- timers().runAllTimers();
1745
- return rstest;
1746
- },
1747
- runAllTimersAsync: async ()=>{
1748
- await timers().runAllTimersAsync();
1749
- return rstest;
1750
- },
1751
- runAllTicks: ()=>{
1752
- timers().runAllTicks();
1753
- return rstest;
1754
- },
1755
- runOnlyPendingTimers: ()=>{
1756
- timers().runOnlyPendingTimers();
1757
- return rstest;
1758
- },
1759
- runOnlyPendingTimersAsync: async ()=>{
1760
- await timers().runOnlyPendingTimersAsync();
1761
- return rstest;
1762
- },
1763
- advanceTimersByTime: (ms)=>{
1764
- timers().advanceTimersByTime(ms);
1765
- return rstest;
1766
- },
1767
- advanceTimersByTimeAsync: async (ms)=>{
1768
- await timers().advanceTimersByTimeAsync(ms);
1769
- return rstest;
1770
- },
1771
- advanceTimersToNextTimer: (steps)=>{
1772
- timers().advanceTimersToNextTimer(steps);
1773
- return rstest;
1774
- },
1775
- advanceTimersToNextTimerAsync: async (steps)=>{
1776
- await timers().advanceTimersToNextTimerAsync(steps);
1777
- return rstest;
1778
- },
1779
- advanceTimersToNextFrame: ()=>{
1780
- timers().advanceTimersToNextFrame();
1781
- return rstest;
1782
- },
1783
- getTimerCount: ()=>timers().getTimerCount(),
1784
- clearAllTimers: ()=>{
1785
- timers().clearAllTimers();
1786
- return rstest;
1787
- }
1788
- };
1789
- return rstest;
1790
- };
1791
- const createRstestRuntime = (workerState)=>{
1792
- const { runner, api: runnerAPI } = createRunner({
1793
- workerState
1794
- });
1795
- const expect = createExpect({
1796
- workerState,
1797
- getCurrentTest: ()=>runner.getCurrentTest()
1798
- });
1799
- Object.defineProperty(globalThis, dist.mZ, {
1800
- value: expect,
1801
- writable: true,
1802
- configurable: true
1803
- });
1804
- const rstest = createRstestUtilities(workerState);
1805
- const runtime = {
1806
- runner,
1807
- api: {
1808
- ...runnerAPI,
1809
- expect,
1810
- assert: node_modules_chai.vA,
1811
- rstest,
1812
- rs: rstest
1813
- }
1814
- };
1815
- globalThis.RSTEST_API = runtime.api;
1816
- return runtime;
1817
- };
1818
- }
1819
- };