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
htmlgeneruje raport HTML wplaywright-report/ - Reporter
listwypisuje 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ówtrace: '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: 7zachowuje artefakt przez 7 dni (domyślnie GitHub to 90 dni; zmniejsz, aby zaoszczędzić storage)
Dostęp do raportu:
- Przejdź do uruchomienia workflow w UI GitHub
- Przewiń do sekcji Artifacts
- Pobierz
playwright-report.zip - Wypakuj i otwórz
index.htmlw 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
- Test failuje w CI
- Alert wysłany do właściciela (Slack, email, komentarz GitHub)
- Właściciel bada (pobiera raport, przegląda trace)
- Właściciel naprawia lub wyłącza (merge fix lub kwarantanna flaky test)
- 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