| import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; |
| import { render, screen, cleanup, act } from "@testing-library/react"; |
| import userEvent from "@testing-library/user-event"; |
| import { createRef } from "react"; |
| import { Visualizer, type VisualizerHandle } from "@/lib/jambuddy/visualizer"; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| class FakeAudio { |
| onended: (() => void) | null = null; |
| paused = true; |
| played = false; |
| play() { |
| this.played = true; |
| this.paused = false; |
| return Promise.resolve(); |
| } |
| pause() { |
| this.paused = true; |
| } |
| } |
| let fakeAudio: FakeAudio | null = null; |
|
|
| |
| class FakeAudioContext { |
| sampleRate = 44100; |
| close() { |
| return Promise.resolve(); |
| } |
| decodeAudioData() { |
| return Promise.resolve({ |
| numberOfChannels: 1, |
| sampleRate: 44100, |
| getChannelData: () => new Float32Array(100), |
| }); |
| } |
| } |
|
|
| beforeEach(() => { |
| fakeAudio = new FakeAudio(); |
| vi.stubGlobal("Audio", class { constructor() { return fakeAudio; } }); |
| vi.stubGlobal("AudioContext", FakeAudioContext); |
| vi.stubGlobal("fetch", vi.fn(() => |
| Promise.resolve({ arrayBuffer: () => Promise.resolve(new ArrayBuffer(0)) }), |
| )); |
| }); |
|
|
| afterEach(() => { |
| cleanup(); |
| vi.unstubAllGlobals(); |
| }); |
|
|
| describe("Visualizer playable waveform", () => { |
| it("fires onStartPlayback BEFORE starting play (exclusivity guard)", async () => { |
| const user = userEvent.setup(); |
| const onStart = vi.fn(); |
| const ref = createRef<VisualizerHandle>(); |
| await act(async () => { |
| render( |
| <Visualizer |
| ref={ref} |
| audioUrl="blob:take" |
| playable |
| onStartPlayback={onStart} |
| />, |
| ); |
| }); |
|
|
| await user.click(screen.getByRole("button", { name: "Play" })); |
|
|
| |
| expect(onStart).toHaveBeenCalledTimes(1); |
| expect(fakeAudio?.played).toBe(true); |
| }); |
|
|
| it("exposes a stop() handle that stops audio and flips the toggle back", async () => { |
| const user = userEvent.setup(); |
| const ref = createRef<VisualizerHandle>(); |
| await act(async () => { |
| render(<Visualizer ref={ref} audioUrl="blob:take" playable />); |
| }); |
|
|
| await user.click(screen.getByRole("button", { name: "Play" })); |
| |
| expect(screen.getByRole("button", { name: "Stop playback" })).toBeInTheDocument(); |
|
|
| act(() => { |
| ref.current?.stop(); |
| }); |
| expect(fakeAudio?.paused).toBe(true); |
| |
| expect(screen.getByRole("button", { name: "Play" })).toBeInTheDocument(); |
| }); |
| }); |
|
|