63 lines
1.9 KiB
TypeScript
63 lines
1.9 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import {
|
|
createPushSubscriptionService,
|
|
memoryPushSubscriptionStore,
|
|
postgresPushSubscriptionStore,
|
|
renderOfflineQueueReview,
|
|
} from "../src/index.ts";
|
|
|
|
test("push subscriptions validate, deduplicate and persist per user", async () => {
|
|
const service = createPushSubscriptionService(memoryPushSubscriptionStore(), {
|
|
maxPerUser: 1,
|
|
now: () => 10,
|
|
});
|
|
const value = { endpoint: "https://push.test/sub", keys: { p256dh: "public", auth: "secret" } };
|
|
const first = await service.subscribe("user", value);
|
|
expect((await service.list("user"))[0]).toEqual(first);
|
|
expect((await service.subscribe("user", value)).id).toBe(first.id);
|
|
await expect(
|
|
service.subscribe("user", { ...value, endpoint: "https://push.test/other" }),
|
|
).rejects.toThrow("CAPACITY");
|
|
await expect(
|
|
service.subscribe("user", { ...value, endpoint: "http://push.test/insecure" }),
|
|
).rejects.toThrow("HTTPS");
|
|
});
|
|
|
|
test("PostgreSQL subscriptions parameterize endpoint and user", async () => {
|
|
const calls: unknown[][] = [];
|
|
const store = postgresPushSubscriptionStore({
|
|
async query<T>(_sql: string, params?: unknown[]) {
|
|
calls.push(params ?? []);
|
|
return { rows: [] as T[] };
|
|
},
|
|
});
|
|
await store.put({
|
|
id: "id",
|
|
userId: "user",
|
|
endpoint: "https://push.test",
|
|
keys: { p256dh: "p", auth: "a" },
|
|
createdAt: 1,
|
|
});
|
|
expect(calls[0]?.slice(0, 3)).toEqual(["id", "user", "https://push.test"]);
|
|
});
|
|
|
|
test("offline review UI escapes payload-derived identifiers and conflicts", () => {
|
|
const html = renderOfflineQueueReview(
|
|
[
|
|
{
|
|
id: `"><script>`,
|
|
endpoint: "/api/save",
|
|
method: "POST",
|
|
payload: {},
|
|
attempts: 2,
|
|
createdAt: 1,
|
|
updatedAt: 1,
|
|
},
|
|
],
|
|
[{ id: "c", message: "<img onerror=alert(1)>" }],
|
|
);
|
|
expect(html).not.toContain("<script>");
|
|
expect(html).not.toContain("<img");
|
|
expect(html).toContain("data-pwa-retry");
|
|
});
|