From 3278f640ce47dfa95024fe0cf811e532f253dbf8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 10 May 2026 12:32:59 +0100 Subject: [PATCH] test: clear apns push broad matchers --- src/infra/push-apns.test.ts | 256 ++++++++++++++++++++---------------- 1 file changed, 143 insertions(+), 113 deletions(-) diff --git a/src/infra/push-apns.test.ts b/src/infra/push-apns.test.ts index 95a3d02acb3..438ae02dbe1 100644 --- a/src/infra/push-apns.test.ts +++ b/src/infra/push-apns.test.ts @@ -164,6 +164,36 @@ async function closeServer(server: HttpServer | http2.Http2SecureServer): Promis }); } +function requireRecord(value: unknown, label: string): Record { + expect(typeof value).toBe("object"); + expect(value).not.toBeNull(); + if (typeof value !== "object" || value === null) { + throw new Error(`${label} was not an object`); + } + return value as Record; +} + +function expectRecordFields(record: Record, fields: Record) { + for (const [key, value] of Object.entries(fields)) { + expect(record[key]).toEqual(value); + } +} + +function expectNoProperties(record: Record, keys: string[]) { + for (const key of keys) { + expect(record).not.toHaveProperty(key); + } +} + +function requireSendRequest(send: ReturnType, label = "APNs send request") { + const request = send.mock.calls[0]?.[0]; + return requireRecord(request, label); +} + +function requirePayload(sendRequest: Record) { + return requireRecord(sendRequest.payload, "APNs payload"); +} + async function startFakeApnsServer(): Promise<{ port: number; requests: CapturedApnsRequest[]; @@ -266,19 +296,20 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent?.pushType).toBe("alert"); - expect(sent?.priority).toBe("10"); - expect(sent?.payload).toMatchObject({ - aps: { - alert: { title: "Wake", body: "Ping" }, - sound: "default", - }, - openclaw: { - kind: "push.test", - nodeId: "ios-node-alert", - }, + const sent = requireSendRequest(send); + expect(sent.pushType).toBe("alert"); + expect(sent.priority).toBe("10"); + const payload = requirePayload(sent); + expect(payload.aps).toEqual({ + alert: { title: "Wake", body: "Ping" }, + sound: "default", }); + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "push.test", + nodeId: "ios-node-alert", + }); + expect(typeof openclawPayload.ts).toBe("number"); expect(result.ok).toBe(true); expect(result.status).toBe(200); expect(result.transport).toBe("direct"); @@ -312,7 +343,7 @@ describe("push APNs send semantics", () => { timeoutMs: 2_500, }); - expect(result).toMatchObject({ + expectRecordFields(requireRecord(result, "APNs result"), { ok: true, status: 200, apnsId: "proxied-apns-id", @@ -358,23 +389,23 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent?.pushType).toBe("background"); - expect(sent?.priority).toBe("5"); - expect(sent?.payload).toMatchObject({ - aps: { - "content-available": 1, - }, - openclaw: { - kind: "node.wake", - reason: "node.invoke", - nodeId: "ios-node-wake", - }, + const sent = requireSendRequest(send); + expect(sent.pushType).toBe("background"); + expect(sent.priority).toBe("5"); + const payload = requirePayload(sent); + expect(payload.aps).toEqual({ + "content-available": 1, }); - const sentPayload = sent?.payload as { aps?: { alert?: unknown; sound?: unknown } } | undefined; - const aps = sentPayload?.aps; - expect(aps?.alert).toBeUndefined(); - expect(aps?.sound).toBeUndefined(); + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "node.wake", + reason: "node.invoke", + nodeId: "ios-node-wake", + }); + expect(typeof openclawPayload.ts).toBe("number"); + const aps = requireRecord(payload.aps, "APNs aps payload"); + expect(aps.alert).toBeUndefined(); + expect(aps.sound).toBeUndefined(); expect(result.ok).toBe(true); expect(result.environment).toBe("production"); expect(result.transport).toBe("direct"); @@ -400,33 +431,32 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent?.pushType).toBe("alert"); - expect(sent?.payload).toMatchObject({ - aps: { - alert: { - title: "Exec approval required", - body: "Open OpenClaw to review this request.", - }, - sound: "default", - category: "openclaw.exec-approval", - "content-available": 1, - }, - openclaw: { - kind: "exec.approval.requested", - approvalId: "approval-123", + const sent = requireSendRequest(send); + expect(sent.pushType).toBe("alert"); + const payload = requirePayload(sent); + expect(payload.aps).toEqual({ + alert: { + title: "Exec approval required", + body: "Open OpenClaw to review this request.", }, + sound: "default", + category: "openclaw.exec-approval", + "content-available": 1, }); - expect(sent?.payload).not.toMatchObject({ - openclaw: { - host: expect.anything(), - nodeId: expect.anything(), - agentId: expect.anything(), - commandText: expect.anything(), - allowedDecisions: expect.anything(), - expiresAtMs: expect.anything(), - }, + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "exec.approval.requested", + approvalId: "approval-123", }); + expect(typeof openclawPayload.ts).toBe("number"); + expectNoProperties(openclawPayload, [ + "host", + "nodeId", + "agentId", + "commandText", + "allowedDecisions", + "expiresAtMs", + ]); expect(result.ok).toBe(true); expect(result.transport).toBe("direct"); }); @@ -451,17 +481,18 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent?.pushType).toBe("background"); - expect(sent?.payload).toMatchObject({ - aps: { - "content-available": 1, - }, - openclaw: { - kind: "exec.approval.resolved", - approvalId: "approval-123", - }, + const sent = requireSendRequest(send); + expect(sent.pushType).toBe("background"); + const payload = requirePayload(sent); + expect(payload.aps).toEqual({ + "content-available": 1, }); + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "exec.approval.resolved", + approvalId: "approval-123", + }); + expect(typeof openclawPayload.ts).toBe("number"); expect(result.ok).toBe(true); expect(result.transport).toBe("direct"); }); @@ -488,7 +519,7 @@ describe("push APNs send semantics", () => { }); expect(send.mock.calls[0]?.[0]?.timeoutMs).toBe(1000); - expect(result).toMatchObject({ + expectRecordFields(requireRecord(result, "APNs result"), { ok: false, status: 400, apnsId: "apns-direct-fail-id", @@ -542,12 +573,11 @@ describe("push APNs send semantics", () => { }); const sent = send.mock.calls[0]?.[0]; - expect(sent?.payload).toMatchObject({ - openclaw: { - kind: "node.wake", - reason: "node.invoke", - nodeId: "ios-node-wake-default-reason", - }, + const payload = requirePayload(requireRecord(sent, "APNs send request")); + expectRecordFields(requireRecord(payload.openclaw, "openclaw payload"), { + kind: "node.wake", + reason: "node.invoke", + nodeId: "ios-node-wake-default-reason", }); }); @@ -574,24 +604,23 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent).toMatchObject({ + const sent = requireSendRequest(send); + expectRecordFields(sent, { relayConfig, sendGrant: "send-grant-123", relayHandle: "relay-handle-12345678", gatewayDeviceId: "gateway-device-1", pushType: "alert", priority: "10", - payload: { - aps: { - alert: { title: "Wake", body: "Ping" }, - sound: "default", - }, - }, }); - expect(sent?.signature).toBeTypeOf("string"); - expect(sent?.signature).not.toBe(""); - expect(result).toMatchObject({ + const payload = requirePayload(sent); + expect(requireRecord(payload.aps, "APNs aps payload")).toEqual({ + alert: { title: "Wake", body: "Ping" }, + sound: "default", + }); + expect(sent.signature).toBeTypeOf("string"); + expect(sent.signature).not.toBe(""); + expectRecordFields(requireRecord(result, "APNs result"), { ok: true, status: 202, apnsId: "relay-alert-id", @@ -623,24 +652,25 @@ describe("push APNs send semantics", () => { }); expect(send).toHaveBeenCalledTimes(1); - const sent = send.mock.calls[0]?.[0]; - expect(sent).toMatchObject({ + const sent = requireSendRequest(send); + expectRecordFields(sent, { relayConfig, sendGrant: "send-grant-123", relayHandle: "relay-handle-12345678", gatewayDeviceId: "gateway-device-1", pushType: "background", priority: "5", - payload: { - aps: { "content-available": 1 }, - openclaw: { - kind: "node.wake", - reason: "queue.retry", - nodeId: "ios-node-relay-wake", - }, - }, }); - expect(result).toMatchObject({ + const payload = requirePayload(sent); + expect(payload.aps).toEqual({ "content-available": 1 }); + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "node.wake", + reason: "queue.retry", + nodeId: "ios-node-relay-wake", + }); + expect(typeof openclawPayload.ts).toBe("number"); + expectRecordFields(requireRecord(result, "APNs result"), { ok: false, status: 429, reason: "TooManyRequests", @@ -671,30 +701,30 @@ describe("push APNs send semantics", () => { }); const sent = send.mock.calls[0]?.[0]; - expect(sent?.payload).toMatchObject({ - aps: { - alert: { - title: "Exec approval required", - body: "Open OpenClaw to review this request.", - }, - category: "openclaw.exec-approval", - "content-available": 1, - }, - openclaw: { - kind: "exec.approval.requested", - approvalId: "approval-relay-1", + const payload = requirePayload(requireRecord(sent, "APNs send request")); + expect(payload.aps).toEqual({ + alert: { + title: "Exec approval required", + body: "Open OpenClaw to review this request.", }, + sound: "default", + category: "openclaw.exec-approval", + "content-available": 1, }); - expect(sent?.payload).not.toMatchObject({ - openclaw: { - commandText: expect.anything(), - host: expect.anything(), - nodeId: expect.anything(), - allowedDecisions: expect.anything(), - expiresAtMs: expect.anything(), - }, + const openclawPayload = requireRecord(payload.openclaw, "openclaw payload"); + expectRecordFields(openclawPayload, { + kind: "exec.approval.requested", + approvalId: "approval-relay-1", }); - expect(result).toMatchObject({ + expect(typeof openclawPayload.ts).toBe("number"); + expectNoProperties(openclawPayload, [ + "commandText", + "host", + "nodeId", + "allowedDecisions", + "expiresAtMs", + ]); + expectRecordFields(requireRecord(result, "APNs result"), { ok: true, status: 202, environment: "production",