@ricsam/quickjs-test-environment 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/describe.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite, RegisteredTest } from \"../types.ts\";\n\nlet suiteIdCounter = 0;\nlet testIdCounter = 0;\n\nexport function createSuite(\n name: string,\n parent: RegisteredSuite | null,\n modifier: RegisteredSuite[\"modifier\"] = \"none\"\n): RegisteredSuite {\n return {\n id: `suite_${++suiteIdCounter}`,\n name,\n path: parent ? [...parent.path, name] : [name],\n tests: [],\n beforeAll: [],\n afterAll: [],\n beforeEach: [],\n afterEach: [],\n children: [],\n parent,\n modifier,\n };\n}\n\nexport function setupDescribe(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create describe function with modifier\n const createDescribeFn = (modifier: RegisteredSuite[\"modifier\"]) => {\n return context.newFunction(\"describe\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n // Create new suite\n const suite = createSuite(name, state.currentSuite, modifier);\n\n // Add to parent or root\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Execute the describe body to discover nested tests\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Error in describe \"${name}\": ${error}`);\n }\n result.value.dispose();\n } finally {\n state.currentSuite = previousSuite;\n }\n\n return context.undefined;\n });\n };\n\n // describe()\n const describeFn = createDescribeFn(\"none\");\n context.setProp(context.global, \"describe\", describeFn);\n handles.push(describeFn);\n\n // describe.skip()\n const describeSkipFn = createDescribeFn(\"skip\");\n context.setProp(describeFn, \"skip\", describeSkipFn);\n handles.push(describeSkipFn);\n\n // describe.only()\n const describeOnlyFn = createDescribeFn(\"only\");\n context.setProp(describeFn, \"only\", describeOnlyFn);\n handles.push(describeOnlyFn);\n\n // describe.todo() - fn is optional\n const describeTodoFn = context.newFunction(\n \"describe.todo\",\n (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n const suite = createSuite(name, state.currentSuite, \"todo\");\n\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Only execute body if provided and is a function\n if (fnHandle && context.typeof(fnHandle) === \"function\") {\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n } finally {\n state.currentSuite = previousSuite;\n }\n }\n\n return context.undefined;\n }\n );\n context.setProp(describeFn, \"todo\", describeTodoFn);\n handles.push(describeTodoFn);\n\n return handles;\n}\n\nexport function setupIt(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create it/test function with modifier\n const createItFn = (modifier: RegisteredTest[\"modifier\"]) => {\n return context.newFunction(\"it\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n // Create implicit root suite for top-level tests\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // Dup the function handle to keep it alive\n const fnDup = fnHandle.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier,\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n };\n\n // it()\n const itFn = createItFn(\"none\");\n context.setProp(context.global, \"it\", itFn);\n handles.push(itFn);\n\n // it.skip()\n const itSkipFn = createItFn(\"skip\");\n context.setProp(itFn, \"skip\", itSkipFn);\n handles.push(itSkipFn);\n\n // it.only()\n const itOnlyFn = createItFn(\"only\");\n context.setProp(itFn, \"only\", itOnlyFn);\n handles.push(itOnlyFn);\n\n // it.todo() - fn is optional\n const itTodoFn = context.newFunction(\"it.todo\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // fn is optional for todo - use undefined dup if not provided\n const fnDup =\n fnHandle && context.typeof(fnHandle) === \"function\"\n ? fnHandle.dup()\n : context.undefined.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier: \"todo\",\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n context.setProp(itFn, \"todo\", itTodoFn);\n handles.push(itTodoFn);\n\n // test() - alias for it()\n const testFn = itFn.dup();\n context.setProp(context.global, \"test\", testFn);\n handles.push(testFn);\n\n // test.skip/only/todo - point to same functions as it.*\n context.setProp(testFn, \"skip\", itSkipFn);\n context.setProp(testFn, \"only\", itOnlyFn);\n context.setProp(testFn, \"todo\", itTodoFn);\n\n return handles;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite, RegisteredTest } from \"../types.cjs\";\n\nlet suiteIdCounter = 0;\nlet testIdCounter = 0;\n\nexport function createSuite(\n name: string,\n parent: RegisteredSuite | null,\n modifier: RegisteredSuite[\"modifier\"] = \"none\"\n): RegisteredSuite {\n return {\n id: `suite_${++suiteIdCounter}`,\n name,\n path: parent ? [...parent.path, name] : [name],\n tests: [],\n beforeAll: [],\n afterAll: [],\n beforeEach: [],\n afterEach: [],\n children: [],\n parent,\n modifier,\n };\n}\n\nexport function setupDescribe(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create describe function with modifier\n const createDescribeFn = (modifier: RegisteredSuite[\"modifier\"]) => {\n return context.newFunction(\"describe\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n // Create new suite\n const suite = createSuite(name, state.currentSuite, modifier);\n\n // Add to parent or root\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Execute the describe body to discover nested tests\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Error in describe \"${name}\": ${error}`);\n }\n result.value.dispose();\n } finally {\n state.currentSuite = previousSuite;\n }\n\n return context.undefined;\n });\n };\n\n // describe()\n const describeFn = createDescribeFn(\"none\");\n context.setProp(context.global, \"describe\", describeFn);\n handles.push(describeFn);\n\n // describe.skip()\n const describeSkipFn = createDescribeFn(\"skip\");\n context.setProp(describeFn, \"skip\", describeSkipFn);\n handles.push(describeSkipFn);\n\n // describe.only()\n const describeOnlyFn = createDescribeFn(\"only\");\n context.setProp(describeFn, \"only\", describeOnlyFn);\n handles.push(describeOnlyFn);\n\n // describe.todo() - fn is optional\n const describeTodoFn = context.newFunction(\n \"describe.todo\",\n (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n const suite = createSuite(name, state.currentSuite, \"todo\");\n\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Only execute body if provided and is a function\n if (fnHandle && context.typeof(fnHandle) === \"function\") {\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n } finally {\n state.currentSuite = previousSuite;\n }\n }\n\n return context.undefined;\n }\n );\n context.setProp(describeFn, \"todo\", describeTodoFn);\n handles.push(describeTodoFn);\n\n return handles;\n}\n\nexport function setupIt(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create it/test function with modifier\n const createItFn = (modifier: RegisteredTest[\"modifier\"]) => {\n return context.newFunction(\"it\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n // Create implicit root suite for top-level tests\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // Dup the function handle to keep it alive\n const fnDup = fnHandle.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier,\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n };\n\n // it()\n const itFn = createItFn(\"none\");\n context.setProp(context.global, \"it\", itFn);\n handles.push(itFn);\n\n // it.skip()\n const itSkipFn = createItFn(\"skip\");\n context.setProp(itFn, \"skip\", itSkipFn);\n handles.push(itSkipFn);\n\n // it.only()\n const itOnlyFn = createItFn(\"only\");\n context.setProp(itFn, \"only\", itOnlyFn);\n handles.push(itOnlyFn);\n\n // it.todo() - fn is optional\n const itTodoFn = context.newFunction(\"it.todo\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // fn is optional for todo - use undefined dup if not provided\n const fnDup =\n fnHandle && context.typeof(fnHandle) === \"function\"\n ? fnHandle.dup()\n : context.undefined.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier: \"todo\",\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n context.setProp(itFn, \"todo\", itTodoFn);\n handles.push(itTodoFn);\n\n // test() - alias for it()\n const testFn = itFn.dup();\n context.setProp(context.global, \"test\", testFn);\n handles.push(testFn);\n\n // test.skip/only/todo - point to same functions as it.*\n context.setProp(testFn, \"skip\", itSkipFn);\n context.setProp(testFn, \"only\", itOnlyFn);\n context.setProp(testFn, \"todo\", itTodoFn);\n\n return handles;\n}\n"
6
6
  ],
