@ricsam/isolate-test-environment 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -24
- package/dist/cjs/index.cjs +402 -104
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/index.mjs +388 -103
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/index.d.ts +83 -12
- package/package.json +1 -1
package/dist/mjs/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/test-environment/src/index.ts
|
|
3
|
+
import IsolatedVM from "isolated-vm";
|
|
3
4
|
var testEnvironmentCode = `
|
|
4
5
|
(function() {
|
|
5
6
|
// ============================================================
|
|
@@ -24,6 +25,33 @@ var testEnvironmentCode = `
|
|
|
24
25
|
let currentSuite = rootSuite;
|
|
25
26
|
const suiteStack = [rootSuite];
|
|
26
27
|
|
|
28
|
+
// Event callback (set from host)
|
|
29
|
+
let eventCallback = null;
|
|
30
|
+
|
|
31
|
+
function emitEvent(event) {
|
|
32
|
+
if (eventCallback) {
|
|
33
|
+
try {
|
|
34
|
+
eventCallback(JSON.stringify(event));
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// Ignore callback errors
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ============================================================
|
|
42
|
+
// TestError class for rich error info
|
|
43
|
+
// ============================================================
|
|
44
|
+
|
|
45
|
+
class TestError extends Error {
|
|
46
|
+
constructor(message, matcherName, expected, actual) {
|
|
47
|
+
super(message);
|
|
48
|
+
this.name = 'TestError';
|
|
49
|
+
this.matcherName = matcherName;
|
|
50
|
+
this.expected = expected;
|
|
51
|
+
this.actual = actual;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
27
55
|
// ============================================================
|
|
28
56
|
// Deep Equality Helper
|
|
29
57
|
// ============================================================
|
|
@@ -123,10 +151,10 @@ var testEnvironmentCode = `
|
|
|
123
151
|
|
|
124
152
|
function expect(actual) {
|
|
125
153
|
function createMatchers(negated = false) {
|
|
126
|
-
const assert = (condition, message) => {
|
|
154
|
+
const assert = (condition, message, matcherName, expected) => {
|
|
127
155
|
const pass = negated ? !condition : condition;
|
|
128
156
|
if (!pass) {
|
|
129
|
-
throw new
|
|
157
|
+
throw new TestError(message, matcherName, expected, actual);
|
|
130
158
|
}
|
|
131
159
|
};
|
|
132
160
|
|
|
@@ -136,7 +164,9 @@ var testEnvironmentCode = `
|
|
|
136
164
|
actual === expected,
|
|
137
165
|
negated
|
|
138
166
|
? \`Expected \${formatValue(actual)} not to be \${formatValue(expected)}\`
|
|
139
|
-
: \`Expected \${formatValue(actual)} to be \${formatValue(expected)}
|
|
167
|
+
: \`Expected \${formatValue(actual)} to be \${formatValue(expected)}\`,
|
|
168
|
+
'toBe',
|
|
169
|
+
expected
|
|
140
170
|
);
|
|
141
171
|
},
|
|
142
172
|
|
|
@@ -145,7 +175,9 @@ var testEnvironmentCode = `
|
|
|
145
175
|
deepEqual(actual, expected),
|
|
146
176
|
negated
|
|
147
177
|
? \`Expected \${formatValue(actual)} not to equal \${formatValue(expected)}\`
|
|
148
|
-
: \`Expected \${formatValue(actual)} to equal \${formatValue(expected)}
|
|
178
|
+
: \`Expected \${formatValue(actual)} to equal \${formatValue(expected)}\`,
|
|
179
|
+
'toEqual',
|
|
180
|
+
expected
|
|
149
181
|
);
|
|
150
182
|
},
|
|
151
183
|
|
|
@@ -154,7 +186,9 @@ var testEnvironmentCode = `
|
|
|
154
186
|
strictDeepEqual(actual, expected),
|
|
155
187
|
negated
|
|
156
188
|
? \`Expected \${formatValue(actual)} not to strictly equal \${formatValue(expected)}\`
|
|
157
|
-
: \`Expected \${formatValue(actual)} to strictly equal \${formatValue(expected)}
|
|
189
|
+
: \`Expected \${formatValue(actual)} to strictly equal \${formatValue(expected)}\`,
|
|
190
|
+
'toStrictEqual',
|
|
191
|
+
expected
|
|
158
192
|
);
|
|
159
193
|
},
|
|
160
194
|
|
|
@@ -163,7 +197,9 @@ var testEnvironmentCode = `
|
|
|
163
197
|
!!actual,
|
|
164
198
|
negated
|
|
165
199
|
? \`Expected \${formatValue(actual)} not to be truthy\`
|
|
166
|
-
: \`Expected \${formatValue(actual)} to be truthy
|
|
200
|
+
: \`Expected \${formatValue(actual)} to be truthy\`,
|
|
201
|
+
'toBeTruthy',
|
|
202
|
+
true
|
|
167
203
|
);
|
|
168
204
|
},
|
|
169
205
|
|
|
@@ -172,7 +208,9 @@ var testEnvironmentCode = `
|
|
|
172
208
|
!actual,
|
|
173
209
|
negated
|
|
174
210
|
? \`Expected \${formatValue(actual)} not to be falsy\`
|
|
175
|
-
: \`Expected \${formatValue(actual)} to be falsy
|
|
211
|
+
: \`Expected \${formatValue(actual)} to be falsy\`,
|
|
212
|
+
'toBeFalsy',
|
|
213
|
+
false
|
|
176
214
|
);
|
|
177
215
|
},
|
|
178
216
|
|
|
@@ -181,7 +219,9 @@ var testEnvironmentCode = `
|
|
|
181
219
|
actual === null,
|
|
182
220
|
negated
|
|
183
221
|
? \`Expected \${formatValue(actual)} not to be null\`
|
|
184
|
-
: \`Expected \${formatValue(actual)} to be null
|
|
222
|
+
: \`Expected \${formatValue(actual)} to be null\`,
|
|
223
|
+
'toBeNull',
|
|
224
|
+
null
|
|
185
225
|
);
|
|
186
226
|
},
|
|
187
227
|
|
|
@@ -190,7 +230,9 @@ var testEnvironmentCode = `
|
|
|
190
230
|
actual === undefined,
|
|
191
231
|
negated
|
|
192
232
|
? \`Expected \${formatValue(actual)} not to be undefined\`
|
|
193
|
-
: \`Expected \${formatValue(actual)} to be undefined
|
|
233
|
+
: \`Expected \${formatValue(actual)} to be undefined\`,
|
|
234
|
+
'toBeUndefined',
|
|
235
|
+
undefined
|
|
194
236
|
);
|
|
195
237
|
},
|
|
196
238
|
|
|
@@ -199,7 +241,9 @@ var testEnvironmentCode = `
|
|
|
199
241
|
actual !== undefined,
|
|
200
242
|
negated
|
|
201
243
|
? \`Expected \${formatValue(actual)} not to be defined\`
|
|
202
|
-
: \`Expected \${formatValue(actual)} to be defined
|
|
244
|
+
: \`Expected \${formatValue(actual)} to be defined\`,
|
|
245
|
+
'toBeDefined',
|
|
246
|
+
'defined'
|
|
203
247
|
);
|
|
204
248
|
},
|
|
205
249
|
|
|
@@ -214,7 +258,9 @@ var testEnvironmentCode = `
|
|
|
214
258
|
contains,
|
|
215
259
|
negated
|
|
216
260
|
? \`Expected \${formatValue(actual)} not to contain \${formatValue(item)}\`
|
|
217
|
-
: \`Expected \${formatValue(actual)} to contain \${formatValue(item)}
|
|
261
|
+
: \`Expected \${formatValue(actual)} to contain \${formatValue(item)}\`,
|
|
262
|
+
'toContain',
|
|
263
|
+
item
|
|
218
264
|
);
|
|
219
265
|
},
|
|
220
266
|
|
|
@@ -242,14 +288,18 @@ var testEnvironmentCode = `
|
|
|
242
288
|
matches,
|
|
243
289
|
negated
|
|
244
290
|
? \`Expected function not to throw \${formatValue(expected)}\`
|
|
245
|
-
: \`Expected function to throw \${formatValue(expected)}, but \${threw ? \`threw: \${error.message}\` : 'did not throw'}
|
|
291
|
+
: \`Expected function to throw \${formatValue(expected)}, but \${threw ? \`threw: \${error.message}\` : 'did not throw'}\`,
|
|
292
|
+
'toThrow',
|
|
293
|
+
expected
|
|
246
294
|
);
|
|
247
295
|
} else {
|
|
248
296
|
assert(
|
|
249
297
|
threw,
|
|
250
298
|
negated
|
|
251
299
|
? \`Expected function not to throw\`
|
|
252
|
-
: \`Expected function to throw
|
|
300
|
+
: \`Expected function to throw\`,
|
|
301
|
+
'toThrow',
|
|
302
|
+
'any error'
|
|
253
303
|
);
|
|
254
304
|
}
|
|
255
305
|
},
|
|
@@ -259,7 +309,9 @@ var testEnvironmentCode = `
|
|
|
259
309
|
actual instanceof cls,
|
|
260
310
|
negated
|
|
261
311
|
? \`Expected \${formatValue(actual)} not to be instance of \${cls.name || cls}\`
|
|
262
|
-
: \`Expected \${formatValue(actual)} to be instance of \${cls.name || cls}
|
|
312
|
+
: \`Expected \${formatValue(actual)} to be instance of \${cls.name || cls}\`,
|
|
313
|
+
'toBeInstanceOf',
|
|
314
|
+
cls.name || cls
|
|
263
315
|
);
|
|
264
316
|
},
|
|
265
317
|
|
|
@@ -269,7 +321,9 @@ var testEnvironmentCode = `
|
|
|
269
321
|
actualLength === length,
|
|
270
322
|
negated
|
|
271
323
|
? \`Expected length not to be \${length}, but got \${actualLength}\`
|
|
272
|
-
: \`Expected length to be \${length}, but got \${actualLength}
|
|
324
|
+
: \`Expected length to be \${length}, but got \${actualLength}\`,
|
|
325
|
+
'toHaveLength',
|
|
326
|
+
length
|
|
273
327
|
);
|
|
274
328
|
},
|
|
275
329
|
|
|
@@ -284,7 +338,9 @@ var testEnvironmentCode = `
|
|
|
284
338
|
matches,
|
|
285
339
|
negated
|
|
286
340
|
? \`Expected \${formatValue(actual)} not to match \${pattern}\`
|
|
287
|
-
: \`Expected \${formatValue(actual)} to match \${pattern}
|
|
341
|
+
: \`Expected \${formatValue(actual)} to match \${pattern}\`,
|
|
342
|
+
'toMatch',
|
|
343
|
+
pattern
|
|
288
344
|
);
|
|
289
345
|
},
|
|
290
346
|
|
|
@@ -297,7 +353,53 @@ var testEnvironmentCode = `
|
|
|
297
353
|
hasProperty && valueMatches,
|
|
298
354
|
negated
|
|
299
355
|
? \`Expected \${formatValue(actual)} not to have property \${path}\${arguments.length >= 2 ? \` with value \${formatValue(value)}\` : ''}\`
|
|
300
|
-
: \`Expected \${formatValue(actual)} to have property \${path}\${arguments.length >= 2 ? \` with value \${formatValue(value)}\` : ''}
|
|
356
|
+
: \`Expected \${formatValue(actual)} to have property \${path}\${arguments.length >= 2 ? \` with value \${formatValue(value)}\` : ''}\`,
|
|
357
|
+
'toHaveProperty',
|
|
358
|
+
arguments.length >= 2 ? { path, value } : { path }
|
|
359
|
+
);
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
toBeGreaterThan(expected) {
|
|
363
|
+
assert(
|
|
364
|
+
actual > expected,
|
|
365
|
+
negated
|
|
366
|
+
? \`Expected \${formatValue(actual)} not to be greater than \${formatValue(expected)}\`
|
|
367
|
+
: \`Expected \${formatValue(actual)} to be greater than \${formatValue(expected)}\`,
|
|
368
|
+
'toBeGreaterThan',
|
|
369
|
+
expected
|
|
370
|
+
);
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
toBeGreaterThanOrEqual(expected) {
|
|
374
|
+
assert(
|
|
375
|
+
actual >= expected,
|
|
376
|
+
negated
|
|
377
|
+
? \`Expected \${formatValue(actual)} not to be greater than or equal to \${formatValue(expected)}\`
|
|
378
|
+
: \`Expected \${formatValue(actual)} to be greater than or equal to \${formatValue(expected)}\`,
|
|
379
|
+
'toBeGreaterThanOrEqual',
|
|
380
|
+
expected
|
|
381
|
+
);
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
toBeLessThan(expected) {
|
|
385
|
+
assert(
|
|
386
|
+
actual < expected,
|
|
387
|
+
negated
|
|
388
|
+
? \`Expected \${formatValue(actual)} not to be less than \${formatValue(expected)}\`
|
|
389
|
+
: \`Expected \${formatValue(actual)} to be less than \${formatValue(expected)}\`,
|
|
390
|
+
'toBeLessThan',
|
|
391
|
+
expected
|
|
392
|
+
);
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
toBeLessThanOrEqual(expected) {
|
|
396
|
+
assert(
|
|
397
|
+
actual <= expected,
|
|
398
|
+
negated
|
|
399
|
+
? \`Expected \${formatValue(actual)} not to be less than or equal to \${formatValue(expected)}\`
|
|
400
|
+
: \`Expected \${formatValue(actual)} to be less than or equal to \${formatValue(expected)}\`,
|
|
401
|
+
'toBeLessThanOrEqual',
|
|
402
|
+
expected
|
|
301
403
|
);
|
|
302
404
|
},
|
|
303
405
|
};
|
|
@@ -420,7 +522,7 @@ var testEnvironmentCode = `
|
|
|
420
522
|
}
|
|
421
523
|
|
|
422
524
|
// ============================================================
|
|
423
|
-
// Test Runner
|
|
525
|
+
// Test Runner Helpers
|
|
424
526
|
// ============================================================
|
|
425
527
|
|
|
426
528
|
function checkForOnly(suite) {
|
|
@@ -445,120 +547,273 @@ var testEnvironmentCode = `
|
|
|
445
547
|
return false;
|
|
446
548
|
}
|
|
447
549
|
|
|
550
|
+
function countTests(suite, hasOnly) {
|
|
551
|
+
let count = 0;
|
|
552
|
+
if (hasOnly && !suiteHasOnly(suite)) return 0;
|
|
553
|
+
if (suite.skip) return suite.tests.length;
|
|
554
|
+
|
|
555
|
+
for (const t of suite.tests) {
|
|
556
|
+
if (hasOnly && !t.only && !suite.only) continue;
|
|
557
|
+
count++;
|
|
558
|
+
}
|
|
559
|
+
for (const child of suite.children) {
|
|
560
|
+
count += countTests(child, hasOnly);
|
|
561
|
+
}
|
|
562
|
+
return count;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function countSuites(suite, hasOnly) {
|
|
566
|
+
let count = 0;
|
|
567
|
+
if (hasOnly && !suiteHasOnly(suite)) return 0;
|
|
568
|
+
|
|
569
|
+
for (const child of suite.children) {
|
|
570
|
+
count++;
|
|
571
|
+
count += countSuites(child, hasOnly);
|
|
572
|
+
}
|
|
573
|
+
return count;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
// ============================================================
|
|
577
|
+
// Test Runner
|
|
578
|
+
// ============================================================
|
|
579
|
+
|
|
448
580
|
async function __runAllTests() {
|
|
449
|
-
const
|
|
581
|
+
const testResults = [];
|
|
582
|
+
const suiteResults = [];
|
|
450
583
|
const hasOnly = checkForOnly(rootSuite);
|
|
584
|
+
const runStart = Date.now();
|
|
585
|
+
|
|
586
|
+
// Emit runStart
|
|
587
|
+
const testCount = countTests(rootSuite, hasOnly);
|
|
588
|
+
const suiteCount = countSuites(rootSuite, hasOnly);
|
|
589
|
+
emitEvent({ type: 'runStart', testCount, suiteCount });
|
|
451
590
|
|
|
452
|
-
async function runSuite(suite, parentHooks,
|
|
591
|
+
async function runSuite(suite, parentHooks, pathArray, depth) {
|
|
453
592
|
// Skip if this suite doesn't have any .only when .only exists elsewhere
|
|
454
593
|
if (hasOnly && !suiteHasOnly(suite)) return;
|
|
455
594
|
|
|
595
|
+
const suitePath = [...pathArray];
|
|
596
|
+
const fullName = suitePath.join(' > ');
|
|
597
|
+
const suiteInfo = {
|
|
598
|
+
name: suite.name,
|
|
599
|
+
path: suitePath.slice(0, -1),
|
|
600
|
+
fullName,
|
|
601
|
+
depth,
|
|
602
|
+
};
|
|
603
|
+
|
|
604
|
+
// Emit suiteStart (only for non-root suites)
|
|
605
|
+
if (suite !== rootSuite) {
|
|
606
|
+
emitEvent({ type: 'suiteStart', suite: suiteInfo });
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const suiteStart = Date.now();
|
|
610
|
+
let suitePassed = 0;
|
|
611
|
+
let suiteFailed = 0;
|
|
612
|
+
let suiteSkipped = 0;
|
|
613
|
+
let suiteTodo = 0;
|
|
614
|
+
|
|
456
615
|
// Skip if suite is marked as skip
|
|
457
616
|
if (suite.skip) {
|
|
458
617
|
// Mark all tests in this suite as skipped
|
|
459
618
|
for (const t of suite.tests) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
619
|
+
const testFullName = fullName ? fullName + ' > ' + t.name : t.name;
|
|
620
|
+
const testInfo = {
|
|
621
|
+
name: t.name,
|
|
622
|
+
suitePath: suitePath,
|
|
623
|
+
fullName: testFullName,
|
|
624
|
+
};
|
|
625
|
+
emitEvent({ type: 'testStart', test: testInfo });
|
|
626
|
+
|
|
627
|
+
const testResult = {
|
|
628
|
+
name: t.name,
|
|
629
|
+
suitePath: suitePath,
|
|
630
|
+
fullName: testFullName,
|
|
631
|
+
status: 'skip',
|
|
464
632
|
duration: 0,
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
// Run beforeAll hooks
|
|
471
|
-
for (const hook of suite.beforeAll) {
|
|
472
|
-
await hook();
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// Run tests
|
|
476
|
-
for (const t of suite.tests) {
|
|
477
|
-
const testName = namePath ? namePath + ' > ' + t.name : t.name;
|
|
633
|
+
};
|
|
634
|
+
testResults.push(testResult);
|
|
635
|
+
suiteSkipped++;
|
|
478
636
|
|
|
479
|
-
|
|
480
|
-
if (hasOnly && !t.only && !suite.only) continue;
|
|
481
|
-
|
|
482
|
-
// Skip if test is marked as skip
|
|
483
|
-
if (t.skip) {
|
|
484
|
-
results.push({
|
|
485
|
-
name: testName,
|
|
486
|
-
passed: true,
|
|
487
|
-
skipped: true,
|
|
488
|
-
duration: 0,
|
|
489
|
-
});
|
|
490
|
-
continue;
|
|
637
|
+
emitEvent({ type: 'testEnd', test: testResult });
|
|
491
638
|
}
|
|
492
|
-
|
|
493
|
-
//
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
name: testName,
|
|
497
|
-
passed: true,
|
|
498
|
-
skipped: true,
|
|
499
|
-
duration: 0,
|
|
500
|
-
});
|
|
501
|
-
continue;
|
|
639
|
+
} else {
|
|
640
|
+
// Run beforeAll hooks
|
|
641
|
+
for (const hook of suite.beforeAll) {
|
|
642
|
+
await hook();
|
|
502
643
|
}
|
|
503
644
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
645
|
+
// Run tests
|
|
646
|
+
for (const t of suite.tests) {
|
|
647
|
+
const testFullName = fullName ? fullName + ' > ' + t.name : t.name;
|
|
648
|
+
const testInfo = {
|
|
649
|
+
name: t.name,
|
|
650
|
+
suitePath: suitePath,
|
|
651
|
+
fullName: testFullName,
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
// Skip if .only is used and this test isn't .only AND the suite doesn't have .only
|
|
655
|
+
if (hasOnly && !t.only && !suite.only) continue;
|
|
656
|
+
|
|
657
|
+
emitEvent({ type: 'testStart', test: testInfo });
|
|
658
|
+
|
|
659
|
+
// Skip if test is marked as skip
|
|
660
|
+
if (t.skip) {
|
|
661
|
+
const testResult = {
|
|
662
|
+
name: t.name,
|
|
663
|
+
suitePath: suitePath,
|
|
664
|
+
fullName: testFullName,
|
|
665
|
+
status: 'skip',
|
|
666
|
+
duration: 0,
|
|
667
|
+
};
|
|
668
|
+
testResults.push(testResult);
|
|
669
|
+
suiteSkipped++;
|
|
670
|
+
emitEvent({ type: 'testEnd', test: testResult });
|
|
671
|
+
continue;
|
|
509
672
|
}
|
|
510
673
|
|
|
511
|
-
//
|
|
512
|
-
|
|
674
|
+
// Handle todo tests (no function provided)
|
|
675
|
+
if (t.todo) {
|
|
676
|
+
const testResult = {
|
|
677
|
+
name: t.name,
|
|
678
|
+
suitePath: suitePath,
|
|
679
|
+
fullName: testFullName,
|
|
680
|
+
status: 'todo',
|
|
681
|
+
duration: 0,
|
|
682
|
+
};
|
|
683
|
+
testResults.push(testResult);
|
|
684
|
+
suiteTodo++;
|
|
685
|
+
emitEvent({ type: 'testEnd', test: testResult });
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
513
688
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
689
|
+
const testStart = Date.now();
|
|
690
|
+
try {
|
|
691
|
+
// Run all beforeEach hooks (parent first, then current)
|
|
692
|
+
for (const hook of [...parentHooks.beforeEach, ...suite.beforeEach]) {
|
|
693
|
+
await hook();
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// Run test
|
|
697
|
+
await t.fn();
|
|
698
|
+
|
|
699
|
+
// Run all afterEach hooks (current first, then parent)
|
|
700
|
+
for (const hook of [...suite.afterEach, ...parentHooks.afterEach]) {
|
|
701
|
+
await hook();
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const testResult = {
|
|
705
|
+
name: t.name,
|
|
706
|
+
suitePath: suitePath,
|
|
707
|
+
fullName: testFullName,
|
|
708
|
+
status: 'pass',
|
|
709
|
+
duration: Date.now() - testStart,
|
|
710
|
+
};
|
|
711
|
+
testResults.push(testResult);
|
|
712
|
+
suitePassed++;
|
|
713
|
+
emitEvent({ type: 'testEnd', test: testResult });
|
|
714
|
+
} catch (err) {
|
|
715
|
+
const testError = {
|
|
716
|
+
message: err.message || String(err),
|
|
717
|
+
stack: err.stack,
|
|
718
|
+
};
|
|
719
|
+
// If it's a TestError, include matcher info
|
|
720
|
+
if (err.matcherName !== undefined) {
|
|
721
|
+
testError.matcherName = err.matcherName;
|
|
722
|
+
testError.expected = err.expected;
|
|
723
|
+
testError.actual = err.actual;
|
|
724
|
+
}
|
|
725
|
+
const testResult = {
|
|
726
|
+
name: t.name,
|
|
727
|
+
suitePath: suitePath,
|
|
728
|
+
fullName: testFullName,
|
|
729
|
+
status: 'fail',
|
|
730
|
+
duration: Date.now() - testStart,
|
|
731
|
+
error: testError,
|
|
732
|
+
};
|
|
733
|
+
testResults.push(testResult);
|
|
734
|
+
suiteFailed++;
|
|
735
|
+
emitEvent({ type: 'testEnd', test: testResult });
|
|
517
736
|
}
|
|
737
|
+
}
|
|
518
738
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
name: testName,
|
|
527
|
-
passed: false,
|
|
528
|
-
error: err.message || String(err),
|
|
529
|
-
duration: Date.now() - start,
|
|
530
|
-
});
|
|
739
|
+
// Run child suites
|
|
740
|
+
for (const child of suite.children) {
|
|
741
|
+
const childPath = [...suitePath, child.name];
|
|
742
|
+
await runSuite(child, {
|
|
743
|
+
beforeEach: [...parentHooks.beforeEach, ...suite.beforeEach],
|
|
744
|
+
afterEach: [...suite.afterEach, ...parentHooks.afterEach],
|
|
745
|
+
}, childPath, depth + 1);
|
|
531
746
|
}
|
|
532
|
-
}
|
|
533
747
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
beforeEach: [...parentHooks.beforeEach, ...suite.beforeEach],
|
|
539
|
-
afterEach: [...suite.afterEach, ...parentHooks.afterEach],
|
|
540
|
-
}, childPath);
|
|
748
|
+
// Run afterAll hooks
|
|
749
|
+
for (const hook of suite.afterAll) {
|
|
750
|
+
await hook();
|
|
751
|
+
}
|
|
541
752
|
}
|
|
542
753
|
|
|
543
|
-
//
|
|
544
|
-
|
|
545
|
-
|
|
754
|
+
// Emit suiteEnd (only for non-root suites)
|
|
755
|
+
if (suite !== rootSuite) {
|
|
756
|
+
const suiteResult = {
|
|
757
|
+
...suiteInfo,
|
|
758
|
+
passed: suitePassed,
|
|
759
|
+
failed: suiteFailed,
|
|
760
|
+
skipped: suiteSkipped,
|
|
761
|
+
todo: suiteTodo,
|
|
762
|
+
duration: Date.now() - suiteStart,
|
|
763
|
+
};
|
|
764
|
+
suiteResults.push(suiteResult);
|
|
765
|
+
emitEvent({ type: 'suiteEnd', suite: suiteResult });
|
|
546
766
|
}
|
|
547
767
|
}
|
|
548
768
|
|
|
549
|
-
await runSuite(rootSuite, { beforeEach: [], afterEach: [] },
|
|
769
|
+
await runSuite(rootSuite, { beforeEach: [], afterEach: [] }, [], -1);
|
|
550
770
|
|
|
551
|
-
const passed =
|
|
552
|
-
const failed =
|
|
553
|
-
const skipped =
|
|
771
|
+
const passed = testResults.filter(r => r.status === 'pass').length;
|
|
772
|
+
const failed = testResults.filter(r => r.status === 'fail').length;
|
|
773
|
+
const skipped = testResults.filter(r => r.status === 'skip').length;
|
|
774
|
+
const todo = testResults.filter(r => r.status === 'todo').length;
|
|
554
775
|
|
|
555
|
-
|
|
776
|
+
const runResults = {
|
|
556
777
|
passed,
|
|
557
778
|
failed,
|
|
558
779
|
skipped,
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
780
|
+
todo,
|
|
781
|
+
total: testResults.length,
|
|
782
|
+
duration: Date.now() - runStart,
|
|
783
|
+
success: failed === 0,
|
|
784
|
+
suites: suiteResults,
|
|
785
|
+
tests: testResults,
|
|
786
|
+
};
|
|
787
|
+
|
|
788
|
+
emitEvent({ type: 'runEnd', results: runResults });
|
|
789
|
+
|
|
790
|
+
return JSON.stringify(runResults);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// ============================================================
|
|
794
|
+
// Helper Functions
|
|
795
|
+
// ============================================================
|
|
796
|
+
|
|
797
|
+
function __hasTests() {
|
|
798
|
+
function checkSuite(suite) {
|
|
799
|
+
if (suite.tests.length > 0) return true;
|
|
800
|
+
for (const child of suite.children) {
|
|
801
|
+
if (checkSuite(child)) return true;
|
|
802
|
+
}
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
return checkSuite(rootSuite);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function __getTestCount() {
|
|
809
|
+
function countInSuite(suite) {
|
|
810
|
+
let count = suite.tests.length;
|
|
811
|
+
for (const child of suite.children) {
|
|
812
|
+
count += countInSuite(child);
|
|
813
|
+
}
|
|
814
|
+
return count;
|
|
815
|
+
}
|
|
816
|
+
return countInSuite(rootSuite);
|
|
562
817
|
}
|
|
563
818
|
|
|
564
819
|
// Reset function to clear state between runs
|
|
@@ -574,6 +829,10 @@ var testEnvironmentCode = `
|
|
|
574
829
|
suiteStack.push(rootSuite);
|
|
575
830
|
}
|
|
576
831
|
|
|
832
|
+
function __setEventCallback(callback) {
|
|
833
|
+
eventCallback = callback;
|
|
834
|
+
}
|
|
835
|
+
|
|
577
836
|
// ============================================================
|
|
578
837
|
// Expose Globals
|
|
579
838
|
// ============================================================
|
|
@@ -588,10 +847,28 @@ var testEnvironmentCode = `
|
|
|
588
847
|
globalThis.afterAll = afterAll;
|
|
589
848
|
globalThis.__runAllTests = __runAllTests;
|
|
590
849
|
globalThis.__resetTestEnvironment = __resetTestEnvironment;
|
|
850
|
+
globalThis.__hasTests = __hasTests;
|
|
851
|
+
globalThis.__getTestCount = __getTestCount;
|
|
852
|
+
globalThis.__setEventCallback = __setEventCallback;
|
|
591
853
|
})();
|
|
592
854
|
`;
|
|
593
|
-
async function setupTestEnvironment(context) {
|
|
855
|
+
async function setupTestEnvironment(context, options) {
|
|
594
856
|
context.evalSync(testEnvironmentCode);
|
|
857
|
+
if (options?.onEvent) {
|
|
858
|
+
const eventCallbackRef = new IsolatedVM.Reference((eventJson) => {
|
|
859
|
+
try {
|
|
860
|
+
const event = JSON.parse(eventJson);
|
|
861
|
+
options.onEvent(event);
|
|
862
|
+
} catch {}
|
|
863
|
+
});
|
|
864
|
+
const global = context.global;
|
|
865
|
+
global.setSync("__eventCallbackRef", eventCallbackRef);
|
|
866
|
+
context.evalSync(`
|
|
867
|
+
__setEventCallback((eventJson) => {
|
|
868
|
+
__eventCallbackRef.applySync(undefined, [eventJson]);
|
|
869
|
+
});
|
|
870
|
+
`);
|
|
871
|
+
}
|
|
595
872
|
return {
|
|
596
873
|
dispose() {
|
|
597
874
|
try {
|
|
@@ -604,9 +881,17 @@ async function runTests(context) {
|
|
|
604
881
|
const resultJson = await context.eval("__runAllTests()", { promise: true });
|
|
605
882
|
return JSON.parse(resultJson);
|
|
606
883
|
}
|
|
884
|
+
function hasTests(context) {
|
|
885
|
+
return context.evalSync("__hasTests()");
|
|
886
|
+
}
|
|
887
|
+
function getTestCount(context) {
|
|
888
|
+
return context.evalSync("__getTestCount()");
|
|
889
|
+
}
|
|
607
890
|
export {
|
|
608
891
|
setupTestEnvironment,
|
|
609
|
-
runTests
|
|
892
|
+
runTests,
|
|
893
|
+
hasTests,
|
|
894
|
+
getTestCount
|
|
610
895
|
};
|
|
611
896
|
|
|
612
|
-
//# debugId=
|
|
897
|
+
//# debugId=E1ED7CC917A46E0364756E2164756E21
|