1import { beforeEach, describe, expect, it } from 'vitest'; 2import { live, note, STALE_MS, type Storage } from './party-directory'; 3 4let store: Map<string, unknown>; 5const storage: Storage = { 6 get: async <T,>(k: string) => store.get(k) as T | undefined, 7 put: async (k: string, v: unknown) => void store.set(k, v), 8 delete: async (k: string) => store.delete(k), 9 list: async <T,>({ prefix, limit }: { prefix: string; limit?: number }) => 10 new Map([...store].filter(([k]) => k.startsWith(prefix)).slice(0, limit ?? Infinity) as [string, T][]), 11}; 12// a Durable Object id: 64 hex characters 13const room = (c: string) => c.repeat(64); 14 15beforeEach(() => { 16 store = new Map(); 17}); 18 19describe('the party directory', () => { 20 it('keeps a live room, since it started, and forgets it once empty', async () => { 21 await note(storage, room('a'), { people: 1, host: true, song: null }, 1000); 22 await note(storage, room('a'), { people: 3, host: true, song: 'jev/dial-up' }, 5000); 23 expect(await live(storage, 6000)).toEqual([{ people: 3, host: true, song: 'jev/dial-up', since: 1000, listed: false }]); 24 await note(storage, room('a'), null, 7000); 25 expect(await live(storage, 8000)).toEqual([]); 26 }); 27 28 it('lists the longest-running first, and drops one that stopped reporting', async () => { 29 await note(storage, room('b'), { people: 2, host: false, song: null }, 2000); 30 await note(storage, room('c'), { people: 1, host: true, song: null }, 1000); 31 expect((await live(storage, 3000)).map((p) => p.since)).toEqual([1000, 2000]); 32 expect(await live(storage, 2000 + STALE_MS + 1)).toEqual([]); 33 expect(store.size).toBe(0); 34 }); 35 36 it("gives a listed room's object id, to join it by, and never an unlisted one's", async () => { 37 await note(storage, room('e'), { people: 2, host: true, song: 'jev/dial-up', listed: true }, 1); 38 await note(storage, room('f'), { people: 1, host: true, song: null, listed: false }, 2); 39 await note(storage, room('0'), { people: 1, host: true, song: null }, 3); 40 const parties = await live(storage, 4); 41 expect(parties).toEqual([ 42 { people: 2, host: true, song: 'jev/dial-up', since: 1, listed: true, id: room('e') }, 43 { people: 1, host: true, song: null, since: 2, listed: false }, 44 { people: 1, host: true, song: null, since: 3, listed: false }, 45 ]); 46 // a host who stops being listed takes the id back at the next report 47 await note(storage, room('e'), { people: 2, host: true, song: 'jev/dial-up', listed: false }, 5); 48 expect((await live(storage, 6)).some((p) => 'id' in p)).toBe(false); 49 }); 50 51 it('takes only a Durable Object id, and bounds what a room says', async () => { 52 await note(storage, 'my-secret-room-name', { people: 1, host: true, song: null }, 1); 53 expect(store.size).toBe(0); 54 await note(storage, room('d'), { people: 1e9, host: true, song: 'x'.repeat(500) }, 1); 55 const [p] = await live(storage, 2); 56 expect(p.people).toBe(1000); 57 expect(p.song).toHaveLength(129); 58 }); 59});