Raporty, artefakty i triage awarii w CI

Nieudane uruchomienia CI są użyteczne tylko wtedy, gdy możesz je szybko zdiagnozować. Naucz się generować raporty HTML, uploadować artefakty trace, ustanawiać pętle odpowiedzialności i powiadamiać.

Ten post to część 4 serii Jakość w CI/CD. Część 3 omawiała Docker i efemeryczne środowiska dla odtwarzalnego testowania E2E.


Wprowadzenie — niepowodzenia to dane

Nieudane uruchomienie CI bez kontekstu to szum. “Testy E2E failed” nic Ci nie mówi. Czy to był prawdziwy bug? Flaky test? Timeout infrastruktury?

Wartość automatycznego testowania jest proporcjonalna do tego, jak szybko możesz zdiagnozować i naprawić niepowodzenia. To wymaga:

  • Bogatych raportów — raporty HTML ze screenshotami, trace’ami i podsumowaniami niepowodzeń
  • Artefaktów — wyników testów do pobrania, logów i danych debugowania
  • Pętli odpowiedzialności — jasnej odpowiedzialności za badanie i rozwiązywanie niepowodzeń
  • Celowanych powiadomień — alertów, które docierają do właściwych osób bez spamowania wszystkich

Ten post omawia, jak generować i uploadować raporty testów, ustanawiać workflow triage niepowodzeń i integrować powiadomienia ze Slackiem i GitHubem bez tworzenia zmęczenia alertami.


Raporty HTML dla wyników testów

Playwright generuje raport HTML pokazujący wyniki testów, czasy wykonania, screenshoty i wideo dla każdego testu.

Generowanie raportów HTML

// playwright.config.ts
import { defineConfig } from '@playwright/test';

export default defineConfig({
  reporter: [
    ['html', { outputFolder: 'playwright-report', open: 'never' }],
    ['list'],
  ],
  use: {
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
    trace: 'retain-on-failure',
  },
});

Rozbicie konfiguracji:

  • Reporter html generuje raport HTML w playwright-report/
  • Reporter list wypisuje wyniki testów do konsoli
  • screenshot: 'only-on-failure' przechwytuje screenshoty tylko gdy testy failują
  • video: 'retain-on-failure' zapisuje nagrania wideo tylko dla nieudanych testów
  • trace: 'retain-on-failure' zapisuje pliki trace tylko dla niepowodzeń

Uploadowanie raportów jako artefakty

GitHub Actions pozwala uploadować pliki jako artefakty. Uploaduj raport HTML, aby był dostępny z uruchomienia workflow.

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npm run test:e2e
      
      - name: Upload Playwright report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7

Kluczowe funkcje:

  • if: always() uploaduje raport nawet jeśli testy failują
  • retention-days: 7 zachowuje artefakt przez 7 dni (domyślnie GitHub to 90 dni; zmniejsz, aby zaoszczędzić storage)

Dostęp do raportu:

  1. Przejdź do uruchomienia workflow w UI GitHub
  2. Przewiń do sekcji Artifacts
  3. Pobierz playwright-report.zip
  4. Wypakuj i otwórz index.html w przeglądarce

:::tip[Przeglądanie trace’ów] Trace’y dostarczają najwięcej szczegółów: pełny timeline, requesty sieciowe, snapshoty DOM, logi konsoli i screenshoty dla każdej akcji. Pobierz trace’y z raportu i otwórz z npx playwright show-trace trace.zip. :::


Uploadowanie logów i wyników testów

Poza raportami HTML uploaduj surowe wyniki testów i logi do programatycznej analizy.

Raporty JUnit XML

JUnit XML to standardowy format dla wyników testów. Wiele dashboardów CI go parsuje.

// playwright.config.ts
export default defineConfig({
  reporter: [
    ['html', { outputFolder: 'playwright-report' }],
    ['junit', { outputFile: 'test-results/junit.xml' }],
    ['list'],
  ],
});

Uploaduj plik JUnit XML:

      - name: Upload JUnit results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: junit-results
          path: test-results/junit.xml

Uploadowanie logów aplikacji

Jeśli Twoja aplikacja loguje do pliku podczas testów, uploaduj te logi do debugowania.

      - name: Upload app logs
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: app-logs
          path: logs/

Ustanawianie pętli odpowiedzialności

Nieudany test bez właściciela to nieudany test, który pozostaje zepsuty.

Pętla odpowiedzialności

  1. Test failuje w CI
  2. Alert wysłany do właściciela (Slack, email, komentarz GitHub)
  3. Właściciel bada (pobiera raport, przegląda trace)
  4. Właściciel naprawia lub wyłącza (merge fix lub kwarantanna flaky test)
  5. Pętla zamyka się, gdy CI jest zielone

Przypisywanie odpowiedzialności

Definiuj odpowiedzialność na poziomie test suite lub pliku.

Przykład: odpowiedzialność według katalogu

tests/
  auth/          # Właściciel: @auth-team
  checkout/      # Właściciel: @payments-team
  admin/         # Właściciel: @platform-team

Użyj GitHub CODEOWNERS do wymuszenia review:

