|
|
import { describe, it, expect, vi, beforeEach } from "vitest"; |
|
|
import { render, screen, waitFor } from "@testing-library/react"; |
|
|
import userEvent from "@testing-library/user-event"; |
|
|
import { server } from "../../mocks/server"; |
|
|
import { errorHandlers, resetCasesAttempts } from "../../mocks/handlers"; |
|
|
import { CaseSelector } from "../CaseSelector"; |
|
|
|
|
|
describe("CaseSelector", () => { |
|
|
const mockOnSelectCase = vi.fn(); |
|
|
|
|
|
beforeEach(() => { |
|
|
mockOnSelectCase.mockClear(); |
|
|
resetCasesAttempts(); |
|
|
}); |
|
|
|
|
|
it("shows loading state initially", () => { |
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
expect(screen.getByText(/loading/i)).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
it("renders select after loading", async () => { |
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
it("displays all cases as options", async () => { |
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
expect( |
|
|
screen.getByRole("option", { name: /sub-stroke0001/i }), |
|
|
).toBeInTheDocument(); |
|
|
expect( |
|
|
screen.getByRole("option", { name: /sub-stroke0002/i }), |
|
|
).toBeInTheDocument(); |
|
|
expect( |
|
|
screen.getByRole("option", { name: /sub-stroke0003/i }), |
|
|
).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
it("has placeholder option", async () => { |
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
expect( |
|
|
screen.getByRole("option", { name: /choose a case/i }), |
|
|
).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
it("calls onSelectCase when case selected", async () => { |
|
|
const user = userEvent.setup(); |
|
|
|
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
await user.selectOptions(screen.getByRole("combobox"), "sub-stroke0001"); |
|
|
|
|
|
expect(mockOnSelectCase).toHaveBeenCalledWith("sub-stroke0001"); |
|
|
}); |
|
|
|
|
|
it("shows selected case value", async () => { |
|
|
render( |
|
|
<CaseSelector |
|
|
selectedCase="sub-stroke0002" |
|
|
onSelectCase={mockOnSelectCase} |
|
|
/>, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toHaveValue("sub-stroke0002"); |
|
|
}); |
|
|
}); |
|
|
|
|
|
it("shows error state on API failure", async () => { |
|
|
server.use(errorHandlers.casesServerError); |
|
|
|
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByText(/failed to load/i)).toBeInTheDocument(); |
|
|
}); |
|
|
}); |
|
|
|
|
|
it("applies correct styling", async () => { |
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
await waitFor(() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}); |
|
|
|
|
|
const container = screen.getByRole("combobox").closest("div"); |
|
|
expect(container).toHaveClass("bg-gray-800"); |
|
|
}); |
|
|
|
|
|
it("retries on 503 cold-start and succeeds", async () => { |
|
|
server.use(errorHandlers.casesColdStart); |
|
|
|
|
|
render( |
|
|
<CaseSelector selectedCase={null} onSelectCase={mockOnSelectCase} />, |
|
|
); |
|
|
|
|
|
|
|
|
await waitFor( |
|
|
() => { |
|
|
expect(screen.getByText(/waking up/i)).toBeInTheDocument(); |
|
|
}, |
|
|
{ timeout: 3000 }, |
|
|
); |
|
|
|
|
|
|
|
|
await waitFor( |
|
|
() => { |
|
|
expect(screen.getByRole("combobox")).toBeInTheDocument(); |
|
|
}, |
|
|
{ timeout: 5000 }, |
|
|
); |
|
|
|
|
|
expect( |
|
|
screen.getByRole("option", { name: /sub-stroke0001/i }), |
|
|
).toBeInTheDocument(); |
|
|
}); |
|
|
}); |
|
|
|