7
7
  "mappings": "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",
8
8
  "debugId": "06E934BB816050EB64756E2164756E21",
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/expect.ts"],
4
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"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState } from \"../types.cjs\";\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
6
  ],
7
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
8
  "debugId": "23905AB9BA5D77BD64756E2164756E21",
@@ -33,7 +33,7 @@ __export(exports_handle, {
33
33
  createTestEnvironmentHandle: () => createTestEnvironmentHandle
34
34
  });
35
35
  module.exports = __toCommonJS(exports_handle);
36
- var import_runner = require("./runner.ts");
36
+ var import_runner = require("./runner.cjs");
37
37
  function createTestEnvironmentHandle(state) {
38
38
  return {
39
39
  get stateMap() {
@@ -76,4 +76,4 @@ function createTestEnvironmentHandle(state) {
76
76
  }
77
77
  })
78
78
 
79
- //# debugId=CD29C4A7C662745A64756E2164756E21
79
+ //# debugId=E9630E2025CBD67064756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/handle.ts"],
4
4
  "sourcesContent": [
5
- "import type { TestEnvironmentHandle, TestState, RunResults } from \"./types.ts\";\nimport { runTests } from \"./runner.ts\";\n\nexport function createTestEnvironmentHandle(state: TestState): TestEnvironmentHandle {\n return {\n get stateMap() {\n return state.stateMap;\n },\n\n async run(): Promise<RunResults> {\n return runTests(state);\n },\n\n hasTests(): boolean {\n return state.suites.some(suite =>\n suite.tests.length > 0 || suite.children.length > 0\n );\n },\n\n getTestCount(): number {\n let count = 0;\n const countSuite = (suite: typeof state.suites[0]) => {\n count += suite.tests.length;\n suite.children.forEach(countSuite);\n };\n state.suites.forEach(countSuite);\n return count;\n },\n\n reset(): void {\n // Dispose test function handles\n const disposeSuite = (suite: typeof state.suites[0]) => {\n suite.tests.forEach(test => test.fn.dispose());\n suite.beforeAll.forEach(fn => fn.dispose());\n suite.afterAll.forEach(fn => fn.dispose());\n suite.beforeEach.forEach(fn => fn.dispose());\n suite.afterEach.forEach(fn => fn.dispose());\n suite.children.forEach(disposeSuite);\n };\n state.suites.forEach(disposeSuite);\n\n state.suites = [];\n state.currentSuite = null;\n },\n\n dispose(): void {\n this.reset();\n // Dispose global function handles\n state.handles.forEach(handle => handle.dispose());\n state.handles = [];\n },\n };\n}\n"
5
+ "import type { TestEnvironmentHandle, TestState, RunResults } from \"./types.cjs\";\nimport { runTests } from \"./runner.cjs\";\n\nexport function createTestEnvironmentHandle(state: TestState): TestEnvironmentHandle {\n return {\n get stateMap() {\n return state.stateMap;\n },\n\n async run(): Promise<RunResults> {\n return runTests(state);\n },\n\n hasTests(): boolean {\n return state.suites.some(suite =>\n suite.tests.length > 0 || suite.children.length > 0\n );\n },\n\n getTestCount(): number {\n let count = 0;\n const countSuite = (suite: typeof state.suites[0]) => {\n count += suite.tests.length;\n suite.children.forEach(countSuite);\n };\n state.suites.forEach(countSuite);\n return count;\n },\n\n reset(): void {\n // Dispose test function handles\n const disposeSuite = (suite: typeof state.suites[0]) => {\n suite.tests.forEach(test => test.fn.dispose());\n suite.beforeAll.forEach(fn => fn.dispose());\n suite.afterAll.forEach(fn => fn.dispose());\n suite.beforeEach.forEach(fn => fn.dispose());\n suite.afterEach.forEach(fn => fn.dispose());\n suite.children.forEach(disposeSuite);\n };\n state.suites.forEach(disposeSuite);\n\n state.suites = [];\n state.currentSuite = null;\n },\n\n dispose(): void {\n this.reset();\n // Dispose global function handles\n state.handles.forEach(handle => handle.dispose());\n state.handles = [];\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACyB,IAAzB;AAEO,SAAS,2BAA2B,CAAC,OAAyC;AAAA,EACnF,OAAO;AAAA,QACD,QAAQ,GAAG;AAAA,MACb,OAAO,MAAM;AAAA;AAAA,SAGT,IAAG,GAAwB;AAAA,MAC/B,OAAO,uBAAS,KAAK;AAAA;AAAA,IAGvB,QAAQ,GAAY;AAAA,MAClB,OAAO,MAAM,OAAO,KAAK,WACvB,MAAM,MAAM,SAAS,KAAK,MAAM,SAAS,SAAS,CACpD;AAAA;AAAA,IAGF,YAAY,GAAW;AAAA,MACrB,IAAI,QAAQ;AAAA,MACZ,MAAM,aAAa,CAAC,UAAkC;AAAA,QACpD,SAAS,MAAM,MAAM;AAAA,QACrB,MAAM,SAAS,QAAQ,UAAU;AAAA;AAAA,MAEnC,MAAM,OAAO,QAAQ,UAAU;AAAA,MAC/B,OAAO;AAAA;AAAA,IAGT,KAAK,GAAS;AAAA,MAEZ,MAAM,eAAe,CAAC,UAAkC;AAAA,QACtD,MAAM,MAAM,QAAQ,UAAQ,KAAK,GAAG,QAAQ,CAAC;AAAA,QAC7C,MAAM,UAAU,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC1C,MAAM,SAAS,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QACzC,MAAM,WAAW,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC3C,MAAM,UAAU,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC1C,MAAM,SAAS,QAAQ,YAAY;AAAA;AAAA,MAErC,MAAM,OAAO,QAAQ,YAAY;AAAA,MAEjC,MAAM,SAAS,CAAC;AAAA,MAChB,MAAM,eAAe;AAAA;AAAA,IAGvB,OAAO,GAAS;AAAA,MACd,KAAK,MAAM;AAAA,MAEX,MAAM,QAAQ,QAAQ,YAAU,OAAO,QAAQ,CAAC;AAAA,MAChD,MAAM,UAAU,CAAC;AAAA;AAAA,EAErB;AAAA;",
8
- "debugId": "CD29C4A7C662745A64756E2164756E21",
8
+ "debugId": "E9630E2025CBD67064756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -33,7 +33,7 @@ __export(exports_hooks, {
33
33
  setupHooks: () => setupHooks
34
34
  });
