| 1 |
import { expect, test } from "bun:test"; |
| 2 |
import { mkdtempSync } from "node:fs"; |
| 3 |
import { tmpdir } from "node:os"; |
| 4 |
import { join } from "node:path"; |
| 5 |
import { addNote, deleteNote, listNotes } from "./actions.ts"; |
| 6 |
import { openDb } from "./db.ts"; |
| 7 |
import type { Who } from "./who.ts"; |
| 8 |
|
| 9 |
const db = openDb(mkdtempSync(join(tmpdir(), "app-actions-"))); |
| 10 |
const anon: Who = { role: "anon" }; |
| 11 |
const alice: Who = { role: "user", id: "u1", name: "alice" }; |
| 12 |
const bob: Who = { role: "user", id: "u2", name: "bob" }; |
| 13 |
const root: Who = { role: "admin", id: "u0", name: "root" }; |
| 14 |
|
| 15 |
test("anyone reads; only a signed-in person adds, as themselves", () => { |
| 16 |
expect(listNotes(db, anon)).toEqual({ ok: true, value: [] }); |
| 17 |
const refused = addNote(db, anon, { body: "hello" }); |
| 18 |
expect(refused.ok).toBe(false); |
| 19 |
if (!refused.ok) expect(refused.error).toBe("signin_required"); |
| 20 |
const added = addNote(db, alice, { body: " hello " }); |
| 21 |
expect(added.ok).toBe(true); |
| 22 |
if (!added.ok) return; |
| 23 |
expect(added.value.body).toBe("hello"); |
| 24 |
expect(added.value.author_id).toBe("u1"); |
| 25 |
expect(added.value.author_name).toBe("alice"); |
| 26 |
const all = listNotes(db, anon); |
| 27 |
expect(all.ok && all.value.length).toBe(1); |
| 28 |
}); |
| 29 |
|
| 30 |
test("a note is one to five hundred characters", () => { |
| 31 |
for (const body of ["", " ", "x".repeat(501)]) { |
| 32 |
const r = addNote(db, alice, { body }); |
| 33 |
expect(r.ok).toBe(false); |
| 34 |
if (!r.ok) expect(r.error).toBe("invalid"); |
| 35 |
} |
| 36 |
}); |
| 37 |
|
| 38 |
test("only the author or an admin removes a note", () => { |
| 39 |
const mine = addNote(db, alice, { body: "mine" }); |
| 40 |
if (!mine.ok) throw new Error(mine.message); |
| 41 |
const byBob = deleteNote(db, bob, { id: mine.value.id }); |
| 42 |
expect(byBob.ok).toBe(false); |
| 43 |
if (!byBob.ok) expect(byBob.error).toBe("forbidden"); |
| 44 |
const byAnon = deleteNote(db, anon, { id: mine.value.id }); |
| 45 |
expect(byAnon.ok).toBe(false); |
| 46 |
if (!byAnon.ok) expect(byAnon.error).toBe("signin_required"); |
| 47 |
expect(deleteNote(db, alice, { id: mine.value.id }).ok).toBe(true); |
| 48 |
const gone = deleteNote(db, alice, { id: mine.value.id }); |
| 49 |
expect(gone.ok).toBe(false); |
| 50 |
if (!gone.ok) expect(gone.error).toBe("not_found"); |
| 51 |
|
| 52 |
const bobs = addNote(db, bob, { body: "bob's" }); |
| 53 |
if (!bobs.ok) throw new Error(bobs.message); |
| 54 |
expect(deleteNote(db, root, { id: bobs.value.id }).ok).toBe(true); |
| 55 |
const odd = deleteNote(db, root, { id: 1.5 }); |
| 56 |
expect(odd.ok).toBe(false); |
| 57 |
if (!odd.ok) expect(odd.error).toBe("invalid"); |
| 58 |
}); |