Spaces:
Sleeping
Sleeping
File size: 7,713 Bytes
e5167b8 86725f7 e5167b8 86725f7 e5167b8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | // Unit tests for the structure YAML grammar and the pure text mutations
// behind sidebar drag-and-drop and groups. No server needed.
import assert from 'node:assert'
import { parseStructure, moveNodeInYaml, moveNodesInYaml, addGroupToYaml, renameGroupInYaml, dissolveGroupInYaml, validGroupLabel } from '../server/pages.js'
const YAML = [
'- home',
'- "Getting started":',
' - intro',
' - setup',
'- design',
' - communication',
'- references',
].join('\n')
// --- parsing ---
{
const { tree, problems } = parseStructure(YAML)
assert.deepStrictEqual(problems, [])
assert.strictEqual(tree.length, 4)
assert.strictEqual(tree[0].slug, 'home')
assert.strictEqual(tree[1].group, 'Getting started')
assert.deepStrictEqual(tree[1].children.map(c => c.slug), ['intro', 'setup'])
assert.strictEqual(tree[2].children[0].slug, 'communication')
}
{
// problem lines are reported, groups can nest, comments are skipped
const { tree, problems } = parseStructure('# comment\n- "A":\n - "B":\n - x\n- ???')
assert.strictEqual(problems.length, 1)
assert.strictEqual(tree[0].group, 'A')
assert.strictEqual(tree[0].children[0].group, 'B')
assert.strictEqual(tree[0].children[0].children[0].slug, 'x')
}
// --- move: reorder at root ---
{
const { raw } = moveNodeInYaml(YAML, 'references', null, 0)
assert.strictEqual(raw.split('\n')[0], '- references')
assert.strictEqual(parseStructure(raw).tree[0].slug, 'references')
}
// --- move: nest a page (subtree travels, reindents) ---
{
const { raw } = moveNodeInYaml(YAML, 'design', ['"Getting started"'], 0)
const t = parseStructure(raw).tree
const g = t.find(n => n.group === 'Getting started')
assert.deepStrictEqual(g.children.map(c => c.slug), ['design', 'intro', 'setup'])
assert.strictEqual(g.children[0].children[0].slug, 'communication')
assert.ok(raw.includes(' - communication'))
}
// --- move: out of a group to root, append ---
{
const { raw } = moveNodeInYaml(YAML, 'intro', null, 99)
const t = parseStructure(raw).tree
assert.strictEqual(t[t.length - 1].slug, 'intro')
const g = t.find(n => n.group === 'Getting started')
assert.deepStrictEqual(g.children.map(c => c.slug), ['setup'])
}
// --- move: index counts after removal (down within same parent) ---
{
const { raw } = moveNodeInYaml(YAML, 'home', null, 2)
assert.deepStrictEqual(
parseStructure(raw).tree.map(n => n.slug || n.group),
['Getting started', 'design', 'home', 'references']
)
}
// --- move: under a page (pages nest pages) ---
{
const { raw } = moveNodeInYaml(YAML, 'references', 'design', 99)
const d = parseStructure(raw).tree.find(n => n.slug === 'design')
assert.deepStrictEqual(d.children.map(c => c.slug), ['communication', 'references'])
}
// --- move: unfiled page gets a line ---
{
const { raw } = moveNodeInYaml(YAML, 'notes', ['"Getting started"'], 1)
const g = parseStructure(raw).tree.find(n => n.group === 'Getting started')
assert.deepStrictEqual(g.children.map(c => c.slug), ['intro', 'notes', 'setup'])
}
// --- move: comments inside a block travel with it ---
{
const withComment = YAML.replace(' - communication', ' # keep\n - communication')
const { raw } = moveNodeInYaml(withComment, 'design', null, 0)
const lines = raw.split('\n')
assert.ok(lines.indexOf(' # keep') === lines.indexOf('- design') + 1)
}
// --- move: rejections ---
assert.ok(moveNodeInYaml(YAML, 'design', 'communication', 0).error, 'nest into own subtree')
assert.ok(moveNodeInYaml(YAML, '_structure', null, 0).error, 'move _structure')
assert.ok(moveNodeInYaml(YAML, 'home', ['"Nope"'], 0).error, 'unknown parent')
assert.ok(moveNodeInYaml(YAML, ['"Nope"'], null, 0).error, 'unknown group node')
assert.ok(moveNodeInYaml(YAML, 'bad slug!', null, 0).error, 'bad slug')
// --- groups: add / rename / dissolve ---
{
const { raw } = addGroupToYaml(YAML, 'References & links', null, 1)
const t = parseStructure(raw).tree
assert.strictEqual(t[1].group, 'References & links')
assert.ok(addGroupToYaml(raw, 'References & links', null, 0).error, 'duplicate sibling label')
}
{
const { raw } = addGroupToYaml(YAML, 'Sub', ['"Getting started"'], 99)
const g = parseStructure(raw).tree.find(n => n.group === 'Getting started')
assert.strictEqual(g.children[2].group, 'Sub')
}
{
const { raw } = renameGroupInYaml(YAML, ['"Getting started"'], 'Start here')
const t = parseStructure(raw).tree
assert.strictEqual(t[1].group, 'Start here')
assert.deepStrictEqual(t[1].children.map(c => c.slug), ['intro', 'setup'])
assert.ok(renameGroupInYaml(YAML, ['"Getting started"'], 'x'.repeat(61)).error, 'label too long')
assert.ok(renameGroupInYaml(YAML, ['"Nope"'], 'ok').error, 'unknown group')
}
{
const { raw } = dissolveGroupInYaml(YAML, ['"Getting started"'])
const t = parseStructure(raw).tree
assert.deepStrictEqual(t.map(n => n.slug), ['home', 'intro', 'setup', 'design', 'references'])
assert.ok(dissolveGroupInYaml(YAML, ['home']).error, 'dissolve a page')
}
// --- multi-node move (sidebar multi-select) ---
{
// two pages from different parents land as consecutive siblings, doc order
const { raw } = moveNodesInYaml(YAML, ['setup', 'references'], 'design', 0)
const d = parseStructure(raw).tree.find(n => n.slug === 'design')
assert.deepStrictEqual(d.children.map(c => c.slug), ['setup', 'references', 'communication'])
}
{
// a group and its own child selected together: the child travels once
const { raw } = moveNodesInYaml(YAML, [['"Getting started"'], 'intro'], 'design', 99)
const t = parseStructure(raw).tree
assert.deepStrictEqual(t.map(n => n.slug || n.group), ['home', 'design', 'references'])
const d = t.find(n => n.slug === 'design')
const g = d.children.find(n => n.group === 'Getting started')
assert.deepStrictEqual(g.children.map(c => c.slug), ['intro', 'setup'])
assert.strictEqual(d.children.filter(n => n.slug === 'intro').length, 0, 'intro not duplicated')
}
{
// index counts after ALL moved nodes leave: home+intro to root index 2
const { raw } = moveNodesInYaml(YAML, ['home', 'intro'], null, 2)
assert.deepStrictEqual(
parseStructure(raw).tree.map(n => n.slug || n.group),
['Getting started', 'design', 'home', 'intro', 'references']
)
}
{
// mixed tree + unfiled refs; duplicates collapse
const { raw } = moveNodesInYaml(YAML, ['setup', 'notes', 'setup'], null, 0)
const t = parseStructure(raw).tree
assert.deepStrictEqual(t.slice(0, 2).map(n => n.slug), ['setup', 'notes'])
assert.strictEqual(JSON.stringify(t).split('"setup"').length, 2, 'setup appears once')
}
assert.ok(moveNodesInYaml(YAML, [], null, 0).error, 'empty selection')
assert.ok(moveNodesInYaml(YAML, ['home', 'design'], 'communication', 0).error, 'parent inside a moved subtree')
// --- labels ---
assert.strictEqual(validGroupLabel(' Reading list '), 'Reading list')
assert.strictEqual(validGroupLabel('a"b'), null)
assert.strictEqual(validGroupLabel(''), null)
// --- a round of moves keeps the yaml parseable with zero problems ---
{
let raw = YAML
for (const [node, parent, index] of [
['setup', null, 0],
['design', ['"Getting started"'], 0],
['setup', 'design', 99],
['home', 'setup', 0],
]) {
const r = moveNodeInYaml(raw, node, parent, index)
assert.ok(!r.error, `${node}: ${r.error}`)
raw = r.raw
assert.deepStrictEqual(parseStructure(raw).problems, [])
}
const g = parseStructure(raw).tree.find(n => n.group === 'Getting started')
assert.strictEqual(g.children[0].slug, 'design')
assert.strictEqual(g.children[0].children[1].slug, 'setup')
assert.strictEqual(g.children[0].children[1].children[0].slug, 'home')
}
console.log('structure tests passed')
|