import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"; import type RAFT from "@robotical/webapp-types/dist-types/src/application/RAFTs/RAFT"; import Addon from "../../models/addons/Addon"; import AddonSub from "../../models/addons/AddonSub"; import getAllAddonsList from "../../utils/get-addons-list"; import GraphArea from "."; import MicroBitWebBluetooth, { MicroBitSensorListener, } from "../../microbit/MicroBitWebBluetooth"; jest.mock("@robotical/webapp-types/dist-types/src/types/raft", () => ({ RaftTypeE: { COG: "Cog", MARTY: "Marty", }, })); jest.mock("../../utils/get-addons-list", () => jest.fn()); jest.mock("../../app-bridge/MartyInterface", () => ({ MartyInterface: class { addEventListener() {} removeEventListener() {} unsubscribeFromPublishedData() {} }, })); jest.mock("../../app-bridge/CogInterface", () => jest.fn()); jest.mock("../../app-bridge/mocks/MockMartyInterface", () => jest.fn()); jest.mock("../../app-bridge/mocks/MockCogInterface", () => jest.fn()); jest.mock("../../mock/MockApplicationManager", () => ({ isMockRaft: () => false, })); jest.mock("../AddonsList", () => ({ __esModule: true, default: ({ addons, }: { addons: Array<{ addonInputs: Array<{ selectedListener?: () => void }> }>; }) => ( ), })); jest.mock("../Graph", () => () =>
); jest.mock("../GraphControls", () => ({ __esModule: true, default: ({ recordingState, onClickPlay, onClickPause, onClickStop, mode = "all", }: { recordingState: string; onClickPlay: () => void; onClickPause: () => void; onClickStop: () => void; mode?: "all" | "primary" | "advanced"; }) => (
{mode !== "advanced" && ( <> {recordingState} )}
), })); describe("GraphArea", () => { beforeEach(() => { (getAllAddonsList as jest.MockedFunction).mockReset(); (getAllAddonsList as jest.MockedFunction).mockReturnValue([]); }); it("labels the graph and exposes an honest initial state", () => { const raft = { id: "raft-1", type: "unsupported-test-type" } as unknown as RAFT; render( ); expect( screen.getByRole("heading", { name: "Sensor graph — Classroom Marty" }) ).not.toBeNull(); expect( screen.getByRole("region", { name: "Sensor graph for Classroom Marty" }) ).not.toBeNull(); expect(screen.getByText("Choose signals")).not.toBeNull(); expect( (screen.getByRole("button", { name: "CSV" }) as HTMLButtonElement).disabled ).toBe(true); expect( screen.getByText( "CSV export becomes available after sensor data has been recorded." ) ).not.toBeNull(); }); it("moves through choose, ready, recording, paused, and reset states", async () => { const signal = new AddonSub("Temperature", 20); (getAllAddonsList as jest.MockedFunction).mockReturnValue([ new Addon("Environment", [signal]), ]); const raft = { id: "raft-2", type: "Marty" } as unknown as RAFT; render( ); expect(screen.getByTestId("control-state").textContent).toBe("choose-signals"); await waitFor(() => expect( (screen.getByRole("button", { name: "Toggle test signal", }) as HTMLButtonElement).disabled ).toBe(false) ); fireEvent.click(screen.getByRole("button", { name: "Toggle test signal" })); expect(screen.getByTestId("control-state").textContent).toBe("ready"); fireEvent.click(screen.getByRole("button", { name: "Test record" })); expect(screen.getByTestId("control-state").textContent).toBe("recording"); fireEvent.click(screen.getByRole("button", { name: "Test pause" })); expect(screen.getByTestId("control-state").textContent).toBe("paused"); fireEvent.click(screen.getByRole("button", { name: "Test reset" })); expect(screen.getByTestId("control-state").textContent).toBe("ready"); expect( (screen.getByRole("button", { name: "CSV" }) as HTMLButtonElement).disabled ).toBe(true); }); it("records micro:bit sensor events through the fixed addon adapter", async () => { let sensorListener: MicroBitSensorListener | null = null; const unsubscribe = jest.fn(); const microBit = { id: "microbit-1", name: "BBC micro:bit", isMicroBitWebBluetooth: true, sensors: MicroBitWebBluetooth.defaultSensors(), addSensorListener: jest.fn((listener: MicroBitSensorListener) => { sensorListener = listener; return unsubscribe; }), } as unknown as MicroBitWebBluetooth; const { unmount } = render( ); await waitFor(() => expect( (screen.getByRole("button", { name: "Toggle test signal", }) as HTMLButtonElement).disabled ).toBe(false) ); expect(getAllAddonsList).not.toHaveBeenCalled(); fireEvent.click(screen.getByRole("button", { name: "Toggle test signal" })); fireEvent.click(screen.getByRole("button", { name: "Test record" })); act(() => { sensorListener?.( { tiltX: 120, tiltY: -40, buttonA: 0, buttonB: 0, touchPins: [0, 0, 0], gestureState: 0, }, MicroBitWebBluetooth.defaultSensors() ); }); await waitFor(() => expect( (screen.getByRole("button", { name: "CSV" }) as HTMLButtonElement) .disabled ).toBe(false) ); unmount(); expect(unsubscribe).toHaveBeenCalledTimes(1); }); });