test(import): add legacy import compatibility coverage

This commit is contained in:
Zimeng Xiong
2026-02-06 14:54:02 -08:00
parent 94694deb91
commit 01fda32bcd
5 changed files with 520 additions and 35 deletions
+152
View File
@@ -0,0 +1,152 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
const apiGet = vi.fn();
const apiPost = vi.fn();
vi.mock("../api", () => ({
api: {
get: (...args: any[]) => apiGet(...args),
post: (...args: any[]) => apiPost(...args),
},
}));
const exportToSvg = vi.fn(async () => ({ outerHTML: "<svg />" }));
vi.mock("@excalidraw/excalidraw", () => ({
exportToSvg: (...args: any[]) => exportToSvg(...args),
}));
import { importLegacyFiles } from "./importUtils";
describe("importLegacyFiles", () => {
const makeTestFile = (json: unknown, name: string) =>
({
name,
text: async () => JSON.stringify(json),
}) as unknown as File;
const makeTextFile = (text: string, name: string) =>
({
name,
text: async () => text,
}) as unknown as File;
beforeEach(() => {
apiGet.mockReset();
apiPost.mockReset();
exportToSvg.mockClear();
});
it("imports a legacy ExcaliDash export JSON ({ drawings: [...] }) and maps collectionName → collectionId", async () => {
apiGet.mockResolvedValueOnce({
data: [{ id: "col-existing", name: "Existing Collection" }],
});
apiPost.mockImplementation(async (url: string) => {
if (url === "/collections") return { data: { id: "col-new", name: "New Collection" } };
if (url === "/drawings") return { data: { success: true } };
throw new Error(`Unexpected POST ${url}`);
});
const legacyExport = {
version: "1.0",
exportedAt: new Date().toISOString(),
drawings: [
{
name: "One",
elements: [],
appState: {},
files: {},
collectionName: "Existing Collection",
},
{
name: "Two",
elements: [],
appState: {},
files: {},
collectionName: "New Collection",
},
{
name: "Trash",
elements: [],
appState: {},
files: {},
collectionId: "trash",
},
],
};
const file = makeTestFile(legacyExport, "legacy-export.json");
const result = await importLegacyFiles([file], null);
expect(result.failed).toBe(0);
expect(result.success).toBe(3);
expect(apiGet).toHaveBeenCalledWith("/collections");
// One new collection created ("New Collection") and three drawings posted.
expect(apiPost.mock.calls.filter((c) => c[0] === "/collections")).toHaveLength(1);
expect(apiPost.mock.calls.filter((c) => c[0] === "/drawings")).toHaveLength(3);
const drawCalls = apiPost.mock.calls.filter((c) => c[0] === "/drawings");
expect(drawCalls[0][1].collectionId).toBe("col-existing");
expect(drawCalls[1][1].collectionId).toBe("col-new");
expect(drawCalls[2][1].collectionId).toBe("trash");
expect(exportToSvg).toHaveBeenCalledTimes(3);
});
it("honors targetCollectionId override for legacy export JSON", async () => {
apiPost.mockImplementation(async (url: string) => {
if (url === "/drawings") return { data: { success: true } };
throw new Error(`Unexpected POST ${url}`);
});
const legacyExport = {
drawings: [
{ name: "One", elements: [], appState: {}, files: {}, collectionName: "A" },
{ name: "Two", elements: [], appState: {}, files: {}, collectionName: "B" },
],
};
const file = makeTestFile(legacyExport, "legacy-export.json");
const result = await importLegacyFiles([file], "target-col");
expect(result.failed).toBe(0);
expect(result.success).toBe(2);
expect(apiGet).not.toHaveBeenCalled();
expect(apiPost.mock.calls.filter((c) => c[0] === "/collections")).toHaveLength(0);
const drawCalls = apiPost.mock.calls.filter((c) => c[0] === "/drawings");
expect(drawCalls).toHaveLength(2);
expect(drawCalls[0][1].collectionId).toBe("target-col");
expect(drawCalls[1][1].collectionId).toBe("target-col");
});
it("imports a single .excalidraw file as a drawing", async () => {
apiPost.mockImplementation(async (url: string) => {
if (url === "/drawings") return { data: { success: true } };
throw new Error(`Unexpected POST ${url}`);
});
const excalidraw = {
type: "excalidraw",
version: 2,
source: "test",
elements: [],
appState: {},
files: {},
};
const file = makeTextFile(JSON.stringify(excalidraw), "hello.excalidraw");
const result = await importLegacyFiles([file], null);
expect(result.failed).toBe(0);
expect(result.success).toBe(1);
const drawCalls = apiPost.mock.calls.filter((c) => c[0] === "/drawings");
expect(drawCalls).toHaveLength(1);
expect(drawCalls[0][1].name).toBe("hello");
expect(exportToSvg).toHaveBeenCalledTimes(1);
});
});