35
35
  module.exports = __toCommonJS(exports_hooks);
36
- var import_describe = require("./describe.ts");
36
+ var import_describe = require("./describe.cjs");
37
37
  function ensureSuite(state) {
38
38
  if (!state.currentSuite) {
39
39
  const rootSuite = import_describe.createSuite("(root)", null);
@@ -80,4 +80,4 @@ function setupHooks(context, state) {
80
80
  }
81
81
  })
82
82
 
83
- //# debugId=5354281E8C85363564756E2164756E21
83
+ //# debugId=A2DCC369CEB556F964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/hooks.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite } from \"../types.ts\";\nimport { createSuite } from \"./describe.ts\";\n\n/**\n * Helper to ensure we have a current suite for hook registration.\n * Creates an implicit root suite if called at top level.\n */\nfunction ensureSuite(state: TestState): RegisteredSuite {\n if (!state.currentSuite) {\n // Create implicit root suite for top-level hooks\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n return state.currentSuite;\n}\n\nexport function setupHooks(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // beforeAll - runs once before all tests in the suite\n const beforeAllFn = context.newFunction(\"beforeAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeAll\", beforeAllFn);\n handles.push(beforeAllFn);\n\n // afterAll - runs once after all tests in the suite\n const afterAllFn = context.newFunction(\"afterAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterAll\", afterAllFn);\n handles.push(afterAllFn);\n\n // beforeEach - runs before each test in the suite and nested suites\n const beforeEachFn = context.newFunction(\"beforeEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeEach\", beforeEachFn);\n handles.push(beforeEachFn);\n\n // afterEach - runs after each test in the suite and nested suites\n const afterEachFn = context.newFunction(\"afterEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterEach\", afterEachFn);\n handles.push(afterEachFn);\n\n return handles;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite } from \"../types.cjs\";\nimport { createSuite } from \"./describe.cjs\";\n\n/**\n * Helper to ensure we have a current suite for hook registration.\n * Creates an implicit root suite if called at top level.\n */\nfunction ensureSuite(state: TestState): RegisteredSuite {\n if (!state.currentSuite) {\n // Create implicit root suite for top-level hooks\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n return state.currentSuite;\n}\n\nexport function setupHooks(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // beforeAll - runs once before all tests in the suite\n const beforeAllFn = context.newFunction(\"beforeAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeAll\", beforeAllFn);\n handles.push(beforeAllFn);\n\n // afterAll - runs once after all tests in the suite\n const afterAllFn = context.newFunction(\"afterAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterAll\", afterAllFn);\n handles.push(afterAllFn);\n\n // beforeEach - runs before each test in the suite and nested suites\n const beforeEachFn = context.newFunction(\"beforeEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeEach\", beforeEachFn);\n handles.push(beforeEachFn);\n\n // afterEach - runs after each test in the suite and nested suites\n const afterEachFn = context.newFunction(\"afterEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterEach\", afterEachFn);\n handles.push(afterEachFn);\n\n return handles;\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE4B,IAA5B;AAMA,SAAS,WAAW,CAAC,OAAmC;AAAA,EACtD,IAAI,CAAC,MAAM,cAAc;AAAA,IAEvB,MAAM,YAAY,4BAAY,UAAU,IAAI;AAAA,IAC5C,MAAM,OAAO,KAAK,SAAS;AAAA,IAC3B,MAAM,eAAe;AAAA,EACvB;AAAA,EACA,OAAO,MAAM;AAAA;AAGR,SAAS,UAAU,CACxB,SACA,OACiB;AAAA,EACjB,MAAM,UAA2B,CAAC;AAAA,EAGlC,MAAM,cAAc,QAAQ,YAAY,aAAa,CAAC,aAAa;AAAA,IACjE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,UAAU,KAAK,KAAK;AAAA,IAC1B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,aAAa,WAAW;AAAA,EACxD,QAAQ,KAAK,WAAW;AAAA,EAGxB,MAAM,aAAa,QAAQ,YAAY,YAAY,CAAC,aAAa;AAAA,IAC/D,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,SAAS,KAAK,KAAK;AAAA,IACzB,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,YAAY,UAAU;AAAA,EACtD,QAAQ,KAAK,UAAU;AAAA,EAGvB,MAAM,eAAe,QAAQ,YAAY,cAAc,CAAC,aAAa;AAAA,IACnE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,WAAW,KAAK,KAAK;AAAA,IAC3B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,cAAc,YAAY;AAAA,EAC1D,QAAQ,KAAK,YAAY;AAAA,EAGzB,MAAM,cAAc,QAAQ,YAAY,aAAa,CAAC,aAAa;AAAA,IACjE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,UAAU,KAAK,KAAK;AAAA,IAC1B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,aAAa,WAAW;AAAA,EACxD,QAAQ,KAAK,WAAW;AAAA,EAExB,OAAO;AAAA;",
8
- "debugId": "5354281E8C85363564756E2164756E21",
8
+ "debugId": "A2DCC369CEB556F964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -33,7 +33,7 @@ __export(exports_src, {
33
33
  setupTestEnvironment: () => import_setup.setupTestEnvironment
