codi-test-framework
Advanced tools
Comparing version 0.0.47 to 1.0.0
{ | ||
"name": "codi-test-framework", | ||
"version": "v0.0.47", | ||
"version": "v1.0.0", | ||
"description": "A simple test framework for JavaScript", | ||
@@ -5,0 +5,0 @@ "main": "src/testRunner.js", |
@@ -1,2 +0,2 @@ | ||
# Codi Test Framework 🐶 | ||
# Codi Test Framework 🐶 | ||
@@ -22,3 +22,3 @@ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) | ||
``` | ||
```bash | ||
npm install --save-dev codi-test-framework | ||
@@ -75,3 +75,3 @@ ``` | ||
``` | ||
```bash | ||
codi ./tests | ||
@@ -86,2 +86,2 @@ ``` | ||
Feel free to contribute to Codi by opening issues or submitting pull requests. Happy testing! 😄 | ||
Feel free to contribute to Codi by opening issues or submitting pull requests. Happy testing! 😄 |
@@ -12,5 +12,8 @@ import chalk from 'chalk'; | ||
*/ | ||
export async function describe(description, callback) { | ||
export async function describe(params, callback) { | ||
const suite = { | ||
description, | ||
description: params.description, | ||
id: params.id, | ||
parentId: params.parentId, | ||
startTime: performance.now() | ||
@@ -22,3 +25,3 @@ }; | ||
try { | ||
await Promise.resolve(callback(nestedSuite.fullPath)); | ||
await Promise.resolve(callback(suite)); | ||
} catch (error) { | ||
@@ -29,5 +32,3 @@ console.error(chalk.red(`Suite failed: ${nestedSuite.fullPath}`)); | ||
nestedSuite.duration = performance.now() - nestedSuite.startTime; | ||
state.testResults.push(nestedSuite); | ||
state.popSuite(); | ||
} | ||
} |
@@ -12,13 +12,12 @@ import { state } from '../state/TestState.js'; | ||
*/ | ||
export async function it(description, callback, suitePath) { | ||
const suite = suitePath | ||
? state.getSuiteByPath(suitePath) | ||
: state.getCurrentSuite(); | ||
export async function it(params, callback) { | ||
const suite = state.getSuite(params) | ||
if (!suite) { | ||
throw new Error('Test case defined outside of describe block'); | ||
throw new Error('A test needs to belong to a suite'); | ||
} | ||
const test = { | ||
description, | ||
description: params.description, | ||
startTime: performance.now() | ||
@@ -39,3 +38,3 @@ }; | ||
state.addTestToSuite(suite.fullPath, test); | ||
state.addTestToSuite(suite, test); | ||
} |
@@ -65,3 +65,3 @@ import fs from 'fs'; | ||
failedTests: state.failedTests, | ||
testResults: state.testResults, | ||
suiteStack: state.suiteStack, | ||
executionTime: state.getExecutionTime() | ||
@@ -99,4 +99,4 @@ }; | ||
failedTests: state.failedTests, | ||
testResults: state.testResults | ||
suiteStack: state.suiteStack | ||
}; | ||
} |
@@ -71,3 +71,3 @@ import { state } from '../state/TestState.js'; | ||
executionTime: state.getExecutionTime(), | ||
testResults: state.testResults | ||
suiteStack: state.suiteStack | ||
}; | ||
@@ -107,4 +107,4 @@ | ||
failedTests: state.failedTests, | ||
testResults: state.testResults | ||
suiteStack: state.suiteStack | ||
}; | ||
} |
@@ -15,6 +15,4 @@ import chalk from 'chalk'; | ||
this.failedTests = 0; | ||
/** @type {Array} Collection of test results */ | ||
this.testResults = []; | ||
/** @type {Array} Stack of active test suites */ | ||
this.suiteStack = []; | ||
this.suiteStack = {}; | ||
/** @type {number|null} Test start time */ | ||
@@ -24,4 +22,2 @@ this.startTime = null; | ||
this.options = {}; | ||
/** @type {Map} Map of suite paths to suite objects */ | ||
this.suiteMap = new Map(); | ||
} | ||
@@ -40,5 +36,3 @@ | ||
this.failedTests = 0; | ||
this.testResults = []; | ||
this.suiteStack = []; | ||
this.suiteMap.clear(); | ||
this.suiteStack = {}; | ||
this.emit('stateReset'); | ||
@@ -62,4 +56,14 @@ } | ||
pushSuite(suite) { | ||
let parentSuite = ''; | ||
// Get parent suite if exists | ||
const parentSuite = this.suiteStack[this.suiteStack.length - 1]; | ||
if (suite.parentId) { | ||
parentSuite = this.suiteStack[suite.parentId]; | ||
} | ||
else { | ||
if (this.suiteStack[suite.id]) { | ||
console.warn(chalk.yellow(`There is already a Suite with the ID: ${suite.id}`)); | ||
suite.id = suite.description + suite.id; | ||
} | ||
} | ||
@@ -69,6 +73,2 @@ // Create nested suite structure | ||
...suite, | ||
fullPath: parentSuite | ||
? `${parentSuite.fullPath} > ${suite.description}` | ||
: suite.description, | ||
parent: parentSuite, | ||
children: [], | ||
@@ -81,7 +81,7 @@ tests: [] | ||
parentSuite.children.push(nestedSuite); | ||
} else { | ||
this.suiteStack[suite.id] = nestedSuite; | ||
} | ||
this.suiteStack.push(nestedSuite); | ||
this.suiteMap.set(nestedSuite.fullPath, nestedSuite); | ||
this.emit('suitePushed', nestedSuite); | ||
// this.emit('suitePushed', nestedSuite); | ||
@@ -92,29 +92,23 @@ return nestedSuite; | ||
/** | ||
* Remove and return the top suite from the stack | ||
* Get suite by id. | ||
* @method | ||
* @returns {object|undefined} Removed test suite | ||
* @param {string} path - Full suite path | ||
* @returns {object|undefined} Found suite | ||
*/ | ||
popSuite() { | ||
const suite = this.suiteStack.pop(); | ||
this.emit('suitePopped', suite); | ||
return suite; | ||
} | ||
getSuite(params) { | ||
let suite = this.suiteStack[params.parentId]; | ||
if (suite) { | ||
return suite; | ||
} | ||
/** | ||
* Get current active suite | ||
* @method | ||
* @returns {object|undefined} Current suite | ||
*/ | ||
getCurrentSuite() { | ||
return this.suiteStack[this.suiteStack.length - 1]; | ||
} | ||
for (const nestedSuite of Object.values(this.suiteStack)) { | ||
if (nestedSuite.children && nestedSuite.children.length > 0) { | ||
const childSuite = nestedSuite.children.find(child => child.id === params.parentId); | ||
if (childSuite) { | ||
return childSuite; | ||
} | ||
} | ||
} | ||
/** | ||
* Get suite by full path | ||
* @method | ||
* @param {string} path - Full suite path | ||
* @returns {object|undefined} Found suite | ||
*/ | ||
getSuiteByPath(path) { | ||
return this.suiteMap.get(path); | ||
return null; | ||
} | ||
@@ -128,7 +122,3 @@ | ||
*/ | ||
addTestToSuite(suitePath, test) { | ||
const suite = this.getSuiteByPath(suitePath); | ||
if (!suite) { | ||
throw new Error(`Cannot find suite: ${suitePath}`); | ||
} | ||
addTestToSuite(suite, test) { | ||
suite.tests.push(test); | ||
@@ -139,39 +129,7 @@ this.emit('testAdded', { suite, test }); | ||
printSummary() { | ||
if (this.testResults.length > 0) { | ||
// Helper function to print suite and its children | ||
const printSuite = (suite, indent = 0) => { | ||
const indentation = ' '.repeat(indent); | ||
// Print suite's tests | ||
let results = suite.tests; | ||
if (this.options.quiet) { | ||
results = results.filter(result => result.status === 'failed'); | ||
} | ||
Object.keys(this.suiteStack).forEach(id => { | ||
printSuite(this.suiteStack[id], 0, this.options); | ||
}); | ||
// Print suite description | ||
if (results.length > 0) { | ||
console.log('\n' + indentation + chalk.yellow(chalk.bold(suite.description))); | ||
} | ||
results.forEach(result => { | ||
if (result.status === 'failed') { | ||
console.log(indentation + chalk.red(` └─ ⛔ ${result.description} (${result.duration.toFixed(2)}ms)`)); | ||
console.log(indentation + chalk.red(` ${result.error.message}`)); | ||
} else { | ||
console.log(indentation + chalk.green(` └─ ✅ ${result.description} (${result.duration.toFixed(2)}ms)`)); | ||
} | ||
}); | ||
// Print child suites | ||
if (suite.children) { | ||
suite.children.forEach(child => printSuite(child, indent + 1)); | ||
} | ||
}; | ||
// Print only top-level suites (they will handle their children) | ||
this.testResults | ||
.filter(suite => !suite.parent) | ||
.forEach(suite => printSuite(suite)); | ||
} | ||
console.log(chalk.bold.cyan('\nTest Summary:')); | ||
@@ -186,2 +144,32 @@ console.log(chalk.green(` Passed: ${this.passedTests}`)); | ||
// Helper function to print suite and its children | ||
const printSuite = (suite, indent, options) => { | ||
const indentation = ' '.repeat(indent); | ||
// Print suite's tests | ||
let results = suite.tests; | ||
if (options.quiet) { | ||
results = results.filter(result => result.status === 'failed'); | ||
} | ||
// Print suite description | ||
if (suite.children.length > 0 || results.length > 0) { | ||
console.log('\n' + indentation + chalk.yellow(chalk.bold(suite.description))); | ||
} | ||
results.forEach(result => { | ||
if (result.status === 'failed') { | ||
console.log(indentation + chalk.red(` └─ ⛔ ${result.description} (${result.duration.toFixed(2)}ms)`)); | ||
console.log(indentation + chalk.red(` ${result.error.message}`)); | ||
} else { | ||
console.log(indentation + chalk.green(` └─ ✅ ${result.description} (${result.duration.toFixed(2)}ms)`)); | ||
} | ||
}); | ||
// Print child suites | ||
if (suite.children) { | ||
suite.children.forEach(child => printSuite(child, indent + 1, options)); | ||
} | ||
}; | ||
export const state = new TestState(); |
@@ -33,3 +33,3 @@ import chalk from 'chalk'; | ||
export const version = 'v0.0.47'; | ||
export const version = 'v1.0.0'; | ||
@@ -36,0 +36,0 @@ /** |
@@ -5,3 +5,3 @@ import { runWebTestFunction } from "../src/runners/webRunner.js"; | ||
// Main test execution | ||
await runWebTestFunction(async () => { | ||
const results = await runWebTestFunction(async () => { | ||
// Sequential setup tests | ||
@@ -23,4 +23,4 @@ await setupTests(); | ||
async function setupTests() { | ||
await describe('Setup Tests', async () => { | ||
await it('should initialize workspace', async () => { | ||
await describe({ description: 'Setup Tests', id: 'setup' }, async () => { | ||
it({ description: 'Should initilise setup', parentId: 'setup' }, async () => { | ||
await simulateDelay(100); | ||
@@ -30,3 +30,3 @@ assertEqual(true, true, 'Workspace initialized'); | ||
await it('should setup query system', async () => { | ||
it({ description: 'Should do some more setup', parentId: 'setup' }, async () => { | ||
await simulateDelay(150); | ||
@@ -40,13 +40,13 @@ assertEqual(true, true, 'Query system ready'); | ||
async function batchOne() { | ||
await describe('First Batch', async () => { | ||
await describe({ description: 'FirstBatch', id: 'first' }, async () => { | ||
await Promise.all([ | ||
it('Test 1.1', async () => { | ||
it({ description: 'Test 1.1', parentId: 'first' }, async () => { | ||
await simulateDelay(100); | ||
assertEqual(true, true, 'Test 1.1 passed'); | ||
}), | ||
it('Test 1.2', async () => { | ||
it({ description: 'Test 1.2', parentId: 'first' }, async () => { | ||
await simulateDelay(75); | ||
assertEqual(true, true, 'Test 1.2 passed'); | ||
}), | ||
it('Test 1.3', async () => { | ||
it({ description: 'Test 1.3', parentId: 'first' }, async () => { | ||
await simulateDelay(50); | ||
@@ -61,13 +61,13 @@ assertEqual(false, false, 'Test 1.3 passed'); | ||
async function batchTwo() { | ||
await describe('Second Batch', async () => { | ||
await describe({ description: 'SecondBatch', id: 'second' }, async () => { | ||
await Promise.all([ | ||
it('Test 2.1', async () => { | ||
it({ description: 'Test 2.1', parentId: 'second' }, async () => { | ||
await simulateDelay(125); | ||
assertEqual(true, true, 'Test 2.1 passed'); | ||
}), | ||
it('Test 2.2', async () => { | ||
it({ description: 'Test 2.2', parentId: 'second' }, async () => { | ||
await simulateDelay(150); | ||
assertEqual(1, 2, 'This test should fail'); | ||
}), | ||
it('Test 2.3', async () => { | ||
it({ description: 'Test 2.3', parentId: 'second' }, async () => { | ||
await simulateDelay(175); | ||
@@ -82,13 +82,13 @@ assertEqual(true, true, 'Test 2.3 passed'); | ||
async function batchThree() { | ||
await describe('Third Batch', async () => { | ||
await describe({ description: 'thirdBatch', id: 'third' }, async () => { | ||
await Promise.all([ | ||
it('Test 3.1', async () => { | ||
it({ description: 'Test 3.1', parentId: 'third' }, async () => { | ||
await simulateDelay(200); | ||
assertEqual(true, true, 'Test 3.1 passed'); | ||
}), | ||
it('Test 3.2', async () => { | ||
it({ description: 'Test 3.2', parentId: 'third' }, async () => { | ||
await simulateDelay(225); | ||
assertEqual(true, true, 'Test 3.2 passed'); | ||
}), | ||
it('Test 3.3', async () => { | ||
it({ description: 'Test 3.3', parentId: 'third' }, async () => { | ||
await simulateDelay(250); | ||
@@ -103,2 +103,4 @@ assertEqual({ a: 1 }, { a: 1 }, 'Test 3.3 passed'); | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
} | ||
} | ||
// console.log(results); |
Sorry, the diff of this file is not supported yet
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
32685
1
85
696