UNPKG

@pmoo/testy

Version:

A minimal testing framework, for educational purposes.

179 lines (144 loc) 5.52 kB
import { isEmpty, isString } from '../utils/index.js'; const off = '\x1b[0m', bold = '\x1b[1m', cyan = '\x1b[36m', red = '\x1b[31m', green = '\x1b[32m', yellow = '\x1b[33m'; const consoleWidth = 80; /** * I present all the events from Testy as formatted text to a [console]{@link ConsoleUI}. */ export class Formatter { #console; #i18n; #timerName; #filter; constructor(console, i18n) { this.#console = console; this.#i18n = i18n; this.#timerName = this.#translated('total_time'); } startTimer() { this.#console.time(this.#timerName); } endTimer() { this.#console.timeEnd(this.#timerName); } displayInitialInformation(configuration, paths) { this.#filter = configuration.filterRaw(); this.#displaySeparator(); this.#displayConfigurationSummary(paths, configuration); this.#displaySeparator(); } displayRunnerEnd(runner) { this.#displayErrorsAndFailuresSummary(runner); this.#displayGeneralSummary(runner); } // displaying suites displaySuiteStart(suite) { this.#console.log(`\n${suite.name()}:`); this.#displaySeparator('-'); } displaySuiteEnd(suite) { this.#displaySeparator('-'); this.#console.log(`${this.#translated('summary_of')} ${suite.name()}:`); this.#displayCountFor(suite); this.#displaySuiteFilePath(suite); this.#displaySeparator(); } // displaying test results displayPendingResult(test) { this.#displayResult(this.#translated('wip'), test, yellow); if (test.isExplicitlyMarkedPending()) { this.#displayResultDetail(test.result().reason()); } } displaySkippedResult(test) { this.#displayResult(this.#translated('skip'), test, cyan); } displaySuccessResult(test) { this.#displayResult(this.#translated('ok'), test, green); } displayFailureResult(test, failType) { this.#displayResult(this.#translated(failType), test, red); this.#displayResultDetail(test.result().failureMessage()); this.#displayResultDetail(test.result().location()); } // displaying other messages displayError(message) { this.#console.log(`${this.#withColor(this.#potentiallyInternationalized(message), red)}`); } #displayConfigurationSummary(paths, configuration) { const testPathsLabel = this.#translated('running_tests_in'); const failFastLabel = this.#translated('fail_fast'); const randomOrderLabel = this.#translated('random_order'); this.#console.log(this.#inBold(this.#translated('starting_testy'))); const padding = Math.max(testPathsLabel.length, failFastLabel.length, randomOrderLabel.length); this.#console.log(`${testPathsLabel.padEnd(padding)} : ${paths}`); this.#console.log(`${failFastLabel.padEnd(padding)} : ${this.#humanBoolean(configuration.failFastMode().enabled())}`); this.#console.log(`${randomOrderLabel.padEnd(padding)} : ${this.#humanBoolean(configuration.randomOrder())}`); } // private - displaying #displayResult(result, test, color) { this.#console.log(`[${color}${this.#inBold(result)}] ${this.#withColor(test.name(), color)}`); } #displayResultDetail(detail) { if (!isEmpty(detail)) { this.#console.log(` => ${this.#potentiallyInternationalized(detail)}`); } } #displayErrorsAndFailuresSummary(runner) { if (runner.hasErrorsOrFailures()) { this.#console.log(`\n${this.#translated('failures_summary')}`); runner.allFailuresAndErrors().forEach(test => { const failType = test.isFailure() ? 'fail' : 'error'; this.displayFailureResult(test, failType); }); this.#displaySeparator(); } } #displayGeneralSummary(runner) { this.#console.log(`\n${this.#translated('total')}`); this.#displayCountFor(runner); this.#displaySeparator(); } #displaySuiteFilePath(suite) { this.#console.log(`\n${this.#translated('file')}: ${suite.locationPath()}`); } #displayCountFor(runner) { const passedCount = this.#displayIfNonZero(runner.successCount(), this.#translated('passed'), green); const failureCount = this.#displayIfNonZero(runner.failuresCount(), this.#translated('failed'), red); const errorCount = this.#displayIfNonZero(runner.errorsCount(), this.#translated('errors'), red); const pendingCount = this.#displayIfNonZero(runner.pendingCount(), this.#translated('pending'), yellow); const skippedCount = this.#displayIfNonZero(runner.skippedCount(), this.#translated('skipped'), yellow); this.#console.log(`${runner.totalCount()} test(s)${passedCount}${failureCount}${errorCount}${pendingCount}${skippedCount}`); if (runner.totalCount() === 0) { this.#console.log(this.#withColor(`\nWarning: Make sure your files matches the ${this.#filter} naming filter.`, yellow)); } } #displayIfNonZero(quantity, word, color = off) { const pluralizedWord = `${quantity} ${word}`; return quantity > 0 ? `, ${this.#withColor(pluralizedWord, color)}` : ''; } #displaySeparator(character = '=') { this.#console.log(character.repeat(consoleWidth)); } // private - formatting and localization #inBold(text) { return `${bold}${text}${off}`; } #withColor(text, color) { return `${color}${text}${off}`; } #humanBoolean(boolean) { return boolean === true ? this.#translated('yes') : this.#translated('no'); } #translated(key) { return this.#i18n.translate(key); } #potentiallyInternationalized(text) { return isString(text) ? text : text.expressedIn(this.#i18n); } }