34
34
  });
35
35
  module.exports = __toCommonJS(exports_src);
36
- var import_setup = require("./setup.ts");
36
+ var import_setup = require("./setup.cjs");
37
37
  })
38
38
 
39
- //# debugId=42D879EBF19B460064756E2164756E21
39
+ //# debugId=3CED267B02A0F88164756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export { setupTestEnvironment } from \"./setup.ts\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.ts\";\n"
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"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqC,IAArC;",
8
- "debugId": "42D879EBF19B460064756E2164756E21",
8
+ "debugId": "3CED267B02A0F88164756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "commonjs"
5
5
  }
@@ -2,7 +2,7 @@
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.ts\";\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} 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"
6
6
  ],
7
7
  "mappings": "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",
8
8
  "debugId": "9BA8E805A3739F0764756E2164756E21",
@@ -34,10 +34,10 @@ __export(exports_setup, {
34
34
  });
35
35
  module.exports = __toCommonJS(exports_setup);
36
36
  var import_quickjs_core = require("@ricsam/quickjs-core");
37
- var import_handle = require("./handle.ts");
38
- var import_describe = require("./globals/describe.ts");
39
- var import_hooks = require("./globals/hooks.ts");
40
- var import_expect = require("./globals/expect.ts");
37
+ var import_handle = require("./handle.cjs");
38
+ var import_describe = require("./globals/describe.cjs");
39
+ var import_hooks = require("./globals/hooks.cjs");
40
+ var import_expect = require("./globals/expect.cjs");
41
41
  function setupTestEnvironment(context, options = {}) {
42
42
  const coreHandle = options.coreHandle ?? import_quickjs_core.setupCore(context);
43
43
  const stateMap = options.stateMap ?? coreHandle.stateMap;
@@ -67,4 +67,4 @@ function setupTestEnvironment(context, options = {}) {
67
67
  }
68
68
  })
69
69
 
70
- //# debugId=227BFD7D386BB81B64756E2164756E21
70
+ //# debugId=53E8384DF049945A64756E2164756E21
@@ -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.ts\";\nimport { createTestEnvironmentHandle } from \"./handle.ts\";\nimport { setupDescribe, setupIt } from \"./globals/describe.ts\";\nimport { setupHooks } from \"./globals/hooks.ts\";\nimport { setupExpect } from \"./globals/expect.ts\";\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 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"
6
6
  ],
