import { fireEvent, render, screen } from "@testing-library/react" import { describe, expect, it, vi } from "vitest" import { Reverb } from "../reverb" // Mock useTranslation vi.mock("react-i18next", () => ({ useTranslation: () => ({ t: (key: string) => key, }), })) describe("Reverb", () => { it("renders with default settings", () => { render() expect(screen.getByText("fairlightAudio.effects.reverb.title")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.reset")).toBeInTheDocument() // Check all control labels expect(screen.getByText("fairlightAudio.effects.reverb.roomSize")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.decay")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.damping")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.wet")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.dry")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.preDelay")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.early")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.late")).toBeInTheDocument() }) it("displays default values", () => { render() // Room size and damping both have default value of 50% const fiftyPercents = screen.getAllByText("50%") expect(fiftyPercents).toHaveLength(2) expect(screen.getByText("2.0s")).toBeInTheDocument() // decay expect(screen.getByText("30%")).toBeInTheDocument() // wet expect(screen.getByText("70%")).toBeInTheDocument() // dry // Pre-delay appears twice (in SVG and in the control) const preDelays = screen.getAllByText("20ms") expect(preDelays).toHaveLength(2) // Early and late reflections both have default value of 80% const eightyPercents = screen.getAllByText("80%") expect(eightyPercents).toHaveLength(2) }) it("renders preset buttons", () => { render() expect(screen.getByText("fairlightAudio.effects.reverb.presets.room")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.presets.hall")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.presets.plate")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.presets.spring")).toBeInTheDocument() expect(screen.getByText("fairlightAudio.effects.reverb.presets.cathedral")).toBeInTheDocument() }) it("calls onParameterChange when parameters are adjusted", () => { const onParameterChange = vi.fn() render() // Click room preset const roomButton = screen.getByText("fairlightAudio.effects.reverb.presets.room") fireEvent.click(roomButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 30) expect(onParameterChange).toHaveBeenCalledWith("decay", 0.8) expect(onParameterChange).toHaveBeenCalledWith("damping", 70) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 20) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 80) expect(onParameterChange).toHaveBeenCalledWith("predelay", 10) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 90) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 60) }) it("applies hall preset correctly", () => { const onParameterChange = vi.fn() render() const hallButton = screen.getByText("fairlightAudio.effects.reverb.presets.hall") fireEvent.click(hallButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 70) expect(onParameterChange).toHaveBeenCalledWith("decay", 2.5) expect(onParameterChange).toHaveBeenCalledWith("damping", 50) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 35) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 65) expect(onParameterChange).toHaveBeenCalledWith("predelay", 25) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 70) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 90) }) it("applies cathedral preset correctly", () => { const onParameterChange = vi.fn() render() const cathedralButton = screen.getByText("fairlightAudio.effects.reverb.presets.cathedral") fireEvent.click(cathedralButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 100) expect(onParameterChange).toHaveBeenCalledWith("decay", 6) expect(onParameterChange).toHaveBeenCalledWith("damping", 40) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 45) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 55) expect(onParameterChange).toHaveBeenCalledWith("predelay", 50) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 60) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 100) }) it("applies plate preset correctly", () => { const onParameterChange = vi.fn() render() const plateButton = screen.getByText("fairlightAudio.effects.reverb.presets.plate") fireEvent.click(plateButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 50) expect(onParameterChange).toHaveBeenCalledWith("decay", 1.5) expect(onParameterChange).toHaveBeenCalledWith("damping", 80) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 40) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 60) expect(onParameterChange).toHaveBeenCalledWith("predelay", 0) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 50) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 100) }) it("applies spring preset correctly", () => { const onParameterChange = vi.fn() render() const springButton = screen.getByText("fairlightAudio.effects.reverb.presets.spring") fireEvent.click(springButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 20) expect(onParameterChange).toHaveBeenCalledWith("decay", 2) expect(onParameterChange).toHaveBeenCalledWith("damping", 30) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 30) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 70) expect(onParameterChange).toHaveBeenCalledWith("predelay", 0) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 100) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 80) }) it("resets to default settings", () => { const onParameterChange = vi.fn() render() // Apply a preset first const hallButton = screen.getByText("fairlightAudio.effects.reverb.presets.hall") fireEvent.click(hallButton) // Clear the mock onParameterChange.mockClear() // Click reset const resetButton = screen.getByText("fairlightAudio.effects.reverb.reset") fireEvent.click(resetButton) expect(onParameterChange).toHaveBeenCalledWith("roomSize", 50) expect(onParameterChange).toHaveBeenCalledWith("decay", 2) expect(onParameterChange).toHaveBeenCalledWith("damping", 50) expect(onParameterChange).toHaveBeenCalledWith("wetLevel", 30) expect(onParameterChange).toHaveBeenCalledWith("dryLevel", 70) expect(onParameterChange).toHaveBeenCalledWith("predelay", 20) expect(onParameterChange).toHaveBeenCalledWith("earlyLevel", 80) expect(onParameterChange).toHaveBeenCalledWith("lateLevel", 80) }) it("applies custom className", () => { const { container } = render() const reverbDiv = container.firstChild expect(reverbDiv).toHaveClass("custom-class") expect(reverbDiv).toHaveClass("bg-zinc-900") }) it("does not call onParameterChange when not provided", () => { // This should not throw render() const roomButton = screen.getByText("fairlightAudio.effects.reverb.presets.room") expect(() => fireEvent.click(roomButton)).not.toThrow() }) it("formats decay time with decimal", () => { render() // Default decay is 2s, should show with decimal expect(screen.getByText("2.0s")).toBeInTheDocument() }) it("formats pre-delay time correctly", () => { render() // Default pre-delay is 20ms (appears twice - in SVG and in control) const preDelays = screen.getAllByText("20ms") expect(preDelays).toHaveLength(2) }) it("shows all slider controls", () => { const { container } = render() // Should have 8 sliders: roomSize, decay, damping, predelay, dryLevel, wetLevel, earlyLevel, lateLevel // Radix UI sliders use data-slot="slider" attribute const sliders = container.querySelectorAll('[data-slot="slider"]') expect(sliders).toHaveLength(8) }) })