# .github/CODEOWNERS
tests/auth/*       @auth-team
tests/checkout/*   @payments-team
tests/admin/*      @platform-team

Gdy test failuje, workflow może otagować posiadający zespół w komentarzu GitHub.


Powiadomienia Slack bez szumu

Powiadomienia Slack są potężne, ale niebezpieczne. Niefiltrowane alerty CI tworzą szum, który szkoli zespoły do ich ignorowania.

Dobra strategia powiadomień

Powiadamiaj o niepowodzeniu — Alertuj, gdy testy failują na branchu main (post-merge)
Powiadamiaj konkretne kanały — Kieruj niepowodzenia testów do kanałów specyficznych dla zespołu
Dołączaj kontekst — Link do uruchomienia workflow, nazwy nieudanych testów i artefakty raportu
Nie powiadamiaj o niepowodzeniach PR — Developerzy już widzą checki PR; powiadomienia Slack są redundantne
Nie powiadamiaj o re-runach flaky testów — Alertuj tylko po wyczerpaniu retry’ów

Workflow powiadomień Slack

Użyj slackapi/slack-github-action do postowania na Slack.

name: E2E Tests

on:
  push:
    branches: [main]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npm run test:e2e
      
      - name: Upload report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
      
      - name: Notify Slack on failure
        if: failure()
        uses: slackapi/slack-github-action@v1
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
          payload: |
            {
              "text": "Testy E2E failed na branchu main",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "🔴 *Testy E2E Failed*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Zobacz uruchomienie workflow>"
                  }
                },
                {
                  "type": "section",
                  "fields": [
                    {
                      "type": "mrkdwn",
                      "text": "*Commit:* <${{ github.event.head_commit.url }}|${{ github.event.head_commit.message }}>"
                    },
                    {
                      "type": "mrkdwn",
                      "text": "*Autor:* ${{ github.event.head_commit.author.name }}"
                    }
                  ]
                }
              ]
            }

Rezultat: Wiadomość Slack z linkiem do workflow, wiadomością commita i autorem.

:::warning[Zmęczenie alertami] Jeśli CI Twojego głównego brancha failuje >5% czasu, napraw flaky testy przed dodaniem powiadomień Slack. Częste fałszywe alarmy niszczą zaufanie do alertów. :::


Komentarze GitHub PR dla niepowodzeń testów

Postuj komentarz w pull requeście, gdy testy failują, podsumowując, które testy failed i linkując do raportu.

Używanie actions/github-script

      - name: Comment on PR with test results
        if: failure() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            const fs = require('fs');
            const reportPath = 'test-results/junit.xml';
            let failedTests = 'Nie można sparsować wyników testów';
            
            if (fs.existsSync(reportPath)) {
              const xml = fs.readFileSync(reportPath, 'utf-8');
              // Parsuj JUnit XML i wyciągnij nazwy nieudanych testów
              failedTests = xml.match(/<testcase.*?name="(.*?)".*?<failure/g)
                ?.map(m => m.match(/name="(.*?)"/)[1])
                .join('\n- ') || 'Nie znaleziono niepowodzeń';
            }
            
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## ❌ Testy E2E Failed\n\n**Nieudane testy:**\n- ${failedTests}\n\n[Zobacz pełny raport](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`
            });

Rezultat: Komentarz GitHub listujący nieudane testy i linkujący do uruchomienia workflow.

:::info[Limity rate] GitHub API ma limity rate. Jeśli Twój workflow postuje wiele komentarzy, możesz osiągnąć limit. Konsoliduj aktualizacje w jeden komentarz, który jest edytowany przy kolejnych uruchomieniach. :::


Praktyczny przykład — pełny workflow triage niepowodzeń

Połącz raporty HTML, artefakty, powiadomienia Slack i komentarze PR w gotowym do produkcji workflow.

name: E2E Tests

on:
  pull_request:
  push:
    branches: [main]

jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'
      
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      
      - name: Run E2E tests
        run: npm run test:e2e
      
      - name: Upload HTML report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7
      
      - name: Upload JUnit results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: junit-results
          path: test-results/junit.xml
      
      - name: Notify Slack on main failure
        if: failure() && github.ref == 'refs/heads/main'
        uses: slackapi/slack-github-action@v1
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK_URL }}
          payload: |
            {
              "text": "🔴 Testy E2E failed na main",
              "blocks": [
                {
                  "type": "section",
                  "text": {
                    "type": "mrkdwn",
                    "text": "*Testy E2E Failed na Main*\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Zobacz run>"
                  }
                }
              ]
            }
      
      - name: Comment on PR
        if: failure() && github.event_name == 'pull_request'
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: context.issue.number,
              body: `## ❌ Testy E2E Failed\n\n[Zobacz uruchomienie workflow](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\n\nPobierz artefakt raportu Playwright po szczegóły.`
            });

Funkcje:

  • Raport HTML i JUnit XML uploadowane dla każdego uruchomienia
  • Powiadomienie Slack tylko dla niepowodzeń brancha main
  • Komentarz GitHub PR tylko dla niepowodzeń PR
  • Wszystkie powiadomienia zawierają linki do uruchomienia workflow

Podsumowanie — czyń niepowodzenia możliwymi do działania

Niepowodzenia CI są wartościowe tylko wtedy, gdy można na nich działać. Test suite, który failuje bez kontekstu, bez właściciela i bez pętli powiadomień, nie różni się od test suite, który nie istnieje.

Zasady:

  • Generuj bogate raporty — HTML, screenshoty, wideo, trace’y
  • Uploaduj artefakty — czyń dane debugowania dostępnymi
  • Ustanów odpowiedzialność — każda test suite ma nazwanego właściciela
  • Powiadamiaj strategicznie — alertuj właściwe osoby we właściwym czasie bez spamowania
  • Zamknij pętlę — niepowodzenia są badane i rozwiązywane, nie ignorowane

Gdy niepowodzenia stają się możliwe do działania, CI staje się zaufane. Gdy CI jest zaufane, zespoły wypuszczają szybciej.

Zadanie na ten tydzień: Skonfiguruj uploady raportów HTML dla swojej test suite. Wywołaj jedno zamierzone niepowodzenie testu i pobierz raport. Zmierz, jak długo trwa zidentyfikowanie pierwotnej przyczyny tylko z raportu.


Dalej w tej serii: Część 5 — Checki w PR, które mają sens — shift-left bez szumu