From e61208a106e08e18e4b16d57c91b8f7fe1ee92bf Mon Sep 17 00:00:00 2001 From: DaKheera47 Date: Tue, 20 Jan 2026 11:40:04 +0000 Subject: [PATCH] url tests --- .../client/pages/OrchestratorPage.test.tsx | 133 ++++++++++++++++-- .../pages/orchestrator/JobListPanel.tsx | 1 + 2 files changed, 123 insertions(+), 11 deletions(-) diff --git a/orchestrator/src/client/pages/OrchestratorPage.test.tsx b/orchestrator/src/client/pages/OrchestratorPage.test.tsx index 1e304df..59a10a9 100644 --- a/orchestrator/src/client/pages/OrchestratorPage.test.tsx +++ b/orchestrator/src/client/pages/OrchestratorPage.test.tsx @@ -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: () =>
, + OrchestratorFilters: ({ + onTabChange, + onSearchQueryChange, + onSortChange, + }: { + onTabChange: (t: FilterTab) => void; + onSearchQueryChange: (q: string) => void; + onSortChange: (s: any) => void; + }) => ( +
+ + + +
+ ), })); vi.mock("./orchestrator/JobDetailPanel", () => ({ @@ -120,7 +137,12 @@ vi.mock("./orchestrator/JobListPanel", () => ({ JobListPanel: ({ onSelectJob, selectedJobId }: { onSelectJob: (id: string) => void; selectedJobId: string | null }) => (
{selectedJobId ?? "none"}
- + +
), })); @@ -129,23 +151,109 @@ vi.mock("../components", () => ({ ManualImportSheet: () =>
, })); +const LocationWatcher = () => { + const location = useLocation(); + return
{location.pathname + location.search}
; +}; + describe("OrchestratorPage", () => { beforeEach(() => { vi.clearAllMocks(); }); + it("syncs tab selection to the URL", () => { + window.matchMedia = createMatchMedia(true) as unknown as typeof window.matchMedia; + + render( + + + + } /> + } /> + + + ); + + 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( + + + + } /> + } /> + + + ); + + // 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( + + + + } /> + } /> + + + ); + + 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( + + + + } /> + } /> + + + ); + + 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( - - + + + } /> + } /> + ); 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( - - + + + } /> + } /> + ); diff --git a/orchestrator/src/client/pages/orchestrator/JobListPanel.tsx b/orchestrator/src/client/pages/orchestrator/JobListPanel.tsx index f7f0541..b41a54d 100644 --- a/orchestrator/src/client/pages/orchestrator/JobListPanel.tsx +++ b/orchestrator/src/client/pages/orchestrator/JobListPanel.tsx @@ -50,6 +50,7 @@ export const JobListPanel: React.FC = ({ 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