|
|
@@ -0,0 +1,145 @@
|
|
|
+import { EditorState } from "prosemirror-state"
|
|
|
+import { EditorView } from "prosemirror-view"
|
|
|
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
|
|
+import { MathBlockView } from "@/composables/useMathBlockView"
|
|
|
+import { schema } from "@/lib/schema"
|
|
|
+
|
|
|
+let views: EditorView[] = []
|
|
|
+
|
|
|
+beforeEach(() => {
|
|
|
+ views = []
|
|
|
+})
|
|
|
+
|
|
|
+afterEach(() => {
|
|
|
+ for (const v of views) {
|
|
|
+ v.destroy()
|
|
|
+ }
|
|
|
+ views = []
|
|
|
+})
|
|
|
+
|
|
|
+function makeDocWithMathBlock(content: string) {
|
|
|
+ const textNode = content ? schema.text(content) : undefined
|
|
|
+ const block = textNode
|
|
|
+ ? schema.nodes.math_block.create(null, [textNode])
|
|
|
+ : schema.nodes.math_block.create()
|
|
|
+ return schema.node("doc", {}, [block])
|
|
|
+}
|
|
|
+
|
|
|
+function createView(content: string) {
|
|
|
+ const doc = makeDocWithMathBlock(content)
|
|
|
+ const state = EditorState.create({ doc, schema })
|
|
|
+ const dom = document.createElement("div")
|
|
|
+ const view = new EditorView(dom, { state })
|
|
|
+ views.push(view)
|
|
|
+ return view
|
|
|
+}
|
|
|
+
|
|
|
+describe("MathBlockView", () => {
|
|
|
+ it("creates DOM structure with correct classes", () => {
|
|
|
+ const node = schema.nodes.math_block.create(null, [schema.text("$$\nE = mc^2\n$$")])
|
|
|
+ const view = createView("$$\nE = mc^2\n$$")
|
|
|
+
|
|
|
+ const nodeView = new MathBlockView(node, view, () => 0)
|
|
|
+
|
|
|
+ expect(nodeView.dom.className).toBe("math-block")
|
|
|
+ expect(nodeView.dom.children).toHaveLength(2)
|
|
|
+
|
|
|
+ const preview = nodeView.dom.children[0] as HTMLElement
|
|
|
+ const source = nodeView.dom.children[1] as HTMLElement
|
|
|
+ expect(preview.className).toBe("math-block-preview")
|
|
|
+ expect(source.className).toBe("math-block-source")
|
|
|
+ expect(nodeView.contentDOM).toBe(source)
|
|
|
+ })
|
|
|
+
|
|
|
+ it("returns false from update for non-math_block nodes", () => {
|
|
|
+ const textNode = schema.text("$$")
|
|
|
+ const mathNode = schema.nodes.math_block.create(null, [textNode])
|
|
|
+ const view = createView("$$")
|
|
|
+
|
|
|
+ const nodeView = new MathBlockView(mathNode, view, () => 0)
|
|
|
+
|
|
|
+ const paraNode = schema.nodes.paragraph.create(null, [schema.text("hello")])
|
|
|
+ expect(nodeView.update(paraNode)).toBe(false)
|
|
|
+ })
|
|
|
+
|
|
|
+ it("returns true from update for math_block nodes", () => {
|
|
|
+ const textNode = schema.text("$$\nE = mc^2\n$$")
|
|
|
+ const mathNode = schema.nodes.math_block.create(null, [textNode])
|
|
|
+ const view = createView("$$\nE = mc^2\n$$")
|
|
|
+
|
|
|
+ const nodeView = new MathBlockView(mathNode, view, () => 0)
|
|
|
+
|
|
|
+ const updatedNode = schema.nodes.math_block.create(null, [schema.text("$$\nx^2\n$$")])
|
|
|
+ expect(nodeView.update(updatedNode)).toBe(true)
|
|
|
+ })
|
|
|
+
|
|
|
+ it("stopEvent returns true", () => {
|
|
|
+ const textNode = schema.text("$$")
|
|
|
+ const mathNode = schema.nodes.math_block.create(null, [textNode])
|
|
|
+ const view = createView("$$")
|
|
|
+
|
|
|
+ const nodeView = new MathBlockView(mathNode, view, () => 0)
|
|
|
+
|
|
|
+ expect(nodeView.stopEvent()).toBe(true)
|
|
|
+ })
|
|
|
+})
|
|
|
+
|
|
|
+describe("CodeBlockView", () => {
|
|
|
+ it("creates DOM with cm-code-block class", async () => {
|
|
|
+ const { CodeBlockView } = await import("@/composables/useCodeBlockView")
|
|
|
+
|
|
|
+ const textNode = schema.text("```js\nconst x = 1\n```")
|
|
|
+ const node = schema.nodes.code_block.create({ language: "js" }, [textNode])
|
|
|
+ const doc = schema.node("doc", {}, [node])
|
|
|
+ const state = EditorState.create({ doc, schema })
|
|
|
+ const dom = document.createElement("div")
|
|
|
+ const view = new EditorView(dom, { state })
|
|
|
+ views.push(view)
|
|
|
+
|
|
|
+ const nodeView = new CodeBlockView(node, view, () => 0)
|
|
|
+
|
|
|
+ expect(nodeView.dom.className).toBe("cm-code-block")
|
|
|
+ expect(nodeView.dom.children.length).toBeGreaterThan(0)
|
|
|
+
|
|
|
+ // Clean up CM6 view
|
|
|
+ nodeView.destroy()
|
|
|
+ })
|
|
|
+
|
|
|
+ it("update returns false for non-code_block nodes", async () => {
|
|
|
+ const { CodeBlockView } = await import("@/composables/useCodeBlockView")
|
|
|
+
|
|
|
+ const textNode = schema.text("```\ncode\n```")
|
|
|
+ const node = schema.nodes.code_block.create({ language: "" }, [textNode])
|
|
|
+ const doc = schema.node("doc", {}, [node])
|
|
|
+ const state = EditorState.create({ doc, schema })
|
|
|
+ const dom = document.createElement("div")
|
|
|
+ const view = new EditorView(dom, { state })
|
|
|
+ views.push(view)
|
|
|
+
|
|
|
+ const nodeView = new CodeBlockView(node, view, () => 0)
|
|
|
+
|
|
|
+ const paraNode = schema.nodes.paragraph.create(null, [schema.text("hello")])
|
|
|
+ expect(nodeView.update(paraNode)).toBe(false)
|
|
|
+
|
|
|
+ nodeView.destroy()
|
|
|
+ })
|
|
|
+
|
|
|
+ it("update returns true for code_block nodes", async () => {
|
|
|
+ const { CodeBlockView } = await import("@/composables/useCodeBlockView")
|
|
|
+
|
|
|
+ const textNode = schema.text("```\ncode\n```")
|
|
|
+ const node = schema.nodes.code_block.create({ language: "" }, [textNode])
|
|
|
+ const doc = schema.node("doc", {}, [node])
|
|
|
+ const state = EditorState.create({ doc, schema })
|
|
|
+ const dom = document.createElement("div")
|
|
|
+ const view = new EditorView(dom, { state })
|
|
|
+ views.push(view)
|
|
|
+
|
|
|
+ const nodeView = new CodeBlockView(node, view, () => 0)
|
|
|
+
|
|
|
+ const updatedNode = schema.nodes.code_block.create({ language: "ts" }, [textNode])
|
|
|
+ expect(nodeView.update(updatedNode)).toBe(true)
|
|
|
+
|
|
|
+ nodeView.destroy()
|
|
|
+ })
|
|
|
+})
|