7
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": "227BFD7D386BB81B64756E2164756E21",
8
+ "debugId": "53E8384DF049945A64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/describe.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite, RegisteredTest } from \"../types.ts\";\n\nlet suiteIdCounter = 0;\nlet testIdCounter = 0;\n\nexport function createSuite(\n name: string,\n parent: RegisteredSuite | null,\n modifier: RegisteredSuite[\"modifier\"] = \"none\"\n): RegisteredSuite {\n return {\n id: `suite_${++suiteIdCounter}`,\n name,\n path: parent ? [...parent.path, name] : [name],\n tests: [],\n beforeAll: [],\n afterAll: [],\n beforeEach: [],\n afterEach: [],\n children: [],\n parent,\n modifier,\n };\n}\n\nexport function setupDescribe(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create describe function with modifier\n const createDescribeFn = (modifier: RegisteredSuite[\"modifier\"]) => {\n return context.newFunction(\"describe\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n // Create new suite\n const suite = createSuite(name, state.currentSuite, modifier);\n\n // Add to parent or root\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Execute the describe body to discover nested tests\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Error in describe \"${name}\": ${error}`);\n }\n result.value.dispose();\n } finally {\n state.currentSuite = previousSuite;\n }\n\n return context.undefined;\n });\n };\n\n // describe()\n const describeFn = createDescribeFn(\"none\");\n context.setProp(context.global, \"describe\", describeFn);\n handles.push(describeFn);\n\n // describe.skip()\n const describeSkipFn = createDescribeFn(\"skip\");\n context.setProp(describeFn, \"skip\", describeSkipFn);\n handles.push(describeSkipFn);\n\n // describe.only()\n const describeOnlyFn = createDescribeFn(\"only\");\n context.setProp(describeFn, \"only\", describeOnlyFn);\n handles.push(describeOnlyFn);\n\n // describe.todo() - fn is optional\n const describeTodoFn = context.newFunction(\n \"describe.todo\",\n (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n const suite = createSuite(name, state.currentSuite, \"todo\");\n\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Only execute body if provided and is a function\n if (fnHandle && context.typeof(fnHandle) === \"function\") {\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n } finally {\n state.currentSuite = previousSuite;\n }\n }\n\n return context.undefined;\n }\n );\n context.setProp(describeFn, \"todo\", describeTodoFn);\n handles.push(describeTodoFn);\n\n return handles;\n}\n\nexport function setupIt(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create it/test function with modifier\n const createItFn = (modifier: RegisteredTest[\"modifier\"]) => {\n return context.newFunction(\"it\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n // Create implicit root suite for top-level tests\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // Dup the function handle to keep it alive\n const fnDup = fnHandle.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier,\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n };\n\n // it()\n const itFn = createItFn(\"none\");\n context.setProp(context.global, \"it\", itFn);\n handles.push(itFn);\n\n // it.skip()\n const itSkipFn = createItFn(\"skip\");\n context.setProp(itFn, \"skip\", itSkipFn);\n handles.push(itSkipFn);\n\n // it.only()\n const itOnlyFn = createItFn(\"only\");\n context.setProp(itFn, \"only\", itOnlyFn);\n handles.push(itOnlyFn);\n\n // it.todo() - fn is optional\n const itTodoFn = context.newFunction(\"it.todo\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // fn is optional for todo - use undefined dup if not provided\n const fnDup =\n fnHandle && context.typeof(fnHandle) === \"function\"\n ? fnHandle.dup()\n : context.undefined.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier: \"todo\",\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n context.setProp(itFn, \"todo\", itTodoFn);\n handles.push(itTodoFn);\n\n // test() - alias for it()\n const testFn = itFn.dup();\n context.setProp(context.global, \"test\", testFn);\n handles.push(testFn);\n\n // test.skip/only/todo - point to same functions as it.*\n context.setProp(testFn, \"skip\", itSkipFn);\n context.setProp(testFn, \"only\", itOnlyFn);\n context.setProp(testFn, \"todo\", itTodoFn);\n\n return handles;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite, RegisteredTest } from \"../types.mjs\";\n\nlet suiteIdCounter = 0;\nlet testIdCounter = 0;\n\nexport function createSuite(\n name: string,\n parent: RegisteredSuite | null,\n modifier: RegisteredSuite[\"modifier\"] = \"none\"\n): RegisteredSuite {\n return {\n id: `suite_${++suiteIdCounter}`,\n name,\n path: parent ? [...parent.path, name] : [name],\n tests: [],\n beforeAll: [],\n afterAll: [],\n beforeEach: [],\n afterEach: [],\n children: [],\n parent,\n modifier,\n };\n}\n\nexport function setupDescribe(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create describe function with modifier\n const createDescribeFn = (modifier: RegisteredSuite[\"modifier\"]) => {\n return context.newFunction(\"describe\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n // Create new suite\n const suite = createSuite(name, state.currentSuite, modifier);\n\n // Add to parent or root\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Execute the describe body to discover nested tests\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n const error = context.dump(result.error);\n result.error.dispose();\n throw new Error(`Error in describe \"${name}\": ${error}`);\n }\n result.value.dispose();\n } finally {\n state.currentSuite = previousSuite;\n }\n\n return context.undefined;\n });\n };\n\n // describe()\n const describeFn = createDescribeFn(\"none\");\n context.setProp(context.global, \"describe\", describeFn);\n handles.push(describeFn);\n\n // describe.skip()\n const describeSkipFn = createDescribeFn(\"skip\");\n context.setProp(describeFn, \"skip\", describeSkipFn);\n handles.push(describeSkipFn);\n\n // describe.only()\n const describeOnlyFn = createDescribeFn(\"only\");\n context.setProp(describeFn, \"only\", describeOnlyFn);\n handles.push(describeOnlyFn);\n\n // describe.todo() - fn is optional\n const describeTodoFn = context.newFunction(\n \"describe.todo\",\n (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n const suite = createSuite(name, state.currentSuite, \"todo\");\n\n if (state.currentSuite) {\n state.currentSuite.children.push(suite);\n } else {\n state.suites.push(suite);\n }\n\n // Only execute body if provided and is a function\n if (fnHandle && context.typeof(fnHandle) === \"function\") {\n const previousSuite = state.currentSuite;\n state.currentSuite = suite;\n\n try {\n const result = context.callFunction(fnHandle, context.undefined);\n if (result.error) {\n result.error.dispose();\n } else {\n result.value.dispose();\n }\n } finally {\n state.currentSuite = previousSuite;\n }\n }\n\n return context.undefined;\n }\n );\n context.setProp(describeFn, \"todo\", describeTodoFn);\n handles.push(describeTodoFn);\n\n return handles;\n}\n\nexport function setupIt(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // Helper to create it/test function with modifier\n const createItFn = (modifier: RegisteredTest[\"modifier\"]) => {\n return context.newFunction(\"it\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n // Create implicit root suite for top-level tests\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // Dup the function handle to keep it alive\n const fnDup = fnHandle.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier,\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n };\n\n // it()\n const itFn = createItFn(\"none\");\n context.setProp(context.global, \"it\", itFn);\n handles.push(itFn);\n\n // it.skip()\n const itSkipFn = createItFn(\"skip\");\n context.setProp(itFn, \"skip\", itSkipFn);\n handles.push(itSkipFn);\n\n // it.only()\n const itOnlyFn = createItFn(\"only\");\n context.setProp(itFn, \"only\", itOnlyFn);\n handles.push(itOnlyFn);\n\n // it.todo() - fn is optional\n const itTodoFn = context.newFunction(\"it.todo\", (nameHandle, fnHandle) => {\n const name = context.getString(nameHandle);\n\n if (!state.currentSuite) {\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n\n // fn is optional for todo - use undefined dup if not provided\n const fnDup =\n fnHandle && context.typeof(fnHandle) === \"function\"\n ? fnHandle.dup()\n : context.undefined.dup();\n\n const test: RegisteredTest = {\n id: `test_${++testIdCounter}`,\n name,\n fn: fnDup,\n suite: state.currentSuite,\n modifier: \"todo\",\n };\n\n state.currentSuite.tests.push(test);\n\n return context.undefined;\n });\n context.setProp(itFn, \"todo\", itTodoFn);\n handles.push(itTodoFn);\n\n // test() - alias for it()\n const testFn = itFn.dup();\n context.setProp(context.global, \"test\", testFn);\n handles.push(testFn);\n\n // test.skip/only/todo - point to same functions as it.*\n context.setProp(testFn, \"skip\", itSkipFn);\n context.setProp(testFn, \"only\", itOnlyFn);\n context.setProp(testFn, \"todo\", itTodoFn);\n\n return handles;\n}\n"
6
6
  ],
