diff --git a/src/core/it.js b/src/core/it.js index e22d0a1..370b68e 100644 --- a/src/core/it.js +++ b/src/core/it.js @@ -29,13 +29,18 @@ export async function it(description, callback) { console.log(chalk.green(` ✅ ${description} (${test.duration.toFixed(2)}ms)`)); } } catch (error) { + test.status = 'failed'; test.error = error; test.duration = performance.now() - test.startTime; state.failedTests++; - // Always show errors, even in quiet mode - console.error(chalk.red(` ⛔ ${description} (${test.duration.toFixed(2)}ms)`)); - console.error(chalk.red(` ${error.message}`)); + + if (!state.options?.quiet) { + + console.error(chalk.red(` ⛔ ${description} (${test.duration.toFixed(2)}ms)`)); + console.error(chalk.red(` ${error.message}`)); + + } } state.currentSuite.tests.push(test); diff --git a/src/runners/nodeRunner.js b/src/runners/nodeRunner.js index 24774c8..96b26dc 100644 --- a/src/runners/nodeRunner.js +++ b/src/runners/nodeRunner.js @@ -56,11 +56,7 @@ export async function runTests(testDirectory, returnResults = false, codiConfig await runTestFile(path.join(testDirectory, file)); } - // Always show the final summary - console.log(chalk.bold.cyan('\nTest Summary:')); - console.log(chalk.green(` Passed: ${state.passedTests}`)); - console.log(chalk.red(` Failed: ${state.failedTests}`)); - console.log(chalk.blue(` Time: ${state.getExecutionTime()}s`)); + state.printSummary(); if (returnResults) { return { @@ -87,7 +83,7 @@ export async function runTests(testDirectory, returnResults = false, codiConfig * @param {Function} testFn - Test function to run * @returns {Promise} Test results */ -export async function runTestFunction(testFn, options = {}) { +export async function runTestFunction(testFn, options) { const suite = { description: `Function: ${testFn.name}`, tests: [], @@ -95,7 +91,10 @@ export async function runTestFunction(testFn, options = {}) { }; state.pushSuite(suite); - state.setOptions(options); + + if (options) { + state.setOptions(options); + } try { await Promise.resolve(testFn()); @@ -108,6 +107,8 @@ export async function runTestFunction(testFn, options = {}) { state.popSuite(); } + state.printSummary(); + return { passedTests: state.passedTests, failedTests: state.failedTests, diff --git a/src/runners/webRunner.js b/src/runners/webRunner.js index dce3d12..acbc25e 100644 --- a/src/runners/webRunner.js +++ b/src/runners/webRunner.js @@ -48,14 +48,14 @@ export async function runWebTests(testFiles, options = {}) { const { parallel = false, timeout = 5000, - silent = false, + quiet = false, batchSize = 5 } = options; state.resetCounters(); state.startTimer(); - if (!silent) { + if (!quiet) { console.log(chalk.bold.magenta(`\nRunning ${testFiles.length} web test file(s)`)); } @@ -69,24 +69,24 @@ export async function runWebTests(testFiles, options = {}) { } for (const [index, batch] of batches.entries()) { - if (!silent) { + if (!quiet) { console.log(chalk.blue(`\nBatch ${index + 1}/${batches.length}`)); } await Promise.all( - batch.map(file => runWebTestFile(file, { timeout, silent })) + batch.map(file => runWebTestFile(file, { timeout, silent: quiet })) ); } } else { // Run all tests in parallel await Promise.all( - testFiles.map(file => runWebTestFile(file, { timeout, silent })) + testFiles.map(file => runWebTestFile(file, { timeout, silent: quiet })) ); } } else { // Run tests sequentially for (const file of testFiles) { - await runWebTestFile(file, { timeout, silent }); + await runWebTestFile(file, { timeout, silent: quiet }); } } } catch (error) { @@ -102,13 +102,7 @@ export async function runWebTests(testFiles, options = {}) { testResults: state.testResults }; - if (!silent) { - console.log(chalk.bold.cyan('\nTest Summary:')); - console.log(chalk.blue(` Total: ${summary.totalTests}`)); - console.log(chalk.green(` Passed: ${summary.passedTests}`)); - console.log(chalk.red(` Failed: ${summary.failedTests}`)); - console.log(chalk.blue(` Time: ${summary.executionTime}s`)); - } + state.printSummary(); return summary; } diff --git a/src/state/TestState.js b/src/state/TestState.js index f3007ef..ae103c1 100644 --- a/src/state/TestState.js +++ b/src/state/TestState.js @@ -1,5 +1,4 @@ -// src/state/TestState.js - +import chalk from 'chalk'; /** * Class representing the state of test execution * @class TestState @@ -87,6 +86,37 @@ class TestState { popSuite() { return this.suiteStack.pop(); } + + printSummary() { + if (state.options.quiet) { + state.printFailures(); + } + // Always show the final summary + console.log(chalk.bold.cyan('\nTest Summary:')); + console.log(chalk.green(` Passed: ${state.passedTests}`)); + console.log(chalk.red(` Failed: ${state.failedTests}`)); + console.log(chalk.blue(` Time: ${state.getExecutionTime()}s`)); + } + + printFailures() { + + if (this.testResults.length > 0) { + this.testResults.forEach(suite => { + + const failures = suite.tests.filter(test => test.status === 'failed'); + + if (failures.length > 0) { + console.log('\nFailed Tests:'); + failures.forEach(failure => { + console.log('\n' + chalk.red('✖ ' + chalk.bold(suite.description))); + console.log(chalk.red(` └─ ${failure.description}`)); + console.log(chalk.red(` ${failure.error.message}`)); + }); + } + + }); + } + } } export const state = new TestState(); \ No newline at end of file diff --git a/tests/example.test.mjs b/tests/example.test.mjs index 8bc34e6..961ed11 100644 --- a/tests/example.test.mjs +++ b/tests/example.test.mjs @@ -4,7 +4,7 @@ import { describe, it, assertEqual, assertNotEqual, assertTrue, assertFalse, ass await describe('I am an Example Test Suite', () => { it('should pass equality assertion', () => { - assertEqual(1, 1, 'Expected 1 to equal 1'); + assertEqual(1, 2, 'Expected 1 to equal 1'); }); it('should pass inequality assertion', () => { @@ -44,5 +44,5 @@ await describe('Running testFunction', async () => { assertEqual(1, 2, 'Expected 1 to equal 1'); }); } - await runTestFunction(testFunction, { quiet: true }); + await runTestFunction(testFunction); }); \ No newline at end of file