// @vitest-environment jsdom import assert from "node:assert/strict"; import { test } from "vitest"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { AssetLibrary, canHardDelete, } from "../../../src/features/tech-log/presentation/studio/components/asset-library.tsx"; import { StudioGatewayError } from "../../../src/features/tech-log/application/ports/studio-gateway-error.ts"; const ASSET = { id: "11111111-1111-4111-8111-111111111111", assetKey: "boundary", kind: "DIAGRAM", mediaType: "image/svg+xml", originalFilename: "b.svg", byteSize: 10, width: 1080, height: 420, altText: "경계", decorative: false, managementStatus: "READY", publicPath: "/media/boundary.svg", usageCount: 0, version: 1, createdAt: "2026-08-14T01:00:00.000Z", updatedAt: "2026-08-14T01:00:00.000Z", } as never; function gatewayOf(detail: unknown, onDelete?: () => never) { return { async listAssets() { return { items: [ASSET], nextCursor: null } as never; }, async getAsset() { return detail as never; }, async uploadAsset() { throw new Error("not used"); }, async updateAssetMetadata() { return ASSET; }, async deleteAsset() { if (onDelete) onDelete(); }, } as never; } test("offers hard delete only for an unused asset with no publication history", () => { assert.equal( canHardDelete({ asset: ASSET, usages: [], hasPublicationHistory: false } as never), true, ); assert.equal( canHardDelete({ asset: ASSET, usages: [], hasPublicationHistory: true } as never), false, ); assert.equal( canHardDelete({ asset: ASSET, usages: [{ documentId: "d", documentKind: "CASE", title: "문서", published: true }], hasPublicationHistory: false, } as never), false, ); }); test("shows archive instead of delete for an asset in use", async () => { const user = userEvent.setup(); render(); await user.click(await screen.findByRole("button", { name: "boundary" })); assert.ok(await screen.findByRole("button", { name: "보관" })); assert.equal(screen.queryByRole("button", { name: "삭제" }), null); }); test("surfaces ASSET_IN_USE when the server rejects a delete", async () => { const user = userEvent.setup(); render( { throw new StudioGatewayError({ type: "https://techlog.local/problems/asset-in-use", title: "ASSET_IN_USE", status: 409, detail: "사용 중인 Asset은 삭제할 수 없습니다.", code: "ASSET_IN_USE", }); }, )} />); await user.click(await screen.findByRole("button", { name: "boundary" })); await user.click(await screen.findByRole("button", { name: "삭제" })); assert.ok(await screen.findByText("사용 중인 Asset은 삭제할 수 없습니다.")); });