7
7
  "mappings": "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",
8
8
  "debugId": "67AFDBA8C37B88F664756E2164756E21",
@@ -2,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/expect.ts"],
4
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"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState } from \"../types.mjs\";\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
6
  ],
7
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
8
  "debugId": "376CF8D2D923E21B64756E2164756E21",
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/test-environment/src/handle.ts
3
- import { runTests } from "./runner.ts";
3
+ import { runTests } from "./runner.mjs";
4
4
  function createTestEnvironmentHandle(state) {
5
5
  return {
6
6
  get stateMap() {
@@ -45,4 +45,4 @@ export {
45
45
  createTestEnvironmentHandle
46
46
  };
47
47
 
48
- //# debugId=2992932296BCF55264756E2164756E21
48
+ //# debugId=1B6E6A16C6B25D0B64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/handle.ts"],
4
4
  "sourcesContent": [
5
- "import type { TestEnvironmentHandle, TestState, RunResults } from \"./types.ts\";\nimport { runTests } from \"./runner.ts\";\n\nexport function createTestEnvironmentHandle(state: TestState): TestEnvironmentHandle {\n return {\n get stateMap() {\n return state.stateMap;\n },\n\n async run(): Promise<RunResults> {\n return runTests(state);\n },\n\n hasTests(): boolean {\n return state.suites.some(suite =>\n suite.tests.length > 0 || suite.children.length > 0\n );\n },\n\n getTestCount(): number {\n let count = 0;\n const countSuite = (suite: typeof state.suites[0]) => {\n count += suite.tests.length;\n suite.children.forEach(countSuite);\n };\n state.suites.forEach(countSuite);\n return count;\n },\n\n reset(): void {\n // Dispose test function handles\n const disposeSuite = (suite: typeof state.suites[0]) => {\n suite.tests.forEach(test => test.fn.dispose());\n suite.beforeAll.forEach(fn => fn.dispose());\n suite.afterAll.forEach(fn => fn.dispose());\n suite.beforeEach.forEach(fn => fn.dispose());\n suite.afterEach.forEach(fn => fn.dispose());\n suite.children.forEach(disposeSuite);\n };\n state.suites.forEach(disposeSuite);\n\n state.suites = [];\n state.currentSuite = null;\n },\n\n dispose(): void {\n this.reset();\n // Dispose global function handles\n state.handles.forEach(handle => handle.dispose());\n state.handles = [];\n },\n };\n}\n"
5
+ "import type { TestEnvironmentHandle, TestState, RunResults } from \"./types.mjs\";\nimport { runTests } from \"./runner.mjs\";\n\nexport function createTestEnvironmentHandle(state: TestState): TestEnvironmentHandle {\n return {\n get stateMap() {\n return state.stateMap;\n },\n\n async run(): Promise<RunResults> {\n return runTests(state);\n },\n\n hasTests(): boolean {\n return state.suites.some(suite =>\n suite.tests.length > 0 || suite.children.length > 0\n );\n },\n\n getTestCount(): number {\n let count = 0;\n const countSuite = (suite: typeof state.suites[0]) => {\n count += suite.tests.length;\n suite.children.forEach(countSuite);\n };\n state.suites.forEach(countSuite);\n return count;\n },\n\n reset(): void {\n // Dispose test function handles\n const disposeSuite = (suite: typeof state.suites[0]) => {\n suite.tests.forEach(test => test.fn.dispose());\n suite.beforeAll.forEach(fn => fn.dispose());\n suite.afterAll.forEach(fn => fn.dispose());\n suite.beforeEach.forEach(fn => fn.dispose());\n suite.afterEach.forEach(fn => fn.dispose());\n suite.children.forEach(disposeSuite);\n };\n state.suites.forEach(disposeSuite);\n\n state.suites = [];\n state.currentSuite = null;\n },\n\n dispose(): void {\n this.reset();\n // Dispose global function handles\n state.handles.forEach(handle => handle.dispose());\n state.handles = [];\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;AACA;AAEO,SAAS,2BAA2B,CAAC,OAAyC;AAAA,EACnF,OAAO;AAAA,QACD,QAAQ,GAAG;AAAA,MACb,OAAO,MAAM;AAAA;AAAA,SAGT,IAAG,GAAwB;AAAA,MAC/B,OAAO,SAAS,KAAK;AAAA;AAAA,IAGvB,QAAQ,GAAY;AAAA,MAClB,OAAO,MAAM,OAAO,KAAK,WACvB,MAAM,MAAM,SAAS,KAAK,MAAM,SAAS,SAAS,CACpD;AAAA;AAAA,IAGF,YAAY,GAAW;AAAA,MACrB,IAAI,QAAQ;AAAA,MACZ,MAAM,aAAa,CAAC,UAAkC;AAAA,QACpD,SAAS,MAAM,MAAM;AAAA,QACrB,MAAM,SAAS,QAAQ,UAAU;AAAA;AAAA,MAEnC,MAAM,OAAO,QAAQ,UAAU;AAAA,MAC/B,OAAO;AAAA;AAAA,IAGT,KAAK,GAAS;AAAA,MAEZ,MAAM,eAAe,CAAC,UAAkC;AAAA,QACtD,MAAM,MAAM,QAAQ,UAAQ,KAAK,GAAG,QAAQ,CAAC;AAAA,QAC7C,MAAM,UAAU,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC1C,MAAM,SAAS,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QACzC,MAAM,WAAW,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC3C,MAAM,UAAU,QAAQ,QAAM,GAAG,QAAQ,CAAC;AAAA,QAC1C,MAAM,SAAS,QAAQ,YAAY;AAAA;AAAA,MAErC,MAAM,OAAO,QAAQ,YAAY;AAAA,MAEjC,MAAM,SAAS,CAAC;AAAA,MAChB,MAAM,eAAe;AAAA;AAAA,IAGvB,OAAO,GAAS;AAAA,MACd,KAAK,MAAM;AAAA,MAEX,MAAM,QAAQ,QAAQ,YAAU,OAAO,QAAQ,CAAC;AAAA,MAChD,MAAM,UAAU,CAAC;AAAA;AAAA,EAErB;AAAA;",
8
- "debugId": "2992932296BCF55264756E2164756E21",
8
+ "debugId": "1B6E6A16C6B25D0B64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,6 +1,6 @@
1
1
  // @bun
2
2
  // packages/test-environment/src/globals/hooks.ts
3
- import { createSuite } from "./describe.ts";
3
+ import { createSuite } from "./describe.mjs";
4
4
  function ensureSuite(state) {
5
5
  if (!state.currentSuite) {
6
6
  const rootSuite = createSuite("(root)", null);
@@ -49,4 +49,4 @@ export {
49
49
  setupHooks
50
50
  };
51
51
 
52
- //# debugId=4B952441388BBE6664756E2164756E21
52
+ //# debugId=337AAC81CA448F0564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/globals/hooks.ts"],
4
4
  "sourcesContent": [
5
- "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite } from \"../types.ts\";\nimport { createSuite } from \"./describe.ts\";\n\n/**\n * Helper to ensure we have a current suite for hook registration.\n * Creates an implicit root suite if called at top level.\n */\nfunction ensureSuite(state: TestState): RegisteredSuite {\n if (!state.currentSuite) {\n // Create implicit root suite for top-level hooks\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n return state.currentSuite;\n}\n\nexport function setupHooks(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // beforeAll - runs once before all tests in the suite\n const beforeAllFn = context.newFunction(\"beforeAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeAll\", beforeAllFn);\n handles.push(beforeAllFn);\n\n // afterAll - runs once after all tests in the suite\n const afterAllFn = context.newFunction(\"afterAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterAll\", afterAllFn);\n handles.push(afterAllFn);\n\n // beforeEach - runs before each test in the suite and nested suites\n const beforeEachFn = context.newFunction(\"beforeEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeEach\", beforeEachFn);\n handles.push(beforeEachFn);\n\n // afterEach - runs after each test in the suite and nested suites\n const afterEachFn = context.newFunction(\"afterEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterEach\", afterEachFn);\n handles.push(afterEachFn);\n\n return handles;\n}\n"
5
+ "import type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport type { TestState, RegisteredSuite } from \"../types.mjs\";\nimport { createSuite } from \"./describe.mjs\";\n\n/**\n * Helper to ensure we have a current suite for hook registration.\n * Creates an implicit root suite if called at top level.\n */\nfunction ensureSuite(state: TestState): RegisteredSuite {\n if (!state.currentSuite) {\n // Create implicit root suite for top-level hooks\n const rootSuite = createSuite(\"(root)\", null);\n state.suites.push(rootSuite);\n state.currentSuite = rootSuite;\n }\n return state.currentSuite;\n}\n\nexport function setupHooks(\n context: QuickJSContext,\n state: TestState\n): QuickJSHandle[] {\n const handles: QuickJSHandle[] = [];\n\n // beforeAll - runs once before all tests in the suite\n const beforeAllFn = context.newFunction(\"beforeAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeAll\", beforeAllFn);\n handles.push(beforeAllFn);\n\n // afterAll - runs once after all tests in the suite\n const afterAllFn = context.newFunction(\"afterAll\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterAll.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterAll\", afterAllFn);\n handles.push(afterAllFn);\n\n // beforeEach - runs before each test in the suite and nested suites\n const beforeEachFn = context.newFunction(\"beforeEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.beforeEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"beforeEach\", beforeEachFn);\n handles.push(beforeEachFn);\n\n // afterEach - runs after each test in the suite and nested suites\n const afterEachFn = context.newFunction(\"afterEach\", (fnHandle) => {\n const suite = ensureSuite(state);\n const fnDup = fnHandle.dup();\n suite.afterEach.push(fnDup);\n return context.undefined;\n });\n context.setProp(context.global, \"afterEach\", afterEachFn);\n handles.push(afterEachFn);\n\n return handles;\n}\n"
6
6
  ],
7
7
  "mappings": ";;AAEA;AAMA,SAAS,WAAW,CAAC,OAAmC;AAAA,EACtD,IAAI,CAAC,MAAM,cAAc;AAAA,IAEvB,MAAM,YAAY,YAAY,UAAU,IAAI;AAAA,IAC5C,MAAM,OAAO,KAAK,SAAS;AAAA,IAC3B,MAAM,eAAe;AAAA,EACvB;AAAA,EACA,OAAO,MAAM;AAAA;AAGR,SAAS,UAAU,CACxB,SACA,OACiB;AAAA,EACjB,MAAM,UAA2B,CAAC;AAAA,EAGlC,MAAM,cAAc,QAAQ,YAAY,aAAa,CAAC,aAAa;AAAA,IACjE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,UAAU,KAAK,KAAK;AAAA,IAC1B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,aAAa,WAAW;AAAA,EACxD,QAAQ,KAAK,WAAW;AAAA,EAGxB,MAAM,aAAa,QAAQ,YAAY,YAAY,CAAC,aAAa;AAAA,IAC/D,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,SAAS,KAAK,KAAK;AAAA,IACzB,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,YAAY,UAAU;AAAA,EACtD,QAAQ,KAAK,UAAU;AAAA,EAGvB,MAAM,eAAe,QAAQ,YAAY,cAAc,CAAC,aAAa;AAAA,IACnE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,WAAW,KAAK,KAAK;AAAA,IAC3B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,cAAc,YAAY;AAAA,EAC1D,QAAQ,KAAK,YAAY;AAAA,EAGzB,MAAM,cAAc,QAAQ,YAAY,aAAa,CAAC,aAAa;AAAA,IACjE,MAAM,QAAQ,YAAY,KAAK;AAAA,IAC/B,MAAM,QAAQ,SAAS,IAAI;AAAA,IAC3B,MAAM,UAAU,KAAK,KAAK;AAAA,IAC1B,OAAO,QAAQ;AAAA,GAChB;AAAA,EACD,QAAQ,QAAQ,QAAQ,QAAQ,aAAa,WAAW;AAAA,EACxD,QAAQ,KAAK,WAAW;AAAA,EAExB,OAAO;AAAA;",
8
- "debugId": "4B952441388BBE6664756E2164756E21",
8
+ "debugId": "337AAC81CA448F0564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  // packages/test-environment/src/index.ts
3
- import { setupTestEnvironment } from "./setup.ts";
3
+ import { setupTestEnvironment } from "./setup.mjs";
4
4
  export {
5
5
  setupTestEnvironment
6
6
  };
7
7
 
8
- //# debugId=BFD175E53A6D950064756E2164756E21
8
+ //# debugId=FCD44CE91F43579C64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export { setupTestEnvironment } from \"./setup.ts\";\n\nexport type {\n SetupTestOptions,\n TestEnvironmentHandle,\n SuiteInfo,\n SuiteResult,\n TestInfo,\n TestResult,\n TestError,\n RunResults,\n} from \"./types.ts\";\n"
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"
6
6
  ],
7
7
  "mappings": ";;AAAA;",
8
- "debugId": "BFD175E53A6D950064756E2164756E21",
8
+ "debugId": "FCD44CE91F43579C64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "type": "module"
5
5
  }
@@ -2,7 +2,7 @@
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.ts\";\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} 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"
6
6
  ],
7
7
  "mappings": "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",
8
8
  "debugId": "846C154A81717D9264756E2164756E21",
@@ -1,10 +1,10 @@
1
1
  // @bun
2
2
  // packages/test-environment/src/setup.ts
3
3
  import { setupCore } from "@ricsam/quickjs-core";
4
- import { createTestEnvironmentHandle } from "./handle.ts";
5
- import { setupDescribe, setupIt } from "./globals/describe.ts";
6
- import { setupHooks } from "./globals/hooks.ts";
7
- import { setupExpect } from "./globals/expect.ts";
4
+ import { createTestEnvironmentHandle } from "./handle.mjs";
5
+ import { setupDescribe, setupIt } from "./globals/describe.mjs";
6
+ import { setupHooks } from "./globals/hooks.mjs";
7
+ import { setupExpect } from "./globals/expect.mjs";
8
8
  function setupTestEnvironment(context, options = {}) {
9
9
  const coreHandle = options.coreHandle ?? setupCore(context);
10
10
  const stateMap = options.stateMap ?? coreHandle.stateMap;
@@ -36,4 +36,4 @@ export {
36
36
  setupTestEnvironment
37
37
  };
38
38
 
39
- //# debugId=C4BD7157FB9C264C64756E2164756E21
39
+ //# debugId=F80D6B4A8EEE5DFF64756E2164756E21
@@ -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.ts\";\nimport { createTestEnvironmentHandle } from \"./handle.ts\";\nimport { setupDescribe, setupIt } from \"./globals/describe.ts\";\nimport { setupHooks } from \"./globals/hooks.ts\";\nimport { setupExpect } from \"./globals/expect.ts\";\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 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"
6
6
  ],
7
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": "C4BD7157FB9C264C64756E2164756E21",
8
+ "debugId": "F80D6B4A8EEE5DFF64756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-environment",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
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",
@@ -19,7 +19,7 @@
19
19
  "quickjs-emscripten": ">=0.31.0"
20
20
  },
21
21
  "dependencies": {
22
- "@ricsam/quickjs-core": "^0.2.1"
22
+ "@ricsam/quickjs-core": "^0.2.2"
23
23
  },
24
24
  "author": "Richard Samuelsson",
25
25
  "license": "MIT",