67 lines
3.9 KiB
TypeScript
67 lines
3.9 KiB
TypeScript
import React from "react";
|
|
import "@testing-library/jest-dom";
|
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
import { MemoryRouter } from "react-router-dom";
|
|
import CropImageDialog from "./components/CropImageDialog";
|
|
import CvCustomizeTab from "./components/cv/CvCustomizeTab";
|
|
import { emptyCvVariantSettings, type CvTheme } from "./cvBuilder";
|
|
import { ConfirmProvider } from "./confirm";
|
|
import { I18nProvider } from "./i18n/I18nProvider";
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
URL.createObjectURL = jest.fn(() => "blob:portrait");
|
|
URL.revokeObjectURL = jest.fn();
|
|
});
|
|
afterEach(() => jest.restoreAllMocks());
|
|
|
|
test("keyboard crop positions are bounded and feed the same exported square as dragging", async () => {
|
|
const drawImage = jest.fn();
|
|
jest.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue({ drawImage } as any);
|
|
jest.spyOn(HTMLCanvasElement.prototype, "toBlob").mockImplementation(callback => callback(new Blob(["portrait"], { type: "image/png" })));
|
|
const save = jest.fn();
|
|
render(<I18nProvider><CropImageDialog open file={new File(["portrait"], "portrait.png", { type: "image/png" })} onClose={jest.fn()} onSave={save} /></I18nProvider>);
|
|
const image = screen.getByRole("img", { name: "Crop preview" });
|
|
Object.defineProperties(image, { naturalWidth: { value: 400 }, naturalHeight: { value: 200 } });
|
|
fireEvent.load(image);
|
|
const horizontal = screen.getByRole("slider", { name: "Horizontal position" });
|
|
const vertical = screen.getByRole("slider", { name: "Vertical position" });
|
|
expect(vertical).toBeDisabled();
|
|
fireEvent.keyDown(horizontal, { key: "Home" });
|
|
expect(horizontal).toHaveAttribute("aria-valuenow", "-280");
|
|
fireEvent.keyDown(horizontal, { key: "ArrowLeft" });
|
|
expect(horizontal).toHaveAttribute("aria-valuenow", "-280");
|
|
fireEvent.change(screen.getByRole("slider", { name: "Zoom" }), { target: { value: "2" } });
|
|
fireEvent.keyDown(vertical, { key: "Home" });
|
|
expect(vertical).toHaveAttribute("aria-valuenow", "-280");
|
|
fireEvent.click(screen.getByRole("button", { name: "Save image" }));
|
|
await waitFor(() => expect(save).toHaveBeenCalledTimes(1));
|
|
expect(drawImage).toHaveBeenLastCalledWith(image, 100, 100, 100, 100, 0, 0, 512, 512);
|
|
});
|
|
|
|
const theme: CvTheme = { id: "modern", name: "Modern", category: "Professional", description: "", layout: "single", accent: "#3157d5", photoShape: "circle", supportsIcons: true, atsFriendly: true, requiresPro: false, available: true, swatches: [] };
|
|
function mountPhoto(photoShape: CvTheme["photoShape"], includeProfileContact = true) {
|
|
const update = jest.fn();
|
|
render(<MemoryRouter><I18nProvider><ConfirmProvider><CvCustomizeTab mode="customize" settings={{ ...emptyCvVariantSettings(), includeProfileContact }} themes={[{ ...theme, photoShape }]} update={update} sectionLabel={(_, fallback) => fallback} /></ConfirmProvider></I18nProvider></MemoryRouter>);
|
|
return update;
|
|
}
|
|
|
|
test("capable CV designs link directly to existing portrait management without changing the CV", () => {
|
|
const update = mountPhoto("circle");
|
|
expect(screen.getByRole("link", { name: "Manage profile photo" })).toHaveAttribute("href", "/career?section=profile");
|
|
expect(screen.getByRole("switch", { name: "Show profile photo" })).toBeInTheDocument();
|
|
expect(update).not.toHaveBeenCalled();
|
|
});
|
|
|
|
test("photo-free designs do not offer portrait controls", () => {
|
|
mountPhoto("none");
|
|
fireEvent.click(screen.getByRole("button", { name: "Advanced document settings" }));
|
|
expect(screen.queryByRole("switch", { name: "Show profile photo" })).not.toBeInTheDocument();
|
|
expect(screen.queryByRole("link", { name: "Manage profile photo" })).not.toBeInTheDocument();
|
|
});
|
|
|
|
test("explicitly excluded profile contact explains why the portrait is omitted", () => {
|
|
mountPhoto("circle", false);
|
|
expect(screen.getByText("Include Career Profile contact details in Content to show its photo. A missing photo leaves the document unchanged.")).toBeInTheDocument();
|
|
});
|