fix(flow): suíte completa verde e rodando em toda PR (CRM-276) - #126
Conversation
…M-276) Três specs de nó (assign-agent, send-transcript, mute-conversation) constroem um nó que cria o CrmClientService no construtor, e ele estoura sem EVOAI_CRM_API_TOKEN antes do spec conseguir injetar o mock. Seguem o precedente do assign-bot.node.spec: a env de teste é setada antes do import, só quando estiver vazia. O campaigns.controller.spec esperava stop(campaignId, accountId), mas o CampaignsService.stop recebe um argumento e o controller chama com um. A asserção passa a refletir a assinatura real; o comportamento do stop não muda. Co-Authored-By: Claude Code <[EMAIL_REDACTED]>
…RM-276) Os workflows existentes rodam só guards pontuais e o build da imagem, então uma suíte quebrada em qualquer outro lugar entrava sem ninguém ver — foi assim que as quatro falhas corrigidas no commit anterior ficaram na develop. O job segue o molde dos demais (node 20, o mesmo do Dockerfile) e roda npx jest --ci. As suítes de integração (Kafka, RabbitMQ, Redis) continuam se desligando sozinhas sem as envs delas. Co-Authored-By: Claude Code <[EMAIL_REDACTED]>
Num runner de 2 vCPU o Jest usa cpus-1 = 1 worker e cai em modo in-band, onde handles abertos (o timer do CircuitBreaker não é limpo depois do Promise.race) o seguram por ~5 min depois do fim da suíte. Fixar dois workers deixa o tempo determinístico sem --forceExit, que esconderia o vazamento. A causa é código de produção e fica fora deste card. O cache: npm segue os workflows irmãos. Co-Authored-By: Claude Code <[EMAIL_REDACTED]>
O npm ci executa scripts de instalação de dependências de terceiros, e o checkout deixa o token gravado no .git/config. No push para develop/main o token herdaria a permissão padrão do repo; declarar contents: read tira essa dependência, no mesmo molde do docker-publish.yml. Co-Authored-By: Claude Code <[EMAIL_REDACTED]>
Reviewer's GuideThis PR makes the full Jest suite visible in CI for every PR and push to main/develop, with least-privilege permissions and a constrained worker count for predictable completion. It also fixes three specs by setting constructor-time CRM test configuration and aligns the campaign stop assertion with the actual one-argument API, without changing production code. Sequence diagram for constructor-time CRM test setupsequenceDiagram
participant Spec as Jest spec
participant Env as process.env
participant Module as Node module
participant CRM as CrmClientService
Spec->>Env: Set EVOAI_CRM_API_TOKEN
Spec->>Env: Set EVOAI_CRM_BASE_URL
Spec->>Module: import node
Module->>CRM: construct with test configuration
CRM-->>Module: initialized
Module-->>Spec: node available for tests
Flow diagram for the full Jest CI workflowflowchart LR
PR[Pull request]
PUSH[Push to main or develop]
CI[unit-tests workflow\nNode 20, contents read]
INSTALL[npm ci]
TEST[npx jest --ci\nmaxWorkers 2]
RESULT[Check passes or fails]
PR --> CI
PUSH --> CI
CI --> INSTALL
INSTALL --> TEST
TEST --> RESULT
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've reviewed your changes and they look great!
Sourcery assessment
Needs a human reviewer. The workflow executes pull-request code and dependency install scripts with a repository-scoped read token, so a malicious or misconfigured dependency could expose private repository contents; reverting the workflow would not undo any data already exfiltrated. Otherwise, test failures or an incorrect test setup would be ordinary CI issues that disappear on revert.
Summary
A suíte do evo-flow tinha 4 suítes falhando na
develophavia pelo menos um mês, e nenhum workflow rodava a suíte completa — então ninguém via. Os workflows existentes são guards pontuais e build de imagem.As 4 suítes voltam a passar (só specs, nenhum código de produção):
assign-agent,send-transcriptemute-conversation: esses nós criam oCrmClientServiceno construtor, e ele lança exceção semEVOAI_CRM_API_TOKENantes de o spec conseguir injetar o mock. Os specs agora setam a env de teste antes do import, com||=, seguindo o precedente deassign-bot.node.spec.ts. Os nós irmãos que passam criam o client sob demanda.campaigns.controller: a asserção esperavastop(campaignId, accountId), masCampaignsService.stoprecebe um argumento e o controller chama com um. A asserção reflete a assinatura real; o comportamento dostopnão muda.Novo workflow
unit-tests: rodanpx jest --ciem toda PR e push paramain/develop, no molde dos workflows existentes (node 20, o mesmo do Dockerfile). As suítes de integração (Kafka, RabbitMQ, Redis) continuam se desligando sozinhas sem as envs delas.A
developdeste repo está sem proteção de branch (nenhum check obrigatório, nenhum ruleset). O check novo fica vermelho quando a suíte quebra, então a regressão deixa de ser invisível, mas uma PR vermelha ainda pode ser mergeada. Para o check virar gate de verdade, alguém com admin precisa marcá-lo como obrigatório. Nenhum dos guards existentes é obrigatório hoje.Security
permissions: contents: readno workflow. Onpm ciexecuta scripts de instalação de terceiros e ocheckoutdeixa o token no.git/config, então no push paradevelopo token não herda a permissão padrão do repo. Segue o molde dodocker-publish.yml.--forceExit. Ele esconderia os handles abertos em vez de encerrá-los (ver abaixo).Test plan
Validado em container
node:20limpo, a versão da CI e não a da máquina (node 24), comnpm cido zero:exit=0, 143 suítes passando, 1126 testes passando e 0 falhas (antes eram 1122; os 4 a mais são os consertados).--maxWorkers=2:exit=0em 26 s.stoppara dois argumentos faznpx jest --cisair comexit=1, ou seja, o workflow reprova.Review independente (veredito aprovado) cobriu: 2 workers, in-band e ordem embaralhada com 3 sementes, tudo verde; mutações nos 3 specs de nó e no
stop, todas vermelhas. Também confirmou que nenhum spec testa a falta do token, então o||=não mascara nada.Por que
--maxWorkers=2: num runner de 2 vCPU o Jest usa 1 worker e cai em modo in-band. Ali, 26 handles abertos o seguram por uns 5 minutos depois do fim da suíte: continua verde, mas lento. O principal é umsetTimeoutdoCircuitBreakerque nunca é limpo depois doPromise.race. Fixar dois workers deixa o tempo previsível.Changed Files
.github/workflows/unit-tests.yml(novo)src/modules/campaigns/controllers/campaigns.controller.spec.tssrc/modules/temporal/activities/nodes/evoai/assignment/assign-agent.node.spec.tssrc/modules/temporal/activities/nodes/evoai/communication/send-transcript.node.spec.tssrc/modules/temporal/activities/nodes/evoai/conversation/mute-conversation.node.spec.tsFollow-ups (fora do escopo deste PR)
CircuitBreaker(src/modules/processing/resilience/circuit-breaker.ts:95): causa os handles abertos no fim da suíte.change-priority,resolve-conversation,snooze-conversationeassign-team. Os quatro criam o client no construtor, então vão bater na mesma armadilha quando alguém escrever o spec deles.stopde campanha não filtra por conta, nem ofindOne(id)por baixo. Já registrado no card de origem como fora do escopo.Linked Issue
CRM-276
🤖 Generated with Claude Code
Summary by Sourcery
Run the complete test suite in CI and restore the previously failing tests so regressions are visible on every pull request.
Bug Fixes:
CI:
Tests: