UNPKG

playwright-custom-reporter

Version:

A custom Playwright reporter.

140 lines (116 loc) 4.78 kB
const { Reporter } = require('@playwright/test'); const fs = require('fs'); class CustomReporter { constructor() { this.results = { tests: [] }; // Store test results } onBegin(config, suite) { console.log(`Starting the test run with ${suite.allTests().length} tests.`); } onTestBegin(test) { console.log(`Running: ${test.title}`); // Initialize step tracking for this test test.stepDetails = []; } async onStepBegin(test, step) { if (!test.stepDetails) test.stepDetails = []; test.stepDetails.push({ title: step.title }); } onTestEnd(test, result) { const testResult = { name: test.title, status: result.status, steps: test.stepDetails || [], errors: result.errors.map(error => ({ message: this.extractErrorMessage(error.message), stack: this.formatStackTrace(error.stack || 'No stack trace available.') })) }; this.results.tests.push(testResult); if (result.status === 'passed') { console.log(`✅ Passed: ${test.title}`); } else if (result.status === 'failed') { console.log(`❌ Failed: ${test.title}`); console.log('\nError Details:'); for (const error of result.errors) { // Extract the base error message console.log(`Message: ${this.extractErrorMessage(error.message)}`); // Extract and log the locator information const locatorMatch = error.message.match(/expect\((.*?)\)\.toBeVisible/); if (locatorMatch) { console.log(`Locator: ${locatorMatch[1]}`); } // Log expected and received values if (error.message.includes('expect(')) { console.log(`Expected: visible`); console.log(`Received: <element(s) not found>`); } // Add call log information console.log('\nCall log:'); console.log(` - expect.toBeVisible with timeout 5000ms`); console.log(` - waiting for ${locatorMatch ? locatorMatch[1] : 'element'}`); // Log stack trace const stack = this.formatStackTrace(error.stack || 'No stack trace available.'); if (stack) { console.log(`\nStack Trace:\n${stack}`); } } } else if (result.status === 'skipped') { console.log(`⏭️ Skipped: ${test.title}`); } } onEnd(result) { console.log(`Finished the test run. Status: ${result.status}`); // Save test results with steps to a JSON file const reportPath = 'test-results/results.json'; fs.writeFileSync(reportPath, JSON.stringify(this.results, null, 2)); console.log(`✅ Test report saved to ${reportPath}`); } // Helper method to extract and refine error messages extractErrorMessage(message) { return message.split('\n')[0]; } // Helper method to format stack traces formatStackTrace(stack) { return stack .split('\n') .filter(line => !line.includes('node_modules')) // Exclude lines from node_modules .map(line => line.replace(/^\s*at\s+/, '')) // Remove "at" prefixes .map(line => line.replace(process.cwd(), '.')) // Replace absolute paths with relative paths .join('\n'); } // Helper method to extract locator, expected, and received details extractErrorDetails(message) { const details = { locator: null, expected: null, received: null, callLog: [] }; // Extract locator information const locatorMatch = message.match(/Locator: ([^\n]+)/); if (locatorMatch) { details.locator = locatorMatch[1]; } // Extract expected value const expectedMatch = message.match(/Expected: ([^\n]+)/); if (expectedMatch) { details.expected = expectedMatch[1]; } // Extract received value const receivedMatch = message.match(/Received: ([^\n]+)/); if (receivedMatch) { details.received = receivedMatch[1]; } // Extract call log const callLogSection = message.match(/Call log:\n((?: - .*\n?)*)/); if (callLogSection) { details.callLog = callLogSection[1] .split('\n') .filter(line => line.trim()) .map(line => line.replace(' - ', '')); } return details; } } module.exports = CustomReporter;