jevstrudel.git / worker / src / parties.test.ts
1// GET /jev/parties and /jev/parties/<id> (party.ts): the live parties, and a
2// listed one's room, given only by the room itself while it is listed.
3import { describe, expect, it } from 'vitest';
4import { parties } from './party';
5
6const ORIGIN = 'https://jevstrudel.example';
7const LISTED = 'a'.repeat(64);
8const UNLISTED = 'b'.repeat(64);
9
10function env({ limited = false } = {}) {
11  const rooms: Record<string, string | null> = { [LISTED]: 'the-listed-room-0123', [UNLISTED]: null };
12  const asked: string[] = [];
13  return {
14    asked,
15    env: {
16      PARTY_LIMIT: { limit: async () => ({ success: !limited }) },
17      PARTY_DIRECTORY: {
18        idFromName: () => ({}),
19        get: () => ({
20          live: async () => [
21            { people: 2, host: true, song: 'jev/dial-up', since: 1, listed: true, id: LISTED },
22            { people: 1, host: true, song: null, since: 2, listed: false },
23          ],
24        }),
25      },
26      PARTY: {
27        idFromString: (hex: string) => {
28          if (!/^[0-9a-f]{64}$/.test(hex)) throw new Error('bad id');
29          return { hex };
30        },
31        get: ({ hex }: { hex: string }) => ({
32          listedRoom: async () => {
33            asked.push(hex);
34            return rooms[hex] ?? null;
35          },
36        }),
37      },
38    } as never,
39  };
40}
41const call = async (path: string, e = env()) => {
42  const res = await parties(new Request(`${ORIGIN}${path}`), e.env);
43  return { status: res.status, body: await res.json(), asked: e.asked };
44};
45
46describe('/jev/parties', () => {
47  it('lists the live parties, a listed one with its id', async () => {
48    const { status, body } = await call('/jev/parties');
49    expect(status).toBe(200);
50    expect(body.parties).toHaveLength(2);
51    expect(body.parties[0]).toMatchObject({ listed: true, id: LISTED });
52    expect(body.parties[1]).not.toHaveProperty('id');
53  });
54
55  it("gives a listed party's room, from the room", async () => {
56    const { status, body, asked } = await call(`/jev/parties/${LISTED}`);
57    expect(status).toBe(200);
58    expect(body).toEqual({ room: 'the-listed-room-0123' });
59    expect(asked).toEqual([LISTED]);
60  });
61
62  it('gives no room for a party not listed, over, or not an id', async () => {
63    expect((await call(`/jev/parties/${UNLISTED}`)).status).toBe(404);
64    const bad = await call('/jev/parties/the-listed-room-0123');
65    expect(bad.status).toBe(404);
66    expect(bad.asked).toEqual([]);
67  });
68
69  it('holds the rate, and reads only', async () => {
70    expect((await call('/jev/parties', env({ limited: true }))).status).toBe(429);
71    const res = await parties(new Request(`${ORIGIN}/jev/parties`, { method: 'POST' }), env().env);
72    expect(res.status).toBe(405);
73  });
74});