Skip to content

fix(flow): suíte completa verde e rodando em toda PR (CRM-276) - #126

Merged
gomessguii merged 4 commits into
developfrom
fix/CRM-276-suite-verde-e-ci
Sep 25, 2026
Merged

gomessguii merged 4 commits into
developfrom
fix/CRM-276-suite-verde-e-ci

Conversation

@nickoliveira23

@nickoliveira23 nickoliveira23 commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A suíte do evo-flow tinha 4 suítes falhando na develop havia 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-transcript e mute-conversation: esses nós criam o CrmClientService no construtor, e ele lança exceção sem EVOAI_CRM_API_TOKEN antes de o spec conseguir injetar o mock. Os specs agora setam a env de teste antes do import, com ||=, seguindo o precedente de assign-bot.node.spec.ts. Os nós irmãos que passam criam o client sob demanda.
  • campaigns.controller: a asserção esperava stop(campaignId, accountId), mas CampaignsService.stop recebe um argumento e o controller chama com um. A asserção reflete a assinatura real; o comportamento do stop não muda.

Novo workflow unit-tests: roda npx jest --ci em toda PR e push para main/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.

⚠️ O check reprova, mas ainda não bloqueia o merge

A develop deste 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: read no workflow. O npm ci executa scripts de instalação de terceiros e o checkout deixa o token no .git/config, então no push para develop o token não herda a permissão padrão do repo. Segue o molde do docker-publish.yml.
  • Não uso --forceExit. Ele esconderia os handles abertos em vez de encerrá-los (ver abaixo).

Test plan

Validado em container node:20 limpo, a versão da CI e não a da máquina (node 24), com npm ci do zero:

  • Suíte completa 3 vezes seguidas: resultado idêntico nas três, com exit=0, 143 suítes passando, 1126 testes passando e 0 falhas (antes eram 1122; os 4 a mais são os consertados).
  • Com --maxWorkers=2: exit=0 em 26 s.
  • Mutação: voltar a asserção do stop para dois argumentos faz npx jest --ci sair com exit=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 é um setTimeout do CircuitBreaker que nunca é limpo depois do Promise.race. Fixar dois workers deixa o tempo previsível.

Changed Files

  • .github/workflows/unit-tests.yml (novo)
  • src/modules/campaigns/controllers/campaigns.controller.spec.ts
  • src/modules/temporal/activities/nodes/evoai/assignment/assign-agent.node.spec.ts
  • src/modules/temporal/activities/nodes/evoai/communication/send-transcript.node.spec.ts
  • src/modules/temporal/activities/nodes/evoai/conversation/mute-conversation.node.spec.ts

Follow-ups (fora do escopo deste PR)

  • Timer não limpo no CircuitBreaker (src/modules/processing/resilience/circuit-breaker.ts:95): causa os handles abertos no fim da suíte.
  • Quatro nós sem teste: change-priority, resolve-conversation, snooze-conversation e assign-team. Os quatro criam o client no construtor, então vão bater na mesma armadilha quando alguém escrever o spec deles.
  • O stop de campanha não filtra por conta, nem o findOne(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:

  • Restore the failing campaign controller and EvoAI node test suites so the complete Jest suite passes reliably.

CI:

  • Add a GitHub Actions workflow that runs the complete Jest suite on pull requests and pushes to the main and develop branches with a read-only repository token.

Tests:

  • Update test setup to provide the CRM client configuration required during node construction and align the campaign stop expectation with the controller contract.

…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]>
@sourcery-ai

sourcery-ai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

This 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 setup

sequenceDiagram
    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
Loading

Flow diagram for the full Jest CI workflow

flowchart 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
Loading

File-Level Changes

Change Details Files
Adds a CI workflow that executes the complete Jest suite on pull requests and pushes to the primary branches.
  • Runs on Node.js 20 with npm dependency caching and a 15-minute timeout.
  • Restricts workflow permissions to read-only repository contents.
  • Executes the suite with two Jest workers to avoid slow shutdown from open handles on small runners.
.github/workflows/unit-tests.yml
Restores three node specs that failed during construction because required CRM configuration was absent.
  • Initializes fallback CRM token and base URL environment variables before importing each node module.
  • Uses
Corrects the campaign stop unit-test expectation to match the controller and service method signature.
  • Verifies that stop is called with only the campaign ID.
  • Leaves controller and production stop behavior unchanged.
src/modules/campaigns/controllers/campaigns.controller.spec.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@gomessguii
gomessguii merged commit 4073413 into develop Sep 25, 2026
9 checks passed
@gomessguii
gomessguii deleted the fix/CRM-276-suite-verde-e-ci branch September 25, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants