GitHub Actions: testes automatizados em Node.js

    Testes automáticos no CI bloqueiam merges com código quebrado — sem precisar de ninguém revisar manualmente se "ainda funciona". Com GitHub Actions, cada PR exibe cobertura de código, relatório de falhas e pode bloquear o merge até todos os testes passarem.

    Workflow de testes com Vitest

    Pipeline de testes para projetos TypeScript com Vitest:

    yaml
    # .github/workflows/tests.yml
    name: Testes
    
    on:
      push:
        branches: [main, develop]
      pull_request:
        branches: [main]
    
    jobs:
      test:
        runs-on: ubuntu-latest
        strategy:
          matrix:
            node-version: [20, 22]   # testar em múltiplas versões
    
        steps:
          - uses: actions/checkout@v4
    
          - name: Configurar Node.js ${{ matrix.node-version }}
            uses: actions/setup-node@v4
            with:
              node-version: ${{ matrix.node-version }}
              cache: 'npm'
    
          - name: Instalar dependências
            run: npm ci
    
          - name: Verificar TypeScript
            run: npx tsc --noEmit
    
          - name: Lint
            run: npm run lint
    
          - name: Testes unitários
            run: npm run test:unit -- --reporter=verbose
    
          - name: Relatório de cobertura
            run: npm run test:coverage
    
          - name: Upload cobertura para Codecov
            uses: codecov/codecov-action@v4
            with:
              token: ${{ secrets.CODECOV_TOKEN }}
              files: ./coverage/lcov.info
              fail_ci_if_error: false

    Testes de integração com banco de dados real

    Rodar testes de integração com PostgreSQL e Redis no CI:

    yaml
    # .github/workflows/tests.yml — job de integração:
      integration:
        runs-on: ubuntu-latest
        services:
          postgres:
            image: postgres:16-alpine
            env:
              POSTGRES_DB: testdb
              POSTGRES_USER: testuser
              POSTGRES_PASSWORD: testpass
            options: >-
              --health-cmd pg_isready
              --health-interval 10s
              --health-timeout 5s
              --health-retries 5
            ports:
              - 5432:5432
    
          redis:
            image: redis:7-alpine
            options: >-
              --health-cmd "redis-cli ping"
              --health-interval 10s
              --health-retries 5
            ports:
              - 6379:6379
    
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with:
              node-version: '22'
              cache: 'npm'
    
          - run: npm ci
    
          - name: Rodar migrations no banco de teste
            env:
              DATABASE_URL: postgresql://testuser:testpass@localhost:5432/testdb
            run: npm run db:migrate
    
          - name: Testes de integração
            env:
              DATABASE_URL: postgresql://testuser:testpass@localhost:5432/testdb
              REDIS_URL: redis://localhost:6379
              NODE_ENV: test
              JWT_SECRET: segredo-de-teste-123
            run: npm run test:integration

    Configurar Vitest para CI

    vitest.config.ts com configurações para ambiente de CI:

    typescript
    // vitest.config.ts
    import { defineConfig } from 'vitest/config'
    import path from 'path'
    
    export default defineConfig({
      test: {
        globals: true,
        environment: 'node',
    
        // Separar testes unitários de integração por pasta:
        include: ['src/**/*.{test,spec}.{ts,tsx}'],
        exclude: ['src/**/*.integration.test.ts'],
    
        // Configuração de cobertura:
        coverage: {
          provider: 'v8',
          reporter: ['text', 'lcov', 'html'],
          include: ['src/**/*.ts'],
          exclude: ['src/**/*.test.ts', 'src/types/**'],
          thresholds: {
            lines: 70,        // bloquear CI se cobertura < 70%
            functions: 70,
            branches: 60,
            statements: 70,
          },
        },
    
        // Timeout mais longo para integração:
        testTimeout: 30_000,
    
        // Relatório para o GitHub Actions (faz anotações no PR):
        reporter: process.env.CI ? ['verbose', 'github-actions'] : ['verbose'],
    
        // Rodar em paralelo (mais rápido no CI):
        pool: 'threads',
        poolOptions: {
          threads: { maxThreads: 4 },
        },
      },
      resolve: {
        alias: { '@': path.resolve(__dirname, 'src') },
      },
    })

    Comentar cobertura de código no Pull Request

    Exibir diff de cobertura diretamente nos comentários do PR:

    yaml
    # .github/workflows/tests.yml — adicionar após os testes:
          - name: Relatório de cobertura no PR
            uses: davelosert/vitest-coverage-report-action@v2
            if: always()
            with:
              github-token: ${{ secrets.GITHUB_TOKEN }}
              # Comentar no PR com o relatório de cobertura:
              # - linhas novas sem cobertura ficam marcadas
              # - comparação com a cobertura da branch main
              json-summary-path: ./coverage/coverage-summary.json
              json-final-path: ./coverage/coverage-final.json
    
    # package.json — scripts de teste:
    # {
    #   "scripts": {
    #     "test": "vitest run",
    #     "test:unit": "vitest run --exclude='**/*.integration.*'",
    #     "test:integration": "vitest run --include='**/*.integration.*'",
    #     "test:coverage": "vitest run --coverage",
    #     "test:watch": "vitest watch"
    #   }
    # }

    Bloquear merge se testes falharem

    Configurar branch protection para exigir CI verde antes do merge:

    bash
    # No GitHub — Settings → Branches → Branch protection rules:
    # Branch name pattern: main
    # Marcar: ✓ Require status checks to pass before merging
    # Status checks required:
    #   - test (Node.js 22)
    #   - integration
    #   - TypeScript check
    # Marcar: ✓ Require branches to be up to date before merging
    
    # Resultado:
    # - PRs com testes vermelhos não podem ser mergeados
    # - O botão de merge fica bloqueado
    # - Cada push no PR roda os testes automaticamente
    
    # Tornar o workflow obrigatório (required check):
    # O nome do check é o campo "name:" do job no workflow
    # Exemplo: se o job se chama "test", o check é "test"
    
    # Para múltiplos SO ou versões (matrix):
    # Cada combinação gera um check separado:
    # "test (ubuntu-latest, 20)"
    # "test (ubuntu-latest, 22)"
    # Adicione todos que quiser como obrigatórios

    $ runstack deploy --plan starter

    Não quer configurar manualmente?

    Não quer configurar manualmente? Implante o VPS para APIs em menos de 3 minutos com a Runstack. Infraestrutura da OPEN DATACENTER, com servidores no Brasil.

    Perguntas frequentes