@web/test-runner
Version:
Test runner for web applications
182 lines (164 loc) • 5.32 kB
text/typescript
import {
TestRunnerCoreConfig,
TestSessionManager,
SESSION_STATUS,
TestCoverage,
CoverageConfig,
BrowserLauncher,
} from '@web/test-runner-core';
import { bold, gray, green, red } from 'nanocolors';
import { getPassedFailedSkippedCount } from './utils/getPassedFailedSkippedCount.js';
import { getCodeCoverage } from './getCodeCoverage.js';
import { renderProgressBar } from './renderProgressBar.js';
export interface TestProgressArgs {
browsers: BrowserLauncher[];
browserNames: string[];
testFiles: string[];
testRun: number;
sessions: TestSessionManager;
startTime: number;
watch: boolean;
focusedTestFile?: string;
coverage: boolean;
coverageConfig?: CoverageConfig;
testCoverage?: TestCoverage;
}
function getProgressReport(
name: string,
minWidth: number,
finishedFiles: number,
activeFiles: number,
testFiles: number,
passedTests: number,
skippedTests: number,
failedTests: number,
) {
const failedText = `${failedTests} failed`;
const testResults =
`${green(`${passedTests} passed`)}` +
`, ${failedTests !== 0 ? red(failedText) : failedText}` +
(skippedTests !== 0 ? `, ${gray(`${skippedTests} skipped`)}` : '');
const progressBar = `${renderProgressBar(
finishedFiles,
activeFiles,
testFiles,
)} ${finishedFiles}/${testFiles} test files`;
return `${`${name}:`.padEnd(minWidth)} ${progressBar} | ${testResults}`;
}
export function getTestProgressReport(config: TestRunnerCoreConfig, args: TestProgressArgs) {
const {
browsers,
browserNames,
testRun,
sessions,
watch,
startTime,
focusedTestFile,
coverage,
coverageConfig,
testCoverage,
} = args;
const entries: string[] = [];
const unfinishedSessions = Array.from(
sessions.forStatusAndTestFile(
focusedTestFile,
SESSION_STATUS.SCHEDULED,
SESSION_STATUS.INITIALIZING,
SESSION_STATUS.TEST_STARTED,
SESSION_STATUS.TEST_FINISHED,
),
);
const finishedFiles = new Set<string>();
let failedTestCount = 0;
let failed = false;
const longestBrowser = [...browserNames].sort((a, b) => b.length - a.length)[0];
const minWidth = longestBrowser ? longestBrowser.length + 1 : 0;
for (const browser of browsers) {
// when started or not initiliazing we render a progress bar
const allSessionsForBrowser = Array.from(sessions.forBrowser(browser));
const sessionsForBrowser = focusedTestFile
? allSessionsForBrowser.filter(s => s.testFile === focusedTestFile)
: allSessionsForBrowser;
const totalTestFiles = sessionsForBrowser.length;
let finishedFilesForBrowser = 0;
let activeFilesForBrowser = 0;
let passedTestsForBrowser = 0;
let skippedTestsForBrowser = 0;
let failedTestsForBrowser = 0;
for (const session of sessionsForBrowser) {
if (!session.passed) {
failed = true;
}
if (![SESSION_STATUS.SCHEDULED, SESSION_STATUS.FINISHED].includes(session.status)) {
activeFilesForBrowser += 1;
}
if (session.status === SESSION_STATUS.FINISHED) {
const { testFile, testResults } = session;
finishedFiles.add(testFile);
finishedFilesForBrowser += 1;
if (testResults) {
const parsed = getPassedFailedSkippedCount(testResults);
passedTestsForBrowser += parsed.passed;
skippedTestsForBrowser += parsed.skipped;
failedTestsForBrowser += parsed.failed;
failedTestCount += parsed.failed;
}
}
}
entries.push(
getProgressReport(
browser.name,
minWidth,
finishedFilesForBrowser,
activeFilesForBrowser,
totalTestFiles,
passedTestsForBrowser,
skippedTestsForBrowser,
failedTestsForBrowser,
),
);
}
entries.push('');
if (coverage && coverageConfig) {
if (testCoverage) {
if (!testCoverage.passed) {
failed = true;
}
const coverageReport = getCodeCoverage(testCoverage, watch, coverageConfig);
entries.push(...coverageReport);
}
}
if (testRun !== -1 && unfinishedSessions.length === 0) {
if (coverage && !testCoverage) {
entries.push(bold('Calculating code coverage...'));
} else if (config.watch) {
entries.push(bold(`Finished running tests, watching for file changes...`));
} else {
const durationInSec = (Date.now() - startTime) / 1000;
const duration = Math.trunc(durationInSec * 10) / 10;
if (failed) {
if (coverage && !testCoverage?.passed) {
entries.push(
bold(red(`Finished running tests in ${duration}s, failed to meet coverage threshold.`)),
);
} else if (failedTestCount > 0) {
entries.push(
bold(
red(`Finished running tests in ${duration}s with ${failedTestCount} failed tests.`),
),
);
} else if (finishedFiles.size > 0) {
entries.push(bold(red(`Error while running tests.`)));
} else {
entries.push(bold(red(`Failed to run any tests.`)));
}
} else {
entries.push(bold(`Finished running tests in ${duration}s, all tests passed! 🎉`));
}
}
} else {
entries.push(bold('Running tests...'));
}
entries.push('');
return entries;
}