import { test } from 'node:test' import assert from 'node:assert/strict' import { describe, categoryOf, kindLabel, CATEGORIES } from '../src/lib/shardEvents.js' // Unit-test the shared shard-event formatter — the single place that decides how // each event kind reads and which filter category it belongs to. These strings // are user-facing on the public Shard page, the Activity feed, and the admin // live feed, so a regression here is visible everywhere at once. // ── describe(): works on both stored (.payload) and live (top-level) frames ── test('describe reads fields from .payload when present, else the top level', () => { const stored = { kind: 'quest.complete', payload: { who: { name: 'Ada' }, quest: 'The Cavern' } } const live = { kind: 'quest.complete', who: { name: 'Ada' }, quest: 'The Cavern' } assert.equal(describe(stored), 'Ada completed “The Cavern”') assert.equal(describe(live), 'Ada completed “The Cavern”') }) test('describe resolves an actor from name → acct → "Someone"', () => { assert.equal(describe({ kind: 'mob.login', who: { name: 'Bob' } }), 'Bob entered the world') assert.equal(describe({ kind: 'mob.login', who: { acct: 'acct7' } }), 'acct7 entered the world') assert.equal(describe({ kind: 'mob.login', who: null }), 'Someone entered the world') assert.equal(describe({ kind: 'mob.login', who: 'RawString' }), 'RawString entered the world') }) test('describe pluralizes a vendor sale only when amount > 1 and formats the price', () => { assert.equal(describe({ kind: 'vendor.sale', itemType: 'Katana', amount: 1, price: 1200 }), 'Katana sold for 1,200gp') assert.equal(describe({ kind: 'vendor.sale', itemType: 'Arrow', amount: 40, price: 80 }), 'Arrow ×40 sold for 80gp') }) test('describe includes the killer only when present (optional clause)', () => { assert.equal(describe({ kind: 'player.death', who: { name: 'Ada' } }), 'Ada was slain') assert.equal( describe({ kind: 'player.death', who: { name: 'Ada' }, killer: { name: 'Orc' } }), 'Ada was slain by Orc', ) }) test('describe champ.update branches on status and boss state', () => { assert.equal(describe({ kind: 'champ.update', name: 'Rikktor', status: 'active', bossUp: true }), 'Rikktor: boss is up') assert.equal( describe({ kind: 'champ.update', name: 'Rikktor', status: 'active', level: 3 }), 'Rikktor is active — level 3', ) assert.equal(describe({ kind: 'champ.update', name: 'Rikktor', status: 'cooldown' }), 'Rikktor is on cooldown') }) test('describe falls back to the raw kind for an unknown event', () => { assert.equal(describe({ kind: 'some.future.kind' }), 'some.future.kind') }) // ── categoryOf(): membership + catch-all ──────────────────────────────── test('categoryOf groups kinds per the CATEGORIES table, and unknowns are "other"', () => { assert.equal(categoryOf('player.death'), 'pvp') assert.equal(categoryOf('skill.gain'), 'progress') assert.equal(categoryOf('house.decay'), 'world') assert.equal(categoryOf('vendor.sale'), 'other') // deliberately not a public category assert.equal(categoryOf('totally.unknown'), 'other') }) test('every kind listed in CATEGORIES maps back to that category (table stays consistent)', () => { for (const cat of CATEGORIES) { if (!cat.kinds) continue for (const kind of cat.kinds) { assert.equal(categoryOf(kind), cat.id, `${kind} should be in ${cat.id}`) } } }) // ── kindLabel(): badge text ───────────────────────────────────────────── test('kindLabel turns dots/underscores into spaces and tolerates empty input', () => { assert.equal(kindLabel('player.death'), 'player death') assert.equal(kindLabel('account.login.attempt'), 'account login attempt') assert.equal(kindLabel(null), '') })