@sigx/lynx-testing 0.2.6 → 0.4.0

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.
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Fire synthetic events on TestNode elements.
3
3
  */
4
- import { TestNode } from './test-node.js';
4
+ import { TestNode } from './test-node';
5
5
  interface SyntheticTouch {
6
6
  identifier?: number;
7
7
  x?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"fire-event.d.ts","sourceRoot":"","sources":["../src/fire-event.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,mBAAmB;IAC3B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,sDAAsD;AACtD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,SAAI,GACb,cAAc,CAEhB;AAmBD,eAAO,MAAM,SAAS;IACpB,kCAAkC;IAClC,GAAG,OAAO,QAAQ,SAAS;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAgB5D,iCAAiC;IACjC,UAAU,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI5D,gCAAgC;IAChC,SAAS,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI3D,+BAA+B;IAC/B,QAAQ,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI1D,kCAAkC;IAClC,WAAW,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI7D,6BAA6B;IAC7B,MAAM,OAAO,QAAQ,SAAS,oBAAoB,GAAG,IAAI;IAoBzD,4BAA4B;IAC5B,KAAK,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAYvD,gCAAgC;IAChC,SAAS,OAAO,QAAQ,GAAG,IAAI;CAWhC,CAAC"}
1
+ {"version":3,"file":"fire-event.d.ts","sourceRoot":"","sources":["../src/fire-event.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,UAAU,cAAc;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,mBAAmB;IAC3B,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,EAAE,CAAC;CACnC;AAED,UAAU,oBAAoB;IAC5B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,UAAU,mBAAmB;IAC3B,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,sDAAsD;AACtD,wBAAgB,KAAK,CACnB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,UAAU,SAAI,GACb,cAAc,CAEhB;AAmBD,eAAO,MAAM,SAAS;IACpB,kCAAkC;IAClC,GAAG,OAAO,QAAQ,SAAS;QAAE,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAgB5D,iCAAiC;IACjC,UAAU,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI5D,gCAAgC;IAChC,SAAS,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI3D,+BAA+B;IAC/B,QAAQ,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI1D,kCAAkC;IAClC,WAAW,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAI7D,6BAA6B;IAC7B,MAAM,OAAO,QAAQ,SAAS,oBAAoB,GAAG,IAAI;IAoBzD,4BAA4B;IAC5B,KAAK,OAAO,QAAQ,SAAS,mBAAmB,GAAG,IAAI;IAYvD,gCAAgC;IAChC,SAAS,OAAO,QAAQ,GAAG,IAAI;CAWhC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export { render } from './render.js';
2
- export type { RenderResult } from './render.js';
3
- export { TestNode } from './test-node.js';
4
- export { fireEvent, touch } from './fire-event.js';
5
- export { waitForUpdate, act } from './flush.js';
6
- export { getByType, getAllByType, getByText, queryByType, queryByText, getByProp, } from './queries.js';
1
+ export { render } from './render';
2
+ export type { RenderResult } from './render';
3
+ export { TestNode } from './test-node';
4
+ export { fireEvent, touch } from './fire-event';
5
+ export { waitForUpdate, act } from './flush';
6
+ export { getByType, getAllByType, getByText, queryByType, queryByText, getByProp, } from './queries';
7
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,SAAS,GACV,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,EACX,SAAS,GACV,MAAM,WAAW,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/test-node.ts","../src/test-renderer.ts","../src/queries.ts","../src/render.ts","../src/fire-event.ts","../src/flush.ts"],"sourcesContent":["/**\n * TestNode — lightweight in-memory tree node for test rendering.\n * Replaces ShadowElement + Lynx PAPI for testing purposes.\n */\nexport class TestNode {\n type: string;\n props: Record<string, unknown> = {};\n children: TestNode[] = [];\n parent: TestNode | null = null;\n text?: string;\n\n /** Event handlers keyed by prop name (e.g. 'bindtap', 'bindtouchstart'). */\n _handlers: Map<string, Function> = new Map();\n\n /** Style object (last value from patchProp 'style'). */\n _style: Record<string, unknown> = {};\n\n /** Class string. */\n _class = '';\n\n constructor(type: string) {\n this.type = type;\n }\n\n // -- Tree queries --\n\n /** Find first descendant matching element type. */\n findByType(type: string): TestNode | null {\n for (const child of this.children) {\n if (child.type === type) return child;\n const found = child.findByType(type);\n if (found) return found;\n }\n return null;\n }\n\n /** Find all descendants matching element type. */\n findAllByType(type: string): TestNode[] {\n const results: TestNode[] = [];\n for (const child of this.children) {\n if (child.type === type) results.push(child);\n results.push(...child.findAllByType(type));\n }\n return results;\n }\n\n /** Find first descendant containing the given text. */\n findByText(text: string): TestNode | null {\n if (this.text !== undefined && String(this.text).includes(text)) return this;\n for (const child of this.children) {\n const found = child.findByText(text);\n if (found) return found;\n }\n return null;\n }\n\n /** Get all text content from this node and descendants. */\n textContent(): string {\n if (this.text !== undefined) return String(this.text);\n return this.children.map(c => c.textContent()).join('');\n }\n\n /** Debug: serialize tree to a readable string. */\n toDebugString(indent = 0): string {\n const pad = ' '.repeat(indent);\n if (this.type === '#text') return `${pad}${JSON.stringify(this.text)}`;\n if (this.type === '#comment') return `${pad}<!-- -->`;\n const attrs = Object.keys(this.props).length > 0\n ? ' ' + Object.entries(this.props).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(' ')\n : '';\n if (this.children.length === 0) return `${pad}<${this.type}${attrs} />`;\n const childStr = this.children.map(c => c.toDebugString(indent + 1)).join('\\n');\n return `${pad}<${this.type}${attrs}>\\n${childStr}\\n${pad}</${this.type}>`;\n }\n}\n","/**\n * Test renderer — implements RendererOptions<TestNode, TestNode> for\n * in-memory rendering without Lynx PAPI.\n */\nimport { createRenderer } from '@sigx/runtime-core/internals';\nimport type { RendererOptions } from '@sigx/runtime-core/internals';\nimport { TestNode } from './test-node.js';\n\nconst nodeOps: RendererOptions<TestNode, TestNode> = {\n createElement(type: string): TestNode {\n return new TestNode(type);\n },\n\n createText(text: string): TestNode {\n const node = new TestNode('#text');\n node.text = text;\n return node;\n },\n\n createComment(_text: string): TestNode {\n return new TestNode('#comment');\n },\n\n setText(node: TestNode, text: string): void {\n node.text = text;\n },\n\n setElementText(el: TestNode, text: string): void {\n el.children = [];\n const textNode = new TestNode('#text');\n textNode.text = text;\n textNode.parent = el;\n el.children.push(textNode);\n },\n\n insert(child: TestNode, parent: TestNode, anchor?: TestNode | null): void {\n // Remove from old parent\n if (child.parent) {\n const idx = child.parent.children.indexOf(child);\n if (idx !== -1) child.parent.children.splice(idx, 1);\n }\n child.parent = parent;\n\n if (anchor) {\n const anchorIdx = parent.children.indexOf(anchor);\n if (anchorIdx !== -1) {\n parent.children.splice(anchorIdx, 0, child);\n return;\n }\n }\n parent.children.push(child);\n },\n\n remove(child: TestNode): void {\n if (child.parent) {\n const idx = child.parent.children.indexOf(child);\n if (idx !== -1) child.parent.children.splice(idx, 1);\n child.parent = null;\n }\n },\n\n patchProp(\n el: TestNode,\n key: string,\n _prevValue: unknown,\n nextValue: unknown,\n ): void {\n if (key === 'style') {\n el._style = (nextValue as Record<string, unknown>) ?? {};\n el.props[key] = nextValue;\n } else if (key === 'class') {\n el._class = (nextValue as string) ?? '';\n el.props[key] = nextValue;\n } else if (\n key.startsWith('bind') ||\n key.startsWith('catch') ||\n key.startsWith('on') ||\n key.startsWith('main-thread-bind') ||\n key.startsWith('main-thread-catch') ||\n key.startsWith('global-')\n ) {\n // Event handler\n if (typeof nextValue === 'function') {\n el._handlers.set(key, nextValue as Function);\n } else {\n el._handlers.delete(key);\n }\n el.props[key] = nextValue;\n } else {\n if (nextValue != null) {\n el.props[key] = nextValue;\n } else {\n delete el.props[key];\n }\n }\n },\n\n parentNode(node: TestNode): TestNode | null {\n return node.parent;\n },\n\n nextSibling(node: TestNode): TestNode | null {\n if (!node.parent) return null;\n const idx = node.parent.children.indexOf(node);\n return node.parent.children[idx + 1] ?? null;\n },\n\n cloneNode(node: TestNode): TestNode {\n return new TestNode(node.type);\n },\n};\n\nexport const testRenderer = createRenderer<TestNode, TestNode>(nodeOps);\nexport { nodeOps as testNodeOps };\n","/**\n * Query helpers for finding nodes in a TestNode tree.\n */\nimport { TestNode } from './test-node.js';\n\nexport function getByType(container: TestNode, type: string): TestNode {\n const node = container.findByType(type);\n if (!node) throw new Error(`No element found with type \"${type}\"`);\n return node;\n}\n\nexport function getAllByType(container: TestNode, type: string): TestNode[] {\n return container.findAllByType(type);\n}\n\nexport function getByText(container: TestNode, text: string): TestNode {\n const node = container.findByText(text);\n if (!node) throw new Error(`No element found with text \"${text}\"`);\n return node;\n}\n\nexport function queryByType(container: TestNode, type: string): TestNode | null {\n return container.findByType(type);\n}\n\nexport function queryByText(container: TestNode, text: string): TestNode | null {\n return container.findByText(text);\n}\n\nexport function getByProp(\n container: TestNode,\n key: string,\n value: unknown,\n): TestNode {\n function find(node: TestNode): TestNode | null {\n if (node.props[key] === value) return node;\n for (const child of node.children) {\n const found = find(child);\n if (found) return found;\n }\n return null;\n }\n const node = find(container);\n if (!node) throw new Error(`No element found with ${key}=\"${value}\"`);\n return node;\n}\n","/**\n * render() — mount a sigx Lynx component into a TestNode tree for testing.\n */\nimport type { JSXElement, AppContext } from '@sigx/lynx';\nimport { testRenderer } from './test-renderer.js';\nimport { TestNode } from './test-node.js';\nimport * as queries from './queries.js';\n\nexport interface RenderResult {\n /** The root container node. */\n container: TestNode;\n /** Unmount the component and clean up. */\n unmount: () => void;\n /** Find first node by element type (throws if not found). */\n getByType: (type: string) => TestNode;\n /** Find all nodes by element type. */\n getAllByType: (type: string) => TestNode[];\n /** Find first node containing text (throws if not found). */\n getByText: (text: string) => TestNode;\n /** Find first node by element type (returns null if not found). */\n queryByType: (type: string) => TestNode | null;\n /** Find first node containing text (returns null if not found). */\n queryByText: (text: string) => TestNode | null;\n /** Find first node by prop key/value (throws if not found). */\n getByProp: (key: string, value: unknown) => TestNode;\n /** Debug print the tree. */\n debug: () => string;\n}\n\n/**\n * Render a JSX element into an in-memory TestNode tree.\n *\n * @example\n * ```tsx\n * const { getByText, container } = render(<MyComponent name=\"World\" />);\n * expect(getByText('Hello World')).toBeTruthy();\n * ```\n */\nexport function render(\n element: JSXElement,\n options?: { appContext?: AppContext },\n): RenderResult {\n const container = new TestNode('root');\n\n testRenderer.render(element, container, options?.appContext ?? undefined);\n\n const unmount = () => {\n testRenderer.render(null, container);\n };\n\n return {\n container,\n unmount,\n getByType: (type) => queries.getByType(container, type),\n getAllByType: (type) => queries.getAllByType(container, type),\n getByText: (text) => queries.getByText(container, text),\n queryByType: (type) => queries.queryByType(container, type),\n queryByText: (text) => queries.queryByText(container, text),\n getByProp: (key, value) => queries.getByProp(container, key, value),\n debug: () => container.toDebugString(),\n };\n}\n","/**\n * Fire synthetic events on TestNode elements.\n */\nimport { TestNode } from './test-node.js';\n\ninterface SyntheticTouch {\n identifier?: number;\n x?: number;\n y?: number;\n pageX?: number;\n pageY?: number;\n clientX?: number;\n clientY?: number;\n}\n\ninterface SyntheticTouchEvent {\n touches?: SyntheticTouch[];\n changedTouches?: SyntheticTouch[];\n}\n\ninterface SyntheticScrollEvent {\n detail?: {\n scrollTop?: number;\n scrollLeft?: number;\n scrollHeight?: number;\n scrollWidth?: number;\n deltaX?: number;\n deltaY?: number;\n };\n}\n\ninterface SyntheticInputEvent {\n detail?: {\n value?: string;\n };\n}\n\n/** Create a normalized touch object with defaults. */\nexport function touch(\n pageX: number,\n pageY: number,\n identifier = 1,\n): SyntheticTouch {\n return { identifier, x: pageX, y: pageY, pageX, pageY, clientX: pageX, clientY: pageY };\n}\n\nfunction dispatchHandler(node: TestNode, handlerKey: string, event: unknown): void {\n const handler = node._handlers.get(handlerKey);\n if (handler) handler(event);\n}\n\nfunction normalizeTouchEvent(data?: SyntheticTouchEvent): object {\n return {\n type: 'touch',\n timestamp: Date.now(),\n touches: data?.touches ?? [],\n changedTouches: data?.changedTouches ?? data?.touches ?? [],\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {},\n };\n}\n\nexport const fireEvent = {\n /** Fire bindtap / onTap event. */\n tap(node: TestNode, data?: { x?: number; y?: number }): void {\n const x = data?.x ?? 0;\n const y = data?.y ?? 0;\n const event = {\n type: 'tap',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: { x, y },\n touches: [touch(x, y)],\n changedTouches: [touch(x, y)],\n };\n dispatchHandler(node, 'bindtap', event);\n dispatchHandler(node, 'onTap', event);\n },\n\n /** Fire bindtouchstart event. */\n touchStart(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchstart', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchmove event. */\n touchMove(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchmove', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchend event. */\n touchEnd(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchend', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchcancel event. */\n touchCancel(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchcancel', normalizeTouchEvent(data));\n },\n\n /** Fire bindscroll event. */\n scroll(node: TestNode, data?: SyntheticScrollEvent): void {\n const event = {\n type: 'scroll',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {\n scrollTop: 0,\n scrollLeft: 0,\n scrollHeight: 0,\n scrollWidth: 0,\n deltaX: 0,\n deltaY: 0,\n ...data?.detail,\n },\n };\n dispatchHandler(node, 'bindscroll', event);\n dispatchHandler(node, 'onScroll', event);\n },\n\n /** Fire bindinput event. */\n input(node: TestNode, data?: SyntheticInputEvent): void {\n const event = {\n type: 'input',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: { value: '', ...data?.detail },\n };\n dispatchHandler(node, 'bindinput', event);\n dispatchHandler(node, 'onInput', event);\n },\n\n /** Fire bindlongpress event. */\n longPress(node: TestNode): void {\n const event = {\n type: 'longpress',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {},\n };\n dispatchHandler(node, 'bindlongpress', event);\n dispatchHandler(node, 'onLongpress', event);\n },\n};\n","/**\n * Utilities for waiting on reactive updates in tests.\n */\n\n/**\n * Wait for all pending reactive effects and microtasks to complete.\n * Use after mutating signal state to ensure the rendered tree is updated.\n *\n * @example\n * ```ts\n * state.count = 5;\n * await waitForUpdate();\n * expect(getByText(container, '5')).toBeTruthy();\n * ```\n */\nexport function waitForUpdate(): Promise<void> {\n return new Promise<void>((resolve) => {\n // Microtask (Promise.resolve) runs reactive effects,\n // then setTimeout(0) ensures any scheduled flushes complete.\n Promise.resolve()\n .then(() => new Promise<void>(r => setTimeout(r, 0)))\n .then(resolve);\n });\n}\n\n/**\n * Run a callback and wait for reactive effects to flush.\n *\n * @example\n * ```ts\n * await act(() => {\n * state.count++;\n * state.name = 'Alice';\n * });\n * // Tree is now updated\n * ```\n */\nexport async function act(fn: () => void | Promise<void>): Promise<void> {\n await fn();\n await waitForUpdate();\n}\n"],"mappings":";;AAIA,IAAa,IAAb,MAAsB;CACpB;CACA,QAAiC,EAAE;CACnC,WAAuB,EAAE;CACzB,SAA0B;CAC1B;CAGA,4BAAmC,IAAI,KAAK;CAG5C,SAAkC,EAAE;CAGpC,SAAS;CAET,YAAY,GAAc;EACxB,KAAK,OAAO;;CAMd,WAAW,GAA+B;EACxC,KAAK,IAAM,KAAS,KAAK,UAAU;GACjC,IAAI,EAAM,SAAS,GAAM,OAAO;GAChC,IAAM,IAAQ,EAAM,WAAW,EAAK;GACpC,IAAI,GAAO,OAAO;;EAEpB,OAAO;;CAIT,cAAc,GAA0B;EACtC,IAAM,IAAsB,EAAE;EAC9B,KAAK,IAAM,KAAS,KAAK,UAEvB,AADI,EAAM,SAAS,KAAM,EAAQ,KAAK,EAAM,EAC5C,EAAQ,KAAK,GAAG,EAAM,cAAc,EAAK,CAAC;EAE5C,OAAO;;CAIT,WAAW,GAA+B;EACxC,IAAI,KAAK,SAAS,KAAA,KAAa,OAAO,KAAK,KAAK,CAAC,SAAS,EAAK,EAAE,OAAO;EACxE,KAAK,IAAM,KAAS,KAAK,UAAU;GACjC,IAAM,IAAQ,EAAM,WAAW,EAAK;GACpC,IAAI,GAAO,OAAO;;EAEpB,OAAO;;CAIT,cAAsB;EAEpB,OADI,KAAK,SAAS,KAAA,IACX,KAAK,SAAS,KAAI,MAAK,EAAE,aAAa,CAAC,CAAC,KAAK,GAAG,GADnB,OAAO,KAAK,KAAK;;CAKvD,cAAc,IAAS,GAAW;EAChC,IAAM,IAAM,KAAK,OAAO,EAAO;EAC/B,IAAI,KAAK,SAAS,SAAS,OAAO,GAAG,IAAM,KAAK,UAAU,KAAK,KAAK;EACpE,IAAI,KAAK,SAAS,YAAY,OAAO,GAAG,EAAI;EAC5C,IAAM,IAAQ,OAAO,KAAK,KAAK,MAAM,CAAC,SAAS,IAC3C,MAAM,OAAO,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,GAAG,EAAE,GAAG,KAAK,UAAU,EAAE,GAAG,CAAC,KAAK,IAAI,GACvF;EACJ,IAAI,KAAK,SAAS,WAAW,GAAG,OAAO,GAAG,EAAI,GAAG,KAAK,OAAO,EAAM;EACnE,IAAM,IAAW,KAAK,SAAS,KAAI,MAAK,EAAE,cAAc,IAAS,EAAE,CAAC,CAAC,KAAK,KAAK;EAC/E,OAAO,GAAG,EAAI,GAAG,KAAK,OAAO,EAAM,KAAK,EAAS,IAAI,EAAI,IAAI,KAAK,KAAK;;GCwC9D,IAAe,EAAmC;CAvG7D,cAAc,GAAwB;EACpC,OAAO,IAAI,EAAS,EAAK;;CAG3B,WAAW,GAAwB;EACjC,IAAM,IAAO,IAAI,EAAS,QAAQ;EAElC,OADA,EAAK,OAAO,GACL;;CAGT,cAAc,GAAyB;EACrC,OAAO,IAAI,EAAS,WAAW;;CAGjC,QAAQ,GAAgB,GAAoB;EAC1C,EAAK,OAAO;;CAGd,eAAe,GAAc,GAAoB;EAC/C,EAAG,WAAW,EAAE;EAChB,IAAM,IAAW,IAAI,EAAS,QAAQ;EAGtC,AAFA,EAAS,OAAO,GAChB,EAAS,SAAS,GAClB,EAAG,SAAS,KAAK,EAAS;;CAG5B,OAAO,GAAiB,GAAkB,GAAgC;EAExE,IAAI,EAAM,QAAQ;GAChB,IAAM,IAAM,EAAM,OAAO,SAAS,QAAQ,EAAM;GAChD,AAAI,MAAQ,MAAI,EAAM,OAAO,SAAS,OAAO,GAAK,EAAE;;EAItD,IAFA,EAAM,SAAS,GAEX,GAAQ;GACV,IAAM,IAAY,EAAO,SAAS,QAAQ,EAAO;GACjD,IAAI,MAAc,IAAI;IACpB,EAAO,SAAS,OAAO,GAAW,GAAG,EAAM;IAC3C;;;EAGJ,EAAO,SAAS,KAAK,EAAM;;CAG7B,OAAO,GAAuB;EAC5B,IAAI,EAAM,QAAQ;GAChB,IAAM,IAAM,EAAM,OAAO,SAAS,QAAQ,EAAM;GAEhD,AADI,MAAQ,MAAI,EAAM,OAAO,SAAS,OAAO,GAAK,EAAE,EACpD,EAAM,SAAS;;;CAInB,UACE,GACA,GACA,GACA,GACM;EACN,AAAI,MAAQ,WACV,EAAG,SAAU,KAAyC,EAAE,EACxD,EAAG,MAAM,KAAO,KACP,MAAQ,WACjB,EAAG,SAAU,KAAwB,IACrC,EAAG,MAAM,KAAO,KAEhB,EAAI,WAAW,OAAO,IACtB,EAAI,WAAW,QAAQ,IACvB,EAAI,WAAW,KAAK,IACpB,EAAI,WAAW,mBAAmB,IAClC,EAAI,WAAW,oBAAoB,IACnC,EAAI,WAAW,UAAU,IAGrB,OAAO,KAAc,aACvB,EAAG,UAAU,IAAI,GAAK,EAAsB,GAE5C,EAAG,UAAU,OAAO,EAAI,EAE1B,EAAG,MAAM,KAAO,KAEZ,KAAa,OAGf,OAAO,EAAG,MAAM,KAFhB,EAAG,MAAM,KAAO;;CAOtB,WAAW,GAAiC;EAC1C,OAAO,EAAK;;CAGd,YAAY,GAAiC;EAC3C,IAAI,CAAC,EAAK,QAAQ,OAAO;EACzB,IAAM,IAAM,EAAK,OAAO,SAAS,QAAQ,EAAK;EAC9C,OAAO,EAAK,OAAO,SAAS,IAAM,MAAM;;CAG1C,UAAU,GAA0B;EAClC,OAAO,IAAI,EAAS,EAAK,KAAK;;CAI6B,CAAQ;;;AC3GvE,SAAgB,EAAU,GAAqB,GAAwB;CACrE,IAAM,IAAO,EAAU,WAAW,EAAK;CACvC,IAAI,CAAC,GAAM,MAAU,MAAM,+BAA+B,EAAK,GAAG;CAClE,OAAO;;AAGT,SAAgB,EAAa,GAAqB,GAA0B;CAC1E,OAAO,EAAU,cAAc,EAAK;;AAGtC,SAAgB,EAAU,GAAqB,GAAwB;CACrE,IAAM,IAAO,EAAU,WAAW,EAAK;CACvC,IAAI,CAAC,GAAM,MAAU,MAAM,+BAA+B,EAAK,GAAG;CAClE,OAAO;;AAGT,SAAgB,EAAY,GAAqB,GAA+B;CAC9E,OAAO,EAAU,WAAW,EAAK;;AAGnC,SAAgB,EAAY,GAAqB,GAA+B;CAC9E,OAAO,EAAU,WAAW,EAAK;;AAGnC,SAAgB,EACd,GACA,GACA,GACU;CACV,SAAS,EAAK,GAAiC;EAC7C,IAAI,EAAK,MAAM,OAAS,GAAO,OAAO;EACtC,KAAK,IAAM,KAAS,EAAK,UAAU;GACjC,IAAM,IAAQ,EAAK,EAAM;GACzB,IAAI,GAAO,OAAO;;EAEpB,OAAO;;CAET,IAAM,IAAO,EAAK,EAAU;CAC5B,IAAI,CAAC,GAAM,MAAU,MAAM,yBAAyB,EAAI,IAAI,EAAM,GAAG;CACrE,OAAO;;;;ACNT,SAAgB,EACd,GACA,GACc;CACd,IAAM,IAAY,IAAI,EAAS,OAAO;CAQtC,OANA,EAAa,OAAO,GAAS,GAAW,GAAS,cAAc,KAAA,EAAU,EAMlE;EACL;EACA,eANoB;GACpB,EAAa,OAAO,MAAM,EAAU;;EAMpC,YAAY,MAAS,EAAkB,GAAW,EAAK;EACvD,eAAe,MAAS,EAAqB,GAAW,EAAK;EAC7D,YAAY,MAAS,EAAkB,GAAW,EAAK;EACvD,cAAc,MAAS,EAAoB,GAAW,EAAK;EAC3D,cAAc,MAAS,EAAoB,GAAW,EAAK;EAC3D,YAAY,GAAK,MAAU,EAAkB,GAAW,GAAK,EAAM;EACnE,aAAa,EAAU,eAAe;EACvC;;;;ACtBH,SAAgB,EACd,GACA,GACA,IAAa,GACG;CAChB,OAAO;EAAE;EAAY,GAAG;EAAO,GAAG;EAAO;EAAO;EAAO,SAAS;EAAO,SAAS;EAAO;;AAGzF,SAAS,EAAgB,GAAgB,GAAoB,GAAsB;CACjF,IAAM,IAAU,EAAK,UAAU,IAAI,EAAW;CAC9C,AAAI,KAAS,EAAQ,EAAM;;AAG7B,SAAS,EAAoB,GAAoC;CAC/D,OAAO;EACL,MAAM;EACN,WAAW,KAAK,KAAK;EACrB,SAAS,GAAM,WAAW,EAAE;EAC5B,gBAAgB,GAAM,kBAAkB,GAAM,WAAW,EAAE;EAC3D,QAAQ;GAAE,IAAI;GAAI,SAAS,EAAE;GAAE,KAAK;GAAG;EACvC,eAAe;GAAE,IAAI;GAAI,SAAS,EAAE;GAAE,KAAK;GAAG;EAC9C,QAAQ,EAAE;EACX;;AAGH,IAAa,IAAY;CAEvB,IAAI,GAAgB,GAAyC;EAC3D,IAAM,IAAI,GAAM,KAAK,GACf,IAAI,GAAM,KAAK,GACf,IAAQ;GACZ,MAAM;GACN,WAAW,KAAK,KAAK;GACrB,QAAQ;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GACvC,eAAe;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GAC9C,QAAQ;IAAE;IAAG;IAAG;GAChB,SAAS,CAAC,EAAM,GAAG,EAAE,CAAC;GACtB,gBAAgB,CAAC,EAAM,GAAG,EAAE,CAAC;GAC9B;EAED,AADA,EAAgB,GAAM,WAAW,EAAM,EACvC,EAAgB,GAAM,SAAS,EAAM;;CAIvC,WAAW,GAAgB,GAAkC;EAC3D,EAAgB,GAAM,kBAAkB,EAAoB,EAAK,CAAC;;CAIpE,UAAU,GAAgB,GAAkC;EAC1D,EAAgB,GAAM,iBAAiB,EAAoB,EAAK,CAAC;;CAInE,SAAS,GAAgB,GAAkC;EACzD,EAAgB,GAAM,gBAAgB,EAAoB,EAAK,CAAC;;CAIlE,YAAY,GAAgB,GAAkC;EAC5D,EAAgB,GAAM,mBAAmB,EAAoB,EAAK,CAAC;;CAIrE,OAAO,GAAgB,GAAmC;EACxD,IAAM,IAAQ;GACZ,MAAM;GACN,WAAW,KAAK,KAAK;GACrB,QAAQ;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GACvC,eAAe;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GAC9C,QAAQ;IACN,WAAW;IACX,YAAY;IACZ,cAAc;IACd,aAAa;IACb,QAAQ;IACR,QAAQ;IACR,GAAG,GAAM;IACV;GACF;EAED,AADA,EAAgB,GAAM,cAAc,EAAM,EAC1C,EAAgB,GAAM,YAAY,EAAM;;CAI1C,MAAM,GAAgB,GAAkC;EACtD,IAAM,IAAQ;GACZ,MAAM;GACN,WAAW,KAAK,KAAK;GACrB,QAAQ;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GACvC,eAAe;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GAC9C,QAAQ;IAAE,OAAO;IAAI,GAAG,GAAM;IAAQ;GACvC;EAED,AADA,EAAgB,GAAM,aAAa,EAAM,EACzC,EAAgB,GAAM,WAAW,EAAM;;CAIzC,UAAU,GAAsB;EAC9B,IAAM,IAAQ;GACZ,MAAM;GACN,WAAW,KAAK,KAAK;GACrB,QAAQ;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GACvC,eAAe;IAAE,IAAI;IAAI,SAAS,EAAE;IAAE,KAAK;IAAG;GAC9C,QAAQ,EAAE;GACX;EAED,AADA,EAAgB,GAAM,iBAAiB,EAAM,EAC7C,EAAgB,GAAM,eAAe,EAAM;;CAE9C;;;ACpID,SAAgB,IAA+B;CAC7C,OAAO,IAAI,SAAe,MAAY;EAGpC,QAAQ,SAAS,CACd,WAAW,IAAI,SAAc,MAAK,WAAW,GAAG,EAAE,CAAC,CAAC,CACpD,KAAK,EAAQ;GAChB;;AAeJ,eAAsB,EAAI,GAA+C;CAEvE,AADA,MAAM,GAAI,EACV,MAAM,GAAe"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/test-node.ts","../src/test-renderer.ts","../src/queries.ts","../src/render.ts","../src/fire-event.ts","../src/flush.ts"],"sourcesContent":["/**\n * TestNode — lightweight in-memory tree node for test rendering.\n * Replaces ShadowElement + Lynx PAPI for testing purposes.\n */\nexport class TestNode {\n type: string;\n props: Record<string, unknown> = {};\n children: TestNode[] = [];\n parent: TestNode | null = null;\n text?: string;\n\n /** Event handlers keyed by prop name (e.g. 'bindtap', 'bindtouchstart'). */\n _handlers: Map<string, Function> = new Map();\n\n /** Style object (last value from patchProp 'style'). */\n _style: Record<string, unknown> = {};\n\n /** Class string. */\n _class = '';\n\n constructor(type: string) {\n this.type = type;\n }\n\n // -- Tree queries --\n\n /** Find first descendant matching element type. */\n findByType(type: string): TestNode | null {\n for (const child of this.children) {\n if (child.type === type) return child;\n const found = child.findByType(type);\n if (found) return found;\n }\n return null;\n }\n\n /** Find all descendants matching element type. */\n findAllByType(type: string): TestNode[] {\n const results: TestNode[] = [];\n for (const child of this.children) {\n if (child.type === type) results.push(child);\n results.push(...child.findAllByType(type));\n }\n return results;\n }\n\n /** Find first descendant containing the given text. */\n findByText(text: string): TestNode | null {\n if (this.text !== undefined && String(this.text).includes(text)) return this;\n for (const child of this.children) {\n const found = child.findByText(text);\n if (found) return found;\n }\n return null;\n }\n\n /** Get all text content from this node and descendants. */\n textContent(): string {\n if (this.text !== undefined) return String(this.text);\n return this.children.map(c => c.textContent()).join('');\n }\n\n /** Debug: serialize tree to a readable string. */\n toDebugString(indent = 0): string {\n const pad = ' '.repeat(indent);\n if (this.type === '#text') return `${pad}${JSON.stringify(this.text)}`;\n if (this.type === '#comment') return `${pad}<!-- -->`;\n const attrs = Object.keys(this.props).length > 0\n ? ' ' + Object.entries(this.props).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(' ')\n : '';\n if (this.children.length === 0) return `${pad}<${this.type}${attrs} />`;\n const childStr = this.children.map(c => c.toDebugString(indent + 1)).join('\\n');\n return `${pad}<${this.type}${attrs}>\\n${childStr}\\n${pad}</${this.type}>`;\n }\n}\n","/**\n * Test renderer — implements RendererOptions<TestNode, TestNode> for\n * in-memory rendering without Lynx PAPI.\n */\nimport { createRenderer } from '@sigx/runtime-core/internals';\nimport type { RendererOptions } from '@sigx/runtime-core/internals';\nimport { TestNode } from './test-node';\n\nconst nodeOps: RendererOptions<TestNode, TestNode> = {\n createElement(type: string): TestNode {\n return new TestNode(type);\n },\n\n createText(text: string): TestNode {\n const node = new TestNode('#text');\n node.text = text;\n return node;\n },\n\n createComment(_text: string): TestNode {\n return new TestNode('#comment');\n },\n\n setText(node: TestNode, text: string): void {\n node.text = text;\n },\n\n setElementText(el: TestNode, text: string): void {\n el.children = [];\n const textNode = new TestNode('#text');\n textNode.text = text;\n textNode.parent = el;\n el.children.push(textNode);\n },\n\n insert(child: TestNode, parent: TestNode, anchor?: TestNode | null): void {\n // Remove from old parent\n if (child.parent) {\n const idx = child.parent.children.indexOf(child);\n if (idx !== -1) child.parent.children.splice(idx, 1);\n }\n child.parent = parent;\n\n if (anchor) {\n const anchorIdx = parent.children.indexOf(anchor);\n if (anchorIdx !== -1) {\n parent.children.splice(anchorIdx, 0, child);\n return;\n }\n }\n parent.children.push(child);\n },\n\n remove(child: TestNode): void {\n if (child.parent) {\n const idx = child.parent.children.indexOf(child);\n if (idx !== -1) child.parent.children.splice(idx, 1);\n child.parent = null;\n }\n },\n\n patchProp(\n el: TestNode,\n key: string,\n _prevValue: unknown,\n nextValue: unknown,\n ): void {\n if (key === 'style') {\n el._style = (nextValue as Record<string, unknown>) ?? {};\n el.props[key] = nextValue;\n } else if (key === 'class') {\n el._class = (nextValue as string) ?? '';\n el.props[key] = nextValue;\n } else if (\n key.startsWith('bind') ||\n key.startsWith('catch') ||\n key.startsWith('on') ||\n key.startsWith('main-thread-bind') ||\n key.startsWith('main-thread-catch') ||\n key.startsWith('global-')\n ) {\n // Event handler\n if (typeof nextValue === 'function') {\n el._handlers.set(key, nextValue as Function);\n } else {\n el._handlers.delete(key);\n }\n el.props[key] = nextValue;\n } else {\n if (nextValue != null) {\n el.props[key] = nextValue;\n } else {\n delete el.props[key];\n }\n }\n },\n\n parentNode(node: TestNode): TestNode | null {\n return node.parent;\n },\n\n nextSibling(node: TestNode): TestNode | null {\n if (!node.parent) return null;\n const idx = node.parent.children.indexOf(node);\n return node.parent.children[idx + 1] ?? null;\n },\n\n cloneNode(node: TestNode): TestNode {\n return new TestNode(node.type);\n },\n};\n\nexport const testRenderer = createRenderer<TestNode, TestNode>(nodeOps);\nexport { nodeOps as testNodeOps };\n","/**\n * Query helpers for finding nodes in a TestNode tree.\n */\nimport { TestNode } from './test-node';\n\nexport function getByType(container: TestNode, type: string): TestNode {\n const node = container.findByType(type);\n if (!node) throw new Error(`No element found with type \"${type}\"`);\n return node;\n}\n\nexport function getAllByType(container: TestNode, type: string): TestNode[] {\n return container.findAllByType(type);\n}\n\nexport function getByText(container: TestNode, text: string): TestNode {\n const node = container.findByText(text);\n if (!node) throw new Error(`No element found with text \"${text}\"`);\n return node;\n}\n\nexport function queryByType(container: TestNode, type: string): TestNode | null {\n return container.findByType(type);\n}\n\nexport function queryByText(container: TestNode, text: string): TestNode | null {\n return container.findByText(text);\n}\n\nexport function getByProp(\n container: TestNode,\n key: string,\n value: unknown,\n): TestNode {\n function find(node: TestNode): TestNode | null {\n if (node.props[key] === value) return node;\n for (const child of node.children) {\n const found = find(child);\n if (found) return found;\n }\n return null;\n }\n const node = find(container);\n if (!node) throw new Error(`No element found with ${key}=\"${value}\"`);\n return node;\n}\n","/**\n * render() — mount a sigx Lynx component into a TestNode tree for testing.\n */\nimport type { JSXElement, AppContext } from '@sigx/lynx';\nimport { testRenderer } from './test-renderer';\nimport { TestNode } from './test-node';\nimport * as queries from './queries';\n\nexport interface RenderResult {\n /** The root container node. */\n container: TestNode;\n /** Unmount the component and clean up. */\n unmount: () => void;\n /** Find first node by element type (throws if not found). */\n getByType: (type: string) => TestNode;\n /** Find all nodes by element type. */\n getAllByType: (type: string) => TestNode[];\n /** Find first node containing text (throws if not found). */\n getByText: (text: string) => TestNode;\n /** Find first node by element type (returns null if not found). */\n queryByType: (type: string) => TestNode | null;\n /** Find first node containing text (returns null if not found). */\n queryByText: (text: string) => TestNode | null;\n /** Find first node by prop key/value (throws if not found). */\n getByProp: (key: string, value: unknown) => TestNode;\n /** Debug print the tree. */\n debug: () => string;\n}\n\n/**\n * Render a JSX element into an in-memory TestNode tree.\n *\n * @example\n * ```tsx\n * const { getByText, container } = render(<MyComponent name=\"World\" />);\n * expect(getByText('Hello World')).toBeTruthy();\n * ```\n */\nexport function render(\n element: JSXElement,\n options?: { appContext?: AppContext },\n): RenderResult {\n const container = new TestNode('root');\n\n testRenderer.render(element, container, options?.appContext ?? undefined);\n\n const unmount = () => {\n testRenderer.render(null, container);\n };\n\n return {\n container,\n unmount,\n getByType: (type) => queries.getByType(container, type),\n getAllByType: (type) => queries.getAllByType(container, type),\n getByText: (text) => queries.getByText(container, text),\n queryByType: (type) => queries.queryByType(container, type),\n queryByText: (text) => queries.queryByText(container, text),\n getByProp: (key, value) => queries.getByProp(container, key, value),\n debug: () => container.toDebugString(),\n };\n}\n","/**\n * Fire synthetic events on TestNode elements.\n */\nimport { TestNode } from './test-node';\n\ninterface SyntheticTouch {\n identifier?: number;\n x?: number;\n y?: number;\n pageX?: number;\n pageY?: number;\n clientX?: number;\n clientY?: number;\n}\n\ninterface SyntheticTouchEvent {\n touches?: SyntheticTouch[];\n changedTouches?: SyntheticTouch[];\n}\n\ninterface SyntheticScrollEvent {\n detail?: {\n scrollTop?: number;\n scrollLeft?: number;\n scrollHeight?: number;\n scrollWidth?: number;\n deltaX?: number;\n deltaY?: number;\n };\n}\n\ninterface SyntheticInputEvent {\n detail?: {\n value?: string;\n };\n}\n\n/** Create a normalized touch object with defaults. */\nexport function touch(\n pageX: number,\n pageY: number,\n identifier = 1,\n): SyntheticTouch {\n return { identifier, x: pageX, y: pageY, pageX, pageY, clientX: pageX, clientY: pageY };\n}\n\nfunction dispatchHandler(node: TestNode, handlerKey: string, event: unknown): void {\n const handler = node._handlers.get(handlerKey);\n if (handler) handler(event);\n}\n\nfunction normalizeTouchEvent(data?: SyntheticTouchEvent): object {\n return {\n type: 'touch',\n timestamp: Date.now(),\n touches: data?.touches ?? [],\n changedTouches: data?.changedTouches ?? data?.touches ?? [],\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {},\n };\n}\n\nexport const fireEvent = {\n /** Fire bindtap / onTap event. */\n tap(node: TestNode, data?: { x?: number; y?: number }): void {\n const x = data?.x ?? 0;\n const y = data?.y ?? 0;\n const event = {\n type: 'tap',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: { x, y },\n touches: [touch(x, y)],\n changedTouches: [touch(x, y)],\n };\n dispatchHandler(node, 'bindtap', event);\n dispatchHandler(node, 'onTap', event);\n },\n\n /** Fire bindtouchstart event. */\n touchStart(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchstart', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchmove event. */\n touchMove(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchmove', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchend event. */\n touchEnd(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchend', normalizeTouchEvent(data));\n },\n\n /** Fire bindtouchcancel event. */\n touchCancel(node: TestNode, data?: SyntheticTouchEvent): void {\n dispatchHandler(node, 'bindtouchcancel', normalizeTouchEvent(data));\n },\n\n /** Fire bindscroll event. */\n scroll(node: TestNode, data?: SyntheticScrollEvent): void {\n const event = {\n type: 'scroll',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {\n scrollTop: 0,\n scrollLeft: 0,\n scrollHeight: 0,\n scrollWidth: 0,\n deltaX: 0,\n deltaY: 0,\n ...data?.detail,\n },\n };\n dispatchHandler(node, 'bindscroll', event);\n dispatchHandler(node, 'onScroll', event);\n },\n\n /** Fire bindinput event. */\n input(node: TestNode, data?: SyntheticInputEvent): void {\n const event = {\n type: 'input',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: { value: '', ...data?.detail },\n };\n dispatchHandler(node, 'bindinput', event);\n dispatchHandler(node, 'onInput', event);\n },\n\n /** Fire bindlongpress event. */\n longPress(node: TestNode): void {\n const event = {\n type: 'longpress',\n timestamp: Date.now(),\n target: { id: '', dataset: {}, uid: 0 },\n currentTarget: { id: '', dataset: {}, uid: 0 },\n detail: {},\n };\n dispatchHandler(node, 'bindlongpress', event);\n dispatchHandler(node, 'onLongpress', event);\n },\n};\n","/**\n * Utilities for waiting on reactive updates in tests.\n */\n\n/**\n * Wait for all pending reactive effects and microtasks to complete.\n * Use after mutating signal state to ensure the rendered tree is updated.\n *\n * @example\n * ```ts\n * state.count = 5;\n * await waitForUpdate();\n * expect(getByText(container, '5')).toBeTruthy();\n * ```\n */\nexport function waitForUpdate(): Promise<void> {\n return new Promise<void>((resolve) => {\n // Microtask (Promise.resolve) runs reactive effects,\n // then setTimeout(0) ensures any scheduled flushes complete.\n Promise.resolve()\n .then(() => new Promise<void>(r => setTimeout(r, 0)))\n .then(resolve);\n });\n}\n\n/**\n * Run a callback and wait for reactive effects to flush.\n *\n * @example\n * ```ts\n * await act(() => {\n * state.count++;\n * state.name = 'Alice';\n * });\n * // Tree is now updated\n * ```\n */\nexport async function act(fn: () => void | Promise<void>): Promise<void> {\n await fn();\n await waitForUpdate();\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/mt/index.ts"],"sourcesContent":["/**\n * Public JS API for the main-thread (MT) gesture/worklet test harness.\n *\n * Pair with `@sigx/lynx-testing/mt/setup` in your vitest setupFiles. See\n * the package README for a full example.\n *\n * The harness lets you write tests that:\n * 1. Compile a `.tsx` source file with `transformReactLynxSync`\n * (target: `LEPUS`) to extract the `registerWorkletInternal(...)`\n * calls the SWC transform emits for `'main thread'` worklets.\n * 2. Eval those registrations into the upstream worklet runtime that\n * `setup.ts` boots, populating `lynxWorkletImpl._workletMap`.\n * 3. Call each worklet directly with a fabricated `_c` capture and a\n * synthetic gesture event, asserting the worklet's MT-side state\n * mutations and any `setStyleProperties` / `runOnBackground` calls.\n *\n * Use `compileMTWorklets()` for the common case (one source file, get\n * the registered worklets back). Drop down to `extractRegistrations()`\n * if you need finer control.\n */\n\nimport { transformReactLynxSync } from '@lynx-js/react/transform';\nimport { _getJsContext, _resetJsContextSpy } from './setup.js';\n\n/**\n * Synthetic `MainThreadRef` shape — `{ current, _wvid }`. Worklets read\n * `ref.current.value` and may mutate `ref.current.value`.\n */\nexport function makeRef<T>(current: T, id = 1): { current: T; _wvid: number } {\n return { current, _wvid: id };\n}\n\n/**\n * Fabricate a Lynx pan-gesture event payload as the iOS arena would\n * deliver it. The payload is nested under `e.params` (NOT top-level on\n * `e`) — your worklet should read pageX/pageY from `e.params.pageX`,\n * mirroring real device behaviour.\n *\n * Verified against `LynxBaseGestureHandler.m::eventParamsFromTouchEvent`\n * + `LynxPanGestureHandler.m::eventParamsInActive` on iOS Lynx 3.5.\n */\nexport function fabricatePanEvent(opts: { pageX: number; pageY?: number }): MTGestureEvent {\n const params = {\n timestamp: Date.now(),\n type: 'touchmove',\n x: opts.pageX,\n y: opts.pageY ?? 0,\n pageX: opts.pageX,\n pageY: opts.pageY ?? 0,\n clientX: opts.pageX,\n clientY: opts.pageY ?? 0,\n scrollX: 0,\n scrollY: 0,\n isAtStart: 0,\n isAtEnd: 0,\n };\n return {\n type: 'onUpdate',\n timestamp: Date.now(),\n currentTarget: { element: null },\n target: { element: null },\n params,\n detail: params,\n };\n}\n\n/**\n * Fabricate a Lynx tap-gesture event payload. Same shape as the pan event\n * minus the scroll-related fields the pan handler adds; tests rarely read\n * either, so the difference is mostly cosmetic.\n */\nexport function fabricateTapEvent(opts: { pageX?: number; pageY?: number } = {}): MTGestureEvent {\n const params = {\n timestamp: Date.now(),\n type: 'touchend',\n x: opts.pageX ?? 0,\n y: opts.pageY ?? 0,\n pageX: opts.pageX ?? 0,\n pageY: opts.pageY ?? 0,\n clientX: opts.pageX ?? 0,\n clientY: opts.pageY ?? 0,\n };\n return {\n type: 'onStart',\n timestamp: Date.now(),\n currentTarget: { element: null },\n target: { element: null },\n params,\n detail: params,\n };\n}\n\n/**\n * Common shape for the events the iOS gesture arena delivers to MT\n * worklets. Top-level keys are dispatch metadata; the actual touch data\n * lives under `params` (and a duplicate `detail`).\n */\nexport interface MTGestureEvent {\n type: string;\n timestamp: number;\n currentTarget: { element: null };\n target: { element: null };\n params: Record<string, unknown>;\n detail: Record<string, unknown>;\n}\n\n/**\n * Extract `registerWorkletInternal(...)` calls from a LEPUS-target\n * transform output. Bracket-depth counting handles nested braces in the\n * function body. Mirror of the lynx-plugin internal so tests don't pull\n * a build-time package in as a runtime dep.\n */\nexport function extractRegistrations(lepusCode: string): string {\n const out: string[] = [];\n const marker = 'registerWorkletInternal(';\n let from = 0;\n\n while (true) {\n const idx = lepusCode.indexOf(marker, from);\n if (idx === -1) break;\n\n let depth = 0;\n let i = idx + marker.length - 1;\n for (; i < lepusCode.length; i++) {\n const ch = lepusCode[i];\n if (ch === '(') depth++;\n else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n\n let end = i + 1;\n if (end < lepusCode.length && lepusCode[end] === ';') end++;\n out.push(lepusCode.slice(idx, end));\n from = end;\n }\n\n return out.join('\\n');\n}\n\n/**\n * Get the live `lynxWorkletImpl._workletMap` populated by the upstream\n * worklet runtime that `mt/setup.ts` bootstrapped. Each entry is a\n * `_wkltId` → callable mapping. After `compileMTWorklets()` evals new\n * registrations, this map will include them.\n *\n * Throws if `mt/setup.ts` didn't run — typically because the consumer\n * forgot to add it to `setupFiles`.\n */\nexport function getWorkletMap(): Record<string, Function> {\n interface WorkletImpl {\n _workletMap: Record<string, Function>;\n }\n const impl = (globalThis as { lynxWorkletImpl?: WorkletImpl }).lynxWorkletImpl;\n if (!impl) {\n throw new Error(\n '[lynx-testing/mt] lynxWorkletImpl is not initialized — add ' +\n '`@sigx/lynx-testing/mt/setup` to your vitest config\\'s ' +\n '`setupFiles` array.'\n );\n }\n return impl._workletMap;\n}\n\n/**\n * Compile a `.tsx` source file as a LEPUS worklet bundle, eval the\n * resulting `registerWorkletInternal(...)` calls into the live runtime,\n * and return the worklets that were just registered (in source order).\n *\n * The returned array indexes into `lynxWorkletImpl._workletMap`'s newest\n * entries — i.e. `result[0]` is the first worklet registered by this\n * compile. For most tests this is enough; for cross-test sharing or\n * per-`_wkltId` access, fall back to `getWorkletMap()`.\n *\n * @example\n * ```ts\n * import { readFileSync } from 'fs';\n * import { compileMTWorklets, fabricatePanEvent, makeRef } from '@sigx/lynx-testing/mt';\n *\n * const SRC = path.resolve(__dirname, '../../src/components/Draggable.tsx');\n * const worklets = compileMTWorklets({\n * filename: SRC,\n * source: readFileSync(SRC, 'utf8'),\n * });\n * // Source-order: onBegin (:1), onStart (:2), onUpdate (:3), onEnd (:4)\n * const onUpdate = worklets[2]!;\n *\n * const drag = { startPageX: 100, startPageY: 50, ... };\n * onUpdate.call({ _c: { drag: makeRef(drag, 1), ... } }, fabricatePanEvent({ pageX: 130, pageY: 55 }));\n * expect(drag.startPageX).toBe(100);\n * ```\n */\nexport function compileMTWorklets(opts: {\n filename: string;\n source: string;\n /**\n * Override the runtime package name passed to the SWC transform.\n * Defaults to `@sigx/lynx-runtime-main`, which matches what the\n * production build uses.\n */\n runtimePkg?: string;\n}): Function[] {\n const { filename, source, runtimePkg = '@sigx/lynx-runtime-main' } = opts;\n\n const result = transformReactLynxSync(source, {\n pluginName: 'sigx:test',\n filename,\n sourcemap: false,\n cssScope: false,\n shake: false,\n compat: false,\n refresh: false,\n defineDCE: false,\n directiveDCE: false,\n snapshot: false,\n worklet: { target: 'LEPUS', filename, runtimePkg },\n });\n\n if (result.errors && result.errors.length > 0) {\n throw new Error(\n '[lynx-testing/mt] LEPUS transform errors for ' + filename + ':\\n' +\n result.errors.map((e) => ' - ' + (e.text ?? '<unknown>')).join('\\n')\n );\n }\n\n // Eval the registrations against `globalThis.registerWorkletInternal`\n // (installed by `setup.ts`). SWC produces deterministic `_wkltId`s\n // from the source content hash + index, so re-compiling the same\n // source overwrites the same map entries — we can't diff by\n // map-presence to find what this call registered. Instead parse the\n // IDs directly out of the registration source.\n const registrations = extractRegistrations(result.code);\n new Function(registrations)();\n\n // Each registration looks like:\n // registerWorkletInternal(\"main-thread\", \"<wkltId>\", function(...) {...});\n // Extract the wkltId from the second string literal in source order.\n const idRegex = /registerWorkletInternal\\(\\s*\"main-thread\"\\s*,\\s*\"([^\"]+)\"/g;\n const ids: string[] = [];\n let m: RegExpExecArray | null;\n while ((m = idRegex.exec(registrations)) !== null) {\n ids.push(m[1]!);\n }\n\n const map = getWorkletMap();\n return ids.map(id => {\n const fn = map[id];\n if (!fn) {\n throw new Error(\n '[lynx-testing/mt] worklet `' + id + '` was registered by the ' +\n 'compile but is missing from lynxWorkletImpl._workletMap. The ' +\n 'upstream worklet runtime may not have evaluated correctly.'\n );\n }\n return fn;\n });\n}\n\n/**\n * Read the JS-context spy that `mt/setup.ts` installed on the lynx mock.\n * Useful for asserting `runOnBackground` / `Lynx.Sigx.AvPublish` event\n * dispatches from within a worklet.\n *\n * @example\n * ```ts\n * import { getJsContext } from '@sigx/lynx-testing/mt';\n *\n * onUpdate.call(ctx, fabricatePanEvent({ pageX: 130 }));\n * const ctx = getJsContext();\n * expect(ctx.dispatchEvent).toHaveBeenCalledWith(\n * expect.objectContaining({ type: 'Lynx.Sigx.AvPublish' })\n * );\n * ```\n */\nexport function getJsContext(): { addEventListener: Function; dispatchEvent: Function } {\n return _getJsContext();\n}\n\n/**\n * Wipe the JS-context spy between tests so dispatchEvent / addEventListener\n * call counts don't bleed across cases.\n */\nexport function resetJsContextSpy(): void {\n _resetJsContextSpy();\n}\n"],"mappings":";;;AA4BA,SAAgB,EAAW,GAAY,IAAK,GAAkC;CAC1E,OAAO;EAAE;EAAS,OAAO;EAAI;;AAYjC,SAAgB,EAAkB,GAAyD;CACvF,IAAM,IAAS;EACX,WAAW,KAAK,KAAK;EACrB,MAAM;EACN,GAAG,EAAK;EACR,GAAG,EAAK,SAAS;EACjB,OAAO,EAAK;EACZ,OAAO,EAAK,SAAS;EACrB,SAAS,EAAK;EACd,SAAS,EAAK,SAAS;EACvB,SAAS;EACT,SAAS;EACT,WAAW;EACX,SAAS;EACZ;CACD,OAAO;EACH,MAAM;EACN,WAAW,KAAK,KAAK;EACrB,eAAe,EAAE,SAAS,MAAM;EAChC,QAAQ,EAAE,SAAS,MAAM;EACzB;EACA,QAAQ;EACX;;AAQL,SAAgB,EAAkB,IAA2C,EAAE,EAAkB;CAC7F,IAAM,IAAS;EACX,WAAW,KAAK,KAAK;EACrB,MAAM;EACN,GAAG,EAAK,SAAS;EACjB,GAAG,EAAK,SAAS;EACjB,OAAO,EAAK,SAAS;EACrB,OAAO,EAAK,SAAS;EACrB,SAAS,EAAK,SAAS;EACvB,SAAS,EAAK,SAAS;EAC1B;CACD,OAAO;EACH,MAAM;EACN,WAAW,KAAK,KAAK;EACrB,eAAe,EAAE,SAAS,MAAM;EAChC,QAAQ,EAAE,SAAS,MAAM;EACzB;EACA,QAAQ;EACX;;AAuBL,SAAgB,EAAqB,GAA2B;CAC5D,IAAM,IAAgB,EAAE,EAEpB,IAAO;CAEX,SAAa;EACT,IAAM,IAAM,EAAU,QAAQ,4BAAQ,EAAK;EAC3C,IAAI,MAAQ,IAAI;EAEhB,IAAI,IAAQ,GACR,IAAI,IAAM,KAAgB;EAC9B,OAAO,IAAI,EAAU,QAAQ,KAAK;GAC9B,IAAM,IAAK,EAAU;GACrB,IAAI,MAAO,KAAK;QACX,IAAI,MAAO,QACZ,KACI,MAAU,IAAG;;EAIzB,IAAI,IAAM,IAAI;EAGd,AAFI,IAAM,EAAU,UAAU,EAAU,OAAS,OAAK,KACtD,EAAI,KAAK,EAAU,MAAM,GAAK,EAAI,CAAC,EACnC,IAAO;;CAGX,OAAO,EAAI,KAAK,KAAK;;AAYzB,SAAgB,IAA0C;CAItD,IAAM,IAAQ,WAAiD;CAC/D,IAAI,CAAC,GACD,MAAU,MACN,uIAGH;CAEL,OAAO,EAAK;;AA+BhB,SAAgB,EAAkB,GASnB;CACX,IAAM,EAAE,aAAU,WAAQ,gBAAa,8BAA8B,GAE/D,IAAS,EAAuB,GAAQ;EAC1C,YAAY;EACZ;EACA,WAAW;EACX,UAAU;EACV,OAAO;EACP,QAAQ;EACR,SAAS;EACT,WAAW;EACX,cAAc;EACd,UAAU;EACV,SAAS;GAAE,QAAQ;GAAS;GAAU;GAAY;EACrD,CAAC;CAEF,IAAI,EAAO,UAAU,EAAO,OAAO,SAAS,GACxC,MAAU,MACN,kDAAkD,IAAW,QAC7D,EAAO,OAAO,KAAK,MAAM,UAAU,EAAE,QAAQ,aAAa,CAAC,KAAK,KAAK,CACxE;CASL,IAAM,IAAgB,EAAqB,EAAO,KAAK;CACvD,AAAI,SAAS,EAAc,EAAE;CAK7B,IAAM,IAAU,8DACV,IAAgB,EAAE,EACpB;CACJ,QAAQ,IAAI,EAAQ,KAAK,EAAc,MAAM,OACzC,EAAI,KAAK,EAAE,GAAI;CAGnB,IAAM,IAAM,GAAe;CAC3B,OAAO,EAAI,KAAI,MAAM;EACjB,IAAM,IAAK,EAAI;EACf,IAAI,CAAC,GACD,MAAU,MACN,gCAAgC,IAAK,kJAGxC;EAEL,OAAO;GACT;;AAmBN,SAAgB,IAAwE;CACpF,OAAO,GAAe;;AAO1B,SAAgB,IAA0B;CACtC,GAAoB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/mt/index.ts"],"sourcesContent":["/**\n * Public JS API for the main-thread (MT) gesture/worklet test harness.\n *\n * Pair with `@sigx/lynx-testing/mt/setup` in your vitest setupFiles. See\n * the package README for a full example.\n *\n * The harness lets you write tests that:\n * 1. Compile a `.tsx` source file with `transformReactLynxSync`\n * (target: `LEPUS`) to extract the `registerWorkletInternal(...)`\n * calls the SWC transform emits for `'main thread'` worklets.\n * 2. Eval those registrations into the upstream worklet runtime that\n * `setup.ts` boots, populating `lynxWorkletImpl._workletMap`.\n * 3. Call each worklet directly with a fabricated `_c` capture and a\n * synthetic gesture event, asserting the worklet's MT-side state\n * mutations and any `setStyleProperties` / `runOnBackground` calls.\n *\n * Use `compileMTWorklets()` for the common case (one source file, get\n * the registered worklets back). Drop down to `extractRegistrations()`\n * if you need finer control.\n */\n\nimport { transformReactLynxSync } from '@lynx-js/react/transform';\nimport { _getJsContext, _resetJsContextSpy } from './setup';\n\n/**\n * Synthetic `MainThreadRef` shape — `{ current, _wvid }`. Worklets read\n * `ref.current.value` and may mutate `ref.current.value`.\n */\nexport function makeRef<T>(current: T, id = 1): { current: T; _wvid: number } {\n return { current, _wvid: id };\n}\n\n/**\n * Fabricate a Lynx pan-gesture event payload as the iOS arena would\n * deliver it. The payload is nested under `e.params` (NOT top-level on\n * `e`) — your worklet should read pageX/pageY from `e.params.pageX`,\n * mirroring real device behaviour.\n *\n * Verified against `LynxBaseGestureHandler.m::eventParamsFromTouchEvent`\n * + `LynxPanGestureHandler.m::eventParamsInActive` on iOS Lynx 3.5.\n */\nexport function fabricatePanEvent(opts: { pageX: number; pageY?: number }): MTGestureEvent {\n const params = {\n timestamp: Date.now(),\n type: 'touchmove',\n x: opts.pageX,\n y: opts.pageY ?? 0,\n pageX: opts.pageX,\n pageY: opts.pageY ?? 0,\n clientX: opts.pageX,\n clientY: opts.pageY ?? 0,\n scrollX: 0,\n scrollY: 0,\n isAtStart: 0,\n isAtEnd: 0,\n };\n return {\n type: 'onUpdate',\n timestamp: Date.now(),\n currentTarget: { element: null },\n target: { element: null },\n params,\n detail: params,\n };\n}\n\n/**\n * Fabricate a Lynx tap-gesture event payload. Same shape as the pan event\n * minus the scroll-related fields the pan handler adds; tests rarely read\n * either, so the difference is mostly cosmetic.\n */\nexport function fabricateTapEvent(opts: { pageX?: number; pageY?: number } = {}): MTGestureEvent {\n const params = {\n timestamp: Date.now(),\n type: 'touchend',\n x: opts.pageX ?? 0,\n y: opts.pageY ?? 0,\n pageX: opts.pageX ?? 0,\n pageY: opts.pageY ?? 0,\n clientX: opts.pageX ?? 0,\n clientY: opts.pageY ?? 0,\n };\n return {\n type: 'onStart',\n timestamp: Date.now(),\n currentTarget: { element: null },\n target: { element: null },\n params,\n detail: params,\n };\n}\n\n/**\n * Common shape for the events the iOS gesture arena delivers to MT\n * worklets. Top-level keys are dispatch metadata; the actual touch data\n * lives under `params` (and a duplicate `detail`).\n */\nexport interface MTGestureEvent {\n type: string;\n timestamp: number;\n currentTarget: { element: null };\n target: { element: null };\n params: Record<string, unknown>;\n detail: Record<string, unknown>;\n}\n\n/**\n * Extract `registerWorkletInternal(...)` calls from a LEPUS-target\n * transform output. Bracket-depth counting handles nested braces in the\n * function body. Mirror of the lynx-plugin internal so tests don't pull\n * a build-time package in as a runtime dep.\n */\nexport function extractRegistrations(lepusCode: string): string {\n const out: string[] = [];\n const marker = 'registerWorkletInternal(';\n let from = 0;\n\n while (true) {\n const idx = lepusCode.indexOf(marker, from);\n if (idx === -1) break;\n\n let depth = 0;\n let i = idx + marker.length - 1;\n for (; i < lepusCode.length; i++) {\n const ch = lepusCode[i];\n if (ch === '(') depth++;\n else if (ch === ')') {\n depth--;\n if (depth === 0) break;\n }\n }\n\n let end = i + 1;\n if (end < lepusCode.length && lepusCode[end] === ';') end++;\n out.push(lepusCode.slice(idx, end));\n from = end;\n }\n\n return out.join('\\n');\n}\n\n/**\n * Get the live `lynxWorkletImpl._workletMap` populated by the upstream\n * worklet runtime that `mt/setup.ts` bootstrapped. Each entry is a\n * `_wkltId` → callable mapping. After `compileMTWorklets()` evals new\n * registrations, this map will include them.\n *\n * Throws if `mt/setup.ts` didn't run — typically because the consumer\n * forgot to add it to `setupFiles`.\n */\nexport function getWorkletMap(): Record<string, Function> {\n interface WorkletImpl {\n _workletMap: Record<string, Function>;\n }\n const impl = (globalThis as { lynxWorkletImpl?: WorkletImpl }).lynxWorkletImpl;\n if (!impl) {\n throw new Error(\n '[lynx-testing/mt] lynxWorkletImpl is not initialized — add ' +\n '`@sigx/lynx-testing/mt/setup` to your vitest config\\'s ' +\n '`setupFiles` array.'\n );\n }\n return impl._workletMap;\n}\n\n/**\n * Compile a `.tsx` source file as a LEPUS worklet bundle, eval the\n * resulting `registerWorkletInternal(...)` calls into the live runtime,\n * and return the worklets that were just registered (in source order).\n *\n * The returned array indexes into `lynxWorkletImpl._workletMap`'s newest\n * entries — i.e. `result[0]` is the first worklet registered by this\n * compile. For most tests this is enough; for cross-test sharing or\n * per-`_wkltId` access, fall back to `getWorkletMap()`.\n *\n * @example\n * ```ts\n * import { readFileSync } from 'fs';\n * import { compileMTWorklets, fabricatePanEvent, makeRef } from '@sigx/lynx-testing/mt';\n *\n * const SRC = path.resolve(__dirname, '../../src/components/Draggable.tsx');\n * const worklets = compileMTWorklets({\n * filename: SRC,\n * source: readFileSync(SRC, 'utf8'),\n * });\n * // Source-order: onBegin (:1), onStart (:2), onUpdate (:3), onEnd (:4)\n * const onUpdate = worklets[2]!;\n *\n * const drag = { startPageX: 100, startPageY: 50, ... };\n * onUpdate.call({ _c: { drag: makeRef(drag, 1), ... } }, fabricatePanEvent({ pageX: 130, pageY: 55 }));\n * expect(drag.startPageX).toBe(100);\n * ```\n */\nexport function compileMTWorklets(opts: {\n filename: string;\n source: string;\n /**\n * Override the runtime package name passed to the SWC transform.\n * Defaults to `@sigx/lynx-runtime-main`, which matches what the\n * production build uses.\n */\n runtimePkg?: string;\n}): Function[] {\n const { filename, source, runtimePkg = '@sigx/lynx-runtime-main' } = opts;\n\n const result = transformReactLynxSync(source, {\n pluginName: 'sigx:test',\n filename,\n sourcemap: false,\n cssScope: false,\n shake: false,\n compat: false,\n refresh: false,\n defineDCE: false,\n directiveDCE: false,\n snapshot: false,\n worklet: { target: 'LEPUS', filename, runtimePkg },\n });\n\n if (result.errors && result.errors.length > 0) {\n throw new Error(\n '[lynx-testing/mt] LEPUS transform errors for ' + filename + ':\\n' +\n result.errors.map((e) => ' - ' + (e.text ?? '<unknown>')).join('\\n')\n );\n }\n\n // Eval the registrations against `globalThis.registerWorkletInternal`\n // (installed by `setup.ts`). SWC produces deterministic `_wkltId`s\n // from the source content hash + index, so re-compiling the same\n // source overwrites the same map entries — we can't diff by\n // map-presence to find what this call registered. Instead parse the\n // IDs directly out of the registration source.\n const registrations = extractRegistrations(result.code);\n new Function(registrations)();\n\n // Each registration looks like:\n // registerWorkletInternal(\"main-thread\", \"<wkltId>\", function(...) {...});\n // Extract the wkltId from the second string literal in source order.\n const idRegex = /registerWorkletInternal\\(\\s*\"main-thread\"\\s*,\\s*\"([^\"]+)\"/g;\n const ids: string[] = [];\n let m: RegExpExecArray | null;\n while ((m = idRegex.exec(registrations)) !== null) {\n ids.push(m[1]!);\n }\n\n const map = getWorkletMap();\n return ids.map(id => {\n const fn = map[id];\n if (!fn) {\n throw new Error(\n '[lynx-testing/mt] worklet `' + id + '` was registered by the ' +\n 'compile but is missing from lynxWorkletImpl._workletMap. The ' +\n 'upstream worklet runtime may not have evaluated correctly.'\n );\n }\n return fn;\n });\n}\n\n/**\n * Read the JS-context spy that `mt/setup.ts` installed on the lynx mock.\n * Useful for asserting `runOnBackground` / `Lynx.Sigx.AvPublish` event\n * dispatches from within a worklet.\n *\n * @example\n * ```ts\n * import { getJsContext } from '@sigx/lynx-testing/mt';\n *\n * onUpdate.call(ctx, fabricatePanEvent({ pageX: 130 }));\n * const ctx = getJsContext();\n * expect(ctx.dispatchEvent).toHaveBeenCalledWith(\n * expect.objectContaining({ type: 'Lynx.Sigx.AvPublish' })\n * );\n * ```\n */\nexport function getJsContext(): { addEventListener: Function; dispatchEvent: Function } {\n return _getJsContext();\n}\n\n/**\n * Wipe the JS-context spy between tests so dispatchEvent / addEventListener\n * call counts don't bleed across cases.\n */\nexport function resetJsContextSpy(): void {\n _resetJsContextSpy();\n}\n"],"mappings":";;;AA4BA,SAAgB,EAAW,GAAY,IAAK,GAAkC;CAC1E,OAAO;EAAE;EAAS,OAAO;EAAI;;AAYjC,SAAgB,EAAkB,GAAyD;CACvF,IAAM,IAAS;EACX,WAAW,KAAK,KAAK;EACrB,MAAM;EACN,GAAG,EAAK;EACR,GAAG,EAAK,SAAS;EACjB,OAAO,EAAK;EACZ,OAAO,EAAK,SAAS;EACrB,SAAS,EAAK;EACd,SAAS,EAAK,SAAS;EACvB,SAAS;EACT,SAAS;EACT,WAAW;EACX,SAAS;EACZ;CACD,OAAO;EACH,MAAM;EACN,WAAW,KAAK,KAAK;EACrB,eAAe,EAAE,SAAS,MAAM;EAChC,QAAQ,EAAE,SAAS,MAAM;EACzB;EACA,QAAQ;EACX;;AAQL,SAAgB,EAAkB,IAA2C,EAAE,EAAkB;CAC7F,IAAM,IAAS;EACX,WAAW,KAAK,KAAK;EACrB,MAAM;EACN,GAAG,EAAK,SAAS;EACjB,GAAG,EAAK,SAAS;EACjB,OAAO,EAAK,SAAS;EACrB,OAAO,EAAK,SAAS;EACrB,SAAS,EAAK,SAAS;EACvB,SAAS,EAAK,SAAS;EAC1B;CACD,OAAO;EACH,MAAM;EACN,WAAW,KAAK,KAAK;EACrB,eAAe,EAAE,SAAS,MAAM;EAChC,QAAQ,EAAE,SAAS,MAAM;EACzB;EACA,QAAQ;EACX;;AAuBL,SAAgB,EAAqB,GAA2B;CAC5D,IAAM,IAAgB,EAAE,EAEpB,IAAO;CAEX,SAAa;EACT,IAAM,IAAM,EAAU,QAAQ,4BAAQ,EAAK;EAC3C,IAAI,MAAQ,IAAI;EAEhB,IAAI,IAAQ,GACR,IAAI,IAAM,KAAgB;EAC9B,OAAO,IAAI,EAAU,QAAQ,KAAK;GAC9B,IAAM,IAAK,EAAU;GACrB,IAAI,MAAO,KAAK;QACX,IAAI,MAAO,QACZ,KACI,MAAU,IAAG;;EAIzB,IAAI,IAAM,IAAI;EAGd,AAFI,IAAM,EAAU,UAAU,EAAU,OAAS,OAAK,KACtD,EAAI,KAAK,EAAU,MAAM,GAAK,EAAI,CAAC,EACnC,IAAO;;CAGX,OAAO,EAAI,KAAK,KAAK;;AAYzB,SAAgB,IAA0C;CAItD,IAAM,IAAQ,WAAiD;CAC/D,IAAI,CAAC,GACD,MAAU,MACN,uIAGH;CAEL,OAAO,EAAK;;AA+BhB,SAAgB,EAAkB,GASnB;CACX,IAAM,EAAE,aAAU,WAAQ,gBAAa,8BAA8B,GAE/D,IAAS,EAAuB,GAAQ;EAC1C,YAAY;EACZ;EACA,WAAW;EACX,UAAU;EACV,OAAO;EACP,QAAQ;EACR,SAAS;EACT,WAAW;EACX,cAAc;EACd,UAAU;EACV,SAAS;GAAE,QAAQ;GAAS;GAAU;GAAY;EACrD,CAAC;CAEF,IAAI,EAAO,UAAU,EAAO,OAAO,SAAS,GACxC,MAAU,MACN,kDAAkD,IAAW,QAC7D,EAAO,OAAO,KAAK,MAAM,UAAU,EAAE,QAAQ,aAAa,CAAC,KAAK,KAAK,CACxE;CASL,IAAM,IAAgB,EAAqB,EAAO,KAAK;CACvD,AAAI,SAAS,EAAc,EAAE;CAK7B,IAAM,IAAU,8DACV,IAAgB,EAAE,EACpB;CACJ,QAAQ,IAAI,EAAQ,KAAK,EAAc,MAAM,OACzC,EAAI,KAAK,EAAE,GAAI;CAGnB,IAAM,IAAM,GAAe;CAC3B,OAAO,EAAI,KAAI,MAAM;EACjB,IAAM,IAAK,EAAI;EACf,IAAI,CAAC,GACD,MAAU,MACN,gCAAgC,IAAK,kJAGxC;EAEL,OAAO;GACT;;AAmBN,SAAgB,IAAwE;CACpF,OAAO,GAAe;;AAO1B,SAAgB,IAA0B;CACtC,GAAoB"}
package/dist/queries.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Query helpers for finding nodes in a TestNode tree.
3
3
  */
4
- import { TestNode } from './test-node.js';
4
+ import { TestNode } from './test-node';
5
5
  export declare function getByType(container: TestNode, type: string): TestNode;
6
6
  export declare function getAllByType(container: TestNode, type: string): TestNode[];
7
7
  export declare function getByText(container: TestNode, text: string): TestNode;
@@ -1 +1 @@
1
- {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,wBAAgB,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAIrE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAE1E;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAIrE;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE9E;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE9E;AAED,wBAAgB,SAAS,CACvB,SAAS,EAAE,QAAQ,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,QAAQ,CAYV"}
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,wBAAgB,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAIrE;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CAE1E;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAIrE;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE9E;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAE9E;AAED,wBAAgB,SAAS,CACvB,SAAS,EAAE,QAAQ,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,QAAQ,CAYV"}
package/dist/render.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * render() — mount a sigx Lynx component into a TestNode tree for testing.
3
3
  */
4
4
  import type { JSXElement, AppContext } from '@sigx/lynx';
5
- import { TestNode } from './test-node.js';
5
+ import { TestNode } from './test-node';
6
6
  export interface RenderResult {
7
7
  /** The root container node. */
8
8
  container: TestNode;
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAG1C,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,SAAS,EAAE,QAAQ,CAAC;IACpB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,6DAA6D;IAC7D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IACtC,sCAAsC;IACtC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC3C,6DAA6D;IAC7D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IACtC,mEAAmE;IACnE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;IAC/C,mEAAmE;IACnE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;IAC/C,+DAA+D;IAC/D,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,QAAQ,CAAC;IACrD,4BAA4B;IAC5B,KAAK,EAAE,MAAM,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,UAAU,EACnB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,GACpC,YAAY,CAoBd"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,SAAS,EAAE,QAAQ,CAAC;IACpB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,6DAA6D;IAC7D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IACtC,sCAAsC;IACtC,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC3C,6DAA6D;IAC7D,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC;IACtC,mEAAmE;IACnE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;IAC/C,mEAAmE;IACnE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,IAAI,CAAC;IAC/C,+DAA+D;IAC/D,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,QAAQ,CAAC;IACrD,4BAA4B;IAC5B,KAAK,EAAE,MAAM,MAAM,CAAC;CACrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,UAAU,EACnB,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,GACpC,YAAY,CAoBd"}
@@ -1,5 +1,5 @@
1
1
  import type { RendererOptions } from '@sigx/runtime-core/internals';
2
- import { TestNode } from './test-node.js';
2
+ import { TestNode } from './test-node';
3
3
  declare const nodeOps: RendererOptions<TestNode, TestNode>;
4
4
  export declare const testRenderer: import("@sigx/runtime-core/internals").Renderer<TestNode, TestNode>;
5
5
  export { nodeOps as testNodeOps };
@@ -1 +1 @@
1
- {"version":3,"file":"test-renderer.d.ts","sourceRoot":"","sources":["../src/test-renderer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,QAAA,MAAM,OAAO,EAAE,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAsGhD,CAAC;AAEF,eAAO,MAAM,YAAY,qEAA8C,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"test-renderer.d.ts","sourceRoot":"","sources":["../src/test-renderer.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,QAAA,MAAM,OAAO,EAAE,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAsGhD,CAAC;AAEF,eAAO,MAAM,YAAY,qEAA8C,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sigx/lynx-testing",
3
- "version": "0.2.6",
3
+ "version": "0.4.0",
4
4
  "description": "Testing utilities for SignalX Lynx components - render, fireEvent, queries",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -32,12 +32,12 @@
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
34
  "@sigx/runtime-core": "^0.4.3",
35
- "@sigx/lynx": "^0.1.4"
35
+ "@sigx/lynx": "^0.4.0"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@lynx-js/react": "^0.120.0",
39
39
  "vitest": "^4.0.0",
40
- "@sigx/lynx-runtime-main": "^0.2.7"
40
+ "@sigx/lynx-runtime-main": "^0.4.0"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "@lynx-js/react": {
@@ -55,7 +55,7 @@
55
55
  "typescript": "^6.0.3",
56
56
  "vite": "^8.0.12",
57
57
  "vitest": "^4.1.6",
58
- "@sigx/lynx-runtime-main": "^0.2.7"
58
+ "@sigx/lynx-runtime-main": "^0.4.0"
59
59
  },
60
60
  "repository": {
61
61
  "type": "git",