import { fireEvent, render } from "@solidjs/testing-library"; import { createRoot, createSignal } from "solid-js"; import { vi } from "vitest"; import { createControllableSignal } from "./create-controllable-signal"; describe("createControllableSignal", () => { it("should handle setValue behavior (uncontrolled mode)", async () => createRoot(async (dispose) => { const onChangeSpy = vi.fn(); const [value, setValue] = createControllableSignal({ defaultValue: () => "defaultValue", onChange: onChangeSpy, }); expect(value()).toBe("defaultValue"); expect(onChangeSpy).not.toHaveBeenCalled(); setValue("newValue"); await Promise.resolve(); expect(value()).toBe("newValue"); expect(onChangeSpy).toHaveBeenLastCalledWith("newValue"); // clear it, so we can check more easily that it's not called in the next expect onChangeSpy.mockClear(); setValue("newValue"); await Promise.resolve(); expect(value()).toBe("newValue"); // won't invoke onChange for the same value twice in a row expect(onChangeSpy).not.toHaveBeenCalled(); dispose(); })); it("should handle setValue with callback behavior (uncontrolled mode)", async () => createRoot(async (dispose) => { const onChangeSpy = vi.fn(); const [value, setValue] = createControllableSignal({ defaultValue: () => "defaultValue", onChange: onChangeSpy, }); expect(value()).toBe("defaultValue"); expect(onChangeSpy).not.toHaveBeenCalled(); setValue((prevValue) => { expect(prevValue).toBe("defaultValue"); return "newValue"; }); await Promise.resolve(); expect(value()).toBe("newValue"); expect(onChangeSpy).toHaveBeenLastCalledWith("newValue"); // clear it, so we can check more easily that it's not called in the next expect onChangeSpy.mockClear(); setValue((prevValue) => { expect(prevValue).toBe("newValue"); return "newValue"; }); await Promise.resolve(); expect(value()).toBe("newValue"); // won't invoke onChange for the same value twice in a row expect(onChangeSpy).not.toHaveBeenCalled(); dispose(); })); it("should handle setValue behavior (controlled mode)", async () => createRoot(async (dispose) => { const onChangeSpy = vi.fn(); const [value, setValue] = createControllableSignal({ value: () => "controlledValue", onChange: onChangeSpy, }); expect(value()).toBe("controlledValue"); expect(onChangeSpy).not.toHaveBeenCalled(); setValue("newValue"); await Promise.resolve(); expect(value()).toBe("controlledValue"); expect(onChangeSpy).toHaveBeenLastCalledWith("newValue"); // clear it, so we can check more easily that it's not called in the next expect onChangeSpy.mockClear(); setValue("controlledValue"); await Promise.resolve(); expect(value()).toBe("controlledValue"); // won't invoke onChange for the same value twice in a row expect(onChangeSpy).not.toHaveBeenCalled(); dispose(); })); it("should handle setValue with callback behavior (controlled mode)", async () => createRoot(async (dispose) => { const onChangeSpy = vi.fn(); const [value, setValue] = createControllableSignal({ value: () => "controlledValue", onChange: onChangeSpy, }); expect(value()).toBe("controlledValue"); expect(onChangeSpy).not.toHaveBeenCalled(); setValue((prevValue) => { expect(prevValue).toBe("controlledValue"); return "newValue"; }); await Promise.resolve(); expect(value()).toBe("controlledValue"); expect(onChangeSpy).toHaveBeenLastCalledWith("newValue"); // clear it, so we can check more easily that it's not called in the next expect onChangeSpy.mockClear(); setValue((prevValue) => { expect(prevValue).toBe("controlledValue"); return "controlledValue"; }); await Promise.resolve(); expect(value()).toBe("controlledValue"); // won't invoke onChange for the same value twice in a row expect(onChangeSpy).not.toHaveBeenCalled(); dispose(); })); it("should update value after props.value change (controlled mode)", async () => createRoot(async (dispose) => { const onChangeSpy = vi.fn(); const TestComponent = (props: any) => { const [value] = createControllableSignal(props); return
{value()}
; }; const TestComponentWrapper = (props: any) => { const [state, setState] = createSignal(props.value); return ( <>