Both registration timestamp orders exercise exact full-event and ID-only payload matching while preserving delivery counts and callback identity.
- commit
- 622e04b8f34e4f7326d9678904142dbd045e17e2
- parent
- 7dc805d39d887ded44edc22d083ef642ae179a64
- author
- FelineStateMachine <dami.etoile@gmail.com>
| M | test/ | 34 | +++++++++++++++++------------- |
@@ -22,38 +22,42 @@ async function trustAndCapture(name: string, capture: (req: Request) => Response
2222 }2323 2424 describe("NIP-9a push engine", () => {25- it("delivers a filtered event with either an id-only or complete payload", async () => {26- const host = "push-engine.bind.ws";25+ it.each([{ order: "older", offset: -1 }, { order: "newer", offset: 1 }])("delivers both payloads when the id-only registration is $order", async ({ order, offset }) => {26+ const name = "push-engine-" + order;27+ const host = name + ".bind.ws";28+ const registeredAt = now() - 10;2729 const owner = generateSecretKey();2830 await enable(host, owner);2931 const socket = await WS.connect(host);3032 await socket.auth(owner, host);3133 const seen: { url: string; body: string }[] = [];32- await trustAndCapture("push-engine", async (req) => { seen.push({ url: req.url, body: await req.text() }); return new Response(null, { status: 204 }); });34+ await trustAndCapture(name, async (req) => { seen.push({ url: req.url, body: await req.text() }); return new Response(null, { status: 204 }); });3335 const registration = ev(owner, KIND_PUSH_REGISTRATION, "", [3436 ["d", "one"], ["relay", "wss://" + host], ["filter", JSON.stringify({ kinds: [1] })], ["callback", callback], ["include_event"],35- ]);37+ ], registeredAt);3638 expect((await socket.ok(registration)).ok).toBe(true);3739 const note = ev(owner, 1, "hello");3840 expect((await socket.ok(note)).ok).toBe(true);39- await runInDurableObject(env.RELAY.getByName("push-engine"), async (r: Relay) => { await r.alarm(); });41+ await runInDurableObject(env.RELAY.getByName(name), async (r: Relay) => { await r.alarm(); });4042 expect(seen).toHaveLength(1);4143 expect(seen[0].url).toBe(callback);42- const body = JSON.parse(seen[0].body) as { id: string; relay: string; event: { id: string; content: string } };43- expect(body.id).toBe(note.id);44- expect(body.relay).toBe("wss://" + host + "/");45- expect(body.event).toMatchObject({ id: note.id, content: "hello" });44+ expect(JSON.parse(seen[0].body)).toEqual({ id: note.id, relay: "wss://" + host + "/", event: JSON.parse(JSON.stringify(note)) });4645 const idsOnly = ev(owner, KIND_PUSH_REGISTRATION, "", [4746 ["d", "two"], ["relay", "wss://" + host], ["filter", JSON.stringify({ kinds: [1] })], ["callback", callback],48- ]);47+ ], registeredAt + offset);4948 expect((await socket.ok(idsOnly)).ok).toBe(true);5049 const second = ev(owner, 1, "id only");51- await socket.ok(second);52- await runInDurableObject(env.RELAY.getByName("push-engine"), async (r: Relay) => { await r.alarm(); });50+ expect((await socket.ok(second)).ok).toBe(true);51+ await runInDurableObject(env.RELAY.getByName(name), async (r: Relay) => { await r.alarm(); });5352 expect(seen).toHaveLength(3);54- const idBody = JSON.parse(seen[2].body) as { id: string; event?: unknown };55- expect(idBody.id).toBe(second.id);56- expect(idBody.event).toBeUndefined();53+ const deliveries = seen.map(({ url, body }) => ({ url, payload: JSON.parse(body) })).filter(({ payload }) => payload.id === second.id);54+ expect(deliveries).toHaveLength(2);55+ // Registration timestamps exercise both selection orders; notification56+ // identity and payload content establish correctness, not arrival position.57+ expect(deliveries).toEqual(expect.arrayContaining([58+ { url: callback, payload: { id: second.id, relay: "wss://" + host + "/", event: JSON.parse(JSON.stringify(second)) } },59+ { url: callback, payload: { id: second.id, relay: "wss://" + host + "/" } },60+ ]));5761 });5862 5963 it("does not deliver ignored events, duplicate broadcasts, or events after member removal", async () => {