Open History to see the last commit
1import { beforeEach, describe, expect, it, vi } from "vite-plus/test";
2
3import type { ComposerImageAttachment } from "../../composerDraftStore";
4import { readFileAsDataUrl } from "../../lib/imageCompression";
5import { serializeComposerImages } from "./composerImagePersistence";
6
7vi.mock("../../lib/imageCompression", () => ({ readFileAsDataUrl: vi.fn() }));
8
9function image(id: string): ComposerImageAttachment {
10 const file = new File([id], `${id}.png`, { type: "image/png" });
11 return {
12 type: "image",
13 id,
14 name: file.name,
15 mimeType: file.type,
16 sizeBytes: file.size,
17 previewUrl: `blob:${id}`,
18 file,
19 };
20}
21
22describe("serializeComposerImages", () => {
23 beforeEach(() => {
24 vi.mocked(readFileAsDataUrl).mockReset();
25 });
26
27 it("reads only new images and drops removed images without rereading retained bytes", async () => {
28 const a = image("a");
29 const b = image("b");
30 vi.mocked(readFileAsDataUrl).mockImplementation(async (file) =>
31 file === a.file ? "data:image/png;base64,YQ==" : "data:image/png;base64,Yg==",
32 );
33
34 const first = await serializeComposerImages([a], []);
35 expect(first).toEqual([
36 {
37 id: "a",
38 name: "a.png",
39 mimeType: "image/png",
40 sizeBytes: 1,
41 dataUrl: "data:image/png;base64,YQ==",
42 },
43 ]);
44 expect(readFileAsDataUrl).toHaveBeenCalledTimes(1);
45
46 const second = await serializeComposerImages([a, b], first);
47 expect(second).toEqual([
48 first[0],
49 {
50 id: "b",
51 name: "b.png",
52 mimeType: "image/png",
53 sizeBytes: 1,
54 dataUrl: "data:image/png;base64,Yg==",
55 },
56 ]);
57 expect(readFileAsDataUrl).toHaveBeenCalledTimes(2);
58 expect(readFileAsDataUrl).toHaveBeenNthCalledWith(2, b.file);
59
60 expect(await serializeComposerImages([a], second)).toEqual(first);
61 expect(await serializeComposerImages([], second)).toEqual([]);
62 expect(readFileAsDataUrl).toHaveBeenCalledTimes(2);
63 });
64
65 it("preserves cached bytes without trying to read an unavailable file", async () => {
66 const a = image("a");
67 const persisted = {
68 id: a.id,
69 name: a.name,
70 mimeType: a.mimeType,
71 sizeBytes: a.sizeBytes,
72 dataUrl: "data:image/png;base64,YQ==",
73 };
74 vi.mocked(readFileAsDataUrl).mockRejectedValue(new Error("File is unavailable"));
75
76 expect(await serializeComposerImages([a], [persisted])).toEqual([persisted]);
77 expect(readFileAsDataUrl).not.toHaveBeenCalled();
78 });
79
80 it("omits failed uncached reads while keeping successfully serialized images", async () => {
81 const a = image("a");
82 const b = image("b");
83 vi.mocked(readFileAsDataUrl)
84 .mockRejectedValueOnce(new Error("File is unavailable"))
85 .mockResolvedValueOnce("data:image/png;base64,Yg==");
86
87 expect(await serializeComposerImages([a, b], [])).toEqual([
88 {
89 id: "b",
90 name: "b.png",
91 mimeType: "image/png",
92 sizeBytes: 1,
93 dataUrl: "data:image/png;base64,Yg==",
94 },
95 ]);
96 expect(readFileAsDataUrl).toHaveBeenCalledTimes(2);
97 });
98});