Implement truenit.js
Closed this issue · 11 comments
Implement truenit.js
as the main script.
Goal API:
- First call
require( 'truenit' );
and reference it. - call
truenit.start( () => { // start testing here } )
- then inside of the truenit.start passed functions start testing via
truenit.testModule
- log the errors if there are any in different colors.
After further investigation, I have decided to use process.stdout.write
for all errors.
I referenced this from this forum. This will allow me to log without new lines (optional) via \n
.
I still need to colorize these, however.
If found this article which demos colorized output via process.stdout.write
.
I converted this to my script:
/**
* A logger for NodeJs that allows for same line logging. Should be wrapped inside a wrapper.
* Use to indicate a new line and to colorize the output.
*
* @param {string} message
* @param {number} [color] - the code for the color. See below:
* Reset = 0 Bright = 1 Di = 2 Underscore = 4
* Blink = 5 Reverse = 7 Hidden = 8 FgBlack = 30
* FgRed = 31 FgGreen = 32 FgYellow = 33 FgBlue = 34
* FgMagenta = 35 FgCyan = 36 FgWhite = 37 BgBlack = 40
* BgRed = 41 BgGreen = 42 BgYellow = 43 BgBlue = 44
* BgMagenta = 45 BgCyan = 46 BgWhite = 47
*/
function log( message, color=0 ) {
assert( typeof message === 'string', `invalid message: ${message}` );
process.stdout.write( '\x1b[' + color + 'm' + message + '\x1b[0m' );
}
I now need to wrap everything in a try-catch statement so that I can properly call log
on all error catches.
I have decided to split this up to 3 layers:
First Layer:
/**
* Wraps a task such that any errors (which stops task) will be thrown via a log call.
* Improves the Node.js error handling.
*
* @param {function} task
*/
function wrap( task ) {
try { task(); }
catch( error ) {
// Catch any errors while executing task and reformat the error message.
log( `${error}`, 31 );
process.exit( 1 );
}
};
This will do a task and log any errors and exit the script. This is the main wrapper for the script.
Second Layer:
/**
* Basic method that attempts to execute a tester. Used as a high-level wrapper to start a large
* section of tests.
* @public
*
* @param {function} tester
* @param {string} [startMessage]
* @param {number} [startColor]
* @param {string} [endMessage]
* @param {number} [endColor]
* @param {string} [failedMessage]
*/
static test( tester, startMessage, startColor, endMessage, endColor, failedMessage ) {
wrap( () => {
assert( typeof tester === 'function', `invalid tester: ${tester}` );
assert( !startMessage || typeof startMessage === 'string', `invalid startMessage: ${startMessage}` );
assert( !endMessage || typeof endMessage === 'string', `invalid endMessage: ${endMessage}` );
assert( !failedMessage || typeof failedMessage === 'string', `invalid failedMessage: ${failedMessage}` );
//----------------------------------------------------------------------------------------
// Start testing
log( startMessage ? startMessage : 'starting test...\n', startColor );
try {
tester();
}
catch( error ) {
assert( false, failedMessage ? failedMessage : `FAILED \n\n${error.stack}\n\n` );
}
log( endMessage ? endMessage : 'Test passed!', endColor );
} )
}
The second layer calls wrap on a task that runs tester. This is public facing but generally won't be used. This is starting to put the module together.
Third layer
Call this.test
in other methods (start and testModule). I haven't added these yet.
I have finished adding the other layers:
/**
* Test method wrapper for the start of a project.
*
* @param {function} tester
*/
static start( tester ) {
truenit.test( tester, 'Testing all...\n\n', 4, '\nAll tests passed!\n\n', 32 );
}
/**
* Test method wrapper for a module. Should be wrapped inside of truenit.start().
*
* @param {string} name - the name of the module
* @param {function} tester
*/
static testModule( name, tester ) {
wrap( () => {
assert( typeof name === 'string', `invalid name: ${name}` );
} );
truenit.test( tester, `Testing ${name}... `, 2, `passed.\n`, 0 );
}
/**
* Tests that a predicate is truthy.
* Should be wrapped inside of a tester.
* @public
*
* @param {boolean} predicate
* @param {string} [message]
*/
static ok( predicate, message ) {
assert( predicate, message || 'unit test failed.' );
}
It is important to note that ok
should be ran inside of start
or testModule
so that it is properly caught and logged.
I have decided on an API change to allow for this change:
truenit.registerModule( 'Point', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Node', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'ScreenView', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Vector', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'VectorProperty', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Merge', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Enum', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Property', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'PointProperty', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'Sim', require( 'TESTS/util/PointTests' ) );
truenit.registerModule( 'ErrorModule', () => { throw new Error( 'Error Message')} );
truenit.start();
As you can see from this example, I'm going to register each module's tester first then start it. This way I can align the "passed"