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.
- Autoria:
- Redação Token & Tech
- 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:
- Links internos. Todo
hrefesrcque aponta para o próprio site leva a um arquivo que existe. - 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://). - Barra final. O formato do endereço é consistente (
/artigo/ou/artigo, não os dois). - 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). - 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
- sitemaps.org - Protocol, sitemaps.org. Acesso em 8 de outubro de 2026
- Configuration Reference, Astro Docs. Acesso em 8 de outubro de 2026
- CLI Commands, Astro Docs. Acesso em 8 de outubro de 2026
- lycheeverse/lychee (README), lycheeverse (GitHub). Acesso em 8 de outubro de 2026
- JustinBeckwith/linkinator (README), Justin Beckwith (GitHub). Acesso em 8 de outubro de 2026
- Page | Playwright (page.goto), Playwright. Acesso em 8 de outubro de 2026
- How to specify a canonical URL with rel="canonical" and other methods, Google Search Central. Acesso em 8 de outubro de 2026
- Tell Google about localized versions of your page, Google Search Central. Acesso em 8 de outubro de 2026