import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' // eslint-disable-next-line @typescript-eslint/no-empty-function const noop = (): void => {} import { __debugListWidgetStores, clearAllCaptureEls, clearAllEchartInstances, clearAllWidgetStores, createWidgetStore, deleteWidgetStore, getCaptureEl, getEchartInstance, getWidgetStore, hasWidgetStore, registerWidgetStore, resetWidgetStore, setCaptureEl, setEchartInstance, subscribeEchartInstance, unregisterWidgetStore, } from './widget-store-registry' import type { ECharts } from 'echarts' describe('widget-store-registry', () => { beforeEach(() => clearAllWidgetStores()) afterEach(() => clearAllWidgetStores()) it('register + get round-trip', () => { const s = createWidgetStore('w1', { data: 1 }) registerWidgetStore('w1', s) expect(getWidgetStore('w1')).toBe(s) expect(hasWidgetStore('w1')).toBe(true) }) it('getWidgetStore throws for unknown id', () => { expect(() => getWidgetStore('missing')).toThrow( /Widget store "missing" not found/, ) }) it('isolates state across stores', () => { const a = createWidgetStore('a', { data: 1 }) const b = createWidgetStore('b', { data: 2 }) registerWidgetStore('a', a) registerWidgetStore('b', b) a.setState({ rawData: 10 }) expect(b.getState().rawData).toBe(2) }) it('deleteWidgetStore removes the store from the registry', () => { const s = createWidgetStore('w', { data: 1 }) registerWidgetStore('w', s) deleteWidgetStore('w') expect(hasWidgetStore('w')).toBe(false) }) it('resetWidgetStore clears transformStates and keeps the store', () => { const s = createWidgetStore('w', { data: 1 }) registerWidgetStore('w', s) s.setState({ transformStates: { foo: { enabled: true } } }) resetWidgetStore('w') expect(s.getState().transformStates).toEqual({}) expect(hasWidgetStore('w')).toBe(true) }) it('clearAllWidgetStores empties everything', () => { registerWidgetStore('a', createWidgetStore('a', { data: 1 })) registerWidgetStore('b', createWidgetStore('b', { data: 2 })) clearAllWidgetStores() expect(__debugListWidgetStores()).toEqual([]) }) it('unregisterWidgetStore drops the store on last unmount when keepAlive is false', () => { registerWidgetStore('w', createWidgetStore('w', { data: 1 })) unregisterWidgetStore('w', { keepAlive: false }) expect(hasWidgetStore('w')).toBe(false) }) it('unregisterWidgetStore preserves the store when keepAlive is true', () => { registerWidgetStore('w', createWidgetStore('w', { data: 1 })) unregisterWidgetStore('w', { keepAlive: true }) expect(hasWidgetStore('w')).toBe(true) }) it('refcounts overlapping registers — store stays until both unregister', () => { const s = createWidgetStore('w', { data: 1 }) registerWidgetStore('w', s) registerWidgetStore('w', s) unregisterWidgetStore('w', { keepAlive: false }) expect(hasWidgetStore('w')).toBe(true) unregisterWidgetStore('w', { keepAlive: false }) expect(hasWidgetStore('w')).toBe(false) }) it('warns once on duplicate concurrent registration with the same id', () => { const warn = vi.spyOn(console, 'warn').mockImplementation(noop) const s = createWidgetStore('dup', { data: 1 }) registerWidgetStore('dup', s) registerWidgetStore('dup', s) expect(warn).toHaveBeenCalledTimes(1) expect(warn.mock.calls[0]?.[0]).toMatch( /Duplicate /, ) warn.mockRestore() }) it('does not warn again on subsequent re-registrations after the first warning', () => { const warn = vi.spyOn(console, 'warn').mockImplementation(noop) const s = createWidgetStore('dup', { data: 1 }) registerWidgetStore('dup', s) registerWidgetStore('dup', s) registerWidgetStore('dup', s) expect(warn).toHaveBeenCalledTimes(1) warn.mockRestore() }) it('createWidgetStore seeds rawData/data from init.data', () => { const s = createWidgetStore('w', { data: { x: 1 } }) expect(s.getState().rawData).toEqual({ x: 1 }) expect(s.getState().data).toEqual({ x: 1 }) }) it('createWidgetStore seeds isLoading/isFetching defaults to false', () => { const s = createWidgetStore('w', { data: 1 }) expect(s.getState().isLoading).toBe(false) expect(s.getState().isFetching).toBe(false) }) it('createWidgetStore preserves init.error', () => { const err = { title: 'oops' } const s = createWidgetStore('w', { data: 1, error: err }) expect(s.getState().error).toBe(err) }) it('__debugListWidgetStores reflects registered ids', () => { registerWidgetStore('a', createWidgetStore('a', { data: 1 })) registerWidgetStore('b', createWidgetStore('b', { data: 1 })) expect(__debugListWidgetStores().sort()).toEqual(['a', 'b']) }) describe('capture-el registry', () => { it('returns null for unregistered ids', () => { expect(getCaptureEl('missing')).toBeNull() }) it('round-trips a set value', () => { const el = document.createElement('div') setCaptureEl('w1', el) expect(getCaptureEl('w1')).toBe(el) }) it('clears when set to null', () => { const el = document.createElement('div') setCaptureEl('w1', el) setCaptureEl('w1', null) expect(getCaptureEl('w1')).toBeNull() }) it('isolates ids', () => { const a = document.createElement('div') const b = document.createElement('section') setCaptureEl('a', a) setCaptureEl('b', b) expect(getCaptureEl('a')).toBe(a) expect(getCaptureEl('b')).toBe(b) }) it('clearAllWidgetStores wipes the capture-el map too', () => { setCaptureEl('w', document.createElement('div')) clearAllWidgetStores() expect(getCaptureEl('w')).toBeNull() }) it('clearAllCaptureEls wipes only the capture-el map', () => { registerWidgetStore('w', createWidgetStore('w', { data: 1 })) setCaptureEl('w', document.createElement('div')) clearAllCaptureEls() expect(getCaptureEl('w')).toBeNull() expect(hasWidgetStore('w')).toBe(true) }) }) describe('echart-instance registry', () => { function makeChart(): ECharts { // Minimal stand-in — only the methods used by registry tests need to // exist. Cast through unknown to keep the signature opaque. return {} as unknown as ECharts } it('returns null for unregistered ids', () => { expect(getEchartInstance('missing')).toBeNull() }) it('round-trips a set value', () => { const chart = makeChart() setEchartInstance('w1', chart) expect(getEchartInstance('w1')).toBe(chart) }) it('clears when set to null', () => { setEchartInstance('w1', makeChart()) setEchartInstance('w1', null) expect(getEchartInstance('w1')).toBeNull() }) it('isolates ids', () => { const a = makeChart() const b = makeChart() setEchartInstance('a', a) setEchartInstance('b', b) expect(getEchartInstance('a')).toBe(a) expect(getEchartInstance('b')).toBe(b) }) it('clearAllWidgetStores wipes the echart-instance map too', () => { setEchartInstance('w', makeChart()) clearAllWidgetStores() expect(getEchartInstance('w')).toBeNull() }) it('clearAllEchartInstances wipes only the echart-instance map', () => { registerWidgetStore('w', createWidgetStore('w', { data: 1 })) setEchartInstance('w', makeChart()) clearAllEchartInstances() expect(getEchartInstance('w')).toBeNull() expect(hasWidgetStore('w')).toBe(true) }) }) describe('subscribeEchartInstance', () => { function makeChart(): ECharts { return {} as unknown as ECharts } it('fires the listener whenever setEchartInstance writes a new value', () => { const seen: (ECharts | null)[] = [] const off = subscribeEchartInstance('s1', (chart) => seen.push(chart)) const a = makeChart() const b = makeChart() setEchartInstance('s1', a) setEchartInstance('s1', b) setEchartInstance('s1', null) expect(seen).toEqual([a, b, null]) off() }) it('the returned unsubscribe stops the listener', () => { const fn = vi.fn() const off = subscribeEchartInstance('s2', fn) setEchartInstance('s2', makeChart()) off() setEchartInstance('s2', makeChart()) expect(fn).toHaveBeenCalledTimes(1) }) it('multiple listeners per id all fire', () => { const a = vi.fn() const b = vi.fn() subscribeEchartInstance('s3', a) subscribeEchartInstance('s3', b) setEchartInstance('s3', makeChart()) expect(a).toHaveBeenCalledTimes(1) expect(b).toHaveBeenCalledTimes(1) }) it('listeners are isolated by id', () => { const a = vi.fn() const b = vi.fn() subscribeEchartInstance('s4', a) subscribeEchartInstance('s5', b) setEchartInstance('s4', makeChart()) expect(a).toHaveBeenCalledTimes(1) expect(b).not.toHaveBeenCalled() }) it('clearAllEchartInstances and clearAllWidgetStores clear subscribers too', () => { const fn = vi.fn() subscribeEchartInstance('s6', fn) clearAllEchartInstances() setEchartInstance('s6', makeChart()) expect(fn).not.toHaveBeenCalled() const fn2 = vi.fn() subscribeEchartInstance('s7', fn2) clearAllWidgetStores() setEchartInstance('s7', makeChart()) expect(fn2).not.toHaveBeenCalled() }) }) })