|
|
@@ -1,5 +1,5 @@
|
|
|
import { describe, expect, it, vi } from "vitest"
|
|
|
-import type { EditorBlock } from "@/lib/block-parser"
|
|
|
+import type { EditorBlockData } from "@/lib/block-parser"
|
|
|
import {
|
|
|
deleteIfEmpty,
|
|
|
indentBlock,
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
splitBlocks,
|
|
|
} from "@/lib/editor-operations"
|
|
|
|
|
|
-function block(overrides: Partial<EditorBlock> & { content: string }): EditorBlock {
|
|
|
+function block(overrides: Partial<EditorBlockData> & { content: string }): EditorBlockData {
|
|
|
return { id: "auto", depth: 0, ...overrides }
|
|
|
}
|
|
|
|
|
|
@@ -26,7 +26,7 @@ function stableId(prefix: string): () => string {
|
|
|
|
|
|
describe("splitBlocks", () => {
|
|
|
it("splits a block into two at the given index", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", depth: 0, content: "first" }),
|
|
|
block({ id: "b", depth: 1, content: "second" }),
|
|
|
]
|
|
|
@@ -47,20 +47,20 @@ describe("splitBlocks", () => {
|
|
|
})
|
|
|
|
|
|
it("preserves depth of the original block", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
const result = splitBlocks(blocks, 0, "a", "b", stableId("n"))
|
|
|
expect(result.blocks[0].depth).toBe(2)
|
|
|
expect(result.blocks[1].depth).toBe(2)
|
|
|
})
|
|
|
|
|
|
it("returns original array copy when index is out of bounds", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", content: "x" })]
|
|
|
expect(splitBlocks(blocks, -1, "", "", stableId("n")).newBlock).toBeNull()
|
|
|
expect(splitBlocks(blocks, 5, "", "", stableId("n")).newBlock).toBeNull()
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 1, content: "original" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 1, content: "original" })]
|
|
|
const copy = [...blocks]
|
|
|
splitBlocks(blocks, 0, "before", "after", stableId("n"))
|
|
|
expect(blocks).toEqual(copy)
|
|
|
@@ -71,7 +71,7 @@ describe("splitBlocks", () => {
|
|
|
|
|
|
describe("mergePrevious", () => {
|
|
|
it("merges two adjacent blocks, appending content", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "hello" }),
|
|
|
block({ id: "b", content: " world" }),
|
|
|
]
|
|
|
@@ -84,7 +84,7 @@ describe("mergePrevious", () => {
|
|
|
})
|
|
|
|
|
|
it("joinPos is 0 when previous block is empty", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "" }),
|
|
|
block({ id: "b", content: "content" }),
|
|
|
]
|
|
|
@@ -94,7 +94,7 @@ describe("mergePrevious", () => {
|
|
|
})
|
|
|
|
|
|
it("returns no change when index is 0 or out of bounds", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", content: "x" }), block({ id: "b", content: "y" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", content: "x" }), block({ id: "b", content: "y" })]
|
|
|
const atZero = mergePrevious(blocks, 0)
|
|
|
expect(atZero.blocks).toHaveLength(2)
|
|
|
|
|
|
@@ -103,7 +103,7 @@ describe("mergePrevious", () => {
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "hello" }),
|
|
|
block({ id: "b", content: " world" }),
|
|
|
]
|
|
|
@@ -117,7 +117,7 @@ describe("mergePrevious", () => {
|
|
|
|
|
|
describe("deleteIfEmpty", () => {
|
|
|
it("removes a block at the given index", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "first" }),
|
|
|
block({ id: "b", content: "second" }),
|
|
|
block({ id: "c", content: "third" }),
|
|
|
@@ -129,7 +129,7 @@ describe("deleteIfEmpty", () => {
|
|
|
})
|
|
|
|
|
|
it("focuses the next block when removing from the beginning", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "first" }),
|
|
|
block({ id: "b", content: "second" }),
|
|
|
]
|
|
|
@@ -138,7 +138,7 @@ describe("deleteIfEmpty", () => {
|
|
|
})
|
|
|
|
|
|
it("focuses the previous block when removing the last block", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "first" }),
|
|
|
block({ id: "b", content: "second" }),
|
|
|
]
|
|
|
@@ -147,14 +147,14 @@ describe("deleteIfEmpty", () => {
|
|
|
})
|
|
|
|
|
|
it("does nothing when only one block exists", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", content: "only" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", content: "only" })]
|
|
|
const result = deleteIfEmpty(blocks, 0)
|
|
|
expect(result.blocks).toHaveLength(1)
|
|
|
expect(result.nextId).toBeNull()
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "x" }),
|
|
|
block({ id: "b", content: "y" }),
|
|
|
]
|
|
|
@@ -168,13 +168,13 @@ describe("deleteIfEmpty", () => {
|
|
|
|
|
|
describe("indentBlock", () => {
|
|
|
it("increments depth of the block", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
const result = indentBlock(blocks, 0)
|
|
|
expect(result.blocks[0].depth).toBe(1)
|
|
|
})
|
|
|
|
|
|
it("also indents child blocks", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "p", depth: 0, content: "parent" }),
|
|
|
block({ id: "c", depth: 1, content: "child" }),
|
|
|
block({ id: "g", depth: 2, content: "grandchild" }),
|
|
|
@@ -190,14 +190,14 @@ describe("indentBlock", () => {
|
|
|
})
|
|
|
|
|
|
it("caps depth at 10", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 10, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 10, content: "x" })]
|
|
|
const result = indentBlock(blocks, 0)
|
|
|
expect(result.blocks[0].depth).toBe(10)
|
|
|
expect(result.childIndices).toEqual([])
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
const copy = [...blocks]
|
|
|
indentBlock(blocks, 0)
|
|
|
expect(blocks).toEqual(copy)
|
|
|
@@ -208,13 +208,13 @@ describe("indentBlock", () => {
|
|
|
|
|
|
describe("outdentBlock", () => {
|
|
|
it("decrements depth of the block", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
const result = outdentBlock(blocks, 0)
|
|
|
expect(result.blocks[0].depth).toBe(1)
|
|
|
})
|
|
|
|
|
|
it("also outdents child blocks", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "p", depth: 2, content: "parent" }),
|
|
|
block({ id: "c", depth: 3, content: "child" }),
|
|
|
block({ id: "g", depth: 4, content: "grandchild" }),
|
|
|
@@ -229,14 +229,14 @@ describe("outdentBlock", () => {
|
|
|
})
|
|
|
|
|
|
it("floors depth at 0", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 0, content: "x" })]
|
|
|
const result = outdentBlock(blocks, 0)
|
|
|
expect(result.blocks[0].depth).toBe(0)
|
|
|
expect(result.childIndices).toEqual([])
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", depth: 2, content: "x" })]
|
|
|
const copy = [...blocks]
|
|
|
outdentBlock(blocks, 0)
|
|
|
expect(blocks).toEqual(copy)
|
|
|
@@ -247,7 +247,7 @@ describe("outdentBlock", () => {
|
|
|
|
|
|
describe("insertBlock", () => {
|
|
|
it("inserts a block at the given index", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "first" }),
|
|
|
block({ id: "b", content: "last" }),
|
|
|
]
|
|
|
@@ -262,14 +262,14 @@ describe("insertBlock", () => {
|
|
|
})
|
|
|
|
|
|
it("inserts at the beginning", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "b", content: "second" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "b", content: "second" })]
|
|
|
const result = insertBlock(blocks, 0, "first", 0, stableId("n"))
|
|
|
expect(result.blocks).toHaveLength(2)
|
|
|
expect(result.blocks[0].content).toBe("first")
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", content: "x" })]
|
|
|
const copy = [...blocks]
|
|
|
insertBlock(blocks, 0, "y", 0, stableId("n"))
|
|
|
expect(blocks).toEqual(copy)
|
|
|
@@ -280,7 +280,7 @@ describe("insertBlock", () => {
|
|
|
|
|
|
describe("setBlockContent", () => {
|
|
|
it("updates content of the matching block", () => {
|
|
|
- const blocks: EditorBlock[] = [
|
|
|
+ const blocks: EditorBlockData[] = [
|
|
|
block({ id: "a", content: "old" }),
|
|
|
block({ id: "b", content: "keep" }),
|
|
|
]
|
|
|
@@ -290,7 +290,7 @@ describe("setBlockContent", () => {
|
|
|
})
|
|
|
|
|
|
it("does not mutate the original array", () => {
|
|
|
- const blocks: EditorBlock[] = [block({ id: "a", content: "x" })]
|
|
|
+ const blocks: EditorBlockData[] = [block({ id: "a", content: "x" })]
|
|
|
setBlockContent(blocks, "a", "y")
|
|
|
expect(blocks[0].content).toBe("x")
|
|
|
})
|