Files
auto-virtual-tryon-frontend/tests/features/libraries/upload-resource.test.ts
2026-03-28 13:42:22 +08:00

174 lines
5.0 KiB
TypeScript

import { expect, test, vi } from "vitest";
import { uploadLibraryResource } from "@/features/libraries/upload-resource";
test("uploads original thumbnail and gallery files before creating the resource record", async () => {
const originalFile = new File(["original"], "ava-original.png", {
type: "image/png",
});
const thumbnailFile = new File(["thumbnail"], "ava-thumb.png", {
type: "image/png",
});
const galleryFile = new File(["gallery"], "ava-gallery.png", {
type: "image/png",
});
const thumbnailGenerator = vi.fn().mockResolvedValue(thumbnailFile);
const fetchMock = vi
.fn()
.mockResolvedValueOnce(
new Response(
JSON.stringify({
data: {
method: "PUT",
uploadUrl: "https://upload.test/original",
headers: { "content-type": "image/png" },
storageKey: "library/models/2026/ava-original.png",
publicUrl: "https://images.test/library/models/2026/ava-original.png",
},
}),
),
)
.mockResolvedValueOnce(new Response(null, { status: 200 }))
.mockResolvedValueOnce(
new Response(
JSON.stringify({
data: {
method: "PUT",
uploadUrl: "https://upload.test/thumbnail",
headers: { "content-type": "image/png" },
storageKey: "library/models/2026/ava-thumb.png",
publicUrl: "https://images.test/library/models/2026/ava-thumb.png",
},
}),
),
)
.mockResolvedValueOnce(new Response(null, { status: 200 }))
.mockResolvedValueOnce(
new Response(
JSON.stringify({
data: {
method: "PUT",
uploadUrl: "https://upload.test/gallery",
headers: { "content-type": "image/png" },
storageKey: "library/models/2026/ava-gallery.png",
publicUrl: "https://images.test/library/models/2026/ava-gallery.png",
},
}),
),
)
.mockResolvedValueOnce(new Response(null, { status: 200 }))
.mockResolvedValueOnce(
new Response(
JSON.stringify({
data: {
item: {
id: "12",
libraryType: "models",
name: "Ava Studio",
description: "棚拍女模特",
previewUri: "https://images.test/library/models/2026/ava-thumb.png",
tags: ["女装", "棚拍"],
isMock: false,
backendId: 12,
},
},
}),
{ status: 201 },
),
);
const created = await uploadLibraryResource({
fetchFn: fetchMock,
thumbnailGenerator,
libraryType: "models",
values: {
name: "Ava Studio",
description: "棚拍女模特",
tags: ["女装", "棚拍"],
gender: "female",
ageGroup: "adult",
environment: "",
category: "",
},
files: {
original: originalFile,
gallery: [galleryFile],
},
});
expect(created).toEqual({
id: "12",
libraryType: "models",
name: "Ava Studio",
description: "棚拍女模特",
previewUri: "https://images.test/library/models/2026/ava-thumb.png",
tags: ["女装", "棚拍"],
isMock: false,
backendId: 12,
});
expect(fetchMock).toHaveBeenNthCalledWith(
1,
"/api/libraries/uploads/presign",
expect.objectContaining({
method: "POST",
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(
2,
"https://upload.test/original",
expect.objectContaining({
method: "PUT",
body: originalFile,
}),
);
expect(fetchMock).toHaveBeenNthCalledWith(
7,
"/api/libraries/models",
expect.objectContaining({
method: "POST",
}),
);
expect(fetchMock).toHaveBeenLastCalledWith(
"/api/libraries/models",
expect.objectContaining({
body: JSON.stringify({
name: "Ava Studio",
description: "棚拍女模特",
tags: ["女装", "棚拍"],
gender: "female",
ageGroup: "adult",
environment: undefined,
category: undefined,
files: [
{
fileRole: "original",
storageKey: "library/models/2026/ava-original.png",
publicUrl: "https://images.test/library/models/2026/ava-original.png",
mimeType: "image/png",
sizeBytes: 8,
sortOrder: 0,
},
{
fileRole: "thumbnail",
storageKey: "library/models/2026/ava-thumb.png",
publicUrl: "https://images.test/library/models/2026/ava-thumb.png",
mimeType: "image/png",
sizeBytes: 9,
sortOrder: 0,
},
{
fileRole: "gallery",
storageKey: "library/models/2026/ava-gallery.png",
publicUrl: "https://images.test/library/models/2026/ava-gallery.png",
mimeType: "image/png",
sizeBytes: 7,
sortOrder: 0,
},
],
}),
}),
);
expect(thumbnailGenerator).toHaveBeenCalledWith(originalFile);
});