77 lines
4.7 KiB
TypeScript
77 lines
4.7 KiB
TypeScript
import React from "react";
|
|
import "@testing-library/jest-dom";
|
|
import { act, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import CvTemplatePreviewDialog from "./components/cv/CvTemplatePreviewDialog";
|
|
import { cvBuilderApi, CvRender, CvTheme } from "./cvBuilder";
|
|
import { I18nProvider } from "./i18n/I18nProvider";
|
|
|
|
const modern: CvTheme = { id: "modern", name: "Modern", category: "Professional", description: "A clear document", layout: "single", accent: "#3157d5", photoShape: "none", supportsIcons: false, atsFriendly: true, requiresPro: false, available: true, swatches: [] };
|
|
const code = { ...modern, id: "code", name: "Code" };
|
|
const sample = (id: string): CvRender => ({ themeId: id, html: `<html><body><div class="page">${id} sample</div></body></html>`, suggestedFileName: "sample.pdf" });
|
|
function deferred<T>() {
|
|
let resolve!: (value: T) => void;
|
|
const promise = new Promise<T>(yes => { resolve = yes; });
|
|
return { promise, resolve };
|
|
}
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
global.ResizeObserver = class { observe() {} unobserve() {} disconnect() {} };
|
|
jest.spyOn(cvBuilderApi, "themePreview").mockResolvedValue(sample("modern"));
|
|
});
|
|
afterEach(() => jest.restoreAllMocks());
|
|
|
|
test("candidate loads a labelled sample without applying; Cancel preserves the draft", async () => {
|
|
const onApply = jest.fn(); const onClose = jest.fn();
|
|
render(<I18nProvider><CvTemplatePreviewDialog theme={modern} onClose={onClose} onApply={onApply} /></I18nProvider>);
|
|
expect(await screen.findByTitle("Template sample preview")).toHaveAttribute("srcdoc", expect.stringContaining("modern sample"));
|
|
expect(screen.getByText(/Sample content/)).toBeVisible();
|
|
expect(onApply).not.toHaveBeenCalled();
|
|
fireEvent.click(screen.getByRole("button", { name: "Cancel" }));
|
|
expect(onClose).toHaveBeenCalledTimes(1);
|
|
expect(onApply).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("sample scales down to a narrow preview host", async () => {
|
|
const width = jest.spyOn(HTMLElement.prototype, "clientWidth", "get").mockReturnValue(280);
|
|
render(<I18nProvider><CvTemplatePreviewDialog theme={modern} onClose={jest.fn()} onApply={jest.fn()} /></I18nProvider>);
|
|
const frame = await screen.findByTitle("Template sample preview");
|
|
expect(Number((frame as HTMLIFrameElement).style.transform.match(/scale\(([^)]+)\)/)?.[1])).toBeLessThan(0.4);
|
|
width.mockRestore();
|
|
});
|
|
|
|
test("a late candidate response cannot replace the selected template", async () => {
|
|
const held = deferred<CvRender>();
|
|
jest.mocked(cvBuilderApi.themePreview).mockImplementation(id => id === "modern" ? held.promise : Promise.resolve(sample("code")));
|
|
const view = render(<I18nProvider><CvTemplatePreviewDialog theme={modern} onClose={jest.fn()} onApply={jest.fn()} /></I18nProvider>);
|
|
view.rerender(<I18nProvider><CvTemplatePreviewDialog theme={code} onClose={jest.fn()} onApply={jest.fn()} /></I18nProvider>);
|
|
await waitFor(() => expect(screen.getByTitle("Template sample preview")).toHaveAttribute("srcdoc", expect.stringContaining("code sample")));
|
|
await act(async () => held.resolve(sample("modern")));
|
|
expect(screen.getByTitle("Template sample preview")).toHaveAttribute("srcdoc", expect.stringContaining("code sample"));
|
|
});
|
|
|
|
test("failed preview has an explicit retry and cannot apply until it succeeds", async () => {
|
|
jest.mocked(cvBuilderApi.themePreview).mockRejectedValueOnce(new Error("synthetic failure"));
|
|
const onApply = jest.fn();
|
|
render(<I18nProvider><CvTemplatePreviewDialog theme={modern} onClose={jest.fn()} onApply={onApply} /></I18nProvider>);
|
|
expect(await screen.findByRole("alert")).toHaveTextContent("Could not preview this design");
|
|
expect(screen.getByRole("button", { name: "Apply template" })).toBeDisabled();
|
|
fireEvent.click(screen.getByRole("button", { name: "Retry preview" }));
|
|
await waitFor(() => expect(screen.getByRole("button", { name: "Apply template" })).toBeEnabled());
|
|
fireEvent.click(screen.getByRole("button", { name: "Apply template" }));
|
|
expect(onApply).toHaveBeenCalledWith(modern);
|
|
});
|
|
|
|
test("locked candidates cannot request or apply a preview", async () => {
|
|
render(<I18nProvider><CvTemplatePreviewDialog theme={{ ...modern, available: false }} onClose={jest.fn()} onApply={jest.fn()} /></I18nProvider>);
|
|
expect(screen.getByRole("button", { name: "Apply template" })).toBeDisabled();
|
|
expect(cvBuilderApi.themePreview).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("Bokmål sample labelling and actions are localised", async () => {
|
|
localStorage.setItem("uiLanguage", "nb");
|
|
render(<I18nProvider><CvTemplatePreviewDialog theme={modern} onClose={jest.fn()} onApply={jest.fn()} /></I18nProvider>);
|
|
expect(await screen.findByTitle("Eksempelforhåndsvisning av mal")).toBeInTheDocument();
|
|
expect(screen.getByRole("button", { name: "Bruk mal" })).toBeEnabled();
|
|
});
|