80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { describe, it, expect, vi, afterEach } from "vitest";
|
|||
|
|
import { dragPreviewIcon } from "./dragPreview";
|
||
|
|
|
||
|
|
afterEach(() => {
|
||
|
|
vi.restoreAllMocks();
|
||
|
|
});
|
||
|
|
|
||
|
|
describe("dragPreviewIcon", () => {
|
||
|
|
it("falls back to a PNG data URL when there is no 2D context", () => {
|
||
|
|
// jsdom has no canvas, and a webview can refuse one. `startDrag` requires
|
||
|
|
// an image and the Rust side accepts nothing but a PNG data URL, so a
|
||
|
|
// fallback that is not one takes the whole drag down with it.
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue(null);
|
||
|
|
expect(dragPreviewIcon("notes.txt")).toMatch(/^data:image\/png;base64,[A-Za-z0-9+/=]+$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("falls back rather than throwing when the canvas throws", () => {
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockImplementation(() => {
|
||
|
|
throw new Error("no canvas here");
|
||
|
|
});
|
||
|
|
expect(dragPreviewIcon("notes.txt")).toMatch(/^data:image\/png;base64,/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("refuses a canvas that encoded nothing", () => {
|
||
|
|
// jsdom's `toDataURL` answers `data:,` — which the Rust side rejects
|
||
|
|
// outright, so returning it would be worse than not drawing at all.
|
||
|
|
const ctx = {
|
||
|
|
scale: vi.fn(),
|
||
|
|
measureText: () => ({ width: 60 }),
|
||
|
|
beginPath: vi.fn(),
|
||
|
|
roundRect: vi.fn(),
|
||
|
|
fill: vi.fn(),
|
||
|
|
stroke: vi.fn(),
|
||
|
|
fillRect: vi.fn(),
|
||
|
|
strokeRect: vi.fn(),
|
||
|
|
fillText: vi.fn(),
|
||
|
|
font: "",
|
||
|
|
fillStyle: "",
|
||
|
|
strokeStyle: "",
|
||
|
|
lineWidth: 0,
|
||
|
|
textBaseline: "",
|
||
|
|
} as unknown as CanvasRenderingContext2D;
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue(ctx);
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "toDataURL").mockReturnValue("data:,");
|
||
|
|
|
||
|
|
expect(dragPreviewIcon("notes.txt")).toMatch(/^data:image\/png;base64,[A-Za-z0-9+/=]+$/);
|
||
|
|
});
|
||
|
|
|
||
|
|
it("uses what the canvas drew when there is one", () => {
|
||
|
|
const ctx = {
|
||
|
|
scale: vi.fn(),
|
||
|
|
measureText: () => ({ width: 60 }),
|
||
|
|
beginPath: vi.fn(),
|
||
|
|
roundRect: vi.fn(),
|
||
|
|
fill: vi.fn(),
|
||
|
|
stroke: vi.fn(),
|
||
|
|
fillRect: vi.fn(),
|
||
|
|
strokeRect: vi.fn(),
|
||
|
|
fillText: vi.fn(),
|
||
|
|
font: "",
|
||
|
|
fillStyle: "",
|
||
|
|
strokeStyle: "",
|
||
|
|
lineWidth: 0,
|
||
|
|
textBaseline: "",
|
||
|
|
} as unknown as CanvasRenderingContext2D;
|
||
|
|
const drawn = "data:image/png;base64,AAAA";
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "getContext").mockReturnValue(ctx);
|
||
|
|
vi.spyOn(HTMLCanvasElement.prototype, "toDataURL").mockReturnValue(drawn);
|
||
|
|
|
||
|
|
expect(dragPreviewIcon("notes.txt")).toBe(drawn);
|
||
|
|
// A long name is elided rather than drawn off the edge of the preview.
|
||
|
|
expect(dragPreviewIcon("a-really-quite-long-file-name-indeed.txt")).toBe(drawn);
|
||
|
|
expect(ctx.fillText).toHaveBeenLastCalledWith(
|
||
|
|
expect.stringContaining("…"),
|
||
|
|
expect.any(Number),
|
||
|
|
expect.any(Number),
|
||
|
|
);
|
||
|
|
});
|
||
|
|
});
|