Files
COMERCIAL-GTI/tests/campaign-messages.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

212 lines
9.4 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
managementFocus,
naturalBusinessName,
renderCampaignMessage,
variantForLead
} from '../src/outreach/campaign-messages.mjs';
const refusal = 'Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.';
const approvedCases = [
{
segment: 'restaurantes',
template: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Hoje voces controlam {foco_gestao} em um unico sistema? ${refusal}`,
expected: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Hoje voces controlam vendas, estoque, comandas e emissão fiscal em um unico sistema? ${refusal}`
},
{
segment: 'restaurantes',
template: `Ola! Aqui e Gustavo, do Grupo GTI. Trabalhamos com gestao para empresas de Santo Antonio de Jesus e regiao. Como voces organizam hoje {foco_gestao}? ${refusal}`,
expected: `Ola! Aqui e Gustavo, do Grupo GTI. Trabalhamos com gestao para empresas de Santo Antonio de Jesus e regiao. Como voces organizam hoje vendas, estoque, comandas e emissão fiscal? ${refusal}`
},
{
segment: 'restaurantes',
template: `Ola, tudo bem? Sou Gustavo, do Grupo GTI. Ha mais de 7 anos atendemos empresas da regiao e ja temos mais de 100 clientes. Voces utilizam algum sistema para {foco_gestao}? ${refusal}`,
expected: `Ola, tudo bem? Sou Gustavo, do Grupo GTI. Ha mais de 7 anos atendemos empresas da regiao e ja temos mais de 100 clientes. Voces utilizam algum sistema para vendas, estoque, comandas e emissão fiscal? ${refusal}`
},
{
segment: 'pizzarias',
template: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Queria entender como voces recebem os pedidos de delivery hoje: possuem um canal proprio ou dependem de aplicativos que cobram comissao? ${refusal}`,
expected: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Queria entender como voces recebem os pedidos de delivery hoje: possuem um canal proprio ou dependem de aplicativos que cobram comissao? ${refusal}`
},
{
segment: 'pizzarias',
template: `Ola! Aqui e Gustavo, do Grupo GTI. Voces ja possuem um link proprio para receber pedidos, sem pagar comissao por venda a aplicativos? ${refusal}`,
expected: `Ola! Aqui e Gustavo, do Grupo GTI. Voces ja possuem um link proprio para receber pedidos, sem pagar comissao por venda a aplicativos? ${refusal}`
},
{
segment: 'pizzarias',
template: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Trabalho com uma solucao de pedidos online por canal proprio e queria primeiro entender como funciona o delivery de voces hoje. ${refusal}`,
expected: `Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Trabalho com uma solucao de pedidos online por canal proprio e queria primeiro entender como funciona o delivery de voces hoje. ${refusal}`
}
];
test('nome natural aceita marcas curtas com pelo menos duas letras', () => {
assert.equal(naturalBusinessName({ empresa: 'OX' }), 'OX');
assert.equal(naturalBusinessName({ empresa: 'BR2' }), 'BR2');
assert.equal(naturalBusinessName({ empresa: 'Pizzaria Central' }), 'Pizzaria Central');
});
test('nome natural rejeita identificadores, nomes legais, controles, placeholders e ruido generico', () => {
const rejected = [
'',
'7',
'7 Mares',
'61.590.668 A ARAUJO',
'12.345.678/0001-90',
'A ARAUJO LTDA',
'Loja Sol MEI',
'Loja Sol ME',
'Loja Sol EPP',
'Loja Sol EIRELI',
'Loja Sol S/A',
'Loja\nSol',
'Loja\u0000Sol',
'Loja\u200bSol',
'Loja {nome}',
'Loja {{nome}}',
'Empresa',
'Nome Fantasia',
'Nao informado',
'Comercio',
'Pizzaria Central com um nome comercial excessivamente longo para uma saudacao natural e segura'
];
for (const empresa of rejected) {
assert.equal(naturalBusinessName({ empresa, legal_name: 'A ARAUJO LTDA' }), '', empresa);
}
});
test('foco de gestao segue os quatro grupos aprovados', () => {
assert.equal(managementFocus('restaurantes'), 'vendas, estoque, comandas e emissão fiscal');
assert.equal(managementFocus('mercados_de_bairro'), 'vendas, estoque e emissão fiscal');
assert.equal(managementFocus('oficinas_mecanicas'), 'ordens de serviço, estoque e financeiro');
assert.equal(managementFocus('lojas_de_roupa'), 'vendas, estoque, financeiro e notas fiscais');
});
test('variante permanece estavel e considera apenas variantes ativas', () => {
const variants = [{ code: 'A', ativo: 1 }, { code: 'B', ativo: 1 }, { code: 'C', ativo: 1 }];
assert.equal(variantForLead(variants, 4).code, 'B');
assert.equal(variantForLead(variants, 4).code, 'B');
assert.equal(variantForLead([{ code: 'A', ativo: 0 }, ...variants.slice(1)], 4).code, 'B');
assert.throws(() => variantForLead([], 4), /variante ativa/i);
});
test('variante usa a ordem ativa mesmo com ids nao contiguos', () => {
const variants = [
{ id: 8, code: 'A', ativo: 1 },
{ id: 37, code: 'B', ativo: 1 },
{ id: 104, code: 'C', ativo: 1 }
];
assert.equal(variantForLead(variants, 4), variants[1]);
});
test('variante rejeita array nao vazio quando todas estao inativas', () => {
assert.throws(() => variantForLead([
{ id: 8, code: 'A', ativo: 0 },
{ id: 37, code: 'B', ativo: false }
], 4), /variante ativa/i);
});
test('renderizacao preserva os seis textos aprovados fora das substituicoes permitidas', () => {
for (const { segment, template, expected } of approvedCases) {
assert.equal(renderCampaignMessage(template, {
empresa: '61.590.668 A ARAUJO',
legal_name: 'A ARAUJO LTDA',
segmento: segment
}), expected);
}
});
test('renderizacao personaliza somente a saudacao inicial com nome natural', () => {
const template = approvedCases[0].template;
const rendered = renderCampaignMessage(template, {
empresa: 'Pizzaria Central',
segmento: 'restaurantes'
});
assert.equal(rendered, `Olá, pessoal da Pizzaria Central, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Hoje voces controlam vendas, estoque, comandas e emissão fiscal em um unico sistema? ${refusal}`);
});
test('validacao aceita texto portugues legitimo sem remover diacriticos', () => {
const template = `Olá, tudo bem? Sou Gustavo, do Grupo GTI. Gestão ágil para comércio. Se não fizer sentido para sua empresa, é só me avisar que não volto a entrar em contato.`;
assert.equal(renderCampaignMessage(template, { empresa: '', segmento: 'lojas_de_roupa' }), template);
const punctuation = `Olá, tudo bem? Sou Gustavo, do Grupo GTI. Gestão simples (vendas/estoque), ágil e segura. Se não fizer sentido para sua empresa, é só me avisar que não volto a entrar em contato.`;
assert.equal(renderCampaignMessage(punctuation, { empresa: '' }), punctuation);
});
test('validacao rejeita placeholders simples ou duplos que restarem no texto', () => {
const safe = `Ola, tudo bem? Sou Gustavo, do Grupo GTI. ${refusal}`;
const placeholders = [
'{produto}',
'{{produto_2}}',
'{ produto }',
'{produto-nome}',
'{123}',
'{{ produto }}',
'{{produto-nome}}',
'{{123}}'
];
for (const placeholder of placeholders) {
const template = safe.replace('Grupo GTI.', `Grupo GTI. ${placeholder}`);
assert.throws(() => renderCampaignMessage(template, {}), /mensagem inicial insegura/i, placeholder);
}
});
test('validacao de placeholders preserva portugues normal sem chaves', () => {
const template = `Olá, tudo bem? Sou Gustavo, do Grupo GTI. Produto 123 - nome e gestão simples. Se não fizer sentido para sua empresa, é só me avisar que não volto a entrar em contato.`;
assert.equal(renderCampaignMessage(template, {}), template);
});
test('validacao rejeita localhost, enderecos IP e caminhos absolutos', () => {
const safe = `Ola, tudo bem? Sou Gustavo, do Grupo GTI. ${refusal}`;
const addresses = [
'localhost',
'localhost:3000/agenda',
'127.0.0.1',
'192.168.0.1:8080/agenda',
'[::1]',
'[2001:db8::1]:8080/agenda',
'2001:db8::1',
'/agenda/demonstracao'
];
for (const address of addresses) {
const template = safe.replace('Grupo GTI.', `Grupo GTI. ${address}`);
assert.throws(() => renderCampaignMessage(template, {}), /mensagem inicial insegura/i, address);
}
});
test('renderizacao e selecao nao alteram os objetos de entrada', () => {
const template = { mensagem: approvedCases[0].template };
const lead = { empresa: 'Pizzaria Central', segmento: 'restaurantes' };
const variants = [{ id: 8, code: 'A', ativo: 0 }, { id: 37, code: 'B', ativo: 1 }];
const before = structuredClone({ template, lead, variants });
renderCampaignMessage(template, lead);
variantForLead(variants, 7);
assert.deepEqual({ template, lead, variants }, before);
});
test('validacao rejeita URL, CNPJ, preco e requisitos obrigatorios ausentes', () => {
const safe = `Ola, tudo bem? Sou Gustavo, do Grupo GTI. ${refusal}`;
const unsafe = [
safe.replace('Grupo GTI.', 'Grupo GTI. https://gti.example'),
safe.replace('Grupo GTI.', 'Grupo GTI. gti.com.br'),
safe.replace('Grupo GTI.', 'Grupo GTI. 12.345.678/0001-90'),
safe.replace('Grupo GTI.', 'Grupo GTI. 12345678000190'),
safe.replace('Grupo GTI.', 'Grupo GTI. R$ 99'),
safe.replace('Gustavo', 'Consultor'),
safe.replace('Grupo GTI', 'nossa empresa'),
safe.replace(` ${refusal}`, '')
];
for (const template of unsafe) {
assert.throws(() => renderCampaignMessage(template, { empresa: '' }), /mensagem inicial insegura/i);
}
});