import test from 'brittle'
import { Wiki } from '../lib/wiki.js'
import { tmpdir } from 'os'
import { join } from 'path'
import { randomBytes } from 'crypto'
function tmpStorage () {
return join(tmpdir(), 'hyper-wiki-test-' + randomBytes(8).toString('hex'))
}
test('Wiki - create and read page', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
const meta = await wiki.create('hello-world', '# Hello World\n\nThis is a test page.', {
title: 'Hello World',
author: 'alice'
})
t.is(meta.title, 'Hello World')
t.is(meta.author, 'alice')
t.is(meta.version, 1)
t.ok(meta.created > 0)
const page = await wiki.read('hello-world')
t.ok(page)
t.is(page.slug, 'hello-world')
t.is(page.content, '# Hello World\n\nThis is a test page.')
t.is(page.title, 'Hello World')
t.is(page.version, 1)
await wiki.close()
})
test('Wiki - read nonexistent returns null', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
const page = await wiki.read('nonexistent')
t.is(page, null)
await wiki.close()
})
test('Wiki - update page increments version', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('test', 'Version 1', { title: 'Test Page' })
const meta = await wiki.update('test', 'Version 2')
t.is(meta.version, 2)
t.is(meta.title, 'Test Page') // title preserved
const page = await wiki.read('test')
t.is(page.content, 'Version 2')
t.is(page.version, 2)
await wiki.close()
})
test('Wiki - delete page', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('to-delete', 'content')
t.ok(await wiki.exists('to-delete'))
await wiki.remove('to-delete')
t.absent(await wiki.exists('to-delete'))
t.is(await wiki.read('to-delete'), null)
await wiki.close()
})
test('Wiki - list pages', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('page-a', 'Content A', { title: 'Page A' })
await wiki.create('page-b', 'Content B', { title: 'Page B' })
await wiki.create('page-c', 'Content C', { title: 'Page C' })
const pages = await wiki.list()
t.is(pages.length, 3)
// Check sorted by updated desc (page-c is most recent)
t.is(pages[0].slug, 'page-c')
t.is(pages[0].title, 'Page C')
await wiki.close()
})
test('Wiki - list empty returns empty array', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
const pages = await wiki.list()
t.alike(pages, [])
await wiki.close()
})
test('Wiki - exists', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
t.absent(await wiki.exists('nope'))
await wiki.create('yep', 'exists')
t.ok(await wiki.exists('yep'))
await wiki.close()
})
test('Wiki - search by content', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('hypercore-guide', '# Hypercore\n\nAppend-only log for P2P', { title: 'Hypercore Guide' })
await wiki.create('hyperbee-guide', '# Hyperbee\n\nDatabase on top of Hypercore', { title: 'Hyperbee Guide' })
await wiki.create('unrelated', '# Cooking\n\nHow to make pasta', { title: 'Cooking' })
const results = await wiki.search('hypercore')
t.ok(results.length >= 2, 'finds pages mentioning hypercore')
t.ok(results.some(r => r.slug === 'hypercore-guide'))
t.ok(results.some(r => r.slug === 'hyperbee-guide'))
await wiki.close()
})
test('Wiki - search by title', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('setup', 'Install instructions', { title: 'Setup Guide' })
await wiki.create('faq', 'Common questions', { title: 'FAQ' })
const results = await wiki.search('setup')
t.ok(results.length >= 1)
t.ok(results.some(r => r.slug === 'setup'))
await wiki.close()
})
test('Wiki - search no results', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('page1', 'some content')
const results = await wiki.search('nonexistent-term-xyz')
t.is(results.length, 0)
await wiki.close()
})
test('Wiki - multiple updates preserve created time', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
const v1 = await wiki.create('evolving', 'v1')
const created = v1.created
await new Promise(r => setTimeout(r, 10))
const v2 = await wiki.update('evolving', 'v2')
t.is(v2.created, created, 'created time unchanged')
t.ok(v2.updated >= created, 'updated time is newer')
t.is(v2.version, 2)
await wiki.close()
})
test('Wiki - unicode content', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('unicode', '# 日本語ページ\n\n🎉 こんにちは世界', {
title: '日本語テスト',
author: 'ユーザー'
})
const page = await wiki.read('unicode')
t.is(page.title, '日本語テスト')
t.ok(page.content.includes('🎉'))
t.ok(page.content.includes('こんにちは'))
await wiki.close()
})
test('Wiki - large content', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
const content = '# Big Page\n\n' + 'Lorem ipsum dolor sit amet. '.repeat(1000)
await wiki.create('big', content, { title: 'Big Page' })
const page = await wiki.read('big')
t.is(page.content, content)
await wiki.close()
})
test('Wiki - tags preserved across updates', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
await wiki.create('tagged', 'content', {
title: 'Tagged Page',
tags: ['p2p', 'hypercore']
})
await wiki.update('tagged', 'updated content')
const page = await wiki.read('tagged')
t.alike(page.tags, ['p2p', 'hypercore'], 'tags preserved')
await wiki.close()
})
test('Wiki - has discoveryKey', async (t) => {
const wiki = new Wiki(tmpStorage())
await wiki.ready()
t.ok(wiki.key, 'has key')
await wiki.close()
})