Desenvolvimento e IA Aplicada · Tutorial

Como testar links internos e rotas automaticamente

Um link quebrado raramente avisa que quebrou. Veja como transformar a checagem de links e rotas em um teste que roda depois de cada build e falha antes de o erro chegar ao leitor.

Editor responsável:
Daniel Ferreira

Publicado em · 6 min de leitura

Também disponível em: English

Em três pontos

  • Teste o site gerado, não o código-fonte: é no HTML final que links, rotas e metadados existem de fato.
  • Ferramentas prontas, como lychee e linkinator, resolvem links quebrados; um script próprio cobre regras do seu site, como canonical e hreflang.
  • O teste só protege se rodar sempre e falhar de verdade: código de saída diferente de zero, em toda publicação.

Você renomeia um artigo, muda o slug e publica. A página nova funciona. As cinco páginas que apontavam para o endereço antigo agora levam a um erro 404, e ninguém percebe até um leitor reclamar.

Esse tipo de falha é silencioso porque o build, a etapa que gera o site, costuma terminar sem erro. Este tutorial mostra como criar uma checagem automática de links internos e rotas para um site estático, com exemplos em Astro, e termina com o caso do próprio Token & Tech.

O que exatamente testar

Antes da ferramenta, defina o que conta como erro. Para um site estático, cinco verificações cobrem a maior parte dos problemas:

  1. Links internos. Todo href e src que aponta para o próprio site leva a um arquivo que existe.
  2. Rotas esperadas. Toda página que deveria existir foi gerada. A lista de referência mais prática é o sitemap, o arquivo XML que lista as URLs do site para os buscadores. Pelo protocolo oficial, cada URL fica numa tag <loc> e precisa ser completa, começando pelo protocolo (https://).
  3. Barra final. O formato do endereço é consistente (/artigo/ ou /artigo, não os dois).
  4. Canonical. A tag rel="canonical" indica qual URL representa a página quando há versões duplicadas. O Google a trata como “sinal forte” e recomenda usar endereços absolutos (Google Search Central).
  5. Hreflang, em sites multilíngues. Cada versão de idioma deve listar a si mesma e todas as outras. Segundo o Google, se duas páginas não apontam uma para a outra, as tags são ignoradas.

As duas primeiras são universais. As três últimas dependem das regras do seu site, e é aí que um script próprio costuma fazer falta.

Passo 1: gere o site e teste a saída

Teste o resultado do build, não os arquivos de origem. Um link escrito em Markdown pode virar outro endereço depois de passar por componentes, layouts e plugins. O que o leitor recebe é o HTML final.

No Astro, astro build grava o site em dist/. Com a opção build.format: "directory", que é o padrão, cada página vira uma pasta com um index.html: /sobre vira /sobre/index.html (referência de configuração). Isso torna a checagem simples: para saber se /sobre/ existe, basta conferir se o arquivo dist/sobre/index.html existe.

A mesma referência recomenda combinar esse formato com trailingSlash: "always", para que o servidor de desenvolvimento e o build se comportem igual. Há uma ressalva: em páginas pré-renderizadas, quem trata a barra final é a hospedagem, que pode não seguir essa configuração. Por isso vale testar a barra final explicitamente.

Passo 2: comece com uma ferramenta pronta

Para links quebrados, há ferramentas de código aberto maduras. Duas opções, com comandos tirados da documentação de cada uma:

lychee. Verificador de links escrito em Rust, que lê HTML e Markdown. O README do projeto documenta as opções úteis aqui: --offline checa só arquivos locais e bloqueia acesso à rede; --root-dir indica a pasta usada para resolver links absolutos, como /pt-br/, e precisa ser um caminho absoluto. Um uso possível:

lychee --offline --root-dir "$PWD/dist" --no-progress dist

O lychee termina com código de saída 2 quando ao menos um link falha, o que basta para interromper uma automação. Há também uma action oficial para GitHub (lycheeverse/lychee-action).

linkinator. Ferramenta em Node.js com linha de comando e API. Segundo o README, ao receber uma pasta local ela sobe um servidor temporário e navega pelo site como se estivesse publicado. A opção --recurse segue os links do mesmo domínio:

npx linkinator ./dist --recurse

Ela aceita --skip com expressões regulares para ignorar endereços e tem opções de nova tentativa para respostas 429 e 5xx, úteis quando você também checa links externos.

Uma recomendação da redação: separe links internos de externos. Links internos devem passar sempre, e o teste pode ser rígido. Links externos dependem de servidores de terceiros, que caem, bloqueiam robôs ou limitam requisições. Checá-los com a mesma rigidez gera falhas que não são suas. Rode-os em outra tarefa, com cache e novas tentativas, e sem bloquear a publicação.

Passo 3: teste as rotas com o site servido

Um arquivo existir em dist/ não prova que o servidor o entrega com status 200. Para testar o comportamento de servidor, sirva o build e faça requisições de verdade.

O comando astro preview sobe um servidor local com o conteúdo de dist/, por padrão na porta 4321. A documentação avisa que ele não foi feito para produção (referência da CLI), o que não é problema num teste.

Com o Playwright, uma biblioteca de testes que controla navegadores, você pode percorrer o sitemap e conferir o status de cada rota. Um cuidado: segundo a documentação do page.goto, o método não lança erro quando o servidor responde com um status HTTP válido, incluindo 404 e 500. Você precisa conferir o status explicitamente:

import { test, expect } from "@playwright/test";
import { readFileSync } from "node:fs";

const paths = [...readFileSync("dist/sitemap.xml", "utf8").matchAll(/<loc>([^<]+)<\/loc>/g)]
  .map((m) => new URL(m[1]).pathname);

for (const path of paths) {
  test(`rota ${path}`, async ({ page }) => {
    const res = await page.goto(`http://localhost:4321${path}`);
    expect(res?.status()).toBe(200);
  });
}

Esse teste é mais lento que a checagem de arquivos, porque abre um navegador. Para centenas de rotas, rode-o só sobre uma amostra ou só no pipeline principal.

Passo 4: escreva as regras que só o seu site tem

Ferramentas genéricas não sabem que a sua canonical deve ser igual à URL do sitemap, que cada página deve ter exatamente um H1 ou que o hreflang precisa ser recíproco. Essas regras cabem num script curto que lê os arquivos de dist/ e falha se encontrar problema.

A estrutura básica tem três partes: carregar a lista de URLs do sitemap, abrir o HTML de cada uma e acumular os erros. No fim, se houver erro, o script imprime a lista e sai com código 1. Esse detalhe é o que faz o teste funcionar: um script que só imprime avisos é ignorado em poucas semanas.

Caso documentado: o verificador do Token & Tech

O site que você está lendo é feito em Astro e tem um verificador próprio, que roda sobre o resultado do build: scripts/check-dist.mjs, chamado por npm run check. Ele não usa dependências externas, só módulos nativos do Node.js.

Para cada URL do sitemap, o script confere que o arquivo existe, que há <html lang>, título, descrição, uma única tag H1 e imagem de compartilhamento, e que a canonical é igual à própria URL. Depois, cruza os hreflang: cada página precisa se citar, ter x-default e receber o link de volta de cada versão que ela cita.

A checagem de links percorre todos os HTML gerados. O trecho central, resumido:

for (const m of h.matchAll(/(?:href|src)="(\/[^"#?]*)[^"]*"/g)) {
  const p = m[1];
  if (!p.endsWith("/")) { errors.push(`${rel}: internal link without trailing slash ${p}`); continue; }
  if (p !== "/" && !existsSync(fileFor(p))) errors.push(`${rel}: broken link ${p}`);
}

Arquivos com extensão, como imagens, são conferidos à parte. Um link interno sem barra final também conta como erro, o que mantém o formato de endereço consistente.

Há um detalhe de processo. O site publica artigo por artigo, e um texto pode citar outro que ainda não está no ar. Para isso, um passo anterior (scripts/postbuild.mjs) transforma em texto simples os links do corpo dos artigos que apontam para páginas inexistentes em dist/. Quando o artigo citado é publicado, o próximo build restaura o link, sem mexer no texto original. O verificador roda depois e, se ainda sobrar algum link quebrado no HTML, termina com código de saída 1 e lista o problema.

A outra metade da prevenção está antes do build: o schema das coleções, que valida o conteúdo de cada artigo, descrito em Content Collections do Astro.

O que levar deste texto

  • Teste dist/, não o código-fonte. Use o sitemap como lista de rotas esperadas.
  • Comece com lychee ou linkinator para links quebrados. Escreva um script só para as regras próprias do site.
  • Separe links internos (rígidos, bloqueiam a publicação) de externos (com cache e novas tentativas, sem bloquear).
  • Garanta que o teste falhe de verdade, com código de saída diferente de zero, e que rode em toda publicação.

Divulgação: O site do Token & Tech é construído com Astro e usa as técnicas descritas aqui.

Fontes

  1. sitemaps.org - Protocol, sitemaps.org. Acesso em 8 de outubro de 2026
  2. Configuration Reference, Astro Docs. Acesso em 8 de outubro de 2026
  3. CLI Commands, Astro Docs. Acesso em 8 de outubro de 2026
  4. lycheeverse/lychee (README), lycheeverse (GitHub). Acesso em 8 de outubro de 2026
  5. JustinBeckwith/linkinator (README), Justin Beckwith (GitHub). Acesso em 8 de outubro de 2026
  6. Page | Playwright (page.goto), Playwright. Acesso em 8 de outubro de 2026
  7. How to specify a canonical URL with rel="canonical" and other methods, Google Search Central. Acesso em 8 de outubro de 2026
  8. Tell Google about localized versions of your page, Google Search Central. Acesso em 8 de outubro de 2026

Leia também

Desenvolvimento e IA Aplicada · Explicador

Content Collections do Astro: conteúdo em escala

Quando um site passa de algumas páginas para centenas de textos, o problema deixa de ser escrever e passa a ser manter tudo consistente. Veja como o Astro resolve isso com coleções tipadas.

Desenvolvimento e IA Aplicada · Explicador

Astro: por que usar em sites com milhares de páginas

Quando um site tem milhares de páginas de conteúdo, cada decisão de arquitetura se multiplica. Veja, pela documentação oficial e por dados de campo datados, o que o Astro faz bem nesse cenário e onde estão os limites.

Desenvolvimento e IA Aplicada · Análise

Astro ou Next.js: arquitetura e desempenho comparados

Astro e Next.js geram HTML no servidor, mas partem de premissas diferentes: um nasceu para sites de conteúdo, o outro para aplicações React. Veja, com documentação oficial e dados de campo datados, o que isso muda na prática.