frontend/src/hooks/useAsset.test.tsx
Rama main · réplica de lectura del repositorio original.
import { describe, it, expect, beforeEach } from "vitest";
import { act, renderHook, waitFor } from "@testing-library/react";
import * as db from "@/lib/localStore/db";
import * as assets from "@/lib/localStore/assets";
import { useAsset } from "./useAsset";
const blobOf = (n: number, type = "image/png") => new Blob([new Uint8Array(n)], { type });
beforeEach(async () => {
await db.destroy();
});
describe("useAsset", () => {
it("starts empty", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.items).toEqual([]);
});
it("saves and lists an asset", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
await act(async () => {
await result.current.save("l.png", blobOf(8));
});
await waitFor(() => expect(result.current.items).toHaveLength(1));
expect(result.current.items[0].name).toBe("l.png");
});
it("returns true on a successful save", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
let ok: boolean | undefined;
await act(async () => {
ok = await result.current.save("l.png", blobOf(8));
});
expect(ok).toBe(true);
});
it("surfaces a quota error instead of throwing", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
let ok: boolean | undefined;
await act(async () => {
ok = await result.current.save("big.png", blobOf(assets.MAX_ASSET_BYTES + 1));
});
expect(ok).toBe(false);
await waitFor(() => expect(result.current.error).toMatch(/too large/i));
expect(result.current.items).toEqual([]);
});
it("clears a previous error on the next successful save", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
await act(async () => {
await result.current.save("big.png", blobOf(assets.MAX_ASSET_BYTES + 1));
});
await waitFor(() => expect(result.current.error).not.toBeNull());
await act(async () => {
await result.current.save("ok.png", blobOf(8));
});
await waitFor(() => expect(result.current.error).toBeNull());
});
it("removes an asset", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
await act(async () => {
await result.current.save("l.png", blobOf(8));
});
await waitFor(() => expect(result.current.items).toHaveLength(1));
await act(async () => {
await result.current.remove(result.current.items[0].id);
});
await waitFor(() => expect(result.current.items).toEqual([]));
});
it("only sees its own kind", async () => {
await assets.putAsset("signature", "s.png", blobOf(4));
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.items).toEqual([]);
});
it("hands back a usable object URL", async () => {
const { result } = renderHook(() => useAsset("logo"));
await waitFor(() => expect(result.current.loading).toBe(false));
await act(async () => {
await result.current.save("l.png", blobOf(8));
});
await waitFor(() => expect(result.current.items).toHaveLength(1));
let url: string | null = null;
await act(async () => {
url = await result.current.dataUrl(result.current.items[0].id);
});
expect(url).toMatch(/^blob:/);
});
});