import { api } from "$lib/api";
import type { Note } from "$lib/model";
import { cleanup, render, screen, waitFor } from "@solidjs/testing-library";
import { JSX } from "solid-js";
import { afterEach, describe, expect, it, vi } from "vitest";
import NoteView from "../NoteView";
vi.mock("$lib/api", () => ({ api: { getNote: vi.fn(), getNotes: vi.fn() } }));
vi.mock(
"@solidjs/router",
() => ({
useParams: () => ({ id: "note-1" }),
A: (props: { href: string; children: JSX.Element }) => {props.children},
}),
);
const mockNote: Note = {
id: "note-1",
owner_did: "did:plc:test123",
title: "Test Note Title",
body: "# Heading\n\nSome **markdown** content with [[Other Note]].",
tags: ["rust", "learning"],
visibility: { type: "Public" },
created_at: "2026-01-01T10:00:00Z",
updated_at: "2026-01-01T12:00:00Z",
};
const mockAllNotes: Note[] = [mockNote, {
id: "note-2",
owner_did: "did:plc:test123",
title: "Other Note",
body: "Links back to [[Test Note Title]]",
tags: [],
visibility: { type: "Private" },
created_at: "2026-01-01T10:00:00Z",
updated_at: "2026-01-01T12:00:00Z",
}];
describe("NoteView", () => {
afterEach(() => {
cleanup();
vi.clearAllMocks();
});
it("renders note title in heading", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getByRole("heading", { level: 1, name: "Test Note Title" })).toBeInTheDocument();
});
});
it("renders tags", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getAllByText("rust").length).toBeGreaterThan(0);
expect(screen.getAllByText("learning").length).toBeGreaterThan(0);
});
});
it("has back to notes link", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getByRole("link", { name: "Notes" })).toBeInTheDocument();
});
});
it("renders not found state when note returns error", async () => {
vi.mocked(api.getNote).mockResolvedValue({ ok: false } as unknown as Response);
vi.mocked(api.getNotes).mockResolvedValue({ ok: true, json: () => Promise.resolve([]) } as unknown as Response);
render(() => );
await waitFor(() => {
expect(screen.getByText("Note not found")).toBeInTheDocument();
});
});
it("renders outline panel heading", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getByText("Outline")).toBeInTheDocument();
});
});
it("renders wikilinks panel heading", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getByText("Wikilinks")).toBeInTheDocument();
});
});
it("renders backlinks panel heading", async () => {
vi.mocked(api.getNote).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockNote) } as unknown as Response,
);
vi.mocked(api.getNotes).mockResolvedValue(
{ ok: true, json: () => Promise.resolve(mockAllNotes) } as unknown as Response,
);
render(() => );
await waitFor(() => {
expect(screen.getByText("Backlinks")).toBeInTheDocument();
});
});
});