Pular para o conteúdo
Development

O bug que meus testes unitários jamais poderiam ter encontrado

Por Victor Da Luz
sveltetestingtauridev-loggreenhouse

Lancei uma visualização em quadro kanban para o Greenhouse essa semana, e a parte interessante não é o quadro, é um bug que minha suíte de testes inteira deixou passar direto, e como eu encontrei ele mesmo assim.

A funcionalidade

O dashboard do Greenhouse tem uma zona “Worklist”: todo projeto ativo numa lista só, o mais negligenciado primeiro. O pedido era uma alternativa estilo kanban, colunas por estágio do pipeline (Select, Explore, Shape…) para você ver a distribuição de relance. Eu limitei o escopo antes de escrever qualquer código: somente leitura (avançar um projeto ainda passa pelo diálogo de confirmação existente, sem drag-and-drop), uma visualização nova ao lado da Worklist em vez de uma substituição, só projetos ativos. Nada disso foi chute, a própria issue já sinalizava essas questões como em aberto, então resolvi elas de saída em vez de presumir.

O lado dos dados acabou não precisando de nenhuma mudança no backend. Uma correção anterior já tinha unificado a antiga divisão entre cooling/available numa worklist só e completa, então todo projeto ativo com seu estágio de pipeline já estava ali, nos dados que o dashboard já buscava. Agrupar por estágio é um filtro de uma linha.

O atalho que parecia grátis

Foi aqui que ficou interessante. O componente do dashboard já mantém o estado diário completo em memória, ideias capturadas, revisão do vault, a worklist, tudo. Meu componente novo do quadro precisava de exatamente uma fatia disso: a worklist. Então fiz o óbvio e passei ela para baixo como prop, em vez de buscar de novo. Parecia uma otimização limpa, por que fazer uma segunda ida e volta de rede para dados que o componente pai já tinha ali mesmo?

Compilou. Passou na checagem de tipos. Todo teste de componente com IPC mockado passou, porque esses testes entregam a worklist diretamente para o componente, não tem como um teste desses expressar “a cópia disso que o pai tem agora está desatualizada.”

O que pegou o bug

Nessa base de código, eu não confio só na suíte de testes mockados para UI nova, também dirijo o app compilado de verdade por uma sessão real de WebDriver, cliques reais, chamadas reais de backend, nenhum mock em nenhum ponto do fluxo. Para esse caso, semeei um projeto ativo novo direto via IPC (ignorando a UI completamente, do mesmo jeito que um script faria), e então cliquei em “Board view.”

Coluna vazia. Zero projetos aparecendo, quando deveria ter um.

O dashboard já tinha buscado seu estado diário uma vez, no próprio momento de montagem, antes mesmo da chamada IPC do meu script acontecer. Meu componente do quadro estava fielmente renderizando uma prop que tinha ficado desatualizada no instante em que novos dados passaram a existir em qualquer outro lugar. No uso real do dia a dia, essa sequência exata não pode acontecer, porque todo botão real da UI que muda a worklist já atualiza a cópia do dashboard depois. Mas esse é justamente o problema: a corretude do quadro dependia silenciosamente de toda funcionalidade futura lembrar de manter essa cadeia de atualização intacta. Nada obriga isso. É o tipo de suposição que se sustenta hoje e quebra daqui a seis meses, quando alguém adiciona um novo caminho de mutação e não sabe que essa prop específica está contando com ela.

A correção de fato

Voltei e olhei como as outras duas visualizações de tela cheia desse app já lidam exatamente com esse formato de problema, uma visualização de detalhes de projeto e um navegador de vault, ambas trocando no mesmo slot do layout. As duas buscam os próprios dados na montagem, toda vez, independente do que o pai já tinha carregado. Eu tinha silenciosamente desviado de um padrão estabelecido porque reutilizar a prop parecia eficiência de graça, e paguei por isso com um bug de verdade.

A correção foi apagar a prop e dar ao quadro sua própria busca, alinhando com o que as outras duas visualizações já fazem. Tem um efeito colateral bom: como o Svelte desmonta e reconstrói esse componente toda vez que ele entra e sai de vista, voltar ao quadro depois de editar um projeto em outro lugar mostra os dados atuais automaticamente, sem precisar conectar nenhuma atualização manual em lugar nenhum.

A lição

Um teste mockado só pode ser tão honesto quanto o mock. Se você entrega ao teste de um componente exatamente os dados que espera que ele receba, o teste vai confirmar que o componente exibe exatamente esses dados, e não diz nada sobre se esses dados ainda são verdadeiros no momento em que um usuário real os vê. A lacuna só aparece quando algo dirige o app de verdade com um backend de verdade que pode mudar por baixo da UI no meio de uma sessão. Vale lembrar disso na próxima vez que reutilizar uma prop que o pai já carregou parecer uma vitória de graça em vez de buscar de novo.

Leitura relacionada

Você também pode achar útil

AdGuard

AdGuard para iOS

Bloqueio de anúncios e rastreadores em todo o sistema no iOS, sem necessidade de um servidor DNS separado.

Como afiliado da AdGuard, ganho com compras qualificadas.

Saiba mais
RackNerd

RackNerd VPS

Hospedagem VPS econômica para serviços leves que funcionam continuamente.

Como afiliado da RackNerd, ganho com compras qualificadas.

Saiba mais
Proton

Proton Drive

Armazenamento em nuvem criptografado, da equipe por trás do Proton Mail.

Como parceiro da Proton, ganho com compras qualificadas dos serviços de privacidade e segurança da Proton (Pass, Mail, VPN, Drive).

Saiba mais