OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-note / test / shared-notebook.test.js

167 lines · javascript ref:
import test from 'brittle'
import fs from 'bare-fs'
import path from 'bare-path'
import os from 'bare-os'
import Corestore from 'corestore'
import * as Y from 'yjs'
import { SharedNotebook } from '../lib/multiwriter/shared-notebook.js'

function tmpDir () {
  const dir = path.join(os.tmpdir(), 'hn-snb-' + Date.now() + '-' + Math.random().toString(36).slice(2))
  fs.mkdirSync(dir, { recursive: true })
  return dir
}

function rmrf (dir) {
  try {
    for (const f of fs.readdirSync(dir)) {
      const fp = path.join(dir, f)
      const stat = fs.statSync(fp)
      if (stat.isDirectory()) rmrf(fp)
      else fs.unlinkSync(fp)
    }
    fs.rmdirSync(dir)
  } catch {}
}

test('create and get note', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'test-nb')
  await nb.ready()

  const { noteId } = await nb.createNote({ title: 'Hello World', author: 'alice', tags: ['greeting'] })
  t.ok(noteId, 'noteId is returned')
  t.is(noteId.length, 16, 'noteId is 16 hex chars')

  const note = await nb.getNote(noteId)
  t.ok(note, 'note exists')
  t.is(note.title, 'Hello World')
  t.is(note.author, 'alice')
  t.alike(note.tags, ['greeting'])
  t.ok(note.createdAt, 'has createdAt')

  await nb.close()
  await store.close()
  rmrf(dir)
})

test('apply Yjs update and reconstruct', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'yjs-nb')
  await nb.ready()

  const { noteId } = await nb.createNote({ title: 'Yjs Note', author: 'alice' })

  // Create a Y.Doc, insert text, encode update
  const doc = new Y.Doc()
  const text = doc.getText('content')
  text.insert(0, 'Hello collaborative world!')
  const update = Y.encodeStateAsUpdate(doc)

  await nb.applyYjsUpdate(noteId, update, 'alice')

  // Verify cached doc has the text
  const cachedDoc = nb.getDoc(noteId)
  t.ok(cachedDoc, 'cached doc exists')
  t.is(cachedDoc.getText('content').toString(), 'Hello collaborative world!')

  // Reconstruct from Autobase storage
  const reconstructed = await nb.reconstructDoc(noteId)
  t.ok(reconstructed, 'reconstructed doc exists')
  t.is(reconstructed.getText('content').toString(), 'Hello collaborative world!')

  await nb.close()
  await store.close()
  rmrf(dir)
})

test('list notes — create 2, verify 2', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'list-nb')
  await nb.ready()

  await nb.createNote({ title: 'Note A', author: 'alice' })
  await nb.createNote({ title: 'Note B', author: 'bob' })

  const notes = await nb.listNotes()
  t.is(notes.length, 2, 'two notes listed')
  const titles = notes.map(n => n.title).sort()
  t.alike(titles, ['Note A', 'Note B'])

  await nb.close()
  await store.close()
  rmrf(dir)
})

test('delete note', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'del-nb')
  await nb.ready()

  const { noteId } = await nb.createNote({ title: 'To Delete', author: 'alice' })
  let note = await nb.getNote(noteId)
  t.ok(note, 'note exists before delete')

  await nb.deleteNote(noteId, 'alice')
  note = await nb.getNote(noteId)
  t.is(note, null, 'note is null after delete')

  await nb.close()
  await store.close()
  rmrf(dir)
})

test('add media metadata', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'media-nb')
  await nb.ready()

  const { noteId } = await nb.createNote({ title: 'Media Note', author: 'alice' })

  await nb.addMedia(noteId, {
    hash: 'abc123def456',
    mimeType: 'image/png',
    filename: 'photo.png',
    size: 12345
  }, 'alice')

  const media = await nb.getMedia(noteId, 'abc123def456')
  t.ok(media, 'media exists')
  t.is(media.hash, 'abc123def456')
  t.is(media.mimeType, 'image/png')
  t.is(media.filename, 'photo.png')
  t.is(media.size, 12345)
  t.is(media.author, 'alice')
  t.ok(media.addedAt, 'has addedAt')

  // Remove media
  await nb.removeMedia(noteId, 'abc123def456', 'alice')
  const removed = await nb.getMedia(noteId, 'abc123def456')
  t.is(removed, null, 'media removed')

  await nb.close()
  await store.close()
  rmrf(dir)
})

test('bootstrapKey available after ready', async (t) => {
  const dir = tmpDir()
  const store = new Corestore(dir)
  const nb = new SharedNotebook(store, 'key-nb')
  await nb.ready()

  t.ok(nb.bootstrapKey, 'bootstrapKey exists')
  t.is(nb.bootstrapKey.length, 32, 'bootstrapKey is 32 bytes')
  t.ok(nb.localWriterKey, 'localWriterKey exists')
  t.is(nb.localWriterKey.length, 32, 'localWriterKey is 32 bytes')

  await nb.close()
  await store.close()
  rmrf(dir)
})