AttachmentPreview.test.tsx (4363B)
1 import { describe, it, expect, vi, beforeEach } from "vitest"; 2 import { render, screen, fireEvent } from "@testing-library/react"; 3 import { AttachmentPreview } from "./AttachmentPreview"; 4 5 describe("AttachmentPreview", () => { 6 it("renders file name", () => { 7 const file = { name: "test.txt", type: "text/plain", size: 1024 }; 8 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 9 expect(screen.getByText("test.txt")).toBeInTheDocument(); 10 }); 11 12 it("renders file icon for non-image files", () => { 13 const file = { name: "doc.pdf", type: "application/pdf", size: 2048 }; 14 const { container } = render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 15 expect(container.querySelector("span")).toHaveTextContent("📄"); 16 }); 17 18 it("renders thumbnail for image files when thumbnailUrl is provided", () => { 19 const file = { name: "image.png", type: "image/png", size: 3000 }; 20 render(<AttachmentPreview file={file} onRemove={vi.fn()} thumbnailUrl="http://example.com/img.png" />); 21 const img = screen.getByRole("img"); 22 expect(img).toHaveAttribute("src", "http://example.com/img.png"); 23 expect(img).toHaveAttribute("alt", "image.png"); 24 }); 25 26 it("renders file icon when image file but no thumbnailUrl", () => { 27 const file = { name: "image.png", type: "image/png", size: 3000 }; 28 const { container } = render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 29 expect(container.querySelector("span")).toHaveTextContent("📄"); 30 }); 31 32 it("calls onRemove when remove button clicked", () => { 33 const onRemove = vi.fn(); 34 const file = { name: "test.txt", type: "text/plain", size: 100 }; 35 render(<AttachmentPreview file={file} onRemove={onRemove} />); 36 fireEvent.click(screen.getByLabelText("Remove attachment")); 37 expect(onRemove).toHaveBeenCalled(); 38 }); 39 40 it("renders file size in bytes", () => { 41 const file = { name: "small.txt", type: "text/plain", size: 500 }; 42 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 43 expect(screen.getByText("500 B")).toBeInTheDocument(); 44 }); 45 46 it("renders file size in KB", () => { 47 const file = { name: "medium.txt", type: "text/plain", size: 2048 }; 48 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 49 expect(screen.getByText("2 KB")).toBeInTheDocument(); 50 }); 51 52 it("renders file size in MB", () => { 53 const file = { name: "large.zip", type: "application/zip", size: 5 * 1024 * 1024 }; 54 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 55 expect(screen.getByText("5.0 MB")).toBeInTheDocument(); 56 }); 57 58 it("shows progress bar when progress is provided", () => { 59 const file = { name: "test.txt", type: "text/plain", size: 100 }; 60 const { container } = render( 61 <AttachmentPreview file={file} onRemove={vi.fn()} progress={50} />, 62 ); 63 const progressBar = container.querySelector(".bg-blue-500"); 64 expect(progressBar).toBeInTheDocument(); 65 }); 66 67 it("shows progress percentage text", () => { 68 const file = { name: "test.txt", type: "text/plain", size: 100 }; 69 render(<AttachmentPreview file={file} onRemove={vi.fn()} progress={75} />); 70 expect(screen.getByText("75%")).toBeInTheDocument(); 71 }); 72 73 it("shows error message when error is provided", () => { 74 const file = { name: "test.txt", type: "text/plain", size: 100 }; 75 render(<AttachmentPreview file={file} onRemove={vi.fn()} error="Upload failed" />); 76 expect(screen.getByText("Upload failed")).toBeInTheDocument(); 77 }); 78 79 it("does not show error when error is not provided", () => { 80 const file = { name: "test.txt", type: "text/plain", size: 100 }; 81 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 82 expect(screen.queryByText("Upload failed")).not.toBeInTheDocument(); 83 }); 84 85 it("caps progress bar at 100%", () => { 86 const file = { name: "test.txt", type: "text/plain", size: 100 }; 87 const { container } = render( 88 <AttachmentPreview file={file} onRemove={vi.fn()} progress={150} />, 89 ); 90 const bar = container.querySelector(".bg-blue-500"); 91 expect(bar).toHaveStyle({ width: "100%" }); 92 }); 93 94 it("handles zero-size file", () => { 95 const file = { name: "empty.txt", type: "text/plain", size: 0 }; 96 render(<AttachmentPreview file={file} onRemove={vi.fn()} />); 97 expect(screen.getByText("0 B")).toBeInTheDocument(); 98 }); 99 });