Files
homarr/packages/widgets/src/notebook/read-only-task-item.spec.ts
T

97 lines
3.4 KiB
TypeScript

import { Editor } from "@tiptap/core";
import { TaskList } from "@tiptap/extension-task-list";
import { Schema } from "@tiptap/pm/model";
import { EditorState } from "@tiptap/pm/state";
import { StarterKit } from "@tiptap/starter-kit";
import { describe, expect, it } from "vitest";
import { createReadOnlyTaskItemTransaction, ReadOnlyTaskItem } from "./read-only-task-item";
const schema = new Schema({
nodes: {
doc: { content: "taskList" },
paragraph: { content: "text*" },
text: { inline: true },
taskList: { content: "taskItem+" },
taskItem: {
attrs: { checked: { default: false } },
content: "paragraph",
},
},
});
const createTaskItem = () =>
schema.node("taskItem", { checked: false }, [schema.node("paragraph", null, [schema.text("Duplicate task")])]);
describe("read-only task item updates", () => {
it("reports the exact position of the clicked duplicate task", () => {
const element = document.createElement("div");
let clickedPosition: number | undefined;
const editor = new Editor({
element,
editable: false,
extensions: [
StarterKit,
TaskList.configure({ itemTypeName: "taskItem" }),
ReadOnlyTaskItem.configure({
nested: true,
onReadOnlyChecked: () => true,
onReadOnlyCheckedAtPosition: (position) => {
clickedPosition = position;
},
}),
],
content: {
type: "doc",
content: [
{
type: "taskList",
content: [
{ type: "taskItem", attrs: { checked: false }, content: [{ type: "paragraph", content: [] }] },
{ type: "taskItem", attrs: { checked: false }, content: [{ type: "paragraph", content: [] }] },
],
},
],
},
});
try {
const positions: number[] = [];
editor.state.doc.descendants((node, position) => {
if (node.type.name === "taskItem") positions.push(position);
});
const secondPosition = positions[1];
const secondCheckbox = element.querySelectorAll<HTMLInputElement>('input[type="checkbox"]').item(1);
if (secondPosition === undefined || !secondCheckbox) throw new Error("Expected a second task item checkbox");
secondCheckbox.checked = true;
secondCheckbox.dispatchEvent(new Event("change", { bubbles: true }));
expect(clickedPosition).toBe(secondPosition);
} finally {
editor.destroy();
}
});
it("updates the selected position when task items are structurally identical", () => {
const doc = schema.node("doc", null, [schema.node("taskList", null, [createTaskItem(), createTaskItem()])]);
const taskItemPositions: number[] = [];
doc.descendants((node, position) => {
if (node.type.name === "taskItem") taskItemPositions.push(position);
});
const secondTaskItemPosition = taskItemPositions[1];
if (secondTaskItemPosition === undefined) throw new Error("Expected a second task item");
const state = EditorState.create({ doc });
const transaction = createReadOnlyTaskItemTransaction(state, secondTaskItemPosition, true);
if (!transaction) throw new Error("Expected a task-item transaction");
const nextState = state.apply(transaction);
const checkedStates: boolean[] = [];
nextState.doc.descendants((node) => {
if (node.type.name === "taskItem") checkedStates.push(Boolean(node.attrs.checked));
});
expect(checkedStates).toEqual([false, true]);
});
});