import { describe, it, expect, beforeEach, afterEach } from 'vitest' import { act, render } from '@testing-library/react' import { clearAllWidgetStores, createWidgetStore, registerWidgetStore, getWidgetStore, } from './widget-store-registry' import { useSingleTransform, useTransform, type TransformControls, } from './use-transform' import { applyTransforms } from './transforms' import type { TransformDescriptor, TransformFn } from './types' function setup(id = 'wt-test') { const store = createWidgetStore(id, { data: 1 }) registerWidgetStore(id, store) return store } const captureRef: { current: TransformControls | null } = { current: null } const onControls = (c: TransformControls): void => { captureRef.current = c } const getCaptured = (): TransformControls | null => captureRef.current function Single({ id, descriptor, fn, initialEnabled, }: { id: string descriptor: TransformDescriptor fn: TransformFn initialEnabled?: boolean }) { const controls = useSingleTransform(id, descriptor, fn, { initialEnabled }) onControls(controls) return null } function Multi({ id, pairs, initialEnabled, }: { id: string pairs: readonly { descriptor: TransformDescriptor; fn: TransformFn }[] initialEnabled?: boolean }) { const controls = useTransform(id, pairs, { initialEnabled }) onControls(controls) return null } beforeEach(() => { clearAllWidgetStores() captureRef.current = null }) afterEach(() => { clearAllWidgetStores() }) describe('useSingleTransform', () => { it('registers the transform on mount with enabled=true by default', () => { setup() render( (n as number) * 2} />, ) expect(captureRef.current?.enabled).toBe(true) expect( getWidgetStore('wt-test') .getState() .dataTransforms.map((t) => t.id), ).toEqual(['a']) expect(getWidgetStore('wt-test').getState().data).toBe(2) }) it('respects initialEnabled=false', () => { setup() render( (n as number) * 2} initialEnabled={false} />, ) expect(captureRef.current?.enabled).toBe(false) expect(getWidgetStore('wt-test').getState().data).toBe(1) }) it('toggle flips enabled and re-runs the pipeline', () => { setup() render( (n as number) * 2} />, ) act(() => captureRef.current?.toggle()) expect(captureRef.current?.enabled).toBe(false) expect(getWidgetStore('wt-test').getState().data).toBe(1) act(() => captureRef.current?.toggle()) expect(captureRef.current?.enabled).toBe(true) expect(getWidgetStore('wt-test').getState().data).toBe(2) }) it('persists enabled to transformStates', () => { setup() render( n} />, ) act(() => captureRef.current?.setEnabled(false)) expect( getWidgetStore('wt-test').getState().transformStates.a, ).toMatchObject({ enabled: false }) }) it('rehydrates enabled from transformStates on remount', () => { setup() const { unmount } = render( n} initialEnabled={true} />, ) act(() => captureRef.current?.setEnabled(false)) unmount() captureRef.current = null render( n} initialEnabled={true} />, ) expect(getCaptured()?.enabled).toBe(false) }) it('cleanup removes the transform on unmount', () => { setup() const { unmount } = render( n} />, ) expect(getWidgetStore('wt-test').getState().dataTransforms).toHaveLength(1) unmount() expect(getWidgetStore('wt-test').getState().dataTransforms).toHaveLength(0) }) it('updates the registered fn when fn identity changes across renders', () => { setup() function Wrap({ multiplier }: { multiplier: number }) { return ( (n as number) * multiplier} /> ) } const { rerender } = render() expect(getWidgetStore('wt-test').getState().data).toBe(2) rerender() expect(getWidgetStore('wt-test').getState().data).toBe(5) }) it('config-type descriptor registers into configTransforms', () => { setup() render( ({ ...(o as object), x: 1 })} />, ) const cfgTransforms = getWidgetStore('wt-test').getState().configTransforms expect(cfgTransforms.map((t) => t.id)).toEqual(['c']) expect(applyTransforms({}, cfgTransforms)).toEqual({ x: 1 }) }) }) describe('useTransform (multi)', () => { it('registers paired data + config transforms with shared enabled', () => { setup() render( (n as number) + 10, }, { descriptor: { id: 'rd-config', type: 'config', order: 1 }, fn: (o) => ({ ...(o as object), tag: 'rel' }), }, ]} />, ) const s = getWidgetStore('wt-test').getState() expect(s.dataTransforms.map((t) => t.id)).toEqual(['rd-data']) expect(s.configTransforms.map((t) => t.id)).toEqual(['rd-config']) expect(s.data).toBe(11) expect(applyTransforms({}, s.configTransforms)).toEqual({ tag: 'rel' }) }) it('toggle affects every paired transform together', () => { setup() render( (n as number) + 10, }, { descriptor: { id: 'rd-config', type: 'config', order: 1 }, fn: (o) => ({ ...(o as object), tag: 'rel' }), }, ]} />, ) act(() => captureRef.current?.toggle()) const s = getWidgetStore('wt-test').getState() expect(s.dataTransforms.every((t) => !t.enabled)).toBe(true) expect(s.configTransforms.every((t) => !t.enabled)).toBe(true) expect(s.data).toBe(1) // All config transforms disabled — applying them to {} leaves it untouched. expect(applyTransforms({}, s.configTransforms)).toEqual({}) }) it('throws when no pair is provided', () => { setup() function NoPairs() { useTransform('wt-test', []) return null } expect(() => render()).toThrow(/at least one pair/) }) })