/** * Shared test helpers for widgets-v2 unit tests. * * Keep this file small: only utilities used by 3+ tests live here. One-off * mocks remain inline in their test files to stay legible. * * NOTE: this file is intentionally `.ts` (not `.tsx`) so consumers must * pass JSX in from their own `.tsx` test files. Keeping the module * JSX-free avoids polluting non-React tests with a React dependency. */ import { vi } from 'vitest' import type { ECharts, EChartsOption } from 'echarts' import { getWidgetStore, type WidgetState, type WidgetStoreApi } from './stores' // ─── ECharts instance mock ──────────────────────────────────────────────── export interface MockChartHandlers { finished?: () => void rendered?: () => void click?: (params: unknown) => void globalcursortaken?: (params: unknown) => void datazoom?: (params: unknown) => void brushselected?: (params: unknown) => void brushend?: (params: unknown) => void [key: string]: ((params?: unknown) => void) | undefined } export interface MockChart { dispatchAction: ReturnType setOption: ReturnType getOption: ReturnType resize: ReturnType clear: ReturnType dispose: ReturnType isDisposed: ReturnType getWidth: ReturnType getHeight: ReturnType getDom: ReturnType on: (event: string, callback: (params?: unknown) => void) => void off: (event: string, callback?: (params?: unknown) => void) => void __handlers: MockChartHandlers __emit: (event: keyof MockChartHandlers, params?: unknown) => void } /** * Returns a duck-typed `ECharts` instance suitable for tests. The instance * captures `on()` handlers in `__handlers` so tests can `__emit('finished')` * directly, and all imperative methods (`dispatchAction`, `setOption`, * `resize`, …) are `vi.fn()` spies. */ export function createMockChart(): MockChart { const handlers: MockChartHandlers = {} const chart: MockChart = { dispatchAction: vi.fn(), setOption: vi.fn(), getOption: vi.fn(() => ({})), resize: vi.fn(), clear: vi.fn(), dispose: vi.fn(), isDisposed: vi.fn(() => false), getWidth: vi.fn(() => 400), getHeight: vi.fn(() => 300), getDom: vi.fn(() => document.createElement('div')), on: (event, callback) => { handlers[event] = callback as MockChartHandlers[string] }, off: (event) => { handlers[event] = undefined }, __handlers: handlers, __emit: (event, params) => { handlers[event as string]?.(params) }, } return chart } /** Convenience cast for tests that need an `ECharts`-typed reference. */ export const asEcharts = (chart: MockChart): ECharts => chart as unknown as ECharts // ─── Option factory helpers ──────────────────────────────────────────────── /** * Returns a `vi.fn()` option factory. The factory takes the standard * `(option, data, ctx)` signature and returns the supplied `output` unchanged. * Useful when the test only cares about how the bridge wires the factory in. */ export function createMockOptionFactory(output: EChartsOption = {}) { return vi.fn(() => output) } // ─── Store accessor ──────────────────────────────────────────────────────── /** * Typed re-export of `getWidgetStore(id).getState()` — the verbose form * shows up dozens of times across the suite. Tests that need the store * api itself (`setState`, `subscribe`) still call `getWidgetStore(id)`. */ export function getState(id: string): WidgetState { return getWidgetStore(id).getState() } /** Typed re-export of `getWidgetStore(id)` for tests that need the api. */ export function getStore(id: string): WidgetStoreApi { return getWidgetStore(id) }