mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 20:24:46 +00:00
test: clear apns push broad matchers
This commit is contained in:
@@ -164,6 +164,36 @@ async function closeServer(server: HttpServer | http2.Http2SecureServer): Promis
|
||||
});
|
||||
}
|
||||
|
||||
function requireRecord(value: unknown, label: string): Record<string, unknown> {
|
||||
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<string, unknown>;
|
||||
}
|
||||
|
||||
function expectRecordFields(record: Record<string, unknown>, fields: Record<string, unknown>) {
|
||||
for (const [key, value] of Object.entries(fields)) {
|
||||
expect(record[key]).toEqual(value);
|
||||
}
|
||||
}
|
||||
|
||||
function expectNoProperties(record: Record<string, unknown>, keys: string[]) {
|
||||
for (const key of keys) {
|
||||
expect(record).not.toHaveProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
function requireSendRequest(send: ReturnType<typeof vi.fn>, label = "APNs send request") {
|
||||
const request = send.mock.calls[0]?.[0];
|
||||
return requireRecord(request, label);
|
||||
}
|
||||
|
||||
function requirePayload(sendRequest: Record<string, unknown>) {
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user