Files
COMERCIAL-GTI/tests/server-whatsapp-integration.test.mjs
T
Gustavo d330bb5ff0 Baseline commit of the existing Maquina Comercial Pessoal project
Tracks the app that was already in place (capture, treatment, outreach,
WhatsApp integration, server, frontend, tests, docs) so future feature
work can branch and use isolated worktrees.
2026-07-31 10:54:07 -03:00

98 lines
4.2 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { openDb, ensureDefaultAdmin } from '../src/db.mjs';
import { createAppServer } from '../src/server/index.mjs';
test('createAppServer injeta o mesmo manager nas rotas WhatsApp e outreach', async (t) => {
const db = openDb(':memory:');
ensureDefaultAdmin(db);
let connects = 0;
const whatsapp = {
getStatus: () => ({ state: 'READY', connected: true, qrExpiresAt: null, error: null }),
getQr: () => null,
connect: async () => { connects += 1; },
disconnect: async () => ({ state: 'STOPPED' }),
sendText: async () => ({ messageId: 'id' })
};
const jobs = { subscribe: () => null, activeJobs: () => [] };
const server = createAppServer({ db, jobs, whatsapp });
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
t.after(async () => {
await new Promise((resolve) => server.close(resolve));
db.close();
});
const { port } = server.address();
const base = `http://127.0.0.1:${port}`;
const login = await fetch(`${base}/api/auth/login`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'admin' })
});
assert.equal(login.headers.get('cache-control'), 'no-store');
const cookie = login.headers.get('set-cookie').split(';')[0];
const status = await fetch(`${base}/api/outreach/status`, { headers: { cookie } }).then((response) => response.json());
assert.equal(status.whatsapp.state, 'READY');
const campaignsResponse = await fetch(`${base}/api/campaigns`, { headers: { cookie } });
assert.equal(campaignsResponse.status, 200);
const campaigns = await campaignsResponse.json();
assert.deepEqual(campaigns.campaigns.map((campaign) => campaign.code), [
'gdelivery-food', 'gti-food', 'gti-retail'
]);
const connect = await fetch(`${base}/api/whatsapp/connect`, { method: 'POST', headers: { cookie } });
assert.equal(connect.status, 202);
assert.equal(connects, 1);
const qr = await fetch(`${base}/api/whatsapp/qr`, { headers: { cookie } });
assert.equal(qr.headers.get('pragma'), 'no-cache');
assert.equal(qr.headers.get('expires'), '0');
});
test('erro global 500 e generico para cliente e detalhado somente no log', async (t) => {
const db = openDb(':memory:');
ensureDefaultAdmin(db);
db.prepare(
`INSERT INTO leads (dedup_key, empresa, whatsapp, segmento, prioridade, score)
VALUES ('global-error', 'Hamburgueria Erro', '5511999990001', 'hamburguerias', 1, 100)`
).run();
const secret = 'GLOBAL-SENTINEL-SECRET';
db.exec(`
CREATE TRIGGER global_sentinel_failure
BEFORE INSERT ON whatsapp_number_verifications
BEGIN SELECT RAISE(FAIL, '${secret}'); END;
`);
const logs = [];
const whatsapp = {
getStatus: () => ({ state: 'READY', connected: true }),
getQr: () => null,
checkNumber: async (number) => ({ registered: true, numero: number, numero_resolvido: number }),
sendText: async () => { throw new Error('sendText nao deveria ser chamado'); },
connect: async () => {},
disconnect: async () => ({ state: 'STOPPED' })
};
const jobs = { subscribe: () => null, activeJobs: () => [] };
const server = createAppServer({ db, jobs, whatsapp, log: (message) => logs.push(message) });
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
t.after(async () => {
await new Promise((resolve) => server.close(resolve));
db.close();
});
const base = `http://127.0.0.1:${server.address().port}`;
const login = await fetch(`${base}/api/auth/login`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'admin' })
});
const cookie = login.headers.get('set-cookie').split(';')[0];
const response = await fetch(`${base}/api/campaigns/1/prepare`, {
method: 'POST', headers: { cookie, 'content-type': 'application/json' }, body: '{}'
});
assert.equal(response.status, 500);
const body = await response.json();
assert.deepEqual(body, { erro: 'erro interno do servidor' });
assert.doesNotMatch(JSON.stringify(body), new RegExp(secret, 'i'));
assert.match(logs.join('\n'), new RegExp(secret, 'i'));
});