diff --git a/src/hooks/domain/useErrorPopoverState.test.ts b/src/hooks/domain/useErrorPopoverState.test.ts index 19c0246..d7d497a 100644 --- a/src/hooks/domain/useErrorPopoverState.test.ts +++ b/src/hooks/domain/useErrorPopoverState.test.ts @@ -30,13 +30,13 @@ describe("useErrorPopoverState", () => { pyodideError: null, hasError, }), - { initialProps: { machineError: undefined } }, + { initialProps: { machineError: undefined as number | undefined } }, ); expect(result.current.isOpen).toBe(false); // Error appears - rerender({ machineError: 1 }); + rerender({ machineError: 1 as number | undefined }); expect(result.current.isOpen).toBe(true); }); @@ -49,12 +49,12 @@ describe("useErrorPopoverState", () => { pyodideError: null, hasError, }), - { initialProps: { machineErrorMessage: null } }, + { initialProps: { machineErrorMessage: null as string | null } }, ); expect(result.current.isOpen).toBe(false); - rerender({ machineErrorMessage: "Error occurred" }); + rerender({ machineErrorMessage: "Error occurred" as string | null }); expect(result.current.isOpen).toBe(true); }); @@ -67,12 +67,12 @@ describe("useErrorPopoverState", () => { pyodideError, hasError, }), - { initialProps: { pyodideError: null } }, + { initialProps: { pyodideError: null as string | null } }, ); expect(result.current.isOpen).toBe(false); - rerender({ pyodideError: "Pyodide error" }); + rerender({ pyodideError: "Pyodide error" as string | null }); expect(result.current.isOpen).toBe(true); }); @@ -98,7 +98,7 @@ describe("useErrorPopoverState", () => { }); it("should track manual dismissal", async () => { - const { result, rerender } = renderHook( + const { result } = renderHook( ({ machineError }) => useErrorPopoverState({ machineError, @@ -218,7 +218,15 @@ describe("useErrorPopoverState", () => { it("should handle multiple error sources", () => { const { result, rerender } = renderHook( - ({ machineError, machineErrorMessage, pyodideError }) => + ({ + machineError, + machineErrorMessage, + pyodideError, + }: { + machineError: number | undefined; + machineErrorMessage: string | null; + pyodideError: string | null; + }) => useErrorPopoverState({ machineError, machineErrorMessage, @@ -227,9 +235,9 @@ describe("useErrorPopoverState", () => { }), { initialProps: { - machineError: undefined, - machineErrorMessage: null, - pyodideError: null, + machineError: undefined as number | undefined, + machineErrorMessage: null as string | null, + pyodideError: null as string | null, }, }, ); @@ -238,34 +246,34 @@ describe("useErrorPopoverState", () => { // Machine error appears rerender({ - machineError: 1, - machineErrorMessage: null, - pyodideError: null, + machineError: 1 as number | undefined, + machineErrorMessage: null as string | null, + pyodideError: null as string | null, }); expect(result.current.isOpen).toBe(true); // Additional pyodide error rerender({ - machineError: 1, - machineErrorMessage: null, - pyodideError: "Pyodide error", + machineError: 1 as number | undefined, + machineErrorMessage: null as string | null, + pyodideError: "Pyodide error" as string | null, }); expect(result.current.isOpen).toBe(true); // Clear machine error but pyodide error remains rerender({ - machineError: 0, - machineErrorMessage: null, - pyodideError: "Pyodide error", + machineError: 0 as number | undefined, + machineErrorMessage: null as string | null, + pyodideError: "Pyodide error" as string | null, }); // Should stay open because pyodide error still exists expect(result.current.isOpen).toBe(true); // Clear all errors rerender({ - machineError: 0, - machineErrorMessage: null, - pyodideError: null, + machineError: 0 as number | undefined, + machineErrorMessage: null as string | null, + pyodideError: null as string | null, }); expect(result.current.isOpen).toBe(false); }); diff --git a/src/hooks/domain/useMachinePolling.test.ts b/src/hooks/domain/useMachinePolling.test.ts index f74e706..59b3ac5 100644 --- a/src/hooks/domain/useMachinePolling.test.ts +++ b/src/hooks/domain/useMachinePolling.test.ts @@ -16,7 +16,7 @@ describe("useMachinePolling", () => { const { result } = renderHook(() => useMachinePolling({ - machineStatus: MachineStatus.READY, + machineStatus: MachineStatus.IDLE, patternInfo: null, onStatusRefresh, onProgressRefresh, @@ -45,7 +45,7 @@ describe("useMachinePolling", () => { const { result } = renderHook(() => useMachinePolling({ - machineStatus: MachineStatus.READY, + machineStatus: MachineStatus.IDLE, patternInfo: null, onStatusRefresh, onProgressRefresh, @@ -139,7 +139,7 @@ describe("useMachinePolling", () => { const mocks2 = createMocks(); const { result: result2 } = renderHook(() => useMachinePolling({ - machineStatus: MachineStatus.READY, + machineStatus: MachineStatus.IDLE, patternInfo: null, ...mocks2, shouldCheckResumablePattern: () => false, diff --git a/src/hooks/platform/useBluetoothDeviceListener.test.ts b/src/hooks/platform/useBluetoothDeviceListener.test.ts index 85e3c59..f89eff5 100644 --- a/src/hooks/platform/useBluetoothDeviceListener.test.ts +++ b/src/hooks/platform/useBluetoothDeviceListener.test.ts @@ -1,5 +1,5 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { renderHook, waitFor } from "@testing-library/react"; +import { renderHook, waitFor, act } from "@testing-library/react"; import { useBluetoothDeviceListener } from "./useBluetoothDeviceListener"; import type { BluetoothDevice } from "../../types/electron"; @@ -23,7 +23,11 @@ describe("useBluetoothDeviceListener", () => { it("should return isSupported=true when Electron API is available", () => { // Mock Electron API - (window as { electronAPI: { onBluetoothDeviceList: () => void } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: () => void }; + } + ).electronAPI = { onBluetoothDeviceList: vi.fn(), }; @@ -34,7 +38,11 @@ describe("useBluetoothDeviceListener", () => { it("should register IPC listener when Electron API is available", () => { const mockListener = vi.fn(); - (window as { electronAPI: { onBluetoothDeviceList: typeof mockListener } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: typeof mockListener }; + } + ).electronAPI = { onBluetoothDeviceList: mockListener, }; @@ -45,13 +53,20 @@ describe("useBluetoothDeviceListener", () => { }); it("should update devices when listener receives data", async () => { - let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = null; + let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = + null; - const mockListener = vi.fn((callback: (devices: BluetoothDevice[]) => void) => { - deviceListCallback = callback; - }); + const mockListener = vi.fn( + (callback: (devices: BluetoothDevice[]) => void) => { + deviceListCallback = callback; + }, + ); - (window as { electronAPI: { onBluetoothDeviceList: typeof mockListener } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: typeof mockListener }; + } + ).electronAPI = { onBluetoothDeviceList: mockListener, }; @@ -61,11 +76,14 @@ describe("useBluetoothDeviceListener", () => { // Simulate device list update const mockDevices: BluetoothDevice[] = [ - { id: "device1", name: "Device 1", address: "00:11:22:33:44:55", paired: false }, - { id: "device2", name: "Device 2", address: "AA:BB:CC:DD:EE:FF", paired: true }, + { deviceId: "device1", deviceName: "Device 1" }, + { deviceId: "device2", deviceName: "Device 2" }, ]; - deviceListCallback?.(mockDevices); + // Trigger the callback + act(() => { + deviceListCallback!(mockDevices); + }); await waitFor(() => { expect(result.current.devices).toEqual(mockDevices); @@ -73,20 +91,29 @@ describe("useBluetoothDeviceListener", () => { }); it("should set isScanning=true when empty device list received", async () => { - let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = null; + let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = + null; - const mockListener = vi.fn((callback: (devices: BluetoothDevice[]) => void) => { - deviceListCallback = callback; - }); + const mockListener = vi.fn( + (callback: (devices: BluetoothDevice[]) => void) => { + deviceListCallback = callback; + }, + ); - (window as { electronAPI: { onBluetoothDeviceList: typeof mockListener } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: typeof mockListener }; + } + ).electronAPI = { onBluetoothDeviceList: mockListener, }; const { result } = renderHook(() => useBluetoothDeviceListener()); // Simulate empty device list (scanning in progress) - deviceListCallback?.([]); + act(() => { + deviceListCallback!([]); + }); await waitFor(() => { expect(result.current.isScanning).toBe(true); @@ -95,29 +122,40 @@ describe("useBluetoothDeviceListener", () => { }); it("should set isScanning=false when devices are received", async () => { - let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = null; + let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = + null; - const mockListener = vi.fn((callback: (devices: BluetoothDevice[]) => void) => { - deviceListCallback = callback; - }); + const mockListener = vi.fn( + (callback: (devices: BluetoothDevice[]) => void) => { + deviceListCallback = callback; + }, + ); - (window as { electronAPI: { onBluetoothDeviceList: typeof mockListener } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: typeof mockListener }; + } + ).electronAPI = { onBluetoothDeviceList: mockListener, }; const { result } = renderHook(() => useBluetoothDeviceListener()); // First update: empty list (scanning) - deviceListCallback?.([]); + act(() => { + deviceListCallback!([]); + }); await waitFor(() => { expect(result.current.isScanning).toBe(true); }); // Second update: devices found (stop scanning indicator) const mockDevices: BluetoothDevice[] = [ - { id: "device1", name: "Device 1", address: "00:11:22:33:44:55", paired: false }, + { deviceId: "device1", deviceName: "Device 1" }, ]; - deviceListCallback?.(mockDevices); + act(() => { + deviceListCallback!(mockDevices); + }); await waitFor(() => { expect(result.current.isScanning).toBe(false); @@ -125,14 +163,21 @@ describe("useBluetoothDeviceListener", () => { expect(result.current.devices).toEqual(mockDevices); }); - it("should call optional callback when devices change", () => { - let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = null; + it("should call optional callback when devices change", async () => { + let deviceListCallback: ((devices: BluetoothDevice[]) => void) | null = + null; - const mockListener = vi.fn((callback: (devices: BluetoothDevice[]) => void) => { - deviceListCallback = callback; - }); + const mockListener = vi.fn( + (callback: (devices: BluetoothDevice[]) => void) => { + deviceListCallback = callback; + }, + ); - (window as { electronAPI: { onBluetoothDeviceList: typeof mockListener } }).electronAPI = { + ( + window as unknown as { + electronAPI: { onBluetoothDeviceList: typeof mockListener }; + } + ).electronAPI = { onBluetoothDeviceList: mockListener, }; @@ -140,11 +185,15 @@ describe("useBluetoothDeviceListener", () => { renderHook(() => useBluetoothDeviceListener(onDevicesChanged)); const mockDevices: BluetoothDevice[] = [ - { id: "device1", name: "Device 1", address: "00:11:22:33:44:55", paired: false }, + { deviceId: "device1", deviceName: "Device 1" }, ]; - deviceListCallback?.(mockDevices); + act(() => { + deviceListCallback!(mockDevices); + }); - expect(onDevicesChanged).toHaveBeenCalledWith(mockDevices); + await waitFor(() => { + expect(onDevicesChanged).toHaveBeenCalledWith(mockDevices); + }); }); }); diff --git a/src/hooks/utility/useAutoScroll.test.ts b/src/hooks/utility/useAutoScroll.test.ts index 285b966..349ebf4 100644 --- a/src/hooks/utility/useAutoScroll.test.ts +++ b/src/hooks/utility/useAutoScroll.test.ts @@ -18,10 +18,9 @@ describe("useAutoScroll", () => { const scrollIntoViewMock = vi.fn(); mockElement.scrollIntoView = scrollIntoViewMock; - const { result, rerender } = renderHook( - ({ dep }) => useAutoScroll(dep), - { initialProps: { dep: 0 } }, - ); + const { result, rerender } = renderHook(({ dep }) => useAutoScroll(dep), { + initialProps: { dep: 0 }, + }); // Attach mock element to ref (result.current as { current: HTMLElement }).current = mockElement; diff --git a/src/hooks/utility/useClickOutside.test.ts b/src/hooks/utility/useClickOutside.test.ts index 35b5d33..6408fb1 100644 --- a/src/hooks/utility/useClickOutside.test.ts +++ b/src/hooks/utility/useClickOutside.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, vi } from "vitest"; import { renderHook } from "@testing-library/react"; import { useClickOutside } from "./useClickOutside"; -import { useRef } from "react"; +import { useRef, type RefObject } from "react"; describe("useClickOutside", () => { it("should call handler when clicking outside element", () => { @@ -91,8 +91,10 @@ describe("useClickOutside", () => { const handler = vi.fn(); const { result } = renderHook(() => { const ref = useRef(null); - const excludeRef = useRef(null); - useClickOutside(ref, handler, { excludeRefs: [excludeRef] }); + const excludeRef = useRef(null); + useClickOutside(ref, handler, { + excludeRefs: [excludeRef as unknown as RefObject], + }); return { ref, excludeRef }; }); @@ -102,7 +104,7 @@ describe("useClickOutside", () => { document.body.appendChild(excludedElement); (result.current.ref as { current: HTMLDivElement }).current = element; - (result.current.excludeRef as { current: HTMLButtonElement }).current = + (result.current.excludeRef as { current: HTMLElement }).current = excludedElement; // Click on excluded element diff --git a/src/hooks/utility/usePrevious.test.ts b/src/hooks/utility/usePrevious.test.ts index f3e8827..22d4f5c 100644 --- a/src/hooks/utility/usePrevious.test.ts +++ b/src/hooks/utility/usePrevious.test.ts @@ -23,12 +23,9 @@ describe("usePrevious", () => { }); it("should handle different types of values", () => { - const { result, rerender } = renderHook( - ({ value }) => usePrevious(value), - { - initialProps: { value: "hello" as string | number | null }, - }, - ); + const { result, rerender } = renderHook(({ value }) => usePrevious(value), { + initialProps: { value: "hello" as string | number | null }, + }); expect(result.current).toBeUndefined(); @@ -43,12 +40,9 @@ describe("usePrevious", () => { const obj1 = { name: "first" }; const obj2 = { name: "second" }; - const { result, rerender } = renderHook( - ({ value }) => usePrevious(value), - { - initialProps: { value: obj1 }, - }, - ); + const { result, rerender } = renderHook(({ value }) => usePrevious(value), { + initialProps: { value: obj1 }, + }); expect(result.current).toBeUndefined();