Sessions 5-7a: 955 tests, deployment ready

This commit is contained in:
Kev
2026-06-08 18:35:13 -04:00
parent 06b82624a2
commit 1fa04dc776
371 changed files with 49366 additions and 955 deletions
+107
View File
@@ -0,0 +1,107 @@
process.env.VAPID_PUBLIC_KEY = 'BTestPublicKey_______________________________________________________________';
process.env.VAPID_PRIVATE_KEY = 'TestPrivateKey_______________________________';
process.env.VAPID_SUBJECT = 'mailto:test@vyndr.app';
const mockSendNotification = jest.fn();
const mockSetVapidDetails = jest.fn();
jest.mock('web-push', () => ({
setVapidDetails: (...args) => mockSetVapidDetails(...args),
sendNotification: (...args) => mockSendNotification(...args),
}));
// Builds a fluent supabase mock where each chained call records intent and
// the terminal promise yields {data, error}. Good enough for what webPush
// actually does (.from().select().eq() / .delete().eq()).
function makeSupabase({ rows = [], error = null } = {}) {
const deleted = [];
const builder = (table) => {
const ctx = { table, filters: [] };
const proxy = {
_ctx: ctx,
select: () => proxy,
eq: (col, val) => {
ctx.filters.push([col, val]);
return ctx.action === 'delete' ? Promise.resolve({ error: null }) : proxy;
},
contains: () => proxy,
delete: () => {
ctx.action = 'delete';
deleted.push(ctx);
return proxy;
},
then: (resolve) => resolve({ data: rows, error }),
};
return proxy;
};
return {
from: jest.fn().mockImplementation(builder),
_deleted: deleted,
};
}
const mockSupabase = { current: makeSupabase() };
jest.mock('../../src/utils/supabase', () => ({
getSupabaseServiceClient: () => mockSupabase.current,
}));
const webPush = require('../../src/services/distribution/webPush');
beforeEach(() => {
mockSendNotification.mockReset();
mockSetVapidDetails.mockReset();
mockSupabase.current = makeSupabase();
});
describe('webPush.configured', () => {
test('returns true when both VAPID keys present', () => {
expect(webPush.configured()).toBe(true);
});
});
describe('webPush.sendPushToUser', () => {
test('returns sent=0 when user has no subscriptions', async () => {
mockSupabase.current = makeSupabase({ rows: [] });
const result = await webPush.sendPushToUser('user-1', { title: 'hi' });
expect(result).toMatchObject({ ok: true, sent: 0 });
expect(mockSendNotification).not.toHaveBeenCalled();
});
test('sends to every subscription and counts successes', async () => {
mockSupabase.current = makeSupabase({
rows: [
{ id: 'a', endpoint: 'https://a', keys_p256dh: 'p1', keys_auth: 'k1' },
{ id: 'b', endpoint: 'https://b', keys_p256dh: 'p2', keys_auth: 'k2' },
],
});
mockSendNotification.mockResolvedValue({ statusCode: 201 });
const result = await webPush.sendPushToUser('user-1', { title: 'hi' });
expect(result.ok).toBe(true);
expect(result.sent).toBe(2);
expect(mockSendNotification).toHaveBeenCalledTimes(2);
});
test('prunes subscription that returns 410 Gone', async () => {
mockSupabase.current = makeSupabase({
rows: [{ id: 'dead', endpoint: 'https://dead', keys_p256dh: 'p', keys_auth: 'k' }],
});
const err = Object.assign(new Error('Gone'), { statusCode: 410 });
mockSendNotification.mockRejectedValue(err);
const result = await webPush.sendPushToUser('user-1', { title: 'hi' });
expect(result.pruned).toBe(1);
expect(result.sent).toBe(0);
expect(mockSupabase.current._deleted.length).toBeGreaterThan(0);
});
test('non-410 failure does not prune, counts as failed', async () => {
mockSupabase.current = makeSupabase({
rows: [{ id: 'flaky', endpoint: 'https://flaky', keys_p256dh: 'p', keys_auth: 'k' }],
});
const err = Object.assign(new Error('boom'), { statusCode: 500 });
mockSendNotification.mockRejectedValue(err);
const result = await webPush.sendPushToUser('user-1', { title: 'hi' });
expect(result.failed).toBe(1);
expect(result.sent).toBe(0);
expect(mockSupabase.current._deleted.length).toBe(0);
});
});