diff --git a/e2e-playwright/playwright.config.minimal.ts b/e2e-playwright/playwright.config.minimal.ts new file mode 100644 index 0000000000..08d460e4c8 --- /dev/null +++ b/e2e-playwright/playwright.config.minimal.ts @@ -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, +}); diff --git a/e2e-playwright/playwright.config.ts b/e2e-playwright/playwright.config.ts index ce1cd5b52e..85622f53b6 100644 --- a/e2e-playwright/playwright.config.ts +++ b/e2e-playwright/playwright.config.ts @@ -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: { diff --git a/package.json b/package.json index b0fc2472ed..3b0c27450c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tools/test-summary.js b/tools/test-summary.js new file mode 100755 index 0000000000..64c6e13dc9 --- /dev/null +++ b/tools/test-summary.js @@ -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();