Skip to content

Commit

Permalink
v0.0.38 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
RobAndrewHurst committed Nov 13, 2024
1 parent 2c1c1bb commit 891c603
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 134 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codi-test-framework",
"version": "v0.0.37",
"version": "v0.0.38",
"description": "A simple test framework for JavaScript",
"main": "src/testRunner.js",
"type": "module",
Expand Down
3 changes: 0 additions & 3 deletions src/core/describe.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ export async function describe(description, callback) {
};

state.pushSuite(suite);
if (!state.options?.quiet) {
console.log(chalk.bold.cyan(`\n${description}`));
}

try {
await Promise.resolve(callback());
Expand Down
10 changes: 1 addition & 9 deletions src/core/it.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,14 @@ export async function it(description, callback) {
test.status = 'passed';
test.duration = performance.now() - test.startTime;
state.passedTests++;
if (!state.options?.quiet) {
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++;

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);
Expand Down
8 changes: 5 additions & 3 deletions src/runners/nodeRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ export async function runTests(testDirectory, returnResults = false, codiConfig
* @param {Function} testFn - Test function to run
* @returns {Promise<object>} Test results
*/
export async function runTestFunction(testFn, options) {
export async function runTestFunction(testFn, options, description) {
const suite = {
description: `Function: ${testFn.name}`,
description: description ? description : `Function: ${testFn.name}`,
tests: [],
startTime: performance.now()
};
Expand All @@ -107,7 +107,9 @@ export async function runTestFunction(testFn, options) {
state.popSuite();
}

state.printSummary();
if (options.showSummary) {
state.printSummary();
}

return {
passedTests: state.passedTests,
Expand Down
109 changes: 23 additions & 86 deletions src/runners/webRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,19 @@ import chalk from 'chalk';
* @param {object} [options={}] - Options for running the test
* @returns {Promise<void>}
*/
export async function runWebTestFile(testFile, options = {}) {
const {
timeout = 5000,
silent = false
} = options;
export async function runWebTestFile(testFile, options) {

const defaults = {
silent: false
};

options ??= defaults;

try {
const startTime = performance.now();

const testPromise = import(testFile);
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Test file ${testFile} timed out after ${timeout}ms`)), timeout);
});
await Promise.resolve(testPromise);

await Promise.race([testPromise, timeoutPromise]);

const duration = performance.now() - startTime;
if (!silent) {
console.log(chalk.green(`✅ ${path.basename(testFile)} (${duration.toFixed(2)}ms)`));
}
} catch (error) {
console.error(`Error running test file ${testFile}:`);
console.error(error.stack);
Expand All @@ -44,13 +37,16 @@ export async function runWebTestFile(testFile, options = {}) {
* @param {object} [options={}] - Options for running the tests
* @returns {Promise<object>} Test results
*/
export async function runWebTests(testFiles, options = {}) {
const {
parallel = false,
timeout = 5000,
quiet = false,
batchSize = 5
} = options;
export async function runWebTests(testFiles, options) {

const defaults = {
parallel: false,
quiet: false,
batchSize: 5,
showSummary: true
}

options ??= defaults;

state.resetCounters();
state.startTimer();
Expand All @@ -74,19 +70,19 @@ export async function runWebTests(testFiles, options = {}) {
}

await Promise.all(
batch.map(file => runWebTestFile(file, { timeout, silent: quiet }))
batch.map(file => runWebTestFile(file, options))
);
}
} else {
// Run all tests in parallel
await Promise.all(
testFiles.map(file => runWebTestFile(file, { timeout, silent: quiet }))
testFiles.map(file => runWebTestFile(file, options))
);
}
} else {
// Run tests sequentially
for (const file of testFiles) {
await runWebTestFile(file, { timeout, silent: quiet });
await runWebTestFile(file, options);
}
}
} catch (error) {
Expand All @@ -102,67 +98,8 @@ export async function runWebTests(testFiles, options = {}) {
testResults: state.testResults
};

state.printSummary();

return summary;
}

/**
* Run a web test function
* @async
* @function runWebTestFunction
* @param {Function} testFn - Test function to run
* @param {object} [options={}] - Options for running the test
* @returns {Promise<object>} Test results
*/
export async function runWebTestFunction(testFn, options = {}) {
const {
timeout = 5000,
silent = false
} = options;

state.resetCounters();
state.startTimer();

const suite = {
description: `Function: ${testFn.name}`,
tests: [],
startTime: performance.now()
};

state.pushSuite(suite);

try {
const testPromise = Promise.resolve(testFn());
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error(`Test function ${testFn.name} timed out after ${timeout}ms`)), timeout);
});

await Promise.race([testPromise, timeoutPromise]);
} catch (error) {
console.error(chalk.red(`Error in test ${testFn.name}:`));
console.error(chalk.red(error.stack));
state.failedTests++;
} finally {
suite.duration = performance.now() - suite.startTime;
state.testResults.push(suite);
state.popSuite();
}

const summary = {
totalTests: state.passedTests + state.failedTests,
passedTests: state.passedTests,
failedTests: state.failedTests,
executionTime: state.getExecutionTime(),
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`));
if (options.showSummary) {
state.printSummary();
}

return summary;
Expand Down
49 changes: 30 additions & 19 deletions src/state/TestState.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@ class TestState {
}

setOptions(options) {
this.options = options;
this.options = {
...this.options,
...options
};
}

/**
Expand Down Expand Up @@ -88,35 +91,43 @@ class TestState {
}

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');
let results = suite.tests;

if (state.options.quiet) {
results = results.filter(result => result.status === 'failed');
}

if (results.length > 0) {
console.log('\n' + chalk.yellow('' + chalk.bold(suite.description)));
}

if (results.length > 0) {
results.forEach(result => {

if (result.status === 'failed') {
console.log(chalk.red(` └─ ⛔ ${result.description} (${result.duration.toFixed(2)}ms)`));
console.log(chalk.red(` ${result.error.message}`));
} else {
console.log(chalk.green(` └─ ✅ ${result.description} (${result.duration.toFixed(2)}ms)`));
}


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}`));
});
}

});
}
// 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`));
}

}

export const state = new TestState();
5 changes: 2 additions & 3 deletions src/testRunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export {

export {
runWebTests,
runWebTestFile,
runWebTestFunction
runWebTestFile
} from './runners/webRunner.js';

// Assertion exports
Expand All @@ -29,7 +28,7 @@ export const assertFalse = assertions.assertFalse;
export const assertThrows = assertions.assertThrows;
export const assertNoDuplicates = assertions.assertNoDuplicates;

export const version = 'v0.0.37';
export const version = 'v0.0.38';

/**
* CLI entry point for running tests
Expand Down
19 changes: 9 additions & 10 deletions tests/example.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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, 2, 'Expected 1 to equal 1');
assertEqual(1, 1, 'Expected 1 to equal 1');
});

it('should pass inequality assertion', () => {
Expand Down Expand Up @@ -37,12 +37,11 @@ await describe('I am an Example Test Suite', () => {
});

});
// Nested describe for a new context
await describe('Running testFunction', async () => {
function testFunction() {
it('First', () => {
assertEqual(1, 2, 'Expected 1 to equal 1');
});
}
await runTestFunction(testFunction);
});

await runTestFunction(testFunction, { showSummary: false });

function testFunction() {
it('First', () => {
assertEqual(1, 2, 'Expected 1 to equal 1');
});
}

0 comments on commit 891c603

Please sign in to comment.