
Sua SPA está vazando memória: faça soak test
O problema: SPAs acumulam memória sem reset
Aplicações de página única (SPAs) nunca recarregam a página, então qualquer vazamento de memória - por menor que seja - cresce até a aba travar ou ser recarregada. Algumas equipes forçam um reload completo a cada poucas horas apenas para contornar o problema. Uma análise estática de 500 repositórios populares de React, Vue e Angular, publicada no início de 2026, encontrou que 86% deles registram algum listener, timer ou subscription sem nunca removê-lo.
O que é um soak test de frontend
No backend, soak tests já são prática estabelecida: scripts enviam tráfego simulado por horas e comparam o uso de memória ao final com a linha de base. O artigo propõe adaptar essa técnica ao frontend. A ideia é construir um fluxo de usuário que comece e termine na mesma tela, executá-lo em loop dentro de um único contexto de navegador e medir se a memória volta ao ponto de partida. O Playwright é a ferramenta escolhida por já estar presente na maioria dos projetos de testes end-to-end.
Métricas e coleta
A medição usa o Chrome DevTools Protocol (CDP), o que restringe a técnica a navegadores Chromium. Após duas chamadas de coleta de lixo (a segunda garante que nós DOM destacados sejam removidos da contagem), o teste lê três valores: tamanho do heap, quantidade de nós DOM e quantidade de event listeners. O heap oscila naturalmente entre execuções, então as asserções devem recair sobre os contadores de nós e listeners.
Estrutura do teste
A função soak() repete o fluxo 200 vezes. Antes de coletar a linha de base, executa cinco iterações de aquecimento para absorver o carregamento inicial de código e dados que só acontece uma vez. A asserção final verifica que o número de listeners não subiu e que o número de nós cresceu menos que um limite fixo (o autor usa 100, acima do ruído observado e muito abaixo do que um vazamento real produziria em 200 loops).
Timers e relógio falso
Timers não limpos representam quase 44% dos vazamentos encontrados na análise dos 500 repositórios. Como 200 loops em poucos minutos disparam muito menos timers do que uma hora de uso real, o artigo usa page.clock.install() e page.clock.pauseAt() do Playwright para controlar o relógio do navegador. Avançar 18 ou 30 segundos por iteração simula horas de polling em minutos.
Mock de rede
Quando um poller encadeia setTimeout() após cada resposta, o relógio falso sozinho não basta: a resposta real chega em tempo real e dessincroniza o fluxo. A solução é interceptar as rotas com page.route() e retornar respostas idênticas às da API de produção, esperando cada resposta antes de avançar o relógio. Para web sockets, page.routeWebSocket() cumpre o mesmo papel. Respostas em streaming (como as de interfaces de IA) permanecem um caso difícil, pois route.fulfill() não permite envio em partes.
Diagnóstico e ferramenta
Quando o teste falha, a localização do vazamento ainda exige heap snapshots no DevTools, filtrando por nós "Detached" e inspecionando os retainers. O autor empacotou a técnica no pacote playwright-soak-test, disponível como fixture do Playwright.
Conclusão
O soak test de frontend detecta vazamentos antes que usuários os encontrem em produção. O autor defende que performance deve ser responsabilidade do time inteiro, não de uma pessoa, e vincula a prática ao conceito "Fast by Default" de seu livro homônimo.