test(e2e): improve test debugging experience

- Add conditional reporters in playwright.config.ts (concise for local, detailed for CI)
- Reduce test timeout from 20s to 10s for faster failure detection
- Add new npm scripts:
  - e2e:playwright:failures - shows only failing tests
  - e2e:playwright:summary - displays concise test summary
  - e2e:playwright:quick - runs tests with minimal output
- Create test-summary.js tool for analyzing test results
- Add playwright.config.minimal.ts for quick test runs

These changes make it easier to identify failing tests without verbose logs
This commit is contained in:
Johannes Millan 2025-07-30 22:12:48 +02:00
parent a933d1fd35
commit fee3b80f02
4 changed files with 137 additions and 8 deletions

View file

@ -0,0 +1,29 @@
import { defineConfig } from '@playwright/test';
import baseConfig from './playwright.config';
/**
* Minimal config for quick test runs with minimal output
*/
export default defineConfig({
...baseConfig,
// Faster timeout for quicker failures
timeout: 10 * 1000,
// Minimal reporter - only show failures
reporter: [['line']],
// No retries for faster results
retries: 0,
// Disable videos and traces for speed
use: {
...baseConfig.use,
trace: 'off',
screenshot: 'only-on-failure',
video: 'off',
},
// Disable parallel execution for cleaner output
workers: 1,
});

View file

@ -16,13 +16,18 @@ export default defineConfig({
/* Opt out of parallel tests on CI. */
workers: process.env.CI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: [
[
'html',
{ outputFolder: '../.tmp/e2e-test-results/playwright-report', open: 'never' },
],
['junit', { outputFile: '../.tmp/e2e-test-results/results.xml' }],
],
reporter: process.env.CI
? [
[
'html',
{ outputFolder: '../.tmp/e2e-test-results/playwright-report', open: 'never' },
],
['junit', { outputFile: '../.tmp/e2e-test-results/results.xml' }],
]
: [
['list', { printSteps: false }],
['json', { outputFile: 'test-results.json' }],
],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
@ -80,7 +85,7 @@ export default defineConfig({
outputDir: '../.tmp/e2e-test-results/test-results',
/* Global timeout for each test */
timeout: 20 * 1000,
timeout: 10 * 1000,
/* Global timeout for each assertion */
expect: {

View file

@ -61,6 +61,9 @@
"e2e:playwright:debug": "cd e2e-playwright && npx playwright test --debug",
"e2e:playwright:headed": "cd e2e-playwright && npx playwright test --headed",
"e2e:playwright:report": "cd e2e-playwright && npx playwright show-report",
"e2e:playwright:failures": "cd e2e-playwright && npx playwright test --reporter=list --grep-invert @skip || true",
"e2e:playwright:summary": "cd e2e-playwright && node ../tools/test-summary.js",
"e2e:playwright:quick": "cd e2e-playwright && npx playwright test --config=playwright.config.minimal.ts",
"electron": "NODE_ENV=PROD electron .",
"electron:build": "tsc -p electron/tsconfig.electron.json",
"electron:watch": "tsc -p electron/tsconfig.electron.json --watch",

92
tools/test-summary.js Executable file
View file

@ -0,0 +1,92 @@
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const TEST_RESULTS_FILE = path.join(__dirname, '../e2e-playwright/test-results.json');
function summarizeResults() {
// Check if results file exists
if (!fs.existsSync(TEST_RESULTS_FILE)) {
console.log('❌ No test results found. Run tests first with: npm run e2e:playwright');
return;
}
try {
const results = JSON.parse(fs.readFileSync(TEST_RESULTS_FILE, 'utf8'));
const stats = results.stats || {};
const suites = results.suites || [];
// Calculate statistics
const total = stats.expected || 0;
const passed = (stats.expected || 0) - (stats.unexpected || 0) - (stats.skipped || 0);
const failed = stats.unexpected || 0;
const skipped = stats.skipped || 0;
const duration = stats.duration || 0;
// Print summary header
console.log('\n📊 Playwright Test Summary');
console.log('=========================\n');
// Print statistics
console.log(`Total Tests: ${total}`);
console.log(`✅ Passed: ${passed}`);
console.log(`❌ Failed: ${failed}`);
console.log(`⏭️ Skipped: ${skipped}`);
console.log(`⏱️ Duration: ${(duration / 1000).toFixed(2)}s\n`);
// Print failed tests if any
if (failed > 0) {
console.log('Failed Tests:');
console.log('-------------');
const failedTests = [];
// Recursively find failed tests
function findFailedTests(suites) {
for (const suite of suites) {
if (suite.suites) {
findFailedTests(suite.suites);
}
if (suite.specs) {
for (const spec of suite.specs) {
if (spec.tests) {
for (const test of spec.tests) {
if (test.status === 'unexpected' || test.status === 'failed') {
failedTests.push({
file: spec.file || suite.file,
title: spec.title || test.title,
error: test.results?.[0]?.error?.message || 'Unknown error',
});
}
}
}
}
}
}
}
findFailedTests(suites);
failedTests.forEach((test, index) => {
console.log(`\n${index + 1}. ${test.file}`);
console.log(` ${test.title}`);
if (test.error) {
console.log(` Error: ${test.error.split('\n')[0]}`);
}
});
}
// Print success message if all passed
if (failed === 0 && passed > 0) {
console.log('🎉 All tests passed!');
}
} catch (error) {
console.error('❌ Error reading test results:', error.message);
console.log('\nMake sure to run tests with: npm run e2e:playwright');
}
}
// Run the summary
summarizeResults();