@ricsam/quickjs-test-environment 0.0.1 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +73 -43
  2. package/dist/cjs/describe.cjs +180 -0
  3. package/dist/cjs/describe.cjs.map +10 -0
  4. package/dist/cjs/expect.cjs +622 -0
  5. package/dist/cjs/expect.cjs.map +10 -0
  6. package/dist/cjs/handle.cjs +79 -0
  7. package/dist/cjs/handle.cjs.map +10 -0
  8. package/dist/cjs/hooks.cjs +83 -0
  9. package/dist/cjs/hooks.cjs.map +10 -0
  10. package/dist/cjs/index.cjs +39 -0
  11. package/dist/cjs/index.cjs.map +10 -0
  12. package/dist/cjs/package.json +5 -0
  13. package/dist/cjs/runner.cjs +346 -0
  14. package/dist/cjs/runner.cjs.map +10 -0
  15. package/dist/cjs/setup.cjs +70 -0
  16. package/dist/cjs/setup.cjs.map +10 -0
  17. package/dist/cjs/types.cjs +26 -0
  18. package/dist/cjs/types.cjs.map +9 -0
  19. package/dist/mjs/describe.mjs +149 -0
  20. package/dist/mjs/describe.mjs.map +10 -0
  21. package/dist/mjs/expect.mjs +591 -0
  22. package/dist/mjs/expect.mjs.map +10 -0
  23. package/dist/mjs/handle.mjs +48 -0
  24. package/dist/mjs/handle.mjs.map +10 -0
  25. package/dist/mjs/hooks.mjs +52 -0
  26. package/dist/mjs/hooks.mjs.map +10 -0
  27. package/dist/mjs/index.mjs +8 -0
  28. package/dist/mjs/index.mjs.map +10 -0
  29. package/dist/mjs/package.json +5 -0
  30. package/dist/mjs/runner.mjs +315 -0
  31. package/dist/mjs/runner.mjs.map +10 -0
  32. package/dist/mjs/setup.mjs +39 -0
  33. package/dist/mjs/setup.mjs.map +10 -0
  34. package/dist/mjs/types.mjs +3 -0
  35. package/dist/mjs/types.mjs.map +9 -0
  36. package/dist/types/globals/describe.d.ts +5 -0
  37. package/dist/types/globals/expect.d.ts +3 -0
  38. package/dist/types/globals/hooks.d.ts +3 -0
  39. package/dist/types/handle.d.ts +2 -0
  40. package/dist/types/index.d.ts +2 -0
  41. package/dist/types/runner.d.ts +5 -0
  42. package/dist/types/setup.d.ts +3 -0
  43. package/dist/types/types.d.ts +95 -0
  44. package/package.json +49 -6
