Add manual outreach funnel clearing
This commit is contained in:
1 parent
6b2e1bc380
commit
4798385d8b
16 files changed
+319
-17
No files matched your search
@@ -1,18 +1,21 @@
|
||||
import express from 'express';
|
||||
import type { AddressInfo } from 'node:net';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { OutreachFunnelResponseSchema } from '../../packages/api-contracts/src/index.js';
|
||||
import {
|
||||
OutreachClearResponseSchema,
|
||||
OutreachFunnelResponseSchema,
|
||||
} from '../../packages/api-contracts/src/index.js';
|
||||
import type { WebContext } from '../../src/web/context.js';
|
||||
import { createOutreachRouter } from '../../src/web/routes/outreach.js';
|
||||
|
||||
const servers: Array<ReturnType<express.Express['listen']>> = [];
|
||||
|
||||
async function request(app: express.Express, path: string): Promise<Response> {
|
||||
async function request(app: express.Express, path: string, init?: RequestInit): Promise<Response> {
|
||||
const server = app.listen(0);
|
||||
servers.push(server);
|
||||
await new Promise<void>((resolve) => server.once('listening', resolve));
|
||||
const { port } = server.address() as AddressInfo;
|
||||
return fetch(`http://127.0.0.1:${port}${path}`);
|
||||
return fetch(`http://127.0.0.1:${port}${path}`, init);
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
@@ -102,4 +105,35 @@ describe('outreach route', () => {
|
||||
expect(response.status).toBe(503);
|
||||
expect(await response.json()).toEqual({ error: 'Outreach queue not initialized' });
|
||||
});
|
||||
|
||||
it('clears unsent candidates, reports retained sends, and records the operator action', async () => {
|
||||
const clearUnsent = vi.fn(() => ({
|
||||
discovered: 2, screening: 1, ready: 3, retryable: 1, total: 7, retainedSending: 1,
|
||||
}));
|
||||
const activity = { push: vi.fn() };
|
||||
const broadcaster = { push: vi.fn() };
|
||||
const context = {
|
||||
services: { candidateQueue: { clearUnsent } }, activity, broadcaster,
|
||||
} as unknown as WebContext;
|
||||
const app = express().use('/api', createOutreachRouter(context));
|
||||
|
||||
const response = await request(app, '/api/outreach', { method: 'DELETE' });
|
||||
const parsed = OutreachClearResponseSchema.parse(await response.json());
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
expect(parsed).toEqual({
|
||||
success: true,
|
||||
cleared: { discovered: 2, screening: 1, ready: 3, retryable: 1, total: 7 },
|
||||
retainedSending: 1,
|
||||
});
|
||||
expect(clearUnsent).toHaveBeenCalledOnce();
|
||||
expect(activity.push).toHaveBeenCalledWith(
|
||||
'info', 'Cleared 7 unsent outreach candidate(s); retained 1 in-flight send(s)',
|
||||
);
|
||||
expect(broadcaster.push).toHaveBeenCalledWith(
|
||||
'warn',
|
||||
'Cleared 7 unsent outreach candidate(s); retained 1 in-flight send(s)',
|
||||
expect.objectContaining({ total: 7, retainedSending: 1 }),
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user