@ricsam/quickjs-test-environment 0.2.15 → 0.2.17

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 CHANGED
@@ -1,25 +1,42 @@
1
1
  # @ricsam/quickjs-test-environment
2
2
 
3
- Test primitives for running tests in sandboxed QuickJS. Provides a Bun/Jest/Vitest-compatible API with handler-based result streaming.
3
+ Test primitives for running tests in sandboxed QuickJS. Provides a Bun/Jest/Vitest-compatible API with event-based result streaming.
4
+
5
+ > **Note**: This is a low-level package. For most use cases, use [`@ricsam/quickjs-runtime`](../runtime) with `createRuntime({ testEnvironment: true })` instead.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ bun add @ricsam/quickjs-test-environment
11
+ ```
12
+
13
+ ## Setup
4
14
 
5
15
  ```typescript
6
16
  import { setupTestEnvironment } from "@ricsam/quickjs-test-environment";
7
17
 
8
18
  const handle = setupTestEnvironment(context, {
9
- onTestPass: (test) => console.log(`✓ ${test.fullName}`),
10
- onTestFail: (test) => console.log(`✗ ${test.fullName}: ${test.error?.message}`),
11
- onRunComplete: (results) => {
12
- console.log(`\n${results.passed}/${results.total} tests passed`);
19
+ onEvent: (event) => {
20
+ if (event.type === "testEnd") {
21
+ const icon = event.test.status === "pass" ? "✓" : "✗";
22
+ console.log(`${icon} ${event.test.fullName}`);
23
+ if (event.test.error) {
24
+ console.log(` Error: ${event.test.error.message}`);
25
+ }
26
+ } else if (event.type === "runEnd") {
27
+ console.log(`\n${event.results.passed}/${event.results.total} tests passed`);
28
+ }
13
29
  },
14
30
  });
15
31
  ```
16
32
 
17
- **Injected Globals:**
33
+ ## Injected Globals
34
+
18
35
  - `describe`, `it`, `test` (with `.skip`, `.only`, `.todo` modifiers)
19
36
  - `beforeAll`, `afterAll`, `beforeEach`, `afterEach`
20
37
  - `expect` with matchers (`toBe`, `toEqual`, `toThrow`, etc.) and modifiers (`.not`, `.resolves`, `.rejects`)
21
38
 
22
- **Usage in QuickJS:**
39
+ ## Usage in QuickJS
23
40
 
24
41
  ```javascript
25
42
  describe("Math operations", () => {
@@ -44,7 +61,7 @@ describe("Math operations", () => {
44
61
  });
45
62
  ```
46
63
 
47
- **Running tests from host:**
64
+ ## Running Tests from Host
48
65
 
49
66
  ```typescript
50
67
  // Load untrusted test code
@@ -63,13 +80,13 @@ handle.reset();
63
80
  handle.dispose();
64
81
  ```
65
82
 
66
- **Event Handlers:**
83
+ ## TestEvent Types
67
84
 
68
- | Handler | Description |
69
- |---------|-------------|
70
- | `onSuiteStart` | Called when a describe block begins |
71
- | `onSuiteEnd` | Called when a describe block completes |
72
- | `onTestStart` | Called before each test runs |
73
- | `onTestPass` | Called when a test passes |
74
- | `onTestFail` | Called when a test fails |
75
- | `onRunComplete` | Called after all tests complete |
85
+ | Event Type | Description |
86
+ |------------|-------------|
87
+ | `runStart` | Emitted when test run begins (includes `testCount`, `suiteCount`) |
88
+ | `suiteStart` | Emitted when a describe block begins |
89
+ | `suiteEnd` | Emitted when a describe block completes |
90
+ | `testStart` | Emitted before each test runs |
91
+ | `testEnd` | Emitted when a test completes (includes `status`: pass/fail/skip/todo) |
92
+ | `runEnd` | Emitted after all tests complete (includes full `results`) |
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export { setupTestEnvironment } from \"./setup.cjs\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.cjs\";\n"
5
+ "export { setupTestEnvironment } from \"./setup.cjs\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n TestEvent,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.cjs\";\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqC,IAArC;",
8
8
  "debugId": "3CED267B02A0F88164756E2164756E21",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "type": "commonjs"
5
5
  }
@@ -207,7 +207,7 @@ async function runTest(runCtx, test) {
207
207
  runCtx.results.todo++;
208
208
  return result2;
209
209
  }
210
- state.handlers.onTestStart?.(testInfo);
210
+ state.onEvent?.({ type: "testStart", test: testInfo });
211
211
  const startTime = performance.now();
212
212
  const beforeEachHooks = collectBeforeEachHooks(test.suite);
213
213
  const beforeResult = await executeHooks(context, beforeEachHooks);
@@ -232,11 +232,10 @@ async function runTest(runCtx, test) {
232
232
  runCtx.results.tests.push(result);
233
233
  if (result.status === "pass") {
234
234
  runCtx.results.passed++;
235
- state.handlers.onTestPass?.(result);
236
235
  } else {
237
236
  runCtx.results.failed++;
238
- state.handlers.onTestFail?.(result);
239
237
  }
238
+ state.onEvent?.({ type: "testEnd", test: result });
240
239
  return result;
241
240
  }
242
241
  async function runSuite(runCtx, suite) {
@@ -246,7 +245,7 @@ async function runSuite(runCtx, suite) {
246
245
  path: suite.path,
247
246
  fullName: suite.path.join(" > ") || suite.name
248
247
  };
249
- state.handlers.onSuiteStart?.(suiteInfo);
248
+ state.onEvent?.({ type: "suiteStart", suite: suiteInfo });
250
249
  const startTime = performance.now();
251
250
  let passed = 0;
252
251
  let failed = 0;
@@ -280,7 +279,7 @@ async function runSuite(runCtx, suite) {
280
279
  runCtx.results.tests.push(testResult);
281
280
  runCtx.results.failed++;
282
281
  failed++;
283
- state.handlers.onTestFail?.(testResult);
282
+ state.onEvent?.({ type: "testEnd", test: testResult });
284
283
  }
285
284
  }
286
285
  await executeHooks(context, suite.afterAll);
@@ -309,9 +308,24 @@ async function runSuite(runCtx, suite) {
309
308
  duration
310
309
  };
311
310
  runCtx.results.suites.push(suiteResult);
312
- state.handlers.onSuiteEnd?.(suiteResult);
311
+ state.onEvent?.({ type: "suiteEnd", suite: suiteResult });
313
312
  return suiteResult;
314
313
  }
314
+ function countTests(suites) {
315
+ let count = 0;
316
+ for (const suite of suites) {
317
+ count += suite.tests.length;
318
+ count += countTests(suite.children);
319
+ }
320
+ return count;
321
+ }
322
+ function countSuites(suites) {
323
+ let count = suites.length;
324
+ for (const suite of suites) {
325
+ count += countSuites(suite.children);
326
+ }
327
+ return count;
328
+ }
315
329
  async function runTests(state) {
316
330
  const startTime = performance.now();
317
331
  const results = {
@@ -332,15 +346,18 @@ async function runTests(state) {
332
346
  results,
333
347
  hasOnly
334
348
  };
349
+ const testCount = countTests(state.suites);
350
+ const suiteCount = countSuites(state.suites);
351
+ state.onEvent?.({ type: "runStart", testCount, suiteCount });
335
352
  for (const suite of state.suites) {
336
353
  await runSuite(runCtx, suite);
337
354
  }
338
355
  results.duration = performance.now() - startTime;
339
356
  results.total = results.passed + results.failed + results.skipped + results.todo;
340
357
  results.success = results.failed === 0;
341
- state.handlers.onRunComplete?.(results);
358
+ state.onEvent?.({ type: "runEnd", results });
342
359
  return results;
343
360
  }
344
361
  })
345
362
 
346
- //# debugId=9BA8E805A3739F0764756E2164756E21
363
+ //# debugId=7C44782526B7BEE164756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/runner.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type {\n TestState,\n RegisteredSuite,\n RegisteredTest,\n RunResults,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n} from \"./types.cjs\";\n\ninterface RunContext {\n state: TestState;\n context: QuickJSContext;\n results: RunResults;\n hasOnly: boolean;\n}\n\n/**\n * Check if any test or suite has .only modifier\n */\nfunction checkForOnly(suites: RegisteredSuite[]): boolean {\n for (const suite of suites) {\n if (suite.modifier === \"only\") return true;\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n if (checkForOnly(suite.children)) return true;\n }\n return false;\n}\n\n/**\n * Execute a function handle (sync or async)\n * Captures AssertionError properties from expect() matchers\n */\nasync function executeFunction(\n context: QuickJSContext,\n fn: QuickJSHandle\n): Promise<{ success: boolean; error?: TestError }> {\n const result = context.callFunction(fn, context.undefined);\n\n if (result.error) {\n const errorDump = context.dump(result.error);\n result.error.dispose();\n\n // Extract error properties (including expect() matcher metadata)\n return {\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n };\n }\n\n // Check if result is a promise\n const isPromiseCode = context.evalCode(`\n (function(val) { return val && typeof val.then === 'function'; })\n `);\n\n if (isPromiseCode.error) {\n isPromiseCode.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const checkResult = context.callFunction(\n isPromiseCode.value,\n context.undefined,\n result.value\n );\n isPromiseCode.value.dispose();\n\n if (checkResult.error) {\n checkResult.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const isPromise = context.dump(checkResult.value);\n checkResult.value.dispose();\n\n if (!isPromise) {\n result.value.dispose();\n return { success: true };\n }\n\n // Handle async - wrap in promise resolution tracking\n return new Promise((resolve) => {\n const promiseHandle = result.value;\n\n // Create resolve/reject callbacks\n const thenFn = context.newFunction(\"then\", () => {\n resolve({ success: true });\n return context.undefined;\n });\n\n const catchFn = context.newFunction(\"catch\", (errorHandle) => {\n const errorDump = context.dump(errorHandle);\n resolve({\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n });\n return context.undefined;\n });\n\n // Get the 'then' property from promise\n const thenProp = context.getProp(promiseHandle, \"then\");\n\n // Call promise.then().catch()\n const thenResult = context.callFunction(thenProp, promiseHandle, thenFn);\n thenProp.dispose();\n\n if (thenResult.error) {\n thenResult.error.dispose();\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n resolve({ success: true });\n return;\n }\n\n // Get 'catch' property from thenResult\n const catchProp = context.getProp(thenResult.value, \"catch\");\n const catchResult = context.callFunction(\n catchProp,\n thenResult.value,\n catchFn\n );\n catchProp.dispose();\n thenResult.value.dispose();\n\n if (catchResult.error) {\n catchResult.error.dispose();\n } else {\n catchResult.value.dispose();\n }\n\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n\n // Execute pending jobs to process the promise\n context.runtime.executePendingJobs();\n });\n}\n\n/**\n * Execute all hooks in an array\n */\nasync function executeHooks(\n context: QuickJSContext,\n hooks: QuickJSHandle[]\n): Promise<{ success: boolean; error?: TestError }> {\n for (const hook of hooks) {\n const result = await executeFunction(context, hook);\n if (!result.success) {\n return result;\n }\n }\n return { success: true };\n}\n\n/**\n * Collect beforeEach hooks from outer to inner\n */\nfunction collectBeforeEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n for (const s of path) {\n hooks.push(...s.beforeEach);\n }\n\n return hooks;\n}\n\n/**\n * Collect afterEach hooks from inner to outer\n */\nfunction collectAfterEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n // Reverse for inner to outer\n for (const s of path.reverse()) {\n hooks.push(...s.afterEach);\n }\n\n return hooks;\n}\n\n/**\n * Check if any ancestor suite has .only modifier\n */\nfunction hasOnlyAncestor(suite: RegisteredSuite): boolean {\n let current: RegisteredSuite | null = suite;\n while (current) {\n if (current.modifier === \"only\") return true;\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Check if suite has any .only descendants\n */\nfunction hasOnlyDescendant(suite: RegisteredSuite): boolean {\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n for (const child of suite.children) {\n if (child.modifier === \"only\") return true;\n if (hasOnlyDescendant(child)) return true;\n }\n return false;\n}\n\n/**\n * Run a single test\n */\nasync function runTest(\n runCtx: RunContext,\n test: RegisteredTest\n): Promise<TestResult> {\n const { state, context } = runCtx;\n\n const testInfo: TestInfo = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n };\n\n // Check if should skip\n const shouldSkip =\n test.modifier === \"skip\" ||\n test.modifier === \"todo\" ||\n test.suite.modifier === \"skip\" ||\n test.suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n test.modifier !== \"only\" &&\n !hasOnlyAncestor(test.suite));\n\n if (shouldSkip) {\n const result: TestResult = {\n ...testInfo,\n status: test.modifier === \"todo\" ? \"todo\" : \"skip\",\n duration: 0,\n };\n\n runCtx.results.tests.push(result);\n if (result.status === \"skip\") runCtx.results.skipped++;\n if (result.status === \"todo\") runCtx.results.todo++;\n\n return result;\n }\n\n // Call onTestStart\n state.handlers.onTestStart?.(testInfo);\n\n const startTime = performance.now();\n\n // Run beforeEach hooks\n const beforeEachHooks = collectBeforeEachHooks(test.suite);\n const beforeResult = await executeHooks(context, beforeEachHooks);\n\n let testError: TestError | undefined;\n\n if (!beforeResult.success) {\n testError = beforeResult.error;\n } else {\n // Run the test\n const testResult = await executeFunction(context, test.fn);\n if (!testResult.success) {\n testError = testResult.error;\n }\n }\n\n // Run afterEach hooks (even if test failed)\n const afterEachHooks = collectAfterEachHooks(test.suite);\n await executeHooks(context, afterEachHooks);\n\n const duration = performance.now() - startTime;\n\n const result: TestResult = {\n ...testInfo,\n status: testError ? \"fail\" : \"pass\",\n duration,\n error: testError,\n };\n\n runCtx.results.tests.push(result);\n\n if (result.status === \"pass\") {\n runCtx.results.passed++;\n state.handlers.onTestPass?.(result);\n } else {\n runCtx.results.failed++;\n state.handlers.onTestFail?.(result);\n }\n\n return result;\n}\n\n/**\n * Run a suite and its children\n */\nasync function runSuite(\n runCtx: RunContext,\n suite: RegisteredSuite\n): Promise<SuiteResult> {\n const { state, context } = runCtx;\n\n const suiteInfo: SuiteInfo = {\n name: suite.name,\n path: suite.path,\n fullName: suite.path.join(\" > \") || suite.name,\n };\n\n // Call onSuiteStart\n state.handlers.onSuiteStart?.(suiteInfo);\n\n const startTime = performance.now();\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n // Check if entire suite should skip\n const shouldSkipSuite =\n suite.modifier === \"skip\" ||\n suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n suite.modifier !== \"only\" &&\n !hasOnlyDescendant(suite) &&\n !hasOnlyAncestor(suite));\n\n if (!shouldSkipSuite) {\n // Run beforeAll hooks\n const beforeAllResult = await executeHooks(context, suite.beforeAll);\n\n if (beforeAllResult.success) {\n // Run tests\n for (const test of suite.tests) {\n const result = await runTest(runCtx, test);\n if (result.status === \"pass\") passed++;\n else if (result.status === \"fail\") failed++;\n else skipped++;\n }\n\n // Run child suites\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n } else {\n // beforeAll failed - skip all tests in this suite\n for (const test of suite.tests) {\n const testResult: TestResult = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"fail\",\n duration: 0,\n error: beforeAllResult.error,\n };\n runCtx.results.tests.push(testResult);\n runCtx.results.failed++;\n failed++;\n state.handlers.onTestFail?.(testResult);\n }\n }\n\n // Run afterAll hooks\n await executeHooks(context, suite.afterAll);\n } else {\n // Skip all tests\n for (const test of suite.tests) {\n skipped++;\n runCtx.results.skipped++;\n runCtx.results.tests.push({\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"skip\",\n duration: 0,\n });\n }\n\n // Still process children (they might have .only)\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n }\n\n const duration = performance.now() - startTime;\n\n const suiteResult: SuiteResult = {\n ...suiteInfo,\n passed,\n failed,\n skipped,\n duration,\n };\n\n runCtx.results.suites.push(suiteResult);\n\n // Call onSuiteEnd\n state.handlers.onSuiteEnd?.(suiteResult);\n\n return suiteResult;\n}\n\n/**\n * Main run function\n */\nexport async function runTests(state: TestState): Promise<RunResults> {\n const startTime = performance.now();\n\n const results: RunResults = {\n passed: 0,\n failed: 0,\n skipped: 0,\n todo: 0,\n total: 0,\n duration: 0,\n suites: [],\n tests: [],\n success: true,\n };\n\n const hasOnly = checkForOnly(state.suites);\n\n const runCtx: RunContext = {\n state,\n context: state.context,\n results,\n hasOnly,\n };\n\n // Run all suites\n for (const suite of state.suites) {\n await runSuite(runCtx, suite);\n }\n\n results.duration = performance.now() - startTime;\n results.total = results.passed + results.failed + results.skipped + results.todo;\n results.success = results.failed === 0;\n\n // Call onRunComplete\n state.handlers.onRunComplete?.(results);\n\n return results;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type {\n TestState,\n RegisteredSuite,\n RegisteredTest,\n RunResults,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n TestEvent,\n} from \"./types.cjs\";\n\ninterface RunContext {\n state: TestState;\n context: QuickJSContext;\n results: RunResults;\n hasOnly: boolean;\n}\n\n/**\n * Check if any test or suite has .only modifier\n */\nfunction checkForOnly(suites: RegisteredSuite[]): boolean {\n for (const suite of suites) {\n if (suite.modifier === \"only\") return true;\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n if (checkForOnly(suite.children)) return true;\n }\n return false;\n}\n\n/**\n * Execute a function handle (sync or async)\n * Captures AssertionError properties from expect() matchers\n */\nasync function executeFunction(\n context: QuickJSContext,\n fn: QuickJSHandle\n): Promise<{ success: boolean; error?: TestError }> {\n const result = context.callFunction(fn, context.undefined);\n\n if (result.error) {\n const errorDump = context.dump(result.error);\n result.error.dispose();\n\n // Extract error properties (including expect() matcher metadata)\n return {\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n };\n }\n\n // Check if result is a promise\n const isPromiseCode = context.evalCode(`\n (function(val) { return val && typeof val.then === 'function'; })\n `);\n\n if (isPromiseCode.error) {\n isPromiseCode.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const checkResult = context.callFunction(\n isPromiseCode.value,\n context.undefined,\n result.value\n );\n isPromiseCode.value.dispose();\n\n if (checkResult.error) {\n checkResult.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const isPromise = context.dump(checkResult.value);\n checkResult.value.dispose();\n\n if (!isPromise) {\n result.value.dispose();\n return { success: true };\n }\n\n // Handle async - wrap in promise resolution tracking\n return new Promise((resolve) => {\n const promiseHandle = result.value;\n\n // Create resolve/reject callbacks\n const thenFn = context.newFunction(\"then\", () => {\n resolve({ success: true });\n return context.undefined;\n });\n\n const catchFn = context.newFunction(\"catch\", (errorHandle) => {\n const errorDump = context.dump(errorHandle);\n resolve({\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n });\n return context.undefined;\n });\n\n // Get the 'then' property from promise\n const thenProp = context.getProp(promiseHandle, \"then\");\n\n // Call promise.then().catch()\n const thenResult = context.callFunction(thenProp, promiseHandle, thenFn);\n thenProp.dispose();\n\n if (thenResult.error) {\n thenResult.error.dispose();\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n resolve({ success: true });\n return;\n }\n\n // Get 'catch' property from thenResult\n const catchProp = context.getProp(thenResult.value, \"catch\");\n const catchResult = context.callFunction(\n catchProp,\n thenResult.value,\n catchFn\n );\n catchProp.dispose();\n thenResult.value.dispose();\n\n if (catchResult.error) {\n catchResult.error.dispose();\n } else {\n catchResult.value.dispose();\n }\n\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n\n // Execute pending jobs to process the promise\n context.runtime.executePendingJobs();\n });\n}\n\n/**\n * Execute all hooks in an array\n */\nasync function executeHooks(\n context: QuickJSContext,\n hooks: QuickJSHandle[]\n): Promise<{ success: boolean; error?: TestError }> {\n for (const hook of hooks) {\n const result = await executeFunction(context, hook);\n if (!result.success) {\n return result;\n }\n }\n return { success: true };\n}\n\n/**\n * Collect beforeEach hooks from outer to inner\n */\nfunction collectBeforeEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n for (const s of path) {\n hooks.push(...s.beforeEach);\n }\n\n return hooks;\n}\n\n/**\n * Collect afterEach hooks from inner to outer\n */\nfunction collectAfterEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n // Reverse for inner to outer\n for (const s of path.reverse()) {\n hooks.push(...s.afterEach);\n }\n\n return hooks;\n}\n\n/**\n * Check if any ancestor suite has .only modifier\n */\nfunction hasOnlyAncestor(suite: RegisteredSuite): boolean {\n let current: RegisteredSuite | null = suite;\n while (current) {\n if (current.modifier === \"only\") return true;\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Check if suite has any .only descendants\n */\nfunction hasOnlyDescendant(suite: RegisteredSuite): boolean {\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n for (const child of suite.children) {\n if (child.modifier === \"only\") return true;\n if (hasOnlyDescendant(child)) return true;\n }\n return false;\n}\n\n/**\n * Run a single test\n */\nasync function runTest(\n runCtx: RunContext,\n test: RegisteredTest\n): Promise<TestResult> {\n const { state, context } = runCtx;\n\n const testInfo: TestInfo = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n };\n\n // Check if should skip\n const shouldSkip =\n test.modifier === \"skip\" ||\n test.modifier === \"todo\" ||\n test.suite.modifier === \"skip\" ||\n test.suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n test.modifier !== \"only\" &&\n !hasOnlyAncestor(test.suite));\n\n if (shouldSkip) {\n const result: TestResult = {\n ...testInfo,\n status: test.modifier === \"todo\" ? \"todo\" : \"skip\",\n duration: 0,\n };\n\n runCtx.results.tests.push(result);\n if (result.status === \"skip\") runCtx.results.skipped++;\n if (result.status === \"todo\") runCtx.results.todo++;\n\n return result;\n }\n\n // Emit testStart event\n state.onEvent?.({ type: \"testStart\", test: testInfo });\n\n const startTime = performance.now();\n\n // Run beforeEach hooks\n const beforeEachHooks = collectBeforeEachHooks(test.suite);\n const beforeResult = await executeHooks(context, beforeEachHooks);\n\n let testError: TestError | undefined;\n\n if (!beforeResult.success) {\n testError = beforeResult.error;\n } else {\n // Run the test\n const testResult = await executeFunction(context, test.fn);\n if (!testResult.success) {\n testError = testResult.error;\n }\n }\n\n // Run afterEach hooks (even if test failed)\n const afterEachHooks = collectAfterEachHooks(test.suite);\n await executeHooks(context, afterEachHooks);\n\n const duration = performance.now() - startTime;\n\n const result: TestResult = {\n ...testInfo,\n status: testError ? \"fail\" : \"pass\",\n duration,\n error: testError,\n };\n\n runCtx.results.tests.push(result);\n\n if (result.status === \"pass\") {\n runCtx.results.passed++;\n } else {\n runCtx.results.failed++;\n }\n\n // Emit testEnd event\n state.onEvent?.({ type: \"testEnd\", test: result });\n\n return result;\n}\n\n/**\n * Run a suite and its children\n */\nasync function runSuite(\n runCtx: RunContext,\n suite: RegisteredSuite\n): Promise<SuiteResult> {\n const { state, context } = runCtx;\n\n const suiteInfo: SuiteInfo = {\n name: suite.name,\n path: suite.path,\n fullName: suite.path.join(\" > \") || suite.name,\n };\n\n // Emit suiteStart event\n state.onEvent?.({ type: \"suiteStart\", suite: suiteInfo });\n\n const startTime = performance.now();\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n // Check if entire suite should skip\n const shouldSkipSuite =\n suite.modifier === \"skip\" ||\n suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n suite.modifier !== \"only\" &&\n !hasOnlyDescendant(suite) &&\n !hasOnlyAncestor(suite));\n\n if (!shouldSkipSuite) {\n // Run beforeAll hooks\n const beforeAllResult = await executeHooks(context, suite.beforeAll);\n\n if (beforeAllResult.success) {\n // Run tests\n for (const test of suite.tests) {\n const result = await runTest(runCtx, test);\n if (result.status === \"pass\") passed++;\n else if (result.status === \"fail\") failed++;\n else skipped++;\n }\n\n // Run child suites\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n } else {\n // beforeAll failed - skip all tests in this suite\n for (const test of suite.tests) {\n const testResult: TestResult = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"fail\",\n duration: 0,\n error: beforeAllResult.error,\n };\n runCtx.results.tests.push(testResult);\n runCtx.results.failed++;\n failed++;\n // Emit testEnd event for the failed test\n state.onEvent?.({ type: \"testEnd\", test: testResult });\n }\n }\n\n // Run afterAll hooks\n await executeHooks(context, suite.afterAll);\n } else {\n // Skip all tests\n for (const test of suite.tests) {\n skipped++;\n runCtx.results.skipped++;\n runCtx.results.tests.push({\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"skip\",\n duration: 0,\n });\n }\n\n // Still process children (they might have .only)\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n }\n\n const duration = performance.now() - startTime;\n\n const suiteResult: SuiteResult = {\n ...suiteInfo,\n passed,\n failed,\n skipped,\n duration,\n };\n\n runCtx.results.suites.push(suiteResult);\n\n // Emit suiteEnd event\n state.onEvent?.({ type: \"suiteEnd\", suite: suiteResult });\n\n return suiteResult;\n}\n\n/**\n * Count tests in suites\n */\nfunction countTests(suites: RegisteredSuite[]): number {\n let count = 0;\n for (const suite of suites) {\n count += suite.tests.length;\n count += countTests(suite.children);\n }\n return count;\n}\n\n/**\n * Count suites\n */\nfunction countSuites(suites: RegisteredSuite[]): number {\n let count = suites.length;\n for (const suite of suites) {\n count += countSuites(suite.children);\n }\n return count;\n}\n\n/**\n * Main run function\n */\nexport async function runTests(state: TestState): Promise<RunResults> {\n const startTime = performance.now();\n\n const results: RunResults = {\n passed: 0,\n failed: 0,\n skipped: 0,\n todo: 0,\n total: 0,\n duration: 0,\n suites: [],\n tests: [],\n success: true,\n };\n\n const hasOnly = checkForOnly(state.suites);\n\n const runCtx: RunContext = {\n state,\n context: state.context,\n results,\n hasOnly,\n };\n\n // Emit runStart event\n const testCount = countTests(state.suites);\n const suiteCount = countSuites(state.suites);\n state.onEvent?.({ type: \"runStart\", testCount, suiteCount });\n\n // Run all suites\n for (const suite of state.suites) {\n await runSuite(runCtx, suite);\n }\n\n results.duration = performance.now() - startTime;\n results.total = results.passed + results.failed + results.skipped + results.todo;\n results.success = results.failed === 0;\n\n // Emit runEnd event\n state.onEvent?.({ type: \"runEnd\", results });\n\n return results;\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "9BA8E805A3739F0764756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "7C44782526B7BEE164756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -44,14 +44,7 @@ function setupTestEnvironment(context, options = {}) {
44
44
  const state = {
45
45
  context,
46
46
  stateMap,
47
- handlers: {
48
- onSuiteStart: options.onSuiteStart,
49
- onSuiteEnd: options.onSuiteEnd,
50
- onTestStart: options.onTestStart,
51
- onTestPass: options.onTestPass,
52
- onTestFail: options.onTestFail,
53
- onRunComplete: options.onRunComplete
54
- },
47
+ onEvent: options.onEvent,
55
48
  suites: [],
56
49
  currentSuite: null,
57
50
  handles: []
@@ -67,4 +60,4 @@ function setupTestEnvironment(context, options = {}) {
67
60
  }
68
61
  })
69
62
 
70
- //# debugId=53E8384DF049945A64756E2164756E21
63
+ //# debugId=581D819CD4BDCD1964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/setup.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext } from \"quickjs-emscripten\";\nimport { setupCore } from \"@ricsam/quickjs-core\";\nimport type { SetupTestOptions, TestEnvironmentHandle, TestState } from \"./types.cjs\";\nimport { createTestEnvironmentHandle } from \"./handle.cjs\";\nimport { setupDescribe, setupIt } from \"./globals/describe.cjs\";\nimport { setupHooks } from \"./globals/hooks.cjs\";\nimport { setupExpect } from \"./globals/expect.cjs\";\n\nexport function setupTestEnvironment(\n context: QuickJSContext,\n options: SetupTestOptions = {}\n): TestEnvironmentHandle {\n // Setup core if not provided\n const coreHandle = options.coreHandle ?? setupCore(context);\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Initialize internal state\n const state: TestState = {\n context,\n stateMap,\n handlers: {\n onSuiteStart: options.onSuiteStart,\n onSuiteEnd: options.onSuiteEnd,\n onTestStart: options.onTestStart,\n onTestPass: options.onTestPass,\n onTestFail: options.onTestFail,\n onRunComplete: options.onRunComplete,\n },\n suites: [],\n currentSuite: null,\n handles: [],\n };\n\n // Register describe/it/test globals\n const describeHandles = setupDescribe(context, state);\n const itHandles = setupIt(context, state);\n state.handles.push(...describeHandles, ...itHandles);\n\n // Register lifecycle hook globals\n const hookHandles = setupHooks(context, state);\n state.handles.push(...hookHandles);\n\n // Register expect global\n const expectHandles = setupExpect(context, state);\n state.handles.push(...expectHandles);\n\n return createTestEnvironmentHandle(state);\n}\n"
5
+ "import type { QuickJSContext } from \"quickjs-emscripten\";\nimport { setupCore } from \"@ricsam/quickjs-core\";\nimport type { SetupTestOptions, TestEnvironmentHandle, TestState } from \"./types.cjs\";\nimport { createTestEnvironmentHandle } from \"./handle.cjs\";\nimport { setupDescribe, setupIt } from \"./globals/describe.cjs\";\nimport { setupHooks } from \"./globals/hooks.cjs\";\nimport { setupExpect } from \"./globals/expect.cjs\";\n\nexport function setupTestEnvironment(\n context: QuickJSContext,\n options: SetupTestOptions = {}\n): TestEnvironmentHandle {\n // Setup core if not provided\n const coreHandle = options.coreHandle ?? setupCore(context);\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Initialize internal state\n const state: TestState = {\n context,\n stateMap,\n onEvent: options.onEvent,\n suites: [],\n currentSuite: null,\n handles: [],\n };\n\n // Register describe/it/test globals\n const describeHandles = setupDescribe(context, state);\n const itHandles = setupIt(context, state);\n state.handles.push(...describeHandles, ...itHandles);\n\n // Register lifecycle hook globals\n const hookHandles = setupHooks(context, state);\n state.handles.push(...hookHandles);\n\n // Register expect global\n const expectHandles = setupExpect(context, state);\n state.handles.push(...expectHandles);\n\n return createTestEnvironmentHandle(state);\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAC0B,IAA1B;AAE4C,IAA5C;AACuC,IAAvC;AAC2B,IAA3B;AAC4B,IAA5B;AAEO,SAAS,oBAAoB,CAClC,SACA,UAA4B,CAAC,GACN;AAAA,EAEvB,MAAM,aAAa,QAAQ,cAAc,8BAAU,OAAO;AAAA,EAC1D,MAAM,WAAW,QAAQ,YAAY,WAAW;AAAA,EAGhD,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,UAAU;AAAA,MACR,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,MACpB,YAAY,QAAQ;AAAA,MACpB,eAAe,QAAQ;AAAA,IACzB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,cAAc;AAAA,IACd,SAAS,CAAC;AAAA,EACZ;AAAA,EAGA,MAAM,kBAAkB,8BAAc,SAAS,KAAK;AAAA,EACpD,MAAM,YAAY,wBAAQ,SAAS,KAAK;AAAA,EACxC,MAAM,QAAQ,KAAK,GAAG,iBAAiB,GAAG,SAAS;AAAA,EAGnD,MAAM,cAAc,wBAAW,SAAS,KAAK;AAAA,EAC7C,MAAM,QAAQ,KAAK,GAAG,WAAW;AAAA,EAGjC,MAAM,gBAAgB,0BAAY,SAAS,KAAK;AAAA,EAChD,MAAM,QAAQ,KAAK,GAAG,aAAa;AAAA,EAEnC,OAAO,0CAA4B,KAAK;AAAA;",
8
- "debugId": "53E8384DF049945A64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAC0B,IAA1B;AAE4C,IAA5C;AACuC,IAAvC;AAC2B,IAA3B;AAC4B,IAA5B;AAEO,SAAS,oBAAoB,CAClC,SACA,UAA4B,CAAC,GACN;AAAA,EAEvB,MAAM,aAAa,QAAQ,cAAc,8BAAU,OAAO;AAAA,EAC1D,MAAM,WAAW,QAAQ,YAAY,WAAW;AAAA,EAGhD,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,cAAc;AAAA,IACd,SAAS,CAAC;AAAA,EACZ;AAAA,EAGA,MAAM,kBAAkB,8BAAc,SAAS,KAAK;AAAA,EACpD,MAAM,YAAY,wBAAQ,SAAS,KAAK;AAAA,EACxC,MAAM,QAAQ,KAAK,GAAG,iBAAiB,GAAG,SAAS;AAAA,EAGnD,MAAM,cAAc,wBAAW,SAAS,KAAK;AAAA,EAC7C,MAAM,QAAQ,KAAK,GAAG,WAAW;AAAA,EAGjC,MAAM,gBAAgB,0BAAY,SAAS,KAAK;AAAA,EAChD,MAAM,QAAQ,KAAK,GAAG,aAAa;AAAA,EAEnC,OAAO,0CAA4B,KAAK;AAAA;",
8
+ "debugId": "581D819CD4BDCD1964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export { setupTestEnvironment } from \"./setup.mjs\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.mjs\";\n"
5
+ "export { setupTestEnvironment } from \"./setup.mjs\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n TestEvent,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.mjs\";\n"
6
6
  ],
7
7
  "mappings": ";;AAAA;",
8
8
  "debugId": "FCD44CE91F43579C64756E2164756E21",
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "type": "module"
5
5
  }
@@ -174,7 +174,7 @@ async function runTest(runCtx, test) {
174
174
  runCtx.results.todo++;
175
175
  return result2;
176
176
  }
177
- state.handlers.onTestStart?.(testInfo);
177
+ state.onEvent?.({ type: "testStart", test: testInfo });
178
178
  const startTime = performance.now();
179
179
  const beforeEachHooks = collectBeforeEachHooks(test.suite);
180
180
  const beforeResult = await executeHooks(context, beforeEachHooks);
@@ -199,11 +199,10 @@ async function runTest(runCtx, test) {
199
199
  runCtx.results.tests.push(result);
200
200
  if (result.status === "pass") {
201
201
  runCtx.results.passed++;
202
- state.handlers.onTestPass?.(result);
203
202
  } else {
204
203
  runCtx.results.failed++;
205
- state.handlers.onTestFail?.(result);
206
204
  }
205
+ state.onEvent?.({ type: "testEnd", test: result });
207
206
  return result;
208
207
  }
209
208
  async function runSuite(runCtx, suite) {
@@ -213,7 +212,7 @@ async function runSuite(runCtx, suite) {
213
212
  path: suite.path,
214
213
  fullName: suite.path.join(" > ") || suite.name
215
214
  };
216
- state.handlers.onSuiteStart?.(suiteInfo);
215
+ state.onEvent?.({ type: "suiteStart", suite: suiteInfo });
217
216
  const startTime = performance.now();
218
217
  let passed = 0;
219
218
  let failed = 0;
@@ -247,7 +246,7 @@ async function runSuite(runCtx, suite) {
247
246
  runCtx.results.tests.push(testResult);
248
247
  runCtx.results.failed++;
249
248
  failed++;
250
- state.handlers.onTestFail?.(testResult);
249
+ state.onEvent?.({ type: "testEnd", test: testResult });
251
250
  }
252
251
  }
253
252
  await executeHooks(context, suite.afterAll);
@@ -276,9 +275,24 @@ async function runSuite(runCtx, suite) {
276
275
  duration
277
276
  };
278
277
  runCtx.results.suites.push(suiteResult);
279
- state.handlers.onSuiteEnd?.(suiteResult);
278
+ state.onEvent?.({ type: "suiteEnd", suite: suiteResult });
280
279
  return suiteResult;
281
280
  }
281
+ function countTests(suites) {
282
+ let count = 0;
283
+ for (const suite of suites) {
284
+ count += suite.tests.length;
285
+ count += countTests(suite.children);
286
+ }
287
+ return count;
288
+ }
289
+ function countSuites(suites) {
290
+ let count = suites.length;
291
+ for (const suite of suites) {
292
+ count += countSuites(suite.children);
293
+ }
294
+ return count;
295
+ }
282
296
  async function runTests(state) {
283
297
  const startTime = performance.now();
284
298
  const results = {
@@ -299,17 +313,20 @@ async function runTests(state) {
299
313
  results,
300
314
  hasOnly
301
315
  };
316
+ const testCount = countTests(state.suites);
317
+ const suiteCount = countSuites(state.suites);
318
+ state.onEvent?.({ type: "runStart", testCount, suiteCount });
302
319
  for (const suite of state.suites) {
303
320
  await runSuite(runCtx, suite);
304
321
  }
305
322
  results.duration = performance.now() - startTime;
306
323
  results.total = results.passed + results.failed + results.skipped + results.todo;
307
324
  results.success = results.failed === 0;
308
- state.handlers.onRunComplete?.(results);
325
+ state.onEvent?.({ type: "runEnd", results });
309
326
  return results;
310
327
  }
311
328
  export {
312
329
  runTests
313
330
  };
314
331
 
315
- //# debugId=846C154A81717D9264756E2164756E21
332
+ //# debugId=0EFFC4F7FAB8133964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/runner.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type {\n TestState,\n RegisteredSuite,\n RegisteredTest,\n RunResults,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n} from \"./types.mjs\";\n\ninterface RunContext {\n state: TestState;\n context: QuickJSContext;\n results: RunResults;\n hasOnly: boolean;\n}\n\n/**\n * Check if any test or suite has .only modifier\n */\nfunction checkForOnly(suites: RegisteredSuite[]): boolean {\n for (const suite of suites) {\n if (suite.modifier === \"only\") return true;\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n if (checkForOnly(suite.children)) return true;\n }\n return false;\n}\n\n/**\n * Execute a function handle (sync or async)\n * Captures AssertionError properties from expect() matchers\n */\nasync function executeFunction(\n context: QuickJSContext,\n fn: QuickJSHandle\n): Promise<{ success: boolean; error?: TestError }> {\n const result = context.callFunction(fn, context.undefined);\n\n if (result.error) {\n const errorDump = context.dump(result.error);\n result.error.dispose();\n\n // Extract error properties (including expect() matcher metadata)\n return {\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n };\n }\n\n // Check if result is a promise\n const isPromiseCode = context.evalCode(`\n (function(val) { return val && typeof val.then === 'function'; })\n `);\n\n if (isPromiseCode.error) {\n isPromiseCode.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const checkResult = context.callFunction(\n isPromiseCode.value,\n context.undefined,\n result.value\n );\n isPromiseCode.value.dispose();\n\n if (checkResult.error) {\n checkResult.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const isPromise = context.dump(checkResult.value);\n checkResult.value.dispose();\n\n if (!isPromise) {\n result.value.dispose();\n return { success: true };\n }\n\n // Handle async - wrap in promise resolution tracking\n return new Promise((resolve) => {\n const promiseHandle = result.value;\n\n // Create resolve/reject callbacks\n const thenFn = context.newFunction(\"then\", () => {\n resolve({ success: true });\n return context.undefined;\n });\n\n const catchFn = context.newFunction(\"catch\", (errorHandle) => {\n const errorDump = context.dump(errorHandle);\n resolve({\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n });\n return context.undefined;\n });\n\n // Get the 'then' property from promise\n const thenProp = context.getProp(promiseHandle, \"then\");\n\n // Call promise.then().catch()\n const thenResult = context.callFunction(thenProp, promiseHandle, thenFn);\n thenProp.dispose();\n\n if (thenResult.error) {\n thenResult.error.dispose();\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n resolve({ success: true });\n return;\n }\n\n // Get 'catch' property from thenResult\n const catchProp = context.getProp(thenResult.value, \"catch\");\n const catchResult = context.callFunction(\n catchProp,\n thenResult.value,\n catchFn\n );\n catchProp.dispose();\n thenResult.value.dispose();\n\n if (catchResult.error) {\n catchResult.error.dispose();\n } else {\n catchResult.value.dispose();\n }\n\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n\n // Execute pending jobs to process the promise\n context.runtime.executePendingJobs();\n });\n}\n\n/**\n * Execute all hooks in an array\n */\nasync function executeHooks(\n context: QuickJSContext,\n hooks: QuickJSHandle[]\n): Promise<{ success: boolean; error?: TestError }> {\n for (const hook of hooks) {\n const result = await executeFunction(context, hook);\n if (!result.success) {\n return result;\n }\n }\n return { success: true };\n}\n\n/**\n * Collect beforeEach hooks from outer to inner\n */\nfunction collectBeforeEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n for (const s of path) {\n hooks.push(...s.beforeEach);\n }\n\n return hooks;\n}\n\n/**\n * Collect afterEach hooks from inner to outer\n */\nfunction collectAfterEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n // Reverse for inner to outer\n for (const s of path.reverse()) {\n hooks.push(...s.afterEach);\n }\n\n return hooks;\n}\n\n/**\n * Check if any ancestor suite has .only modifier\n */\nfunction hasOnlyAncestor(suite: RegisteredSuite): boolean {\n let current: RegisteredSuite | null = suite;\n while (current) {\n if (current.modifier === \"only\") return true;\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Check if suite has any .only descendants\n */\nfunction hasOnlyDescendant(suite: RegisteredSuite): boolean {\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n for (const child of suite.children) {\n if (child.modifier === \"only\") return true;\n if (hasOnlyDescendant(child)) return true;\n }\n return false;\n}\n\n/**\n * Run a single test\n */\nasync function runTest(\n runCtx: RunContext,\n test: RegisteredTest\n): Promise<TestResult> {\n const { state, context } = runCtx;\n\n const testInfo: TestInfo = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n };\n\n // Check if should skip\n const shouldSkip =\n test.modifier === \"skip\" ||\n test.modifier === \"todo\" ||\n test.suite.modifier === \"skip\" ||\n test.suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n test.modifier !== \"only\" &&\n !hasOnlyAncestor(test.suite));\n\n if (shouldSkip) {\n const result: TestResult = {\n ...testInfo,\n status: test.modifier === \"todo\" ? \"todo\" : \"skip\",\n duration: 0,\n };\n\n runCtx.results.tests.push(result);\n if (result.status === \"skip\") runCtx.results.skipped++;\n if (result.status === \"todo\") runCtx.results.todo++;\n\n return result;\n }\n\n // Call onTestStart\n state.handlers.onTestStart?.(testInfo);\n\n const startTime = performance.now();\n\n // Run beforeEach hooks\n const beforeEachHooks = collectBeforeEachHooks(test.suite);\n const beforeResult = await executeHooks(context, beforeEachHooks);\n\n let testError: TestError | undefined;\n\n if (!beforeResult.success) {\n testError = beforeResult.error;\n } else {\n // Run the test\n const testResult = await executeFunction(context, test.fn);\n if (!testResult.success) {\n testError = testResult.error;\n }\n }\n\n // Run afterEach hooks (even if test failed)\n const afterEachHooks = collectAfterEachHooks(test.suite);\n await executeHooks(context, afterEachHooks);\n\n const duration = performance.now() - startTime;\n\n const result: TestResult = {\n ...testInfo,\n status: testError ? \"fail\" : \"pass\",\n duration,\n error: testError,\n };\n\n runCtx.results.tests.push(result);\n\n if (result.status === \"pass\") {\n runCtx.results.passed++;\n state.handlers.onTestPass?.(result);\n } else {\n runCtx.results.failed++;\n state.handlers.onTestFail?.(result);\n }\n\n return result;\n}\n\n/**\n * Run a suite and its children\n */\nasync function runSuite(\n runCtx: RunContext,\n suite: RegisteredSuite\n): Promise<SuiteResult> {\n const { state, context } = runCtx;\n\n const suiteInfo: SuiteInfo = {\n name: suite.name,\n path: suite.path,\n fullName: suite.path.join(\" > \") || suite.name,\n };\n\n // Call onSuiteStart\n state.handlers.onSuiteStart?.(suiteInfo);\n\n const startTime = performance.now();\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n // Check if entire suite should skip\n const shouldSkipSuite =\n suite.modifier === \"skip\" ||\n suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n suite.modifier !== \"only\" &&\n !hasOnlyDescendant(suite) &&\n !hasOnlyAncestor(suite));\n\n if (!shouldSkipSuite) {\n // Run beforeAll hooks\n const beforeAllResult = await executeHooks(context, suite.beforeAll);\n\n if (beforeAllResult.success) {\n // Run tests\n for (const test of suite.tests) {\n const result = await runTest(runCtx, test);\n if (result.status === \"pass\") passed++;\n else if (result.status === \"fail\") failed++;\n else skipped++;\n }\n\n // Run child suites\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n } else {\n // beforeAll failed - skip all tests in this suite\n for (const test of suite.tests) {\n const testResult: TestResult = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"fail\",\n duration: 0,\n error: beforeAllResult.error,\n };\n runCtx.results.tests.push(testResult);\n runCtx.results.failed++;\n failed++;\n state.handlers.onTestFail?.(testResult);\n }\n }\n\n // Run afterAll hooks\n await executeHooks(context, suite.afterAll);\n } else {\n // Skip all tests\n for (const test of suite.tests) {\n skipped++;\n runCtx.results.skipped++;\n runCtx.results.tests.push({\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"skip\",\n duration: 0,\n });\n }\n\n // Still process children (they might have .only)\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n }\n\n const duration = performance.now() - startTime;\n\n const suiteResult: SuiteResult = {\n ...suiteInfo,\n passed,\n failed,\n skipped,\n duration,\n };\n\n runCtx.results.suites.push(suiteResult);\n\n // Call onSuiteEnd\n state.handlers.onSuiteEnd?.(suiteResult);\n\n return suiteResult;\n}\n\n/**\n * Main run function\n */\nexport async function runTests(state: TestState): Promise<RunResults> {\n const startTime = performance.now();\n\n const results: RunResults = {\n passed: 0,\n failed: 0,\n skipped: 0,\n todo: 0,\n total: 0,\n duration: 0,\n suites: [],\n tests: [],\n success: true,\n };\n\n const hasOnly = checkForOnly(state.suites);\n\n const runCtx: RunContext = {\n state,\n context: state.context,\n results,\n hasOnly,\n };\n\n // Run all suites\n for (const suite of state.suites) {\n await runSuite(runCtx, suite);\n }\n\n results.duration = performance.now() - startTime;\n results.total = results.passed + results.failed + results.skipped + results.todo;\n results.success = results.failed === 0;\n\n // Call onRunComplete\n state.handlers.onRunComplete?.(results);\n\n return results;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type {\n TestState,\n RegisteredSuite,\n RegisteredTest,\n RunResults,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n TestEvent,\n} from \"./types.mjs\";\n\ninterface RunContext {\n state: TestState;\n context: QuickJSContext;\n results: RunResults;\n hasOnly: boolean;\n}\n\n/**\n * Check if any test or suite has .only modifier\n */\nfunction checkForOnly(suites: RegisteredSuite[]): boolean {\n for (const suite of suites) {\n if (suite.modifier === \"only\") return true;\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n if (checkForOnly(suite.children)) return true;\n }\n return false;\n}\n\n/**\n * Execute a function handle (sync or async)\n * Captures AssertionError properties from expect() matchers\n */\nasync function executeFunction(\n context: QuickJSContext,\n fn: QuickJSHandle\n): Promise<{ success: boolean; error?: TestError }> {\n const result = context.callFunction(fn, context.undefined);\n\n if (result.error) {\n const errorDump = context.dump(result.error);\n result.error.dispose();\n\n // Extract error properties (including expect() matcher metadata)\n return {\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n };\n }\n\n // Check if result is a promise\n const isPromiseCode = context.evalCode(`\n (function(val) { return val && typeof val.then === 'function'; })\n `);\n\n if (isPromiseCode.error) {\n isPromiseCode.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const checkResult = context.callFunction(\n isPromiseCode.value,\n context.undefined,\n result.value\n );\n isPromiseCode.value.dispose();\n\n if (checkResult.error) {\n checkResult.error.dispose();\n result.value.dispose();\n return { success: true };\n }\n\n const isPromise = context.dump(checkResult.value);\n checkResult.value.dispose();\n\n if (!isPromise) {\n result.value.dispose();\n return { success: true };\n }\n\n // Handle async - wrap in promise resolution tracking\n return new Promise((resolve) => {\n const promiseHandle = result.value;\n\n // Create resolve/reject callbacks\n const thenFn = context.newFunction(\"then\", () => {\n resolve({ success: true });\n return context.undefined;\n });\n\n const catchFn = context.newFunction(\"catch\", (errorHandle) => {\n const errorDump = context.dump(errorHandle);\n resolve({\n success: false,\n error: {\n message: errorDump?.message || String(errorDump),\n stack: errorDump?.stack,\n expected: errorDump?.expected,\n actual: errorDump?.actual,\n matcherName: errorDump?.matcherName,\n },\n });\n return context.undefined;\n });\n\n // Get the 'then' property from promise\n const thenProp = context.getProp(promiseHandle, \"then\");\n\n // Call promise.then().catch()\n const thenResult = context.callFunction(thenProp, promiseHandle, thenFn);\n thenProp.dispose();\n\n if (thenResult.error) {\n thenResult.error.dispose();\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n resolve({ success: true });\n return;\n }\n\n // Get 'catch' property from thenResult\n const catchProp = context.getProp(thenResult.value, \"catch\");\n const catchResult = context.callFunction(\n catchProp,\n thenResult.value,\n catchFn\n );\n catchProp.dispose();\n thenResult.value.dispose();\n\n if (catchResult.error) {\n catchResult.error.dispose();\n } else {\n catchResult.value.dispose();\n }\n\n promiseHandle.dispose();\n thenFn.dispose();\n catchFn.dispose();\n\n // Execute pending jobs to process the promise\n context.runtime.executePendingJobs();\n });\n}\n\n/**\n * Execute all hooks in an array\n */\nasync function executeHooks(\n context: QuickJSContext,\n hooks: QuickJSHandle[]\n): Promise<{ success: boolean; error?: TestError }> {\n for (const hook of hooks) {\n const result = await executeFunction(context, hook);\n if (!result.success) {\n return result;\n }\n }\n return { success: true };\n}\n\n/**\n * Collect beforeEach hooks from outer to inner\n */\nfunction collectBeforeEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n for (const s of path) {\n hooks.push(...s.beforeEach);\n }\n\n return hooks;\n}\n\n/**\n * Collect afterEach hooks from inner to outer\n */\nfunction collectAfterEachHooks(suite: RegisteredSuite): QuickJSHandle[] {\n const hooks: QuickJSHandle[] = [];\n const path: RegisteredSuite[] = [];\n\n let current: RegisteredSuite | null = suite;\n while (current) {\n path.unshift(current);\n current = current.parent;\n }\n\n // Reverse for inner to outer\n for (const s of path.reverse()) {\n hooks.push(...s.afterEach);\n }\n\n return hooks;\n}\n\n/**\n * Check if any ancestor suite has .only modifier\n */\nfunction hasOnlyAncestor(suite: RegisteredSuite): boolean {\n let current: RegisteredSuite | null = suite;\n while (current) {\n if (current.modifier === \"only\") return true;\n current = current.parent;\n }\n return false;\n}\n\n/**\n * Check if suite has any .only descendants\n */\nfunction hasOnlyDescendant(suite: RegisteredSuite): boolean {\n for (const test of suite.tests) {\n if (test.modifier === \"only\") return true;\n }\n for (const child of suite.children) {\n if (child.modifier === \"only\") return true;\n if (hasOnlyDescendant(child)) return true;\n }\n return false;\n}\n\n/**\n * Run a single test\n */\nasync function runTest(\n runCtx: RunContext,\n test: RegisteredTest\n): Promise<TestResult> {\n const { state, context } = runCtx;\n\n const testInfo: TestInfo = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n };\n\n // Check if should skip\n const shouldSkip =\n test.modifier === \"skip\" ||\n test.modifier === \"todo\" ||\n test.suite.modifier === \"skip\" ||\n test.suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n test.modifier !== \"only\" &&\n !hasOnlyAncestor(test.suite));\n\n if (shouldSkip) {\n const result: TestResult = {\n ...testInfo,\n status: test.modifier === \"todo\" ? \"todo\" : \"skip\",\n duration: 0,\n };\n\n runCtx.results.tests.push(result);\n if (result.status === \"skip\") runCtx.results.skipped++;\n if (result.status === \"todo\") runCtx.results.todo++;\n\n return result;\n }\n\n // Emit testStart event\n state.onEvent?.({ type: \"testStart\", test: testInfo });\n\n const startTime = performance.now();\n\n // Run beforeEach hooks\n const beforeEachHooks = collectBeforeEachHooks(test.suite);\n const beforeResult = await executeHooks(context, beforeEachHooks);\n\n let testError: TestError | undefined;\n\n if (!beforeResult.success) {\n testError = beforeResult.error;\n } else {\n // Run the test\n const testResult = await executeFunction(context, test.fn);\n if (!testResult.success) {\n testError = testResult.error;\n }\n }\n\n // Run afterEach hooks (even if test failed)\n const afterEachHooks = collectAfterEachHooks(test.suite);\n await executeHooks(context, afterEachHooks);\n\n const duration = performance.now() - startTime;\n\n const result: TestResult = {\n ...testInfo,\n status: testError ? \"fail\" : \"pass\",\n duration,\n error: testError,\n };\n\n runCtx.results.tests.push(result);\n\n if (result.status === \"pass\") {\n runCtx.results.passed++;\n } else {\n runCtx.results.failed++;\n }\n\n // Emit testEnd event\n state.onEvent?.({ type: \"testEnd\", test: result });\n\n return result;\n}\n\n/**\n * Run a suite and its children\n */\nasync function runSuite(\n runCtx: RunContext,\n suite: RegisteredSuite\n): Promise<SuiteResult> {\n const { state, context } = runCtx;\n\n const suiteInfo: SuiteInfo = {\n name: suite.name,\n path: suite.path,\n fullName: suite.path.join(\" > \") || suite.name,\n };\n\n // Emit suiteStart event\n state.onEvent?.({ type: \"suiteStart\", suite: suiteInfo });\n\n const startTime = performance.now();\n let passed = 0;\n let failed = 0;\n let skipped = 0;\n\n // Check if entire suite should skip\n const shouldSkipSuite =\n suite.modifier === \"skip\" ||\n suite.modifier === \"todo\" ||\n (runCtx.hasOnly &&\n suite.modifier !== \"only\" &&\n !hasOnlyDescendant(suite) &&\n !hasOnlyAncestor(suite));\n\n if (!shouldSkipSuite) {\n // Run beforeAll hooks\n const beforeAllResult = await executeHooks(context, suite.beforeAll);\n\n if (beforeAllResult.success) {\n // Run tests\n for (const test of suite.tests) {\n const result = await runTest(runCtx, test);\n if (result.status === \"pass\") passed++;\n else if (result.status === \"fail\") failed++;\n else skipped++;\n }\n\n // Run child suites\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n } else {\n // beforeAll failed - skip all tests in this suite\n for (const test of suite.tests) {\n const testResult: TestResult = {\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"fail\",\n duration: 0,\n error: beforeAllResult.error,\n };\n runCtx.results.tests.push(testResult);\n runCtx.results.failed++;\n failed++;\n // Emit testEnd event for the failed test\n state.onEvent?.({ type: \"testEnd\", test: testResult });\n }\n }\n\n // Run afterAll hooks\n await executeHooks(context, suite.afterAll);\n } else {\n // Skip all tests\n for (const test of suite.tests) {\n skipped++;\n runCtx.results.skipped++;\n runCtx.results.tests.push({\n name: test.name,\n suite: test.suite.path,\n fullName:\n test.suite.path.length > 0\n ? [...test.suite.path, test.name].join(\" > \")\n : test.name,\n status: \"skip\",\n duration: 0,\n });\n }\n\n // Still process children (they might have .only)\n for (const child of suite.children) {\n await runSuite(runCtx, child);\n }\n }\n\n const duration = performance.now() - startTime;\n\n const suiteResult: SuiteResult = {\n ...suiteInfo,\n passed,\n failed,\n skipped,\n duration,\n };\n\n runCtx.results.suites.push(suiteResult);\n\n // Emit suiteEnd event\n state.onEvent?.({ type: \"suiteEnd\", suite: suiteResult });\n\n return suiteResult;\n}\n\n/**\n * Count tests in suites\n */\nfunction countTests(suites: RegisteredSuite[]): number {\n let count = 0;\n for (const suite of suites) {\n count += suite.tests.length;\n count += countTests(suite.children);\n }\n return count;\n}\n\n/**\n * Count suites\n */\nfunction countSuites(suites: RegisteredSuite[]): number {\n let count = suites.length;\n for (const suite of suites) {\n count += countSuites(suite.children);\n }\n return count;\n}\n\n/**\n * Main run function\n */\nexport async function runTests(state: TestState): Promise<RunResults> {\n const startTime = performance.now();\n\n const results: RunResults = {\n passed: 0,\n failed: 0,\n skipped: 0,\n todo: 0,\n total: 0,\n duration: 0,\n suites: [],\n tests: [],\n success: true,\n };\n\n const hasOnly = checkForOnly(state.suites);\n\n const runCtx: RunContext = {\n state,\n context: state.context,\n results,\n hasOnly,\n };\n\n // Emit runStart event\n const testCount = countTests(state.suites);\n const suiteCount = countSuites(state.suites);\n state.onEvent?.({ type: \"runStart\", testCount, suiteCount });\n\n // Run all suites\n for (const suite of state.suites) {\n await runSuite(runCtx, suite);\n }\n\n results.duration = performance.now() - startTime;\n results.total = results.passed + results.failed + results.skipped + results.todo;\n results.success = results.failed === 0;\n\n // Emit runEnd event\n state.onEvent?.({ type: \"runEnd\", results });\n\n return results;\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "846C154A81717D9264756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "0EFFC4F7FAB8133964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -11,14 +11,7 @@ function setupTestEnvironment(context, options = {}) {
11
11
  const state = {
12
12
  context,
13
13
  stateMap,
14
- handlers: {
15
- onSuiteStart: options.onSuiteStart,
16
- onSuiteEnd: options.onSuiteEnd,
17
- onTestStart: options.onTestStart,
18
- onTestPass: options.onTestPass,
19
- onTestFail: options.onTestFail,
20
- onRunComplete: options.onRunComplete
21
- },
14
+ onEvent: options.onEvent,
22
15
  suites: [],
23
16
  currentSuite: null,
24
17
  handles: []
@@ -36,4 +29,4 @@ export {
36
29
  setupTestEnvironment
37
30
  };
38
31
 
39
- //# debugId=F80D6B4A8EEE5DFF64756E2164756E21
32
+ //# debugId=404E566BCE6A227164756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/setup.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext } from \"quickjs-emscripten\";\nimport { setupCore } from \"@ricsam/quickjs-core\";\nimport type { SetupTestOptions, TestEnvironmentHandle, TestState } from \"./types.mjs\";\nimport { createTestEnvironmentHandle } from \"./handle.mjs\";\nimport { setupDescribe, setupIt } from \"./globals/describe.mjs\";\nimport { setupHooks } from \"./globals/hooks.mjs\";\nimport { setupExpect } from \"./globals/expect.mjs\";\n\nexport function setupTestEnvironment(\n context: QuickJSContext,\n options: SetupTestOptions = {}\n): TestEnvironmentHandle {\n // Setup core if not provided\n const coreHandle = options.coreHandle ?? setupCore(context);\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Initialize internal state\n const state: TestState = {\n context,\n stateMap,\n handlers: {\n onSuiteStart: options.onSuiteStart,\n onSuiteEnd: options.onSuiteEnd,\n onTestStart: options.onTestStart,\n onTestPass: options.onTestPass,\n onTestFail: options.onTestFail,\n onRunComplete: options.onRunComplete,\n },\n suites: [],\n currentSuite: null,\n handles: [],\n };\n\n // Register describe/it/test globals\n const describeHandles = setupDescribe(context, state);\n const itHandles = setupIt(context, state);\n state.handles.push(...describeHandles, ...itHandles);\n\n // Register lifecycle hook globals\n const hookHandles = setupHooks(context, state);\n state.handles.push(...hookHandles);\n\n // Register expect global\n const expectHandles = setupExpect(context, state);\n state.handles.push(...expectHandles);\n\n return createTestEnvironmentHandle(state);\n}\n"
5
+ "import type { QuickJSContext } from \"quickjs-emscripten\";\nimport { setupCore } from \"@ricsam/quickjs-core\";\nimport type { SetupTestOptions, TestEnvironmentHandle, TestState } from \"./types.mjs\";\nimport { createTestEnvironmentHandle } from \"./handle.mjs\";\nimport { setupDescribe, setupIt } from \"./globals/describe.mjs\";\nimport { setupHooks } from \"./globals/hooks.mjs\";\nimport { setupExpect } from \"./globals/expect.mjs\";\n\nexport function setupTestEnvironment(\n context: QuickJSContext,\n options: SetupTestOptions = {}\n): TestEnvironmentHandle {\n // Setup core if not provided\n const coreHandle = options.coreHandle ?? setupCore(context);\n const stateMap = options.stateMap ?? coreHandle.stateMap;\n\n // Initialize internal state\n const state: TestState = {\n context,\n stateMap,\n onEvent: options.onEvent,\n suites: [],\n currentSuite: null,\n handles: [],\n };\n\n // Register describe/it/test globals\n const describeHandles = setupDescribe(context, state);\n const itHandles = setupIt(context, state);\n state.handles.push(...describeHandles, ...itHandles);\n\n // Register lifecycle hook globals\n const hookHandles = setupHooks(context, state);\n state.handles.push(...hookHandles);\n\n // Register expect global\n const expectHandles = setupExpect(context, state);\n state.handles.push(...expectHandles);\n\n return createTestEnvironmentHandle(state);\n}\n"
6
6
  ],
7
- "mappings": ";;AACA;AAEA;AACA;AACA;AACA;AAEO,SAAS,oBAAoB,CAClC,SACA,UAA4B,CAAC,GACN;AAAA,EAEvB,MAAM,aAAa,QAAQ,cAAc,UAAU,OAAO;AAAA,EAC1D,MAAM,WAAW,QAAQ,YAAY,WAAW;AAAA,EAGhD,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,UAAU;AAAA,MACR,cAAc,QAAQ;AAAA,MACtB,YAAY,QAAQ;AAAA,MACpB,aAAa,QAAQ;AAAA,MACrB,YAAY,QAAQ;AAAA,MACpB,YAAY,QAAQ;AAAA,MACpB,eAAe,QAAQ;AAAA,IACzB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,cAAc;AAAA,IACd,SAAS,CAAC;AAAA,EACZ;AAAA,EAGA,MAAM,kBAAkB,cAAc,SAAS,KAAK;AAAA,EACpD,MAAM,YAAY,QAAQ,SAAS,KAAK;AAAA,EACxC,MAAM,QAAQ,KAAK,GAAG,iBAAiB,GAAG,SAAS;AAAA,EAGnD,MAAM,cAAc,WAAW,SAAS,KAAK;AAAA,EAC7C,MAAM,QAAQ,KAAK,GAAG,WAAW;AAAA,EAGjC,MAAM,gBAAgB,YAAY,SAAS,KAAK;AAAA,EAChD,MAAM,QAAQ,KAAK,GAAG,aAAa;AAAA,EAEnC,OAAO,4BAA4B,KAAK;AAAA;",
8
- "debugId": "F80D6B4A8EEE5DFF64756E2164756E21",
7
+ "mappings": ";;AACA;AAEA;AACA;AACA;AACA;AAEO,SAAS,oBAAoB,CAClC,SACA,UAA4B,CAAC,GACN;AAAA,EAEvB,MAAM,aAAa,QAAQ,cAAc,UAAU,OAAO;AAAA,EAC1D,MAAM,WAAW,QAAQ,YAAY,WAAW;AAAA,EAGhD,MAAM,QAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA,SAAS,QAAQ;AAAA,IACjB,QAAQ,CAAC;AAAA,IACT,cAAc;AAAA,IACd,SAAS,CAAC;AAAA,EACZ;AAAA,EAGA,MAAM,kBAAkB,cAAc,SAAS,KAAK;AAAA,EACpD,MAAM,YAAY,QAAQ,SAAS,KAAK;AAAA,EACxC,MAAM,QAAQ,KAAK,GAAG,iBAAiB,GAAG,SAAS;AAAA,EAGnD,MAAM,cAAc,WAAW,SAAS,KAAK;AAAA,EAC7C,MAAM,QAAQ,KAAK,GAAG,WAAW;AAAA,EAGjC,MAAM,gBAAgB,YAAY,SAAS,KAAK;AAAA,EAChD,MAAM,QAAQ,KAAK,GAAG,aAAa;AAAA,EAEnC,OAAO,4BAA4B,KAAK;AAAA;",
8
+ "debugId": "404E566BCE6A227164756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,2 +1,2 @@
1
1
  export { setupTestEnvironment } from "./setup.ts";
2
- export type { SetupTestOptions, TestEnvironmentHandle, SuiteInfo, SuiteResult, TestInfo, TestResult, TestError, RunResults, } from "./types.ts";
2
+ export type { SetupTestOptions, TestEnvironmentHandle, TestEvent, SuiteInfo, SuiteResult, TestInfo, TestResult, TestError, RunResults, } from "./types.ts";
@@ -1,12 +1,28 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
  import type { StateMap, CoreHandle } from "@ricsam/quickjs-core";
3
+ export type TestEvent = {
4
+ type: "runStart";
5
+ testCount: number;
6
+ suiteCount: number;
7
+ } | {
8
+ type: "suiteStart";
9
+ suite: SuiteInfo;
10
+ } | {
11
+ type: "suiteEnd";
12
+ suite: SuiteResult;
13
+ } | {
14
+ type: "testStart";
15
+ test: TestInfo;
16
+ } | {
17
+ type: "testEnd";
18
+ test: TestResult;
19
+ } | {
20
+ type: "runEnd";
21
+ results: RunResults;
22
+ };
3
23
  export interface SetupTestOptions {
4
- onSuiteStart?: (suite: SuiteInfo) => void;
5
- onSuiteEnd?: (suite: SuiteResult) => void;
6
- onTestStart?: (test: TestInfo) => void;
7
- onTestPass?: (test: TestResult) => void;
8
- onTestFail?: (test: TestResult) => void;
9
- onRunComplete?: (results: RunResults) => void;
24
+ onEvent?: (event: TestEvent) => void;
25
+ testTimeout?: number;
10
26
  stateMap?: StateMap;
11
27
  coreHandle?: CoreHandle;
12
28
  }
@@ -60,14 +76,7 @@ export interface RunResults {
60
76
  export interface TestState {
61
77
  context: QuickJSContext;
62
78
  stateMap: StateMap;
63
- handlers: {
64
- onSuiteStart?: (suite: SuiteInfo) => void;
65
- onSuiteEnd?: (suite: SuiteResult) => void;
66
- onTestStart?: (test: TestInfo) => void;
67
- onTestPass?: (test: TestResult) => void;
68
- onTestFail?: (test: TestResult) => void;
69
- onRunComplete?: (results: RunResults) => void;
70
- };
79
+ onEvent?: (event: TestEvent) => void;
71
80
  suites: RegisteredSuite[];
72
81
  currentSuite: RegisteredSuite | null;
73
82
  /** Handles to dispose when environment is disposed */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "description": "Test environment for QuickJS with Bun/Jest/Vitest-compatible primitives",
5
5
  "main": "./dist/cjs/index.cjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -22,7 +22,7 @@
22
22
  "quickjs-emscripten": ">=0.31.0"
23
23
  },
24
24
  "dependencies": {
25
- "@ricsam/quickjs-core": "^0.2.15"
25
+ "@ricsam/quickjs-core": "^0.2.16"
26
26
  },
27
27
  "author": "Richard Samuelsson",
28
28
  "license": "MIT",