feat(career): clarify workspace actions
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import React from "react";
|
||||
import "@testing-library/jest-dom";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
|
||||
import { cvBuilderApi } from "./cvBuilder";
|
||||
import CareerWorkspaceOverview, { CareerWorkspaceImportRun } from "./views/career/CareerWorkspaceOverview";
|
||||
|
||||
jest.mock("./cvBuilder", () => ({
|
||||
cvBuilderApi: { list: jest.fn() },
|
||||
}));
|
||||
|
||||
const mockedList = cvBuilderApi.list as jest.MockedFunction<typeof cvBuilderApi.list>;
|
||||
|
||||
function renderOverview({
|
||||
percent = 0,
|
||||
missing = [],
|
||||
runs = [],
|
||||
loading = false,
|
||||
loadError = null,
|
||||
}: {
|
||||
percent?: number;
|
||||
missing?: string[];
|
||||
runs?: CareerWorkspaceImportRun[];
|
||||
loading?: boolean;
|
||||
loadError?: string | null;
|
||||
} = {}) {
|
||||
return render(
|
||||
<CareerWorkspaceOverview
|
||||
completeness={{ percent, missing }}
|
||||
runs={runs}
|
||||
loading={loading}
|
||||
loadError={loadError}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
mockedList.mockResolvedValue([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test("first-run workspace presents concise profile, import, general CV and job-specific actions", async () => {
|
||||
renderOverview();
|
||||
|
||||
expect(screen.getByRole("heading", { name: "Career Workspace", level: 1 })).toBeInTheDocument();
|
||||
expect(await screen.findByText(/start by adding career information manually or importing a cv/i)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/job-specific CVs stay separate and never overwrite/i)).not.toBeInTheDocument();
|
||||
expect(screen.getByRole("link", { name: "Edit career profile" })).toHaveAttribute("href", "#career-profile-editor");
|
||||
expect(screen.getAllByRole("link", { name: "Import a CV" })[0]).toHaveAttribute("href", "#career-cv-import");
|
||||
expect(screen.getByRole("link", { name: "Create a general CV" })).toHaveAttribute("href", "/career/builder");
|
||||
expect(screen.getByRole("link", { name: "Choose a job" })).toHaveAttribute("href", "/jobs");
|
||||
expect(await screen.findByText("No CV documents yet.")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("returning workspace shows missing profile information and recent general and job-specific CVs", async () => {
|
||||
mockedList.mockResolvedValue([
|
||||
{ id: 8, name: "Backend CV", themeId: "modern", publicSlug: "backend", isPublic: false, version: 2, jobApplicationId: 42, updatedAtUtc: "2026-08-08T10:00:00Z" },
|
||||
{ id: 7, name: "General CV", themeId: "modern", publicSlug: "general", isPublic: false, version: 1, jobApplicationId: null, updatedAtUtc: "2026-08-07T10:00:00Z" },
|
||||
]);
|
||||
|
||||
renderOverview({ percent: 70, missing: ["Projects", "Education", "Languages", "Interests"] });
|
||||
|
||||
expect(screen.getByText("70%")).toBeInTheDocument();
|
||||
expect(screen.getByText("Add next: Projects, Education, Languages")).toBeInTheDocument();
|
||||
expect(await screen.findByText("Backend CV")).toBeInTheDocument();
|
||||
expect(screen.getAllByText("General CV").length).toBeGreaterThan(1);
|
||||
expect(screen.getByText("Job-specific")).toBeInTheDocument();
|
||||
expect(screen.getAllByRole("link", { name: "Open", exact: true })[0]).toHaveAttribute("href", "/career/builder/8");
|
||||
});
|
||||
|
||||
test.each([
|
||||
["pending_review", "Review imported CV", /waiting for your approval/i],
|
||||
["queued", "View CV processing", /is processing/i],
|
||||
["failed", "Resolve CV import", /needs attention/i],
|
||||
])("workspace exposes the %s import state as a resumable action", async (status, label, message) => {
|
||||
renderOverview({ runs: [{ id: 13, status }] });
|
||||
|
||||
expect(screen.getAllByRole("link", { name: label })[0]).toHaveAttribute("href", "#career-cv-import");
|
||||
expect(screen.getByText(message)).toBeInTheDocument();
|
||||
await waitFor(() => expect(mockedList).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
|
||||
test("workspace represents loading and profile-load errors without inventing status", async () => {
|
||||
renderOverview({ loading: true, loadError: "offline" });
|
||||
|
||||
expect(screen.getByRole("progressbar", { name: "Career profile completeness" })).toBeInTheDocument();
|
||||
expect(screen.getByText(/workspace status is unavailable/i)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/start by adding career information/i)).not.toBeInTheDocument();
|
||||
await waitFor(() => expect(mockedList).toHaveBeenCalledTimes(1));
|
||||
});
|
||||
Reference in New Issue
Block a user