nandi/oripublic Fork 0
34e69b510306161654f26903a269247aefa9c94d
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

FileTree.test.tsx · 110 lines · 3.4 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
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { FileEntry } from "../api";
import { resetWorkspace, useWorkspace } from "../workspace";
import { FileTree } from "./FileTree";

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

vi.mock("../api", () => ({
	listFiles: listFilesMock,
}));

const rootEntries: FileEntry[] = [
	{ name: "src", path: "/w/src", isDir: true, size: 0 },
	{ name: "README.md", path: "/w/README.md", isDir: false, size: 7 },
];

describe("FileTree", () => {
	beforeEach(() => {
		resetWorkspace();
		listFilesMock.mockReset();
	});

	it("lists the workspace root", async () => {
		listFilesMock.mockResolvedValue({ path: "/w", entries: rootEntries });
		render(<FileTree />);

		await waitFor(() => expect(screen.getByText("README.md")).toBeDefined());
		expect(screen.getByText(/src/)).toBeDefined();
		expect(listFilesMock.mock.calls[0]).toEqual([]);
	});

	it("expands a directory lazily", async () => {
		listFilesMock.mockImplementation((path?: string) =>
			Promise.resolve(
				path === "/w/src"
					? {
							path: "/w/src",
							entries: [
								{
									name: "main.go",
									path: "/w/src/main.go",
									isDir: false,
									size: 3,
								},
							],
						}
					: { path: "/w", entries: rootEntries },
			),
		);
		render(<FileTree />);
		await waitFor(() => expect(screen.getByText(/src/)).toBeDefined());

		fireEvent.click(screen.getByText(/src/));
		await waitFor(() => expect(screen.getByText("main.go")).toBeDefined());
		expect(listFilesMock).toHaveBeenCalledWith("/w/src");
	});

	it("opens a file in preview on click and in editor on double-click", async () => {
		listFilesMock.mockResolvedValue({ path: "/w", entries: rootEntries });
		render(<FileTree />);
		await waitFor(() => expect(screen.getByText("README.md")).toBeDefined());

		fireEvent.click(screen.getByText("README.md"));
		expect(useWorkspace.getState()).toMatchObject({
			tab: "preview",
			previewPath: "/w/README.md",
		});

		fireEvent.dblClick(screen.getByText("README.md"));
		expect(useWorkspace.getState()).toMatchObject({
			tab: "editor",
			editorPath: "/w/README.md",
		});
	});

	it("shows Material icons for files and directories", async () => {
		listFilesMock.mockResolvedValue({ path: "/w", entries: rootEntries });
		const { container } = render(<FileTree />);
		await waitFor(() => expect(screen.getByText("README.md")).toBeDefined());

		const icons = Array.from(
			container.querySelectorAll("img.filetree-icon"),
		).map((img) => img.getAttribute("src"));
		expect(icons).toHaveLength(2);
		for (const src of icons) {
			expect(src).toMatch(/^\/material-icons\/.+\.svg$/);
		}
	});

	it("highlights the file open in the preview", async () => {
		listFilesMock.mockResolvedValue({ path: "/w", entries: rootEntries });
		const { container } = render(<FileTree />);
		await waitFor(() => expect(screen.getByText("README.md")).toBeDefined());

		expect(container.querySelector(".filetree-active")).toBeNull();
		fireEvent.click(screen.getByText("README.md"));
		await waitFor(() =>
			expect(container.querySelector(".filetree-active")).not.toBeNull(),
		);
	});

	it("surfaces API errors", async () => {
		listFilesMock.mockRejectedValue(new Error("permission denied"));
		render(<FileTree />);
		await waitFor(() =>
			expect(screen.getByText("permission denied")).toBeDefined(),
		);
	});
});