chore: import maquina-comercial-pessoal history via subtree
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> git-subtree-dir: maquina-comercial-pessoal git-subtree-mainline:f5af038e19git-subtree-split:a9ef4d776d
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { openDb, saveWhatsAppVerification } from '../src/db.mjs';
|
||||
import { seedCampaigns } from '../src/outreach/campaign-store.mjs';
|
||||
import { runOutreachBatch } from '../src/outreach/run.mjs';
|
||||
import { renderTemplate } from '../src/outreach/templates.mjs';
|
||||
|
||||
function addScheduledQueue(db, scheduledAt = '2026-07-29T12:00:00.000Z') {
|
||||
seedCampaigns(db);
|
||||
const campaign = db.prepare('SELECT * FROM outreach_campaigns ORDER BY id LIMIT 1').get();
|
||||
db.prepare("UPDATE outreach_campaigns SET status = 'running' WHERE id = ?").run(campaign.id);
|
||||
const leadId = Number(db.prepare(
|
||||
`INSERT INTO leads (dedup_key, empresa, whatsapp, segmento, telefone_valido)
|
||||
VALUES ('queue-lead', 'Empresa Fila', '5511999990001', 'restaurantes', 1)`
|
||||
).run().lastInsertRowid);
|
||||
saveWhatsAppVerification(db, { numero: '5511999990001', status: 'confirmado' });
|
||||
const variantId = db.prepare(
|
||||
'SELECT id FROM outreach_campaign_variants WHERE campaign_id = ? ORDER BY id LIMIT 1'
|
||||
).get(campaign.id).id;
|
||||
return Number(db.prepare(
|
||||
`INSERT INTO outreach_campaign_queue
|
||||
(campaign_id, lead_id, variant_id, produto, numero, segmento,
|
||||
rendered_message, selection_reason, status, scheduled_at)
|
||||
VALUES (?, ?, ?, ?, '5511999990001', 'restaurantes',
|
||||
'Mensagem aprovada e imutavel', 'teste', 'scheduled', ?)`
|
||||
).run(campaign.id, leadId, variantId, campaign.produto, scheduledAt).lastInsertRowid);
|
||||
}
|
||||
|
||||
function whatsappFake() {
|
||||
const sent = [];
|
||||
return {
|
||||
sent,
|
||||
getStatus: () => ({ state: 'READY' }),
|
||||
sendText: async (args) => {
|
||||
const context = await args.beforeSend();
|
||||
sent.push({ number: args.number, message: args.message });
|
||||
const result = { messageId: 'queue-message-1' };
|
||||
await args.afterSend(result, null, context);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
test('renderTemplate inclui produto no contexto pessoal', () => {
|
||||
assert.equal(renderTemplate('{empresa}: {produto}', { empresa: 'Loja', produto: 'ERP' }), 'Loja: ERP');
|
||||
});
|
||||
|
||||
test('runOutreachBatch consome somente uma linha aprovada e vencida da fila', async () => {
|
||||
const db = openDb(':memory:');
|
||||
const queueId = addScheduledQueue(db);
|
||||
const whatsapp = whatsappFake();
|
||||
|
||||
const result = await runOutreachBatch({
|
||||
db,
|
||||
whatsapp,
|
||||
now: new Date('2026-07-29T12:00:00.000Z'),
|
||||
log: () => {}
|
||||
});
|
||||
|
||||
assert.deepEqual(result, { tentados: 1, enviados: 1, erros: 0, pulados: 0 });
|
||||
assert.deepEqual(whatsapp.sent, [{
|
||||
number: '5511999990001',
|
||||
message: 'Mensagem aprovada e imutavel'
|
||||
}]);
|
||||
assert.equal(db.prepare('SELECT status FROM outreach_campaign_queue WHERE id = ?').get(queueId).status, 'sent');
|
||||
assert.deepEqual(
|
||||
{ ...db.prepare(
|
||||
'SELECT mensagem_enviada, provider_message_id, status, canal, origem FROM outreach_sends'
|
||||
).get() },
|
||||
{
|
||||
mensagem_enviada: 'Mensagem aprovada e imutavel',
|
||||
provider_message_id: 'queue-message-1',
|
||||
status: 'aceito',
|
||||
canal: 'local',
|
||||
origem: 'automatico'
|
||||
}
|
||||
);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('runOutreachBatch sem WhatsApp READY preserva fila e registra adiamento', async () => {
|
||||
const db = openDb(':memory:');
|
||||
const queueId = addScheduledQueue(db);
|
||||
const logs = [];
|
||||
let sends = 0;
|
||||
|
||||
const result = await runOutreachBatch({
|
||||
db,
|
||||
whatsapp: {
|
||||
getStatus: () => ({ state: 'DISCONNECTED' }),
|
||||
sendText: async () => { sends += 1; }
|
||||
},
|
||||
now: new Date('2026-07-29T12:00:00.000Z'),
|
||||
log: (line) => logs.push(line)
|
||||
});
|
||||
|
||||
assert.deepEqual(result, { tentados: 0, enviados: 0, erros: 0, pulados: 0 });
|
||||
assert.equal(sends, 0);
|
||||
assert.equal(db.prepare('SELECT status FROM outreach_campaign_queue WHERE id = ?').get(queueId).status, 'scheduled');
|
||||
assert.match(logs[0], /nao esta conectado/i);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('runOutreachBatch nunca seleciona lead cru sem fila supervisionada', async () => {
|
||||
const db = openDb(':memory:');
|
||||
db.prepare(
|
||||
`INSERT INTO leads
|
||||
(dedup_key, empresa, whatsapp, segmento, telefone_valido, produto_principal)
|
||||
VALUES ('raw-lead', 'Lead Cru', '5511999990002', 'restaurantes', 1, 'G-Delivery')`
|
||||
).run();
|
||||
saveWhatsAppVerification(db, { numero: '5511999990002', status: 'confirmado' });
|
||||
const whatsapp = whatsappFake();
|
||||
|
||||
const result = await runOutreachBatch({
|
||||
db,
|
||||
whatsapp,
|
||||
now: new Date('2026-07-29T12:00:00.000Z'),
|
||||
log: () => {}
|
||||
});
|
||||
|
||||
assert.deepEqual(result, { tentados: 0, enviados: 0, erros: 0, pulados: 0 });
|
||||
assert.equal(whatsapp.sent.length, 0);
|
||||
assert.equal(db.prepare('SELECT COUNT(*) AS total FROM outreach_sends').get().total, 0);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('runOutreachBatch respeita cancelamento antes da reserva', async () => {
|
||||
const db = openDb(':memory:');
|
||||
const queueId = addScheduledQueue(db);
|
||||
const whatsapp = whatsappFake();
|
||||
const controller = new AbortController();
|
||||
controller.abort();
|
||||
|
||||
const result = await runOutreachBatch({
|
||||
db,
|
||||
whatsapp,
|
||||
now: new Date('2026-07-29T12:00:00.000Z'),
|
||||
signal: controller.signal,
|
||||
log: () => {}
|
||||
});
|
||||
|
||||
assert.deepEqual(result, { tentados: 0, enviados: 0, erros: 0, pulados: 0 });
|
||||
assert.equal(db.prepare('SELECT status FROM outreach_campaign_queue WHERE id = ?').get(queueId).status, 'scheduled');
|
||||
assert.equal(whatsapp.sent.length, 0);
|
||||
db.close();
|
||||
});
|
||||
Reference in New Issue
Block a user