|
@@ -0,0 +1,160 @@
|
|
|
|
|
+import { mount } from "@vue/test-utils"
|
|
|
|
|
+import { describe, expect, it, vi } from "vitest"
|
|
|
|
|
+import EditorToolbar from "@/components/EditorToolbar.vue"
|
|
|
|
|
+
|
|
|
|
|
+function createMockHandlers() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ isActive: vi.fn(() => false),
|
|
|
|
|
+ getActiveHeading: vi.fn(() => null),
|
|
|
|
|
+ getActiveTask: vi.fn(() => null),
|
|
|
|
|
+ setHeading: vi.fn(),
|
|
|
|
|
+ toggleBold: vi.fn(),
|
|
|
|
|
+ toggleItalic: vi.fn(),
|
|
|
|
|
+ toggleCode: vi.fn(),
|
|
|
|
|
+ toggleStrikethrough: vi.fn(),
|
|
|
|
|
+ toggleHighlight: vi.fn(),
|
|
|
|
|
+ toggleTask: vi.fn(),
|
|
|
|
|
+ insertLink: vi.fn(),
|
|
|
|
|
+ insertInlineMath: vi.fn(),
|
|
|
|
|
+ insertBlockMath: vi.fn(),
|
|
|
|
|
+ insertPageRef: vi.fn(),
|
|
|
|
|
+ insertBlockRef: vi.fn(),
|
|
|
|
|
+ insertTag: vi.fn(),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function createWrapper(handlers: unknown = null) {
|
|
|
|
|
+ return mount(EditorToolbar, {
|
|
|
|
|
+ props: {
|
|
|
|
|
+ handlers: handlers as any,
|
|
|
|
|
+ },
|
|
|
|
|
+ global: {
|
|
|
|
|
+ stubs: {
|
|
|
|
|
+ UButton: { template: '<button><slot /></button>' },
|
|
|
|
|
+ UDropdownMenu: { template: '<div><slot /></div>' },
|
|
|
|
|
+ UTooltip: { template: '<div><slot /></div>' },
|
|
|
|
|
+ USeparator: { template: '<div />' },
|
|
|
|
|
+ UModal: {
|
|
|
|
|
+ props: ["open"],
|
|
|
|
|
+ template: '<div v-if="open" class="modal-content"><slot name="content" /></div>',
|
|
|
|
|
+ },
|
|
|
|
|
+ UCard: { template: '<div><slot name="header" /><slot /><slot name="footer" /></div>' },
|
|
|
|
|
+ UInput: {
|
|
|
|
|
+ props: ["modelValue", "placeholder"],
|
|
|
|
|
+ template: '<input :placeholder="placeholder" :value="modelValue" @input="$emit(\'update:modelValue\', $event.target.value)" @keydown="$emit(\'keydown\', $event)" />',
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+describe("EditorToolbar", () => {
|
|
|
|
|
+ it("disables all buttons when handlers is null", () => {
|
|
|
|
|
+ const wrapper = createWrapper(null)
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ for (const btn of buttons) {
|
|
|
|
|
+ expect(btn.attributes("disabled")).toBeDefined()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it("enables buttons when handlers is provided", () => {
|
|
|
|
|
+ const wrapper = createWrapper(createMockHandlers())
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ // First button is the dropdown trigger (disabled via :disabled="!handlers")
|
|
|
|
|
+ // but the stub doesn't pass disabled; the inner buttons should work.
|
|
|
|
|
+ expect(buttons.length).toBeGreaterThan(0)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it("opens modal for page reference", async () => {
|
|
|
|
|
+ const handlers = createMockHandlers()
|
|
|
|
|
+ const wrapper = createWrapper(handlers)
|
|
|
|
|
+
|
|
|
|
|
+ // Find and click the page reference button
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ // Last group is references. Click the first reference button (page ref).
|
|
|
|
|
+ const refButtons = buttons.filter((b) =>
|
|
|
|
|
+ b.attributes("icon")?.includes("book-marked"),
|
|
|
|
|
+ )
|
|
|
|
|
+ if (refButtons.length > 0) {
|
|
|
|
|
+ await refButtons[0].trigger("click")
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Fallback: click the last 3 buttons which are ref buttons
|
|
|
|
|
+ const lastButtons = buttons.slice(-3)
|
|
|
|
|
+ await lastButtons[0].trigger("click")
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Wait for nextTick (openPrompt uses it)
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+
|
|
|
|
|
+ // Modal should now be visible
|
|
|
|
|
+ expect(wrapper.find(".modal-content").exists()).toBe(true)
|
|
|
|
|
+ expect(wrapper.find("h3").text()).toBe("Insert Page Reference")
|
|
|
|
|
+ expect(wrapper.find("input").attributes("placeholder")).toBe(
|
|
|
|
|
+ "Enter page name...",
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it("confirming page ref calls insertPageRef", async () => {
|
|
|
|
|
+ const handlers = createMockHandlers()
|
|
|
|
|
+ const wrapper = createWrapper(handlers)
|
|
|
|
|
+
|
|
|
|
|
+ // Open the page ref prompt
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ const lastButtons = buttons.slice(-3)
|
|
|
|
|
+ await lastButtons[0].trigger("click")
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+
|
|
|
|
|
+ // Type a value and press Enter
|
|
|
|
|
+ const input = wrapper.find("input")
|
|
|
|
|
+ await input.setValue("My Page")
|
|
|
|
|
+ await input.trigger("keydown", { key: "Enter" })
|
|
|
|
|
+
|
|
|
|
|
+ expect(handlers.insertPageRef).toHaveBeenCalledWith("My Page")
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it("pressing Escape closes the modal", async () => {
|
|
|
|
|
+ const handlers = createMockHandlers()
|
|
|
|
|
+ const wrapper = createWrapper(handlers)
|
|
|
|
|
+
|
|
|
|
|
+ // Open the page ref prompt
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ const lastButtons = buttons.slice(-3)
|
|
|
|
|
+ await lastButtons[0].trigger("click")
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+
|
|
|
|
|
+ expect(wrapper.find(".modal-content").exists()).toBe(true)
|
|
|
|
|
+
|
|
|
|
|
+ // Press Escape
|
|
|
|
|
+ const input = wrapper.find("input")
|
|
|
|
|
+ await input.trigger("keydown", { key: "Escape" })
|
|
|
|
|
+
|
|
|
|
|
+ expect(wrapper.find(".modal-content").exists()).toBe(false)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ it("shows correct labels for block ref and tag modals", async () => {
|
|
|
|
|
+ const handlers = createMockHandlers()
|
|
|
|
|
+ const wrapper = createWrapper(handlers)
|
|
|
|
|
+ const buttons = wrapper.findAll("button")
|
|
|
|
|
+ const lastButtons = buttons.slice(-3)
|
|
|
|
|
+
|
|
|
|
|
+ // Block ref
|
|
|
|
|
+ await lastButtons[1].trigger("click")
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+ expect(wrapper.find("h3").text()).toBe("Insert Block Reference")
|
|
|
|
|
+ expect(wrapper.find("input").attributes("placeholder")).toBe(
|
|
|
|
|
+ "Enter block ID...",
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ // Close
|
|
|
|
|
+ await wrapper.find("input").trigger("keydown", { key: "Escape" })
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+
|
|
|
|
|
+ // Tag
|
|
|
|
|
+ await lastButtons[2].trigger("click")
|
|
|
|
|
+ await new Promise((r) => setTimeout(r, 10))
|
|
|
|
|
+ expect(wrapper.find("h3").text()).toBe("Insert Tag")
|
|
|
|
|
+ expect(wrapper.find("input").attributes("placeholder")).toBe(
|
|
|
|
|
+ "Enter tag name...",
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+})
|