UNPKG

@momsfriendlydevco/testa

Version:

Low-overhead, parallel-first testkit harness

105 lines (91 loc) 3.75 kB
import {styleText} from 'node:util'; import {cleanError, formatSize} from '../lib/utils.js'; /** * Testa UI output that is also designed to simply report on already run tests * * @param {Object} context The UI context * @param {TestaBase} context.TestaBase The root TestaBase instance * @param {Array<TestaTest>} [context.failed] Optional, pre-existing array of failed tests. If provided `execAll()` is skipped * * @param {Object} [context.options] Additional options to mutate behaviour. Some settings can accept a Boolean or `err` (only perform if there are failed tests) or `no-err` (the inverse) * @param {Boolean|'err'|'no-err'} [context.options.border='err'] Add a horizontal line above the report area * @param {Boolean} [context.options.paddingBorder=true] Add a line space before the border line * @param {Boolean|'err'|'no-err'} [context.options.paddingTop='err'] Add a line space at the top of the report (this occurs after the border) * @param {Boolean} [context.options.paddingBetween=true] Add a line space between items * @param {Boolean|'err'|'no-err'} [context.options.paddingBottom='err'] Add a line space at the bottom of the report * * @returns {Promise} A promise which resolves when the operation has completed */ export default async function TestaUIFancy({TestaBase, failed, options}) { let settings = { border: 'err', paddingBorder: true, paddingTop: 'err', paddingBetween: true, paddingBottom: true, ...options, }; let failedTests; // Eventual array of tests that failed /** * Helper function to perform a callback if the settings is literal boolean `true` or if the settings is `err` + the are any failed tests * This is used by various formatting settings like `border` + `paddingBorder` to determine if those UI elements should be added * * @param {Boolean|'err'} setting Setting to examine * @param {Function} action The callback action to run if the conditions are satisfied */ let selectiveAction = (setting, action) => { if ( setting === true || (setting == 'err' && failedTests.length > 0) || (setting == 'no-err' && failedTests.length == 0) ) { action(); } }; return Promise.resolve() .then(()=> { if (failed) { failedTests = failed; } else { // No pre-existing list - collect return TestaBase.execAll({ onTestRejected: test => failedTests.push(test), onTestTimeout: test => failedTests.push(test), }) } }) .then(()=> { selectiveAction(settings.border, ()=> { // Add UI border? if (settings.paddingBorder) console.log(); console.log(styleText('grey', '┄').repeat(process.stdout.columns)); }); selectiveAction(settings.paddingTop, ()=> console.log()); // Add top padding? failedTests.forEach(test => { // Header line - show ID + name + (reason) console.log( styleText(['bold', 'red'], test.toString('id')) + '. ' + styleText('red', test.toString('title')), test._status == 'rejected' ? styleText(['bold', 'red'], '(failed)') : test._status == 'timeout' ? styleText(['bold', 'yellow'], '(timeout)') : '' ); // Output location sub-header if we have one if (test._location) console.log( styleText('grey', '@ ' + test.toString('location')) ); // Output test artefacts if we have any if (test._dumps.length > 0) test._dumps.forEach((dump, dumpOffset) => console.log( styleText(['italic', 'cyan'], `ARTEFACT #${dumpOffset+1}`), dump.path, styleText('grey', '(' + formatSize(dump.size) + ')'), ) ); console.log(cleanError(test._error)); if (settings.paddingBetween) console.log(); }); selectiveAction(settings.paddingBottom, ()=> console.log()); // Add bottom padding? }); }