159 lines
4.2 KiB
TypeScript
159 lines
4.2 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import type { ReactNode } from "react"
|
|
import {
|
|
cleanup,
|
|
fireEvent,
|
|
render,
|
|
screen,
|
|
waitFor,
|
|
} from "@testing-library/react"
|
|
import { afterEach, describe, expect, it, vi } from "vitest"
|
|
import { I18nProvider } from "@workspace/i18n"
|
|
|
|
import { MediaProvider } from "./context"
|
|
import { MediaLibrary } from "./media-library"
|
|
import { MediaPickerDialog } from "./media-picker-dialog"
|
|
import type { MediaAdapter, MediaAsset } from "./types"
|
|
import {
|
|
defaultMediaReference,
|
|
getMediaFolderPath,
|
|
splitMediaName,
|
|
} from "./utils"
|
|
|
|
const imageAsset: MediaAsset = {
|
|
createdAt: "2026-08-01T00:00:00Z",
|
|
favorite: false,
|
|
folderId: null,
|
|
height: 600,
|
|
id: "image-1",
|
|
kind: "image",
|
|
mimeType: "image/png",
|
|
name: "product.png",
|
|
sizeBytes: 1024,
|
|
url: "/media/product.png",
|
|
width: 800,
|
|
}
|
|
|
|
function createAdapter(): MediaAdapter {
|
|
return {
|
|
createFolder: vi.fn(async ({ name, parentId }) => ({
|
|
id: name,
|
|
name,
|
|
parentId,
|
|
})),
|
|
deleteAsset: vi.fn(async () => undefined),
|
|
deleteFolder: vi.fn(async () => undefined),
|
|
listAssets: vi.fn(async () => ({
|
|
assets: [imageAsset],
|
|
hasNextPage: false,
|
|
})),
|
|
listFolders: vi.fn(async () => []),
|
|
listStorageTargets: vi.fn(async () => [
|
|
{ id: "local", kind: "local" as const, label: "Local" },
|
|
]),
|
|
moveAsset: vi.fn(async () => imageAsset),
|
|
renameAsset: vi.fn(async () => imageAsset),
|
|
updateFavorite: vi.fn(async () => imageAsset),
|
|
updateFolder: vi.fn(async ({ id, name, parentId }) => ({
|
|
id,
|
|
name,
|
|
parentId,
|
|
})),
|
|
upload: vi.fn(async () => [imageAsset]),
|
|
}
|
|
}
|
|
|
|
function MediaTestProvider({
|
|
adapter,
|
|
children,
|
|
}: {
|
|
adapter: MediaAdapter
|
|
children: ReactNode
|
|
}) {
|
|
return (
|
|
<I18nProvider locale="en-US">
|
|
<MediaProvider adapter={adapter}>{children}</MediaProvider>
|
|
</I18nProvider>
|
|
)
|
|
}
|
|
|
|
describe("media blocks", () => {
|
|
afterEach(cleanup)
|
|
|
|
it("loads and uploads media only through the provider adapter", async () => {
|
|
const adapter = createAdapter()
|
|
const { container } = render(
|
|
<MediaTestProvider adapter={adapter}>
|
|
<MediaLibrary />
|
|
</MediaTestProvider>
|
|
)
|
|
|
|
expect(await screen.findByRole("img", { name: "product.png" })).toBeTruthy()
|
|
const fileInput =
|
|
container.querySelector<HTMLInputElement>('input[type="file"]')
|
|
expect(fileInput).not.toBeNull()
|
|
|
|
fireEvent.change(fileInput!, {
|
|
target: {
|
|
files: [new File(["image"], "new-image.png", { type: "image/png" })],
|
|
},
|
|
})
|
|
|
|
await waitFor(() => expect(adapter.upload).toHaveBeenCalledOnce())
|
|
expect(adapter.upload).toHaveBeenCalledWith(
|
|
expect.objectContaining({
|
|
files: expect.arrayContaining([expect.any(File)]),
|
|
target: expect.objectContaining({ id: "local" }),
|
|
})
|
|
)
|
|
})
|
|
|
|
it("returns image picker selections with an intrinsic-size reference URL", async () => {
|
|
const adapter = createAdapter()
|
|
const onConfirm = vi.fn()
|
|
render(
|
|
<MediaTestProvider adapter={adapter}>
|
|
<MediaPickerDialog
|
|
open
|
|
onOpenChange={() => undefined}
|
|
onConfirm={onConfirm}
|
|
/>
|
|
</MediaTestProvider>
|
|
)
|
|
|
|
const image = await screen.findByRole("img", { name: "product.png" })
|
|
fireEvent.click(image.closest("button")!)
|
|
await waitFor(() =>
|
|
expect(
|
|
(
|
|
screen.getByRole("button", {
|
|
name: "Use selected media",
|
|
}) as HTMLButtonElement
|
|
).disabled
|
|
).toBe(false)
|
|
)
|
|
fireEvent.click(screen.getByRole("button", { name: "Use selected media" }))
|
|
|
|
expect(onConfirm).toHaveBeenCalledWith([
|
|
expect.objectContaining({ url: "/media/product.png?w=800&h=600" }),
|
|
])
|
|
})
|
|
|
|
it("builds stable media references and folder paths", () => {
|
|
expect(defaultMediaReference(imageAsset)).toBe(
|
|
"/media/product.png?w=800&h=600"
|
|
)
|
|
expect(splitMediaName("archive.tar.gz")).toEqual({
|
|
baseName: "archive.tar",
|
|
extension: ".gz",
|
|
})
|
|
expect(
|
|
getMediaFolderPath({ id: "child", name: "Shoes", parentId: "root" }, [
|
|
{ id: "root", name: "Products", parentId: null },
|
|
{ id: "child", name: "Shoes", parentId: "root" },
|
|
])
|
|
).toBe("Products / Shoes")
|
|
})
|
|
})
|