@@ -0,0 +1,591 @@
1
+ // @bun
2
+ // packages/test-environment/src/globals/expect.ts
3
+ function setupExpect(context, state) {
4
+ const handles = [];
5
+ const expectCode = `
6
+ (function() {
7
+ // Deep equality check
8
+ function deepEqual(a, b) {
9
+ if (a === b) return true;
10
+ if (a === null || b === null) return false;
11
+ if (typeof a !== typeof b) return false;
12
+
13
+ if (typeof a === 'object') {
14
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
15
+
16
+ if (Array.isArray(a)) {
17
+ if (a.length !== b.length) return false;
18
+ for (let i = 0; i < a.length; i++) {
19
+ if (!deepEqual(a[i], b[i])) return false;
20
+ }
21
+ return true;
22
+ }
23
+
24
+ const keysA = Object.keys(a);
25
+ const keysB = Object.keys(b);
26
+ if (keysA.length !== keysB.length) return false;
27
+
28
+ for (const key of keysA) {
29
+ if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
30
+ if (!deepEqual(a[key], b[key])) return false;
31
+ }
32
+ return true;
33
+ }
34
+
35
+ return false;
36
+ }
37
+
38
+ // Strict equality (checks undefined values and array holes)
39
+ function strictEqual(a, b) {
40
+ if (!deepEqual(a, b)) return false;
41
+
42
+ if (typeof a === 'object' && a !== null) {
43
+ if (Array.isArray(a)) {
44
+ // Check for sparse arrays
45
+ for (let i = 0; i < a.length; i++) {
46
+ if ((i in a) !== (i in b)) return false;
47
+ }
48
+ } else {
49
+ // Check for undefined values
50
+ const keysA = Object.keys(a);
51
+ for (const key of keysA) {
52
+ if (a[key] === undefined && !(key in b)) return false;
53
+ }
54
+ }
55
+ }
56
+
57
+ return true;
58
+ }
59
+
60
+ // Format value for error messages
61
+ function format(value) {
62
+ if (value === undefined) return 'undefined';
63
+ if (value === null) return 'null';
64
+ if (typeof value === 'string') return JSON.stringify(value);
65
+ if (typeof value === 'function') return '[Function]';
66
+ if (typeof value === 'symbol') return value.toString();
67
+ try {
68
+ return JSON.stringify(value);
69
+ } catch {
70
+ return String(value);
71
+ }
72
+ }
73
+
74
+ // Create assertion error
75
+ function AssertionError(message, matcherName, expected, actual) {
76
+ const error = new Error(message);
77
+ error.name = 'AssertionError';
78
+ error.matcherName = matcherName;
79
+ error.expected = expected;
80
+ error.actual = actual;
81
+ return error;
82
+ }
83
+
84
+ // Create matchers object
85
+ function createMatchers(actual, isNot) {
86
+ const matchers = {
87
+ // Strict equality (===)
88
+ toBe(expected) {
89
+ const pass = actual === expected;
90
+ if (isNot ? pass : !pass) {
91
+ throw AssertionError(
92
+ isNot
93
+ ? \`Expected \${format(actual)} not to be \${format(expected)}\`
94
+ : \`Expected \${format(actual)} to be \${format(expected)}\`,
95
+ 'toBe',
96
+ expected,
97
+ actual
98
+ );
99
+ }
100
+ },
101
+
102
+ // Deep equality
103
+ toEqual(expected) {
104
+ const pass = deepEqual(actual, expected);
105
+ if (isNot ? pass : !pass) {
106
+ throw AssertionError(
107
+ isNot
108
+ ? \`Expected \${format(actual)} not to equal \${format(expected)}\`
109
+ : \`Expected \${format(actual)} to equal \${format(expected)}\`,
110
+ 'toEqual',
111
+ expected,
112
+ actual
113
+ );
114
+ }
115
+ },
116
+
117
+ // Strict deep equality
118
+ toStrictEqual(expected) {
119
+ const pass = strictEqual(actual, expected);
120
+ if (isNot ? pass : !pass) {
121
+ throw AssertionError(
122
+ isNot
123
+ ? \`Expected \${format(actual)} not to strictly equal \${format(expected)}\`
124
+ : \`Expected \${format(actual)} to strictly equal \${format(expected)}\`,
125
+ 'toStrictEqual',
126
+ expected,
127
+ actual
128
+ );
129
+ }
130
+ },
131
+
132
+ // Truthy/Falsy
133
+ toBeTruthy() {
134
+ const pass = !!actual;
135
+ if (isNot ? pass : !pass) {
136
+ throw AssertionError(
137
+ isNot
138
+ ? \`Expected \${format(actual)} not to be truthy\`
139
+ : \`Expected \${format(actual)} to be truthy\`,
140
+ 'toBeTruthy',
141
+ 'truthy value',
142
+ actual
143
+ );
144
+ }
145
+ },
146
+
147
+ toBeFalsy() {
148
+ const pass = !actual;
149
+ if (isNot ? pass : !pass) {
150
+ throw AssertionError(
151
+ isNot
152
+ ? \`Expected \${format(actual)} not to be falsy\`
153
+ : \`Expected \${format(actual)} to be falsy\`,
154
+ 'toBeFalsy',
155
+ 'falsy value',
156
+ actual
157
+ );
158
+ }
159
+ },
160
+
161
+ // Null/Undefined/Defined
162
+ toBeNull() {
163
+ const pass = actual === null;
164
+ if (isNot ? pass : !pass) {
165
+ throw AssertionError(
166
+ isNot
167
+ ? \`Expected \${format(actual)} not to be null\`
168
+ : \`Expected \${format(actual)} to be null\`,
169
+ 'toBeNull',
170
+ null,
171
+ actual
172
+ );
173
+ }
174
+ },
175
+
176
+ toBeUndefined() {
177
+ const pass = actual === undefined;
178
+ if (isNot ? pass : !pass) {
179
+ throw AssertionError(
180
+ isNot
181
+ ? \`Expected \${format(actual)} not to be undefined\`
182
+ : \`Expected \${format(actual)} to be undefined\`,
183
+ 'toBeUndefined',
184
+ undefined,
185
+ actual
186
+ );
187
+ }
188
+ },
189
+
190
+ toBeDefined() {
191
+ const pass = actual !== undefined;
192
+ if (isNot ? pass : !pass) {
193
+ throw AssertionError(
194
+ isNot
195
+ ? \`Expected \${format(actual)} to be undefined\`
196
+ : \`Expected \${format(actual)} to be defined\`,
197
+ 'toBeDefined',
198
+ 'defined value',
199
+ actual
200
+ );
201
+ }
202
+ },
203
+
204
+ toBeNaN() {
205
+ const pass = Number.isNaN(actual);
206
+ if (isNot ? pass : !pass) {
207
+ throw AssertionError(
208
+ isNot
209
+ ? \`Expected \${format(actual)} not to be NaN\`
210
+ : \`Expected \${format(actual)} to be NaN\`,
211
+ 'toBeNaN',
212
+ NaN,
213
+ actual
214
+ );
215
+ }
216
+ },
217
+
218
+ // Numeric comparisons
219
+ toBeGreaterThan(expected) {
220
+ const pass = actual > expected;
221
+ if (isNot ? pass : !pass) {
222
+ throw AssertionError(
223
+ isNot
224
+ ? \`Expected \${format(actual)} not to be greater than \${format(expected)}\`
225
+ : \`Expected \${format(actual)} to be greater than \${format(expected)}\`,
226
+ 'toBeGreaterThan',
227
+ expected,
228
+ actual
229
+ );
230
+ }
231
+ },
232
+
233
+ toBeGreaterThanOrEqual(expected) {
234
+ const pass = actual >= expected;
235
+ if (isNot ? pass : !pass) {
236
+ throw AssertionError(
237
+ isNot
238
+ ? \`Expected \${format(actual)} not to be greater than or equal to \${format(expected)}\`
239
+ : \`Expected \${format(actual)} to be greater than or equal to \${format(expected)}\`,
240
+ 'toBeGreaterThanOrEqual',
241
+ expected,
242
+ actual
243
+ );
244
+ }
245
+ },
246
+
247
+ toBeLessThan(expected) {
248
+ const pass = actual < expected;
249
+ if (isNot ? pass : !pass) {
250
+ throw AssertionError(
251
+ isNot
252
+ ? \`Expected \${format(actual)} not to be less than \${format(expected)}\`
253
+ : \`Expected \${format(actual)} to be less than \${format(expected)}\`,
254
+ 'toBeLessThan',
255
+ expected,
256
+ actual
257
+ );
258
+ }
259
+ },
260
+
261
+ toBeLessThanOrEqual(expected) {
262
+ const pass = actual <= expected;
263
+ if (isNot ? pass : !pass) {
264
+ throw AssertionError(
265
+ isNot
266
+ ? \`Expected \${format(actual)} not to be less than or equal to \${format(expected)}\`
267
+ : \`Expected \${format(actual)} to be less than or equal to \${format(expected)}\`,
268
+ 'toBeLessThanOrEqual',
269
+ expected,
270
+ actual
271
+ );
272
+ }
273
+ },
274
+
275
+ // Contains
276
+ toContain(expected) {
277
+ let pass = false;
278
+ if (typeof actual === 'string') {
279
+ pass = actual.includes(expected);
280
+ } else if (Array.isArray(actual)) {
281
+ pass = actual.includes(expected);
282
+ }
283
+ if (isNot ? pass : !pass) {
284
+ throw AssertionError(
285
+ isNot
286
+ ? \`Expected \${format(actual)} not to contain \${format(expected)}\`
287
+ : \`Expected \${format(actual)} to contain \${format(expected)}\`,
288
+ 'toContain',
289
+ expected,
290
+ actual
291
+ );
292
+ }
293
+ },
294
+
295
+ // Length
296
+ toHaveLength(expected) {
297
+ const actualLength = actual?.length;
298
+ const pass = actualLength === expected;
299
+ if (isNot ? pass : !pass) {
300
+ throw AssertionError(
301
+ isNot
302
+ ? \`Expected length not to be \${expected}, but got \${actualLength}\`
303
+ : \`Expected length to be \${expected}, but got \${actualLength}\`,
304
+ 'toHaveLength',
305
+ expected,
306
+ actualLength
307
+ );
308
+ }
309
+ },
310
+
311
+ // Property
312
+ toHaveProperty(key, value) {
313
+ const hasKey = key in Object(actual);
314
+ let pass = hasKey;
315
+ if (hasKey && arguments.length > 1) {
316
+ pass = deepEqual(actual[key], value);
317
+ }
318
+ if (isNot ? pass : !pass) {
319
+ const message = arguments.length > 1
320
+ ? (isNot
321
+ ? \`Expected \${format(actual)} not to have property "\${key}" with value \${format(value)}\`
322
+ : \`Expected \${format(actual)} to have property "\${key}" with value \${format(value)}\`)
323
+ : (isNot
324
+ ? \`Expected \${format(actual)} not to have property "\${key}"\`
325
+ : \`Expected \${format(actual)} to have property "\${key}"\`);
326
+ throw AssertionError(message, 'toHaveProperty', value, actual?.[key]);
327
+ }
328
+ },
329
+
330
+ // Throws
331
+ toThrow(expected) {
332
+ if (typeof actual !== 'function') {
333
+ throw AssertionError('Expected a function', 'toThrow', 'function', typeof actual);
334
+ }
335
+
336
+ let threw = false;
337
+ let error;
338
+ try {
339
+ actual();
340
+ } catch (e) {
341
+ threw = true;
342
+ error = e;
343
+ }
344
+
345
+ let pass = threw;
346
+ if (threw && expected !== undefined) {
347
+ if (typeof expected === 'string') {
348
+ pass = error?.message?.includes(expected);
349
+ } else if (expected instanceof RegExp) {
350
+ pass = expected.test(error?.message);
351
+ } else if (expected instanceof Error) {
352
+ pass = error?.message === expected.message;
353
+ }
354
+ }
355
+
356
+ if (isNot ? pass : !pass) {
357
+ throw AssertionError(
358
+ isNot
359
+ ? \`Expected function not to throw\`
360
+ : threw
361
+ ? \`Expected error message to match \${format(expected)}, got \${format(error?.message)}\`
362
+ : \`Expected function to throw\`,
363
+ 'toThrow',
364
+ expected,
365
+ error
366
+ );
367
+ }
368
+ },
369
+
370
+ // Match
371
+ toMatch(pattern) {
372
+ const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
373
+ const pass = regex.test(actual);
374
+ if (isNot ? pass : !pass) {
375
+ throw AssertionError(
376
+ isNot
377
+ ? \`Expected \${format(actual)} not to match \${format(pattern)}\`
378
+ : \`Expected \${format(actual)} to match \${format(pattern)}\`,
379
+ 'toMatch',
380
+ pattern,
381
+ actual
382
+ );
383
+ }
384
+ },
385
+
386
+ // Match object
387
+ toMatchObject(expected) {
388
+ function matches(actual, expected) {
389
+ if (typeof expected !== 'object' || expected === null) {
390
+ return deepEqual(actual, expected);
391
+ }
392
+ for (const key of Object.keys(expected)) {
393
+ if (!matches(actual?.[key], expected[key])) return false;
394
+ }
395
+ return true;
396
+ }
397
+
398
+ const pass = matches(actual, expected);
399
+ if (isNot ? pass : !pass) {
400
+ throw AssertionError(
401
+ isNot
402
+ ? \`Expected \${format(actual)} not to match object \${format(expected)}\`
403
+ : \`Expected \${format(actual)} to match object \${format(expected)}\`,
404
+ 'toMatchObject',
405
+ expected,
406
+ actual
407
+ );
408
+ }
409
+ },
410
+
411
+ // Instance of
412
+ toBeInstanceOf(expected) {
413
+ const pass = actual instanceof expected;
414
+ if (isNot ? pass : !pass) {
415
+ throw AssertionError(
416
+ isNot
417
+ ? \`Expected \${format(actual)} not to be instance of \${expected?.name || expected}\`
418
+ : \`Expected \${format(actual)} to be instance of \${expected?.name || expected}\`,
419
+ 'toBeInstanceOf',
420
+ expected?.name || expected,
421
+ actual?.constructor?.name || actual
422
+ );
423
+ }
424
+ },
425
+ };
426
+
427
+ // Add .not modifier
428
+ if (!isNot) {
429
+ matchers.not = createMatchers(actual, true);
430
+ }
431
+
432
+ return matchers;
433
+ }
434
+
435
+ // Create promise matchers
436
+ function createPromiseMatchers(promise, isRejects) {
437
+ return {
438
+ async toBe(expected) {
439
+ try {
440
+ const result = await promise;
441
+ if (isRejects) {
442
+ throw AssertionError('Expected promise to reject', 'rejects.toBe', 'rejection', result);
443
+ }
444
+ expect(result).toBe(expected);
445
+ } catch (error) {
446
+ if (error.name === 'AssertionError') throw error;
447
+ if (!isRejects) throw error;
448
+ expect(error).toBe(expected);
449
+ }
450
+ },
451
+ async toEqual(expected) {
452
+ try {
453
+ const result = await promise;
454
+ if (isRejects) {
455
+ throw AssertionError('Expected promise to reject', 'rejects.toEqual', 'rejection', result);
456
+ }
457
+ expect(result).toEqual(expected);
458
+ } catch (error) {
459
+ if (error.name === 'AssertionError') throw error;
460
+ if (!isRejects) throw error;
461
+ expect(error).toEqual(expected);
462
+ }
463
+ },
464
+ async toBeTruthy() {
465
+ try {
466
+ const result = await promise;
467
+ if (isRejects) {
468
+ throw AssertionError('Expected promise to reject', 'rejects.toBeTruthy', 'rejection', result);
469
+ }
470
+ expect(result).toBeTruthy();
471
+ } catch (error) {
472
+ if (error.name === 'AssertionError') throw error;
473
+ if (!isRejects) throw error;
474
+ expect(error).toBeTruthy();
475
+ }
476
+ },
477
+ async toBeFalsy() {
478
+ try {
479
+ const result = await promise;
480
+ if (isRejects) {
481
+ throw AssertionError('Expected promise to reject', 'rejects.toBeFalsy', 'rejection', result);
482
+ }
483
+ expect(result).toBeFalsy();
484
+ } catch (error) {
485
+ if (error.name === 'AssertionError') throw error;
486
+ if (!isRejects) throw error;
487
+ expect(error).toBeFalsy();
488
+ }
489
+ },
490
+ async toBeNull() {
491
+ try {
492
+ const result = await promise;
493
+ if (isRejects) {
494
+ throw AssertionError('Expected promise to reject', 'rejects.toBeNull', 'rejection', result);
495
+ }
496
+ expect(result).toBeNull();
497
+ } catch (error) {
498
+ if (error.name === 'AssertionError') throw error;
499
+ if (!isRejects) throw error;
500
+ expect(error).toBeNull();
501
+ }
502
+ },
503
+ async toBeUndefined() {
504
+ try {
505
+ const result = await promise;
506
+ if (isRejects) {
507
+ throw AssertionError('Expected promise to reject', 'rejects.toBeUndefined', 'rejection', result);
508
+ }
509
+ expect(result).toBeUndefined();
510
+ } catch (error) {
511
+ if (error.name === 'AssertionError') throw error;
512
+ if (!isRejects) throw error;
513
+ expect(error).toBeUndefined();
514
+ }
515
+ },
516
+ async toBeDefined() {
517
+ try {
518
+ const result = await promise;
519
+ if (isRejects) {
520
+ throw AssertionError('Expected promise to reject', 'rejects.toBeDefined', 'rejection', result);
521
+ }
522
+ expect(result).toBeDefined();
523
+ } catch (error) {
524
+ if (error.name === 'AssertionError') throw error;
525
+ if (!isRejects) throw error;
526
+ expect(error).toBeDefined();
527
+ }
528
+ },
529
+ async toThrow(expected) {
530
+ if (!isRejects) {
531
+ throw AssertionError('toThrow can only be used with rejects', 'toThrow', 'rejects', 'resolves');
532
+ }
533
+ try {
534
+ await promise;
535
+ throw AssertionError('Expected promise to reject', 'rejects.toThrow', 'rejection', 'resolved');
536
+ } catch (error) {
537
+ if (error.name === 'AssertionError') throw error;
538
+ if (expected !== undefined) {
539
+ if (typeof expected === 'string' && !error?.message?.includes(expected)) {
540
+ throw AssertionError(
541
+ \`Expected error message to include "\${expected}", got "\${error?.message}"\`,
542
+ 'rejects.toThrow',
543
+ expected,
544
+ error?.message
545
+ );
546
+ }
547
+ if (expected instanceof RegExp && !expected.test(error?.message)) {
548
+ throw AssertionError(
549
+ \`Expected error message to match \${expected}, got "\${error?.message}"\`,
550
+ 'rejects.toThrow',
551
+ expected,
552
+ error?.message
553
+ );
554
+ }
555
+ }
556
+ }
557
+ }
558
+ };
559
+ }
560
+
561
+ // Main expect function
562
+ function expect(actual) {
563
+ const matchers = createMatchers(actual, false);
564
+
565
+ // Add .resolves modifier
566
+ matchers.resolves = createPromiseMatchers(Promise.resolve(actual), false);
567
+
568
+ // Add .rejects modifier
569
+ matchers.rejects = createPromiseMatchers(actual, true);
570
+
571
+ return matchers;
572
+ }
573
+
574
+ // Expose globally
575
+ globalThis.expect = expect;
576
+ })();
577
+ `;
578
+ const result = context.evalCode(expectCode);
579
+ if (result.error) {
580
+ const errorDump = context.dump(result.error);
581
+ result.error.dispose();
582
+ throw new Error(`Failed to setup expect: ${errorDump}`);
583
+ }
584
+ result.value.dispose();
585
+ return handles;
586
+ }
587
+ export {
588
+ setupExpect
589
+ };
590
+
591
+ //# debugId=376CF8D2D923E21B64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/globals/expect.ts"],
4
+ "sourcesContent": [
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState } from \"../types.ts\";\n\nexport function setupExpect(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Implement expect entirely in JavaScript for simplicity\n const expectCode = `\n(function() {\n // Deep equality check\n function deepEqual(a, b) {\n if (a === b) return true;\n if (a === null || b === null) return false;\n if (typeof a !== typeof b) return false;\n\n if (typeof a === 'object') {\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n\n if (Array.isArray(a)) {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!deepEqual(a[i], b[i])) return false;\n }\n return true;\n }\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!Object.prototype.hasOwnProperty.call(b, key)) return false;\n if (!deepEqual(a[key], b[key])) return false;\n }\n return true;\n }\n\n return false;\n }\n\n // Strict equality (checks undefined values and array holes)\n function strictEqual(a, b) {\n if (!deepEqual(a, b)) return false;\n\n if (typeof a === 'object' && a !== null) {\n if (Array.isArray(a)) {\n // Check for sparse arrays\n for (let i = 0; i < a.length; i++) {\n if ((i in a) !== (i in b)) return false;\n }\n } else {\n // Check for undefined values\n const keysA = Object.keys(a);\n for (const key of keysA) {\n if (a[key] === undefined && !(key in b)) return false;\n }\n }\n }\n\n return true;\n }\n\n // Format value for error messages\n function format(value) {\n if (value === undefined) return 'undefined';\n if (value === null) return 'null';\n if (typeof value === 'string') return JSON.stringify(value);\n if (typeof value === 'function') return '[Function]';\n if (typeof value === 'symbol') return value.toString();\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n }\n\n // Create assertion error\n function AssertionError(message, matcherName, expected, actual) {\n const error = new Error(message);\n error.name = 'AssertionError';\n error.matcherName = matcherName;\n error.expected = expected;\n error.actual = actual;\n return error;\n }\n\n // Create matchers object\n function createMatchers(actual, isNot) {\n const matchers = {\n // Strict equality (===)\n toBe(expected) {\n const pass = actual === expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to be \\${format(expected)}\\`,\n 'toBe',\n expected,\n actual\n );\n }\n },\n\n // Deep equality\n toEqual(expected) {\n const pass = deepEqual(actual, expected);\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to equal \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to equal \\${format(expected)}\\`,\n 'toEqual',\n expected,\n actual\n );\n }\n },\n\n // Strict deep equality\n toStrictEqual(expected) {\n const pass = strictEqual(actual, expected);\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to strictly equal \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to strictly equal \\${format(expected)}\\`,\n 'toStrictEqual',\n expected,\n actual\n );\n }\n },\n\n // Truthy/Falsy\n toBeTruthy() {\n const pass = !!actual;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be truthy\\`\n : \\`Expected \\${format(actual)} to be truthy\\`,\n 'toBeTruthy',\n 'truthy value',\n actual\n );\n }\n },\n\n toBeFalsy() {\n const pass = !actual;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be falsy\\`\n : \\`Expected \\${format(actual)} to be falsy\\`,\n 'toBeFalsy',\n 'falsy value',\n actual\n );\n }\n },\n\n // Null/Undefined/Defined\n toBeNull() {\n const pass = actual === null;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be null\\`\n : \\`Expected \\${format(actual)} to be null\\`,\n 'toBeNull',\n null,\n actual\n );\n }\n },\n\n toBeUndefined() {\n const pass = actual === undefined;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be undefined\\`\n : \\`Expected \\${format(actual)} to be undefined\\`,\n 'toBeUndefined',\n undefined,\n actual\n );\n }\n },\n\n toBeDefined() {\n const pass = actual !== undefined;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} to be undefined\\`\n : \\`Expected \\${format(actual)} to be defined\\`,\n 'toBeDefined',\n 'defined value',\n actual\n );\n }\n },\n\n toBeNaN() {\n const pass = Number.isNaN(actual);\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be NaN\\`\n : \\`Expected \\${format(actual)} to be NaN\\`,\n 'toBeNaN',\n NaN,\n actual\n );\n }\n },\n\n // Numeric comparisons\n toBeGreaterThan(expected) {\n const pass = actual > expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be greater than \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to be greater than \\${format(expected)}\\`,\n 'toBeGreaterThan',\n expected,\n actual\n );\n }\n },\n\n toBeGreaterThanOrEqual(expected) {\n const pass = actual >= expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be greater than or equal to \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to be greater than or equal to \\${format(expected)}\\`,\n 'toBeGreaterThanOrEqual',\n expected,\n actual\n );\n }\n },\n\n toBeLessThan(expected) {\n const pass = actual < expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be less than \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to be less than \\${format(expected)}\\`,\n 'toBeLessThan',\n expected,\n actual\n );\n }\n },\n\n toBeLessThanOrEqual(expected) {\n const pass = actual <= expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be less than or equal to \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to be less than or equal to \\${format(expected)}\\`,\n 'toBeLessThanOrEqual',\n expected,\n actual\n );\n }\n },\n\n // Contains\n toContain(expected) {\n let pass = false;\n if (typeof actual === 'string') {\n pass = actual.includes(expected);\n } else if (Array.isArray(actual)) {\n pass = actual.includes(expected);\n }\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to contain \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to contain \\${format(expected)}\\`,\n 'toContain',\n expected,\n actual\n );\n }\n },\n\n // Length\n toHaveLength(expected) {\n const actualLength = actual?.length;\n const pass = actualLength === expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected length not to be \\${expected}, but got \\${actualLength}\\`\n : \\`Expected length to be \\${expected}, but got \\${actualLength}\\`,\n 'toHaveLength',\n expected,\n actualLength\n );\n }\n },\n\n // Property\n toHaveProperty(key, value) {\n const hasKey = key in Object(actual);\n let pass = hasKey;\n if (hasKey && arguments.length > 1) {\n pass = deepEqual(actual[key], value);\n }\n if (isNot ? pass : !pass) {\n const message = arguments.length > 1\n ? (isNot\n ? \\`Expected \\${format(actual)} not to have property \"\\${key}\" with value \\${format(value)}\\`\n : \\`Expected \\${format(actual)} to have property \"\\${key}\" with value \\${format(value)}\\`)\n : (isNot\n ? \\`Expected \\${format(actual)} not to have property \"\\${key}\"\\`\n : \\`Expected \\${format(actual)} to have property \"\\${key}\"\\`);\n throw AssertionError(message, 'toHaveProperty', value, actual?.[key]);\n }\n },\n\n // Throws\n toThrow(expected) {\n if (typeof actual !== 'function') {\n throw AssertionError('Expected a function', 'toThrow', 'function', typeof actual);\n }\n\n let threw = false;\n let error;\n try {\n actual();\n } catch (e) {\n threw = true;\n error = e;\n }\n\n let pass = threw;\n if (threw && expected !== undefined) {\n if (typeof expected === 'string') {\n pass = error?.message?.includes(expected);\n } else if (expected instanceof RegExp) {\n pass = expected.test(error?.message);\n } else if (expected instanceof Error) {\n pass = error?.message === expected.message;\n }\n }\n\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected function not to throw\\`\n : threw\n ? \\`Expected error message to match \\${format(expected)}, got \\${format(error?.message)}\\`\n : \\`Expected function to throw\\`,\n 'toThrow',\n expected,\n error\n );\n }\n },\n\n // Match\n toMatch(pattern) {\n const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;\n const pass = regex.test(actual);\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to match \\${format(pattern)}\\`\n : \\`Expected \\${format(actual)} to match \\${format(pattern)}\\`,\n 'toMatch',\n pattern,\n actual\n );\n }\n },\n\n // Match object\n toMatchObject(expected) {\n function matches(actual, expected) {\n if (typeof expected !== 'object' || expected === null) {\n return deepEqual(actual, expected);\n }\n for (const key of Object.keys(expected)) {\n if (!matches(actual?.[key], expected[key])) return false;\n }\n return true;\n }\n\n const pass = matches(actual, expected);\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to match object \\${format(expected)}\\`\n : \\`Expected \\${format(actual)} to match object \\${format(expected)}\\`,\n 'toMatchObject',\n expected,\n actual\n );\n }\n },\n\n // Instance of\n toBeInstanceOf(expected) {\n const pass = actual instanceof expected;\n if (isNot ? pass : !pass) {\n throw AssertionError(\n isNot\n ? \\`Expected \\${format(actual)} not to be instance of \\${expected?.name || expected}\\`\n : \\`Expected \\${format(actual)} to be instance of \\${expected?.name || expected}\\`,\n 'toBeInstanceOf',\n expected?.name || expected,\n actual?.constructor?.name || actual\n );\n }\n },\n };\n\n // Add .not modifier\n if (!isNot) {\n matchers.not = createMatchers(actual, true);\n }\n\n return matchers;\n }\n\n // Create promise matchers\n function createPromiseMatchers(promise, isRejects) {\n return {\n async toBe(expected) {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBe', 'rejection', result);\n }\n expect(result).toBe(expected);\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBe(expected);\n }\n },\n async toEqual(expected) {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toEqual', 'rejection', result);\n }\n expect(result).toEqual(expected);\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toEqual(expected);\n }\n },\n async toBeTruthy() {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBeTruthy', 'rejection', result);\n }\n expect(result).toBeTruthy();\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBeTruthy();\n }\n },\n async toBeFalsy() {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBeFalsy', 'rejection', result);\n }\n expect(result).toBeFalsy();\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBeFalsy();\n }\n },\n async toBeNull() {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBeNull', 'rejection', result);\n }\n expect(result).toBeNull();\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBeNull();\n }\n },\n async toBeUndefined() {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBeUndefined', 'rejection', result);\n }\n expect(result).toBeUndefined();\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBeUndefined();\n }\n },\n async toBeDefined() {\n try {\n const result = await promise;\n if (isRejects) {\n throw AssertionError('Expected promise to reject', 'rejects.toBeDefined', 'rejection', result);\n }\n expect(result).toBeDefined();\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (!isRejects) throw error;\n expect(error).toBeDefined();\n }\n },\n async toThrow(expected) {\n if (!isRejects) {\n throw AssertionError('toThrow can only be used with rejects', 'toThrow', 'rejects', 'resolves');\n }\n try {\n await promise;\n throw AssertionError('Expected promise to reject', 'rejects.toThrow', 'rejection', 'resolved');\n } catch (error) {\n if (error.name === 'AssertionError') throw error;\n if (expected !== undefined) {\n if (typeof expected === 'string' && !error?.message?.includes(expected)) {\n throw AssertionError(\n \\`Expected error message to include \"\\${expected}\", got \"\\${error?.message}\"\\`,\n 'rejects.toThrow',\n expected,\n error?.message\n );\n }\n if (expected instanceof RegExp && !expected.test(error?.message)) {\n throw AssertionError(\n \\`Expected error message to match \\${expected}, got \"\\${error?.message}\"\\`,\n 'rejects.toThrow',\n expected,\n error?.message\n );\n }\n }\n }\n }\n };\n }\n\n // Main expect function\n function expect(actual) {\n const matchers = createMatchers(actual, false);\n\n // Add .resolves modifier\n matchers.resolves = createPromiseMatchers(Promise.resolve(actual), false);\n\n // Add .rejects modifier\n matchers.rejects = createPromiseMatchers(actual, true);\n\n return matchers;\n }\n\n // Expose globally\n globalThis.expect = expect;\n})();\n`;\n\n const result = context.evalCode(expectCode);\n if (result.error) {\n const errorDump = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Failed to setup expect: ${errorDump}`);\n }\n result.value.dispose();\n\n return handles;\n}\n"
6
+ ],
7
+ "mappings": ";;AAGO,SAAS,WAAW,CACzB,SACA,OACiB;AAAA,EACjB,MAAM,UAA2B,CAAC;AAAA,EAGlC,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8jBnB,MAAM,SAAS,QAAQ,SAAS,UAAU;AAAA,EAC1C,IAAI,OAAO,OAAO;AAAA,IAChB,MAAM,YAAY,QAAQ,KAAK,OAAO,KAAK;AAAA,IAC3C,OAAO,MAAM,QAAQ;AAAA,IACrB,MAAM,IAAI,MAAM,2BAA2B,WAAW;AAAA,EACxD;AAAA,EACA,OAAO,MAAM,QAAQ;AAAA,EAErB,OAAO;AAAA;",
8
+ "debugId": "376CF8D2D923E21B64756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,48 @@
1
+ // @bun
2
+ // packages/test-environment/src/handle.ts
3
+ import { runTests } from "./runner.ts";
4
+ function createTestEnvironmentHandle(state) {
5
+ return {
6
+ get stateMap() {
7
+ return state.stateMap;
8
+ },
9
+ async run() {
10
+ return runTests(state);
11
+ },
12
+ hasTests() {
13
+ return state.suites.some((suite) => suite.tests.length > 0 || suite.children.length > 0);
14
+ },
15
+ getTestCount() {
16
+ let count = 0;
17
+ const countSuite = (suite) => {
18
+ count += suite.tests.length;
19
+ suite.children.forEach(countSuite);
20
+ };
21
+ state.suites.forEach(countSuite);
22
+ return count;
23
+ },
24
+ reset() {
25
+ const disposeSuite = (suite) => {
26
+ suite.tests.forEach((test) => test.fn.dispose());
27
+ suite.beforeAll.forEach((fn) => fn.dispose());
28
+ suite.afterAll.forEach((fn) => fn.dispose());
29
+ suite.beforeEach.forEach((fn) => fn.dispose());
30
+ suite.afterEach.forEach((fn) => fn.dispose());
31
+ suite.children.forEach(disposeSuite);
32
+ };
33
+ state.suites.forEach(disposeSuite);
34
+ state.suites = [];
35
+ state.currentSuite = null;
36
+ },
37
+ dispose() {
38
+ this.reset();
39
+ state.handles.forEach((handle) => handle.dispose());
40
+ state.handles = [];
41
+ }
42
+ };
43
+ }
44
+ export {
45
+ createTestEnvironmentHandle
46
+ };
47
+
48
+ //# debugId=2992932296BCF55264756E2164756E21