Jobber/orchestrator/src/client/components/LogEventModal.test.tsx
Shaheer Sarfaraz 6e771ce728
Timeline introduced (#38)
* initial implementation

* onboarding doesn't pop until invalid values are present

* link to job page

* proactive inputs working slightly

* onboarding gate reinstated

* better proactive buttons

* fully manual tracking for now.

* edit and delete timeline events

* status showing correctly

* tests update

* tests

* Update orchestrator/src/server/services/applicationTracking.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update orchestrator/src/server/services/applicationTracking.test.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update orchestrator/src/server/services/applicationTracking.test.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update orchestrator/src/client/pages/job/Timeline.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update orchestrator/src/client/pages/JobPage.tsx

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* add tests for application tracking routes and remove unused actionId from client API

* remove unnecessary await from synchronous transitionStage calls and improve test isolation

* relax externalUrl validation to allow non-URL metadata

* add toast notifications for data loading and event logging in JobPage

* comments

* fix: resolve type error in sponsor-matching.test.ts

* fix ci

* tests fix for github

* lint

* github comments

* build fix

* dedupe

* format

* types fix

* Apply suggestion from @Copilot

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* formatting

* title and group id are discrete fields

* backfill

* hide view button on page

* show relevant dropdown options

* confetti!

* remove redundant

* confirm delete is a custom element now

* formatting

* fix styling

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-27 23:49:11 +00:00

114 lines
3.1 KiB
TypeScript

import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import type React from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { LogEventModal } from "./LogEventModal";
vi.mock("@/components/ui/alert-dialog", () => ({
AlertDialog: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogContent: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogDescription: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogFooter: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogHeader: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogTitle: ({ children }: { children: React.ReactNode }) => (
<div>{children}</div>
),
AlertDialogCancel: ({
children,
...props
}: {
children: React.ReactNode;
}) => (
<button type="button" {...props}>
{children}
</button>
),
}));
vi.mock("@/components/ui/select", () => ({
Select: ({
children,
value,
onValueChange,
}: {
children: React.ReactNode;
value?: string;
onValueChange?: (value: string) => void;
}) => (
<select
data-testid="select"
value={value}
onChange={(event) => onValueChange?.(event.target.value)}
>
{children}
</select>
),
SelectContent: ({ children }: { children: React.ReactNode }) => (
<>{children}</>
),
SelectItem: ({
children,
value,
}: {
children: React.ReactNode;
value: string;
}) => <option value={value}>{children}</option>,
SelectTrigger: () => null,
SelectValue: () => null,
}));
describe("LogEventModal", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("shows the rejection reason selector and submits the form", async () => {
const onLog = vi.fn().mockResolvedValue(undefined);
const onClose = vi.fn();
render(<LogEventModal isOpen onClose={onClose} onLog={onLog} />);
const stageSelect = screen.getAllByTestId("select")[0];
fireEvent.change(stageSelect, { target: { value: "rejected" } });
expect(screen.getByText("Reason")).toBeInTheDocument();
const reasonSelect = screen.getAllByTestId("select")[1];
fireEvent.change(reasonSelect, { target: { value: "Visa" } });
fireEvent.click(screen.getByRole("button", { name: /log event/i }));
await waitFor(() =>
expect(onLog).toHaveBeenCalledWith(
expect.objectContaining({ stage: "rejected", reasonCode: "Visa" }),
undefined,
),
);
});
it("blocks submit when the title is cleared", async () => {
const onLog = vi.fn().mockResolvedValue(undefined);
const onClose = vi.fn();
render(<LogEventModal isOpen onClose={onClose} onLog={onLog} />);
const titleInput = screen.getByPlaceholderText("e.g. Recruiter Screen");
fireEvent.change(titleInput, { target: { value: "" } });
fireEvent.click(screen.getByRole("button", { name: /log event/i }));
expect(await screen.findByText("Title is required")).toBeInTheDocument();
expect(onLog).not.toHaveBeenCalled();
});
});