Files
simple-react-app-kit/packages/media/src/media.test.tsx
T
2026-09-20 16:44:15 +08:00

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")
})
})