Files
selfphoneng/apps/api/test/blocked.test.ts
T
iamdoubz 4fc0fb4084 blocked: blocked numbers page and API; M6 milestone check
/api/blocked-numbers stores numbers normalized (any input format) and
mirrors them to AstDB SP/BLOCK/<number>, which every trunk entry checks
(Hangup 21); the AstDB resync on connect includes them. Blocked numbers
page: add with a note, unblock.

e2e m6-check runs the M6 milestone scenario with real calls into a trunk
entry: DID → office hours (closed → voicemail; *31N from an admin's phone
forces open) → menu (1 → ring group ringing two phones together, 2 → a
user), and a caller blocked in the UI is rejected while others get
through.

Task: M6-T8
2026-10-18 13:57:27 -05:00

63 lines
2.1 KiB
TypeScript

// SPDX-License-Identifier: AGPL-3.0-or-later
// M6-T8: /api/blocked-numbers and the AstDB mirror (04 §5.5).
import type { LightMyRequestResponse } from 'fastify';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { syncAstDb } from '../src/services/astdb.ts';
import { hasTestDb } from './db.ts';
import { ADMIN, H, createTestApp } from './app.ts';
describe.skipIf(!hasTestDb)('/api/blocked-numbers', () => {
let t: Awaited<ReturnType<typeof createTestApp>>;
let req: (method: string, url: string, payload?: unknown) => Promise<LightMyRequestResponse>;
beforeAll(async () => {
t = await createTestApp();
await t.clearMustChange(ADMIN.email);
const cookie = await t.login(ADMIN.email, ADMIN.password);
req = (method, url, payload) =>
t.app.inject({
method: method as 'GET',
url,
payload: payload as object,
headers: { ...H, cookie },
});
});
afterAll(() => t?.close());
it('blocks a number in any format (stored normalized), mirrors AstDB, unblocks', async () => {
const r = await req('POST', '/api/blocked-numbers', {
number: '(312) 555-0199',
reason: 'Spam',
});
expect(r.statusCode, r.body).toBe(201);
expect(r.json()).toMatchObject({ number: '13125550199', reason: 'Spam' });
expect(t.ami.actions.at(-1)).toEqual({
Action: 'DBPut',
Family: 'SP',
Key: 'BLOCK/13125550199',
Val: '1',
});
expect(
(await req('POST', '/api/blocked-numbers', { number: '+1 312 555 0199' })).statusCode,
).toBe(409);
expect((await req('POST', '/api/blocked-numbers', { number: 'spam' })).statusCode).toBe(400);
t.ami.actions.length = 0;
await syncAstDb(t.db, t.ami);
expect(t.ami.actions).toContainEqual({
Action: 'DBPut',
Family: 'SP',
Key: 'BLOCK/13125550199',
Val: '1',
});
expect((await req('DELETE', `/api/blocked-numbers/${r.json().id}`)).statusCode).toBe(200);
expect(t.ami.actions.at(-1)).toEqual({
Action: 'DBDel',
Family: 'SP',
Key: 'BLOCK/13125550199',
});
expect((await req('GET', '/api/blocked-numbers')).json().items).toEqual([]);
});
});