url tests

This commit is contained in:
DaKheera47 2026-01-20 11:40:04 +00:00
parent 7f99db7873
commit e61208a106
2 changed files with 123 additions and 11 deletions

View File

@ -1,9 +1,10 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { MemoryRouter, Route, Routes, useLocation } from "react-router-dom";
import { OrchestratorPage } from "./OrchestratorPage";
import type { Job } from "../../shared/types";
import type { FilterTab } from "./orchestrator/constants";
const jobFixture: Job = {
id: "job-1",
@ -63,6 +64,8 @@ const jobFixture: Job = {
updatedAt: "2025-01-02T00:00:00Z",
};
const job2: Job = { ...jobFixture, id: "job-2", status: "discovered" };
const createMatchMedia = (matches: boolean) =>
vi.fn().mockImplementation((query: string) => ({
matches,
@ -76,9 +79,9 @@ const createMatchMedia = (matches: boolean) =>
vi.mock("./orchestrator/useOrchestratorData", () => ({
useOrchestratorData: () => ({
jobs: [jobFixture],
jobs: [jobFixture, job2],
stats: {
discovered: 0,
discovered: 1,
processing: 0,
ready: 1,
applied: 0,
@ -109,7 +112,21 @@ vi.mock("./orchestrator/OrchestratorSummary", () => ({
}));
vi.mock("./orchestrator/OrchestratorFilters", () => ({
OrchestratorFilters: () => <div data-testid="filters" />,
OrchestratorFilters: ({
onTabChange,
onSearchQueryChange,
onSortChange,
}: {
onTabChange: (t: FilterTab) => void;
onSearchQueryChange: (q: string) => void;
onSortChange: (s: any) => void;
}) => (
<div data-testid="filters">
<button onClick={() => onTabChange("discovered")}>To Discovered</button>
<button onClick={() => onSearchQueryChange("test search")}>Set Search</button>
<button onClick={() => onSortChange({ key: "title", direction: "asc" })}>Set Sort</button>
</div>
),
}));
vi.mock("./orchestrator/JobDetailPanel", () => ({
@ -120,7 +137,12 @@ vi.mock("./orchestrator/JobListPanel", () => ({
JobListPanel: ({ onSelectJob, selectedJobId }: { onSelectJob: (id: string) => void; selectedJobId: string | null }) => (
<div>
<div data-testid="selected-job">{selectedJobId ?? "none"}</div>
<button type="button" onClick={() => onSelectJob("job-1")}>Select job</button>
<button data-testid="select-job-1" type="button" onClick={() => onSelectJob("job-1")}>
Select job 1
</button>
<button data-testid="select-job-2" type="button" onClick={() => onSelectJob("job-2")}>
Select job 2
</button>
</div>
),
}));
@ -129,23 +151,109 @@ vi.mock("../components", () => ({
ManualImportSheet: () => <div data-testid="manual-import" />,
}));
const LocationWatcher = () => {
const location = useLocation();
return <div data-testid="location">{location.pathname + location.search}</div>;
};
describe("OrchestratorPage", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("syncs tab selection to the URL", () => {
window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia;
render(
<MemoryRouter initialEntries={["/ready"]}>
<LocationWatcher />
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);
fireEvent.click(screen.getByText("To Discovered"));
expect(screen.getByTestId("location").textContent).toContain("/discovered");
});
it("syncs job selection to the URL", async () => {
window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia;
render(
<MemoryRouter initialEntries={["/all"]}>
<LocationWatcher />
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);
// Initial load will auto-select the first matching job (job-1 for all tab)
const locationText = () => screen.getByTestId("location").textContent;
expect(locationText()).toContain("/all/job-1");
// Clicking job-2 should update URL
const job2Button = screen.getByTestId("select-job-2");
fireEvent.click(job2Button);
// Wait for URL to update
await waitFor(() => {
expect(locationText()).toContain("/all/job-2");
});
});
it("syncs search query to URL as a parameter", () => {
window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia;
render(
<MemoryRouter initialEntries={["/ready"]}>
<LocationWatcher />
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);
fireEvent.click(screen.getByText("Set Search"));
expect(screen.getByTestId("location").textContent).toContain("q=test+search");
});
it("syncs sorting to URL and removes it when default", () => {
window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia;
render(
<MemoryRouter initialEntries={["/ready"]}>
<LocationWatcher />
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);
fireEvent.click(screen.getByText("Set Sort"));
expect(screen.getByTestId("location").textContent).toContain("sort=title-asc");
});
it("opens the detail drawer on mobile when a job is selected", () => {
window.matchMedia = createMatchMedia(false) as unknown as typeof window.matchMedia;
render(
<MemoryRouter>
<OrchestratorPage />
<MemoryRouter initialEntries={["/ready"]}>
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);
expect(screen.queryByTestId("detail-panel")).not.toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: /select job/i }));
fireEvent.click(screen.getByTestId("select-job-1"));
expect(screen.getByTestId("detail-panel")).toBeInTheDocument();
});
@ -154,8 +262,11 @@ describe("OrchestratorPage", () => {
window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia;
render(
<MemoryRouter>
<OrchestratorPage />
<MemoryRouter initialEntries={["/ready"]}>
<Routes>
<Route path="/:tab" element={<OrchestratorPage />} />
<Route path="/:tab/:jobId" element={<OrchestratorPage />} />
</Routes>
</MemoryRouter>
);

View File

@ -50,6 +50,7 @@ export const JobListPanel: React.FC<JobListPanelProps> = ({
key={job.id}
type="button"
onClick={() => onSelectJob(job.id)}
data-testid={`select-${job.id}`}
className={cn(
"flex w-full items-center gap-3 px-4 py-3 text-left transition-colors",
isSelected