@zapo-js/fake-server é um servidor WhatsApp Web falso in-process que fala Noise XX/IK, X3DH + Double Ratchet, SenderKey de grupo, sincronização de app-state e upload/download de mídia sobre HTTPS auto-assinado — tudo o que um client conforme real vê no wire. Ele existe para você testar seu app end-to-end sem tocar no WhatsApp: sem número real ocupado, sem risco pra conta de produção, sem flakiness de rede real, CI-friendly.
Este guia tem como público autores de app — bots, CRMs, serviços de notificação, integrações — independente de a lib WhatsApp abaixo ser
zapo-js, Baileys, whatsmeow ou outro client conforme. Para o uso interno da lib (suíte cross-check, benchmarks) veja Dev tools.Funciona com qualquer lib WhatsApp
O fake server é uma implementação em nível de wire do protocolo WhatsApp. Não tem dependência de runtime emzapo-js — fala os mesmos bytes de Noise / Signal / app-state que os edges do próprio WhatsApp. Clients estritos (forks de Baileys, whatsmeow, entre outros) funcionam contra ele de saída:
- A cadeia de cert Noise define
notBefore/notAfterpara clients que validam validade aceitarem como não-expirado. - O IQ de passive-set e a query
<count>de prekey no encrypt são respondidos por default (clients não-zapobloqueiam nos dois). - Após todo login o server envia
<ib><offline count="0"/></ib>para clients de evento bufferizado darem flush. - Ids de mensagem do
FakePeersão hex WA-style — sem@que decoders binários estritos tokenizariam como JID.
Instalação
zapo-js é peer dependency do fake server (importa as primitivas de Noise / Signal / crypto / proto por baixo em runtime), então precisa estar presente na árvore mesmo quando seu app é construído em cima de outra lib WhatsApp. Node.js >= 20.9.0.
Início rápido (programático)
A ligaçãozapo-js abaixo é como um app zapo-js se parece; para Baileys / whatsmeow, mantenha seu setup de client existente e sobrescreva apenas a URL do socket, o proxy de mídia e o Noise root CA para apontar pro fake server.
testHooks.noiseRootCa confia no certificado do fake server sem burlar a verificação — a checagem completa da cadeia continua rodando.
Desde o
@zapo-js/fake-server 1.3.1 o servidor envia stream:error 515 depois que um companion responde o pair-success, exatamente como o real faz, então um client sob teste reinicia pelo sinal do servidor em vez de por timeout. Testes de pareamento escritos contra um fake server mais antigo podem ter passado pelo motivo errado — veja Depois que o telefone aceita.Pinning entre processos
listen() gera um root CA aleatório novo a cada start e expõe a metade pública em server.noiseRootCa — perfeito pro teste in-process acima, onde o client é construído depois que o server já está escutando. Um client num processo separado precisa pinnar o trust anchor antes de discar, e nesse ponto o server ainda não está escutando: não tem nada pra ler.
Passe um noiseRootCa derivado de uma seed compartilhada, então os dois lados calculam o mesmo CA de antemão:
FakeNoiseRootCa carrega a metade de assinatura — o server precisa dela pra assinar a cert chain — enquanto o client sempre só segura a contraparte pública. Ela assina uma chain que nenhum client WhatsApp real confia, então é material de teste e não segredo de verdade, mas uma seed commitada junto dos testes é a fonte pretendida, não uma compartilhada com algo que importe. Omitir a opção mantém o comportamento anterior: um CA aleatório novo por listen().
Simulando um peer
createFakePeer te dá um contato simulado com cripto Signal real. Empurre mensagens pro seu client com sendConversation / sendGroupConversation, e capture o que o seu client envia com expectMessage:
Validando stanzas outbound
Para asserts que não precisam do ponto de vista de um peer (um<presence> que seu app enviou, um <receipt> que ele ackeou, um IQ que ele fez) inscreva-se em stanzas capturadas:
onCapturedStanza retorna uma função de unsubscribe; chame em afterEach para manter os testes isolados.
Isolamento multi-sessão
Rode muitas instâncias de app contra um único server sem cross-talk. Forneça um resolversessionKey — o fake server roteia cada conexão autenticada pro próprio FakeServerSession (peers, grupos, prekeys, app-state, stanzas capturadas isolados):
info.clientPayload está disponível para chavear por identidade de login. Handlers server-wide (server.registerIqHandler) continuam aplicando a toda sessão; os escopados por sessão (session.registerIqHandler) ficam locais.
Mobile-primary + companion hosting
Para testar uma sessão mobile-primary — o papel doclient.mobile, onde o zapo hospeda companions — inicie o server com o listener TCP raw que o transporte mobile disca, e semeie um primary registrado no store. O registro mobile acontece out-of-band contra os endpoints HTTP do WhatsApp, então o fake server não consegue rodá-lo; o seedFakeMobilePrimary grava as credentials diretamente.
server.offerCompanionPairing(companionPipeline) — o inverso do runPairing. O primary assina a identidade de verdade; o server só relay:
client.mobile.linkCompanion / linkCompanionByCode — assinatura, ADV epoch, republish da key-index list, evento companion_host_linked — end to end.
Pareamento por código roda entre os dois clients com o server no meio; o fake server relay cada estágio.
parseClientPayload no pipeline classifica o login como web ou mobile e expõe a identidade do phone (manufacturer, model, os, app version, phone id) pra asserts.Config programática
FakeWaServer.start(options) aceita:
onPipeline(listener) fanout pra múltiplos subscribers e retorna uma função de unsubscribe; o clientPayload parseado da pipeline é exposto em WaFakeConnectionPipeline pra checagens de identidade. IQ handlers podem retornar null pra fall through pro próximo handler que casa (observe-then-delegate).
CLI standalone
O pacote traz um bináriofake-wa-server. Rode uma vez que a dev dep estiver instalada:
--pair <jid> conduz o pareamento QR pedindo no stdin o payload QR que o client mostra — pareie uma vez, depois reconecte contra o mesmo fake server para iterar.
Recipe de CI
Suba um server por arquivo de teste (ou por suíte), derrube no final. Providersmemory no client mantêm cada teste hermético:
Combine o fake server com stores in-memory no client. Cada teste reseta — sem estado de pareamento vazando, sem malabarismo de fixture em disco.
Veja também
Dev tools
Benchmarks, suíte cross-check e o MCP dev-server — tooling interno da lib.
README do fake server
Referência completa de CLI e superfície de API.
