nandi/oripublic Fork 0
b6cd929ab1425a4ef6073ea9c189917cca02cf3c
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
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { resetWorkspace, useWorkspace } from "../workspace";
import { PreviewPane } from "./PreviewPane";

const { readFileMock } = vi.hoisted(() => ({ readFileMock: vi.fn() }));

vi.mock("../api", () => ({
	readFile: readFileMock,
	rawFileUrl: (path: string) => `/api/raw?path=${encodeURIComponent(path)}`,
}));

vi.mock("./DrawioView", () => ({
	DrawioView: ({ xml }: { xml: string }) => (
		<div data-testid="drawio-view">{xml}</div>
	),
}));

// The heavy viewers are replaced by inspectable stubs.
vi.mock("./CodeView", () => ({
	CodeView: ({ content, language }: { content: string; language: string }) => (
		<pre data-testid="code-view" data-language={language}>
			{content}
		</pre>
	),
}));

vi.mock("./AsciiDocView", () => ({
	AsciiDocView: ({ content }: { content: string }) => (
		<div data-testid="asciidoc-view">{content}</div>
	),
}));

describe("PreviewPane", () => {
	beforeEach(() => {
		resetWorkspace();
		readFileMock.mockReset();
	});

	it("asks for a selection when no file is open", () => {
		render(<PreviewPane path={null} />);
		expect(screen.getByText(/Select a file/)).toBeDefined();
	});

	it("previews code with the detected language", async () => {
		readFileMock.mockResolvedValue({
			path: "/w/main.go",
			content: "package main",
		});
		render(<PreviewPane path="/w/main.go" />);

		const view = await screen.findByTestId("code-view");
		expect(view.getAttribute("data-language")).toBe("go");
		expect(view.textContent).toBe("package main");
		// Code has no rendered form: no mode toggle.
		expect(screen.queryByRole("button", { name: "Rendered" })).toBeNull();
	});

	it("renders markdown by default and toggles to source", async () => {
		readFileMock.mockResolvedValue({
			path: "/w/README.md",
			content: "# Title",
		});
		render(<PreviewPane path="/w/README.md" />);

		expect(await screen.findByRole("heading", { name: "Title" })).toBeDefined();

		fireEvent.click(screen.getByRole("button", { name: "Source" }));
		const view = await screen.findByTestId("code-view");
		expect(view.getAttribute("data-language")).toBe("markdown");
		expect(view.textContent).toBe("# Title");
	});

	it("renders asciidoc through the AsciiDoc viewer", async () => {
		readFileMock.mockResolvedValue({ path: "/w/book.adoc", content: "= Book" });
		render(<PreviewPane path="/w/book.adoc" />);

		expect(await screen.findByTestId("asciidoc-view")).toBeDefined();
	});

	it("sends the file to the editor with the Edit button", async () => {
		readFileMock.mockResolvedValue({
			path: "/w/main.go",
			content: "package main",
		});
		render(<PreviewPane path="/w/main.go" />);
		await screen.findByTestId("code-view");

		fireEvent.click(screen.getByRole("button", { name: "Edit" }));
		expect(useWorkspace.getState()).toMatchObject({
			tab: "editor",
			editorPath: "/w/main.go",
		});
	});

	it("shows images from the raw endpoint without reading them as text", async () => {
		render(<PreviewPane path="/w/docs/logo.png" />);

		const img = (await screen.findByRole("img", {
			name: "logo.png",
		})) as HTMLImageElement;
		expect(img.getAttribute("src")).toBe(
			"/api/raw?path=%2Fw%2Fdocs%2Flogo.png",
		);
		expect(readFileMock).not.toHaveBeenCalled();
		// Images have no text form: no toggle, no Edit button.
		expect(screen.queryByRole("button", { name: "Source" })).toBeNull();
		expect(screen.queryByRole("button", { name: "Edit" })).toBeNull();

		Object.defineProperty(img, "naturalWidth", { value: 640 });
		Object.defineProperty(img, "naturalHeight", { value: 480 });
		fireEvent.load(img);
		expect(screen.getByText("640 × 480 px")).toBeDefined();
	});

	it("treats .drawio.svg exports as images", async () => {
		render(<PreviewPane path="/w/docs/flow.drawio.svg" />);
		expect(
			await screen.findByRole("img", { name: "flow.drawio.svg" }),
		).toBeDefined();
	});

	it("renders draw.io diagrams through the viewer and toggles to the XML source", async () => {
		readFileMock.mockResolvedValue({
			path: "/w/docs/arch.drawio",
			content: "<mxfile><diagram/></mxfile>",
		});
		render(<PreviewPane path="/w/docs/arch.drawio" />);

		const view = await screen.findByTestId("drawio-view");
		expect(view.textContent).toBe("<mxfile><diagram/></mxfile>");

		fireEvent.click(screen.getByRole("button", { name: "Source" }));
		const code = await screen.findByTestId("code-view");
		expect(code.getAttribute("data-language")).toBe("xml");
		expect(code.textContent).toBe("<mxfile><diagram/></mxfile>");
	});

	it("surfaces read errors", async () => {
		readFileMock.mockRejectedValue(new Error("not a text file"));
		render(<PreviewPane path="/w/blob.bin" />);
		await waitFor(() =>
			expect(screen.getByText("not a text file")).toBeDefined(),
		);
	});
});