common.skipToContent

Qualidade sem segredos

Este site testa a si mesmo.

Cada push executa a suíte unitária, uma suíte de fluxos em navegador real e um limite de cobertura antes que o build chegue à produção. O que você vê aqui é o resultado real da última execução, além de uma suíte que você pode rodar no seu próprio navegador agora.

Execute você mesmo

Quatorze verificações rodam nesta mesma página: DOM, acessibilidade, i18n, rede e tempos. Nada é simulado e nada vem do cache.

Test Runner no Navegador

Executa testes de fumaça, estrutura DOM, acessibilidade e desempenho diretamente no seu navegador.

14Total de Testes
0Aprovados
0Falhas
Duração
Pronto para executar

O que o CI reportou

Números direto do GitHub Actions. Os resultados do Jest saem com o build; o resumo do Puppeteer é buscado ao vivo de um Gist que o pipeline atualiza a cada execução.

Testes Jest

Carregando resultados Jest...

Testes E2E

Carregando resultados E2E...

Cobertura de Código

Carregando cobertura...

Como é testado

Quatro camadas, quatro ferramentas. Cada trecho vem direto deste repositório.

  1. 01Unitário & componente

    O menu fecha quando você escolhe um destino

    Jest + Testing Library

    Os componentes renderizam no jsdom e são operados como um visitante faria: por rótulo, papel e clique. Sem detalhes de implementação, sem snapshots.

    O que prova

    • A navegação mobile abre e fecha pelo seu toggle acessível
    • aria-expanded nunca diverge do estado visível
    • Escolher uma rota fecha o menu em vez de deixá-lo aberto
    src/components/Navbar.test.jsxjsx · trecho
    test('closes mobile menu when a nav link is clicked', async () => {
      const { container } = render(
        <MemoryRouter>
          <Navbar />
        </MemoryRouter>
      );
    
      const toggle = screen.getByLabelText('Toggle navigation');
      const menu = container.querySelector('#mobileMenu');
    
      fireEvent.click(toggle);
      expect(toggle).toHaveAttribute('aria-expanded', 'true');
      expect(menu).toHaveClass('active');
    
      fireEvent.click(screen.getByText(/Personal Projects/i));
    
      await waitFor(() => {
        expect(toggle).toHaveAttribute('aria-expanded', 'false');
        expect(menu).not.toHaveClass('active');
      });
    });
  2. 02Artefato de build & segurança

    A CSP publicada é a que o build prometeu

    Jest sobre o build de produção

    Alguns testes nunca tocam um componente. Estes leem a pasta dist gerada e verificam os cabeçalhos de segurança que a Cloudflare vai servir.

    O que prova

    • script-src não carrega unsafe-inline
    • O hash do JSON-LD no cabeçalho bate byte a byte com o script
    • Uma regressão no pipeline de build falha antes de publicar
    tests/jest/csp-validation.test.jsjavascript · trecho
    it('should NOT contain unsafe-inline in script-src', () => {
      const headers = fs.readFileSync(headersPath, 'utf-8');
      const cspLine = headers.match(/Content-Security-Policy:.*$/m);
      expect(cspLine).toBeTruthy();
    
      const scriptSrc = cspLine[0].match(/script-src ([^;]+)/)[1];
      expect(scriptSrc).not.toContain("'unsafe-inline'");
    });
    
    it('should generate correct SHA-256 hash for JSON-LD script', () => {
      const html = fs.readFileSync(htmlPath, 'utf-8');
      const [, scriptContent] = html.match(
        /<script type="application\/ld\+json">([\s\S]*?)<\/script>/
      );
    
      const calculatedHash = crypto
        .createHash('sha256')
        .update(scriptContent)
        .digest('base64');
      const hashes = JSON.parse(fs.readFileSync(hashesPath, 'utf-8'));
    
      expect(hashes.jsonLd).toBe(`'sha256-${calculatedHash}'`);
    });
  3. 03Ponta a ponta

    Aceitar cookies esconde o banner e persiste

    Puppeteer + Chromium headless

    Cada fluxo recebe um contexto de navegador novo e uma lista de passos nomeados, então uma falha aponta o passo exato e o relatório se lê como um roteiro.

    O que prova

    • O bundle real de produção funciona em um navegador real
    • Estado que precisa sobreviver a um reload de fato sobrevive
    • Cada passo é cronometrado e aparece no relatório E2E acima
    tests/e2e/run-e2e.jsjavascript · trecho
    {
      name: 'Cookie consent accept hides banner and stores consent',
      run: async (page, step) => {
        await step('Navigate to home page', () =>
          page.goto(BASE_URL, { waitUntil: 'networkidle2', timeout: NAV_TIMEOUT })
        );
        await step('Cookie banner is shown', () =>
          page.waitForSelector('#cookieConsentBanner', { timeout: NAV_TIMEOUT })
        );
        await step('Click "Accept all cookies"', () => page.click('#acceptCookies'));
        await step('Banner is dismissed', () =>
          page.waitForSelector('#cookieConsentBanner', { hidden: true, timeout: NAV_TIMEOUT })
        );
        await step('Consent cookie is stored', async () => {
          const cookie = await page.evaluate(() => document.cookie);
          assert(/cookie_consent=accepted/.test(cookie), `Consent cookie not set: "${cookie}"`);
        });
      },
    },
  4. 04No seu navegador

    Todo link externo é seguro para abrir

    Runner feito à mão, zero dependências

    O runner no topo desta página é um pequeno motor de verificações assíncronas contra o DOM ao vivo. É por isso que você pode confiar nos links deste site.

    O que prova

    • target="_blank" sempre vem com rel="noopener noreferrer"
    • A verificação roda no seu dispositivo, contra a página que você está lendo
    • As falhas nomeiam os hrefs problemáticos, não só uma contagem
    src/utils/inBrowserTestRunner.jsjavascript · trecho
    {
      id: 'dom-safe-links',
      nameKey: 'testDashboard.runner.tests.safeLinks.name',
      run: async () => {
        const externalLinks = Array.from(document.querySelectorAll('a[target="_blank"]'));
        const insecureLinks = externalLinks.filter((link) => {
          const rel = (link.getAttribute('rel') || '').toLowerCase();
          return !rel.includes('noopener') && !rel.includes('noreferrer');
        });
    
        if (insecureLinks.length > 0) {
          const hrefs = insecureLinks
            .slice(0, 3)
            .map((l) => l.getAttribute('href'))
            .join(', ');
          throw new Error(
            `Found ${insecureLinks.length} external link(s) without rel="noopener noreferrer": ${hrefs}`
          );
        }
        return {
          message: `Verified ${externalLinks.length} external link(s) have secure rel attributes.`,
        };
      },
    },

Relatórios

Relatórios HTML estáticos, regenerados a cada deploy.