nandi/oripublic Fork 0
00224b167266e7d496672adfe1e60fcffeab7e63
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

PreviewPane.test.tsx · 146 lines · 4.7 KBTypeScript Blame HistoryRaw
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday1import { fireEvent, render, screen, waitFor } from "@testing-library/react";
2import { beforeEach, describe, expect, it, vi } from "vitest";
3import { resetWorkspace, useWorkspace } from "../workspace";
4import { PreviewPane } from "./PreviewPane";
5
6const { readFileMock } = vi.hoisted(() => ({ readFileMock: vi.fn() }));
7
8vi.mock("../api", () => ({
9 readFile: readFileMock,
10 rawFileUrl: (path: string) => `/api/raw?path=${encodeURIComponent(path)}`,
11}));
12
13vi.mock("./DrawioView", () => ({
14 DrawioView: ({ xml }: { xml: string }) => (
15 <div data-testid="drawio-view">{xml}</div>
16 ),
17}));
18
19// The heavy viewers are replaced by inspectable stubs.
20vi.mock("./CodeView", () => ({
21 CodeView: ({ content, language }: { content: string; language: string }) => (
22 <pre data-testid="code-view" data-language={language}>
23 {content}
24 </pre>
25 ),
26}));
27
28vi.mock("./AsciiDocView", () => ({
29 AsciiDocView: ({ content }: { content: string }) => (
30 <div data-testid="asciidoc-view">{content}</div>
31 ),
32}));
33
34describe("PreviewPane", () => {
35 beforeEach(() => {
36 resetWorkspace();
37 readFileMock.mockReset();
38 });
39
40 it("asks for a selection when no file is open", () => {
41 render(<PreviewPane path={null} />);
42 expect(screen.getByText(/Select a file/)).toBeDefined();
43 });
44
45 it("previews code with the detected language", async () => {
46 readFileMock.mockResolvedValue({
47 path: "/w/main.go",
48 content: "package main",
49 });
50 render(<PreviewPane path="/w/main.go" />);
51
52 const view = await screen.findByTestId("code-view");
53 expect(view.getAttribute("data-language")).toBe("go");
54 expect(view.textContent).toBe("package main");
55 // Code has no rendered form: no mode toggle.
56 expect(screen.queryByRole("button", { name: "Rendered" })).toBeNull();
57 });
58
59 it("renders markdown by default and toggles to source", async () => {
60 readFileMock.mockResolvedValue({
61 path: "/w/README.md",
62 content: "# Title",
63 });
64 render(<PreviewPane path="/w/README.md" />);
65
66 expect(await screen.findByRole("heading", { name: "Title" })).toBeDefined();
67
68 fireEvent.click(screen.getByRole("button", { name: "Source" }));
69 const view = await screen.findByTestId("code-view");
70 expect(view.getAttribute("data-language")).toBe("markdown");
71 expect(view.textContent).toBe("# Title");
72 });
73
74 it("renders asciidoc through the AsciiDoc viewer", async () => {
75 readFileMock.mockResolvedValue({ path: "/w/book.adoc", content: "= Book" });
76 render(<PreviewPane path="/w/book.adoc" />);
77
78 expect(await screen.findByTestId("asciidoc-view")).toBeDefined();
79 });
80
81 it("sends the file to the editor with the Edit button", async () => {
82 readFileMock.mockResolvedValue({
83 path: "/w/main.go",
84 content: "package main",
85 });
86 render(<PreviewPane path="/w/main.go" />);
87 await screen.findByTestId("code-view");
88
89 fireEvent.click(screen.getByRole("button", { name: "Edit" }));
90 expect(useWorkspace.getState()).toMatchObject({
91 tab: "editor",
92 editorPath: "/w/main.go",
93 });
94 });
95
96 it("shows images from the raw endpoint without reading them as text", async () => {
97 render(<PreviewPane path="/w/docs/logo.png" />);
98
99 const img = (await screen.findByRole("img", {
100 name: "logo.png",
101 })) as HTMLImageElement;
102 expect(img.getAttribute("src")).toBe(
103 "/api/raw?path=%2Fw%2Fdocs%2Flogo.png",
104 );
105 expect(readFileMock).not.toHaveBeenCalled();
106 // Images have no text form: no toggle, no Edit button.
107 expect(screen.queryByRole("button", { name: "Source" })).toBeNull();
108 expect(screen.queryByRole("button", { name: "Edit" })).toBeNull();
109
110 Object.defineProperty(img, "naturalWidth", { value: 640 });
111 Object.defineProperty(img, "naturalHeight", { value: 480 });
112 fireEvent.load(img);
113 expect(screen.getByText("640 × 480 px")).toBeDefined();
114 });
115
116 it("treats .drawio.svg exports as images", async () => {
117 render(<PreviewPane path="/w/docs/flow.drawio.svg" />);
118 expect(
119 await screen.findByRole("img", { name: "flow.drawio.svg" }),
120 ).toBeDefined();
121 });
122
123 it("renders draw.io diagrams through the viewer and toggles to the XML source", async () => {
124 readFileMock.mockResolvedValue({
125 path: "/w/docs/arch.drawio",
126 content: "<mxfile><diagram/></mxfile>",
127 });
128 render(<PreviewPane path="/w/docs/arch.drawio" />);
129
130 const view = await screen.findByTestId("drawio-view");
131 expect(view.textContent).toBe("<mxfile><diagram/></mxfile>");
132
133 fireEvent.click(screen.getByRole("button", { name: "Source" }));
134 const code = await screen.findByTestId("code-view");
135 expect(code.getAttribute("data-language")).toBe("xml");
136 expect(code.textContent).toBe("<mxfile><diagram/></mxfile>");
137 });
138
139 it("surfaces read errors", async () => {
140 readFileMock.mockRejectedValue(new Error("not a text file"));
141 render(<PreviewPane path="/w/blob.bin" />);
142 await waitFor(() =>
143 expect(screen.getByText("not a text file")).toBeDefined(),
144 );
145 });
146});