specs/debug-console/logger.ts
/*
* SPDX-FileCopyrightText: The Microsoft Corporation
*
* SPDX-License-Identifier: MIT
*/
import { bold, black, green, purple, red, yellow, darkGray, greenBg, redBg } from './colorize';
export var didFailure: boolean = false;
export function logger(text: string): string | boolean {
text = text.replace(/\n$/, '');
let message = formatTestHeader(text);
if (!message) {
message = formatTestDescription(text);
}
if (!message) {
message = formatTestError(text);
}
if (!message) {
message = formatSnapshotMessage(text);
}
if (!message) {
message = formatTestSummary(text);
}
if (process.env.NODE_ENV === 'unknown') {
return message || text;
}
/* eslint-disable no-console */
console.log(message || text);
return true;
}
function formatTestHeader(text: string): string {
const filepath = text.replace(/^(PASS|FAIL)/, '').trim();
const [testFilename, ...testPathParts] = filepath.split('/').reverse();
const testPath = testPathParts.reverse().join('/');
if (text.startsWith('PASS')) {
return `${bold(greenBg(black(' PASS ')))} ${darkGray(`${testPath}/`)}${bold(testFilename)}`;
}
if (text.startsWith('FAIL')) {
didFailure = true;
return `${bold(redBg(black(' FAIL ')))} ${darkGray(`${testPath}/`)}${bold(testFilename)}`;
}
return '';
}
function formatTestDescription(text: string): string {
if (text.includes('✓')) {
return ` ${green('✓')} ${darkGray(text.replace(/✓/, '').trim())}`;
}
if (text.includes('✕')) {
return ` ${red('✕')} ${darkGray(text.replace(/✕/, '').trim())}`;
}
if (text.includes('○')) {
return ` ${yellow('○')} ${darkGray(text.replace(/○/, '').trim())}`;
}
if (text.includes('✎')) {
return ` ${purple('✎')} ${darkGray(text.replace(/✎/, '').trim())}`;
}
return '';
}
function formatTestError(text: string): string {
return text.includes('●') ? red(text) : '';
}
function formatSnapshotMessage(text: string): string {
if (text.endsWith('updated.') || text.endsWith('written.') || text.endsWith('removed.')) {
return bold(green(text));
}
if (text.endsWith('obsolete.')) {
return bold(yellow(text));
}
if (text.endsWith('failed.')) {
return bold(red(text));
}
if (text === 'Snapshot Summary') {
return bold(text);
}
if (text.includes('written from')) {
return formatSnapshotSummary(text, 'written', green);
}
if (text.includes('updated from')) {
return formatSnapshotSummary(text, 'updated', green);
}
if (text.includes('removed from')) {
// Use custom messaging for removed snapshot files
if (text.includes('file')) {
const [numSnapshots, numTestSuites] = /(\d)+/.exec(text)!;
return ` ${bold(
green(`› ${numSnapshots} snapshot ${Number(numSnapshots) > 1 ? 'files' : 'file'} removed`)
)} from ${numTestSuites} ${Number(numTestSuites) > 1 ? 'test suites' : 'test suite'}.`;
}
return formatSnapshotSummary(text, 'removed', green);
}
if (text.includes('obsolete from')) {
return `${formatSnapshotSummary(text, 'obsolete', yellow)} ${darkGray(
'To remove them all, re-run jest with `JEST_RUNNER_UPDATE_SNAPSHOTS=true`.'
)}`;
}
if (text.includes('↳')) {
const filepath = text.replace(/↳/, '').trim();
const [testFilename, ...testPathParts] = filepath.split('/').reverse();
const testPath = testPathParts.reverse().join('/');
return ` ↳ ${darkGray(`${testPath}/`)}${bold(testFilename)}`;
}
if (text.includes('failed from')) {
return `${formatSnapshotSummary(text, 'failed', red)} ${darkGray(
'Inspect your code changes or re-run jest with `JEST_RUNNER_UPDATE_SNAPSHOTS=true` to update them.'
)}`;
}
return '';
}
function formatSnapshotSummary(
text: string,
status: 'written' | 'updated' | 'failed' | 'removed' | 'obsolete',
colorFunc: (text: string) => string
): string {
const [numSnapshots, numTestSuites] = /(\d)+/.exec(text)!;
return ` ${bold(
colorFunc(`› ${numSnapshots} ${Number(numSnapshots) > 1 ? 'snapshots' : 'snapshot'} ${status}`)
)} from ${numTestSuites} ${Number(numTestSuites) > 1 ? 'test suites' : 'test suite'}.`;
}
function formatTestSummary(text: string): string {
if (!text.includes('\n')) {
return '';
}
const summary = [];
for (let line of text.split('\n')) {
if (line.includes('Ran all test suites.')) {
summary.push(darkGray(line));
continue;
}
if (line.includes('Test Suites:')) {
line = line.replace('Test Suites:', bold('Test Suites:'));
}
if (line.includes('Tests:')) {
line = line.replace('Tests:', bold('Tests:'));
}
if (line.includes('Snapshots:')) {
line = line.replace('Snapshots:', bold('Snapshots:'));
}
if (line.includes('Time:')) {
line = line.replace('Time:', bold('Time:'));
}
if (line.includes('passed')) {
line = line.replace(/(?<num>\d+) passed/, bold(green('$<num> passed')));
}
if (line.includes('updated')) {
line = line.replace(/(?<num>\d+) updated/, bold(green('$<num> updated')));
}
if (line.includes('written')) {
line = line.replace(/(?<num>\d+) written/, bold(green('$<num> written')));
}
if (line.includes('removed')) {
// Use custom messaging for removed snapshot files
line = line.replace(/(?<num>\d+) (?<fileText>file|files) removed/, bold(green('$<num> $<fileText> removed')));
line = line.replace(/(?<num>\d+) removed/, bold(green('$<num> removed')));
}
if (line.includes('todo')) {
line = line.replace(/(?<num>\d+) todo/, bold(purple('$<num> todo')));
}
if (line.includes('skipped')) {
line = line.replace(/(?<num>\d+) skipped/, bold(yellow('$<num> skipped')));
}
if (line.includes('obsolete')) {
line = line.replace(/(?<num>\d+) obsolete/, bold(yellow('$<num> obsolete')));
}
if (line.includes('failed')) {
line = line.replace(/(?<num>\d+) failed/, bold(red('$<num> failed')));
}
summary.push(line);
}
return summary.join('\n');
}