83 lines
3 KiB
TypeScript
83 lines
3 KiB
TypeScript
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||
|
|
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||
|
|
import { SportIconUploader } from "../SportIconUploader";
|
||
|
|
import type { FormEvent } from "react";
|
||
|
|
|
||
|
|
beforeEach(() => {
|
||
|
|
vi.restoreAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("SportIconUploader", () => {
|
||
|
|
it("stores the initial icon URL in a hidden input", () => {
|
||
|
|
const { container } = render(
|
||
|
|
<SportIconUploader uploadUrl="/api/upload-sport-icon" initialIconUrl="nfl.svg" sportName="NFL" />
|
||
|
|
);
|
||
|
|
|
||
|
|
expect(container.querySelector('input[name="iconUrl"]')).toHaveValue("nfl.svg");
|
||
|
|
expect(screen.getByText("Current icon")).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("rejects non-SVG files before upload", async () => {
|
||
|
|
const { container } = render(<SportIconUploader uploadUrl="/api/upload-sport-icon" />);
|
||
|
|
const fileInput = container.querySelector('input[type="file"]') as HTMLInputElement;
|
||
|
|
|
||
|
|
fireEvent.change(fileInput, {
|
||
|
|
target: { files: [new File(["not svg"], "icon.png", { type: "image/png" })] },
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(await screen.findByText("Choose an SVG file.")).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("uploads an SVG and updates the hidden input", async () => {
|
||
|
|
vi.stubGlobal(
|
||
|
|
"fetch",
|
||
|
|
vi.fn().mockResolvedValue({
|
||
|
|
ok: true,
|
||
|
|
json: async () => ({ iconUrl: "https://res.cloudinary.com/demo/image/upload/v1/sports-icons/nfl.svg" }),
|
||
|
|
})
|
||
|
|
);
|
||
|
|
|
||
|
|
const { container } = render(<SportIconUploader uploadUrl="/api/upload-sport-icon" />);
|
||
|
|
const fileInput = container.querySelector('input[type="file"]') as HTMLInputElement;
|
||
|
|
|
||
|
|
fireEvent.change(fileInput, {
|
||
|
|
target: { files: [new File(["<svg />"], "icon.svg", { type: "image/svg+xml" })] },
|
||
|
|
});
|
||
|
|
|
||
|
|
fireEvent.click(await screen.findByRole("button", { name: "Upload SVG" }));
|
||
|
|
|
||
|
|
await waitFor(() => {
|
||
|
|
expect(container.querySelector('input[name="iconUrl"]')).toHaveValue(
|
||
|
|
"https://res.cloudinary.com/demo/image/upload/v1/sports-icons/nfl.svg"
|
||
|
|
);
|
||
|
|
});
|
||
|
|
expect(screen.getByText("Icon uploaded. Save the sport to apply it.")).toBeInTheDocument();
|
||
|
|
});
|
||
|
|
|
||
|
|
it("does not submit a parent form when uploading an SVG", async () => {
|
||
|
|
vi.stubGlobal(
|
||
|
|
"fetch",
|
||
|
|
vi.fn().mockResolvedValue({
|
||
|
|
ok: true,
|
||
|
|
json: async () => ({ iconUrl: "https://res.cloudinary.com/demo/image/upload/v1/sports-icons/nfl.svg" }),
|
||
|
|
})
|
||
|
|
);
|
||
|
|
const onSubmit = vi.fn((event: FormEvent<HTMLFormElement>) => event.preventDefault());
|
||
|
|
|
||
|
|
const { container } = render(
|
||
|
|
<form onSubmit={onSubmit}>
|
||
|
|
<SportIconUploader uploadUrl="/api/upload-sport-icon" />
|
||
|
|
</form>
|
||
|
|
);
|
||
|
|
const fileInput = container.querySelector('input[type="file"]') as HTMLInputElement;
|
||
|
|
|
||
|
|
fireEvent.change(fileInput, {
|
||
|
|
target: { files: [new File(["<svg />"], "icon.svg", { type: "image/svg+xml" })] },
|
||
|
|
});
|
||
|
|
fireEvent.click(await screen.findByRole("button", { name: "Upload SVG" }));
|
||
|
|
|
||
|
|
await waitFor(() => expect(global.fetch).toHaveBeenCalled());
|
||
|
|
expect(onSubmit).not.toHaveBeenCalled();
|
||
|
|
});
|
||
|
|
});
|