insta-toc
Version:
Simultaneously generate, update, and maintain a table of contents for your notes in real time.
110 lines (90 loc) • 3.86 kB
text/typescript
import { describe, expect, test } from "vitest";
import { TocModel } from "../src/tocModel";
import type { FileKey, FoldKey, TocBlockModel } from "../src/types";
import { createTocModelPluginMock } from "./mocks/pluginClassMocks";
type CreateModelOptions = {
sourceFilePath?: FileKey;
initialFoldState?: Partial<Record<FoldKey, boolean>>;
settingsOverrides?: {
tocTitle?: string;
tocTitleLevel?: 1 | 2 | 3 | 4 | 5 | 6;
tocTitleCentered?: boolean;
excludedChars?: string[];
};
};
function createModel(
source: string,
{ sourceFilePath = "notes/my-note.md", initialFoldState = {}, settingsOverrides = {} }: CreateModelOptions = {}
): { model: TocBlockModel; pruneSpy: ReturnType<typeof createTocModelPluginMock>["pruneSpy"]; } {
const { app, pruneSpy, settings, uiStateManager } = createTocModelPluginMock(settingsOverrides, {
tocFoldState: initialFoldState
});
const model = new TocModel(
uiStateManager,
app,
settings,
{ localSettings: source, sourceFilePath },
(key) => uiStateManager.getTocFoldState(key)
)
.model;
return { model, pruneSpy };
}
describe("TocModel fold state", () => {
test("assigns foldKey and initialCollapsed=false when no persisted state exists", () => {
// Arrange
const source = `- Heading 1\n - Heading 2`;
// Act
const { model, pruneSpy } = createModel(source);
const [ parent ] = model.items;
const [ child ] = parent.children;
// Assert
expect(parent.foldKey).toBe("notes/my-note.md::1");
expect(parent.initialCollapsed).toBe(false);
expect(child.foldKey).toBeNull();
expect(pruneSpy).toHaveBeenCalledTimes(1);
expect(pruneSpy).toHaveBeenCalledWith(
"notes/my-note.md",
expect.objectContaining({ activeModernFoldKeys: expect.any(Set) })
);
expect([ ...(pruneSpy.mock.calls[0]?.[1].activeModernFoldKeys ?? []) ]).toEqual([ "notes/my-note.md::1" ]);
});
test("restores collapsed state from persisted modern fold key", () => {
// Arrange
const source = `- Heading 1\n - Heading 2`;
// Act
const { model } = createModel(source, { initialFoldState: { "notes/my-note.md::1": true } });
// Assert
expect(model.items[0].initialCollapsed).toBe(true);
});
test("does not leak fold state across different file paths", () => {
// Arrange
const source = `- Heading 1\n - Heading 2`;
// Act
const { model } = createModel(source, {
sourceFilePath: "notes/file-b.md",
initialFoldState: { "notes/file-a.md::1": true }
});
// Assert
expect(model.items[0].initialCollapsed).toBe(false);
});
test("tracks foldParentIndex across nested items", () => {
// Arrange
const source = `- Heading 1\n - Heading 2\n - Heading 3`;
// Act
const { model, pruneSpy } = createModel(source, { sourceFilePath: "note.md" });
const [ parent ] = model.items;
const [ child ] = parent.children;
// Assert
expect(parent.foldKey).toBe("note.md::1");
expect(child.foldKey).toBe("note.md::2");
expect([ ...(pruneSpy.mock.calls[0]?.[1].activeModernFoldKeys ?? []) ]).toEqual([ "note.md::1", "note.md::2" ]);
});
test("resolves the rendered title from local settings while building the model", () => {
// Arrange
const source = `---\ntitle:\n name: Local TOC\n level: 2\n center: true\n---\n\n- Heading 1`;
// Act
const { model } = createModel(source);
// Assert
expect(model.title).toEqual({ text: "Local TOC", level: 2, centered: true, usesGlobalCentering: false });
});
});