Not logged in


The builtin unit-testing feature is enabled with -u:

jsish -u tests/test.js 
[PASS] tests/test.js

For a test script to pass, output simply needs to match the expected puts output (contained in an EXPECT* comment), eg:

#!/usr/local/bin/jsish -u %s

function foo(n) {
    return "FOO"+n;



Scripts not having an EXPECT* comment will pass testing as long as they are error-free.

We can also provide expected output from the command-line using -expectFile.


An EXPECT* comment can be updated/inserted in-place using:

jsish -u -update true DIRORFILES

Implicit puts()

Javascript (like many languages) supports multiple consecutive semicolons or empty statements. In testing mode, we take advantage of this fact.

When using jsish -u lines starting and ending with ';' are reformatted with puts("%s ==>", %s) to echo both the expression and the result to stdout:

#!/usr/local/bin/jsish -u %s

function a(n) {
    var sum = 0;
    for (var i = 0; i < n; i++)
        sum = sum + i;
    return sum;

;'===Begin Test===';

'===Begin Test==='
a(10) ==>  45
a(100) ==>  4950
a(1000) ==>  499500

Double-quotes are illegal, and single-quoted strings are output as-is. The transformed code becomes:

puts("'===Begin Test==='");
puts("a(10) ==> ", a(10));
puts("a(100) ==> ", a(100));
puts("a(1000) ==> ", a(1000));

We can see this output using the -U option:

jsish -U tests/func.js
'===Begin Test==='
a(10) ==>  45
a(100) ==>  4950
a(1000) ==>  499500

Implicit and explicit puts can freely be intermixed.

#!/usr/local/bin/jsish -u %s

function foo() { return true; }
function bar() { return true; }

puts('foo() ==> ', foo());

bar() ==>  true
foo() ==>  true

The following rules apply to implicit puts:

On the downside, adding semicolons may require extra bracing of expressions.

Test Results

By default, a test result is either PASS (when output matches) else a FAIL followed by a description of the differences:

jsish -u prob/testfail.js
[FAIL] prob/testfail.js
at line 2 of output:
    output: <bar failed>
    expect: <bar passed>
 foo passed
-bar passed
+bar failed
 baz passed

The return code is zero if the test did not failed.

Multiple Tests

Arguments to jsish -u can either be one or more files, or a single directory in which to look for .js or .jsi files:

jsish -u tests/
[PASS] tests/49.js
[PASS] tests/99bottles.js
[PASS] tests/alias.js
[PASS] tests/apply.js
[FAIL] tests/arg.js
at line 9 of output:
    output: <4>
    expect: <5>
[FAIL] tests/arg2.js
at line 9 of output:
    output: <1>
    expect: <2>
[PASS] tests/alias.js
Test tests/array.js
[PASS] tests/yhsj.js
2 FAIL, 97 PASS: runtime 21551 ms
echo $?

The return code is the number of failed tests (up to a maximum of 127). There is a summary when multiple test are run, but no DIFF (unless context>3).

Script Input

A scripts requiring test input (to read from stdin) it can be specified as follows:


This can also be provided from the command-line using -inStr or -inFile. The default is no input.

Script Arguments

A may script may specify arguments with:

-debug 1 able baker charlie

This should be on a single line: newlines will be stripped.

This can also be provided from the command-line using -args. The default is no arguments.


During unit-testing Interp.asserts is set to true, which means asserts are enabled.

This can result in test scripts failing when assert throws an uncaught error.

There are various ways to adjust the behaviour of assert when working with test scripts, eg. assert.jsi:

#!/usr/local/bin/jsish -u %s
"use asserts";

assert(2*3 == 6,'math');
try {
} catch(e) {
    puts('caught error');
var x = 1;

var i=1, j=2;
;assert(function () { return (i<j); },'fail');

try {
} catch(e) {
    puts('caught error2: '+e);
try {
;   assert(false,'false');
} catch(e) {
    puts('caught error2: '+e);

;assert(false,'this assert failed',{mode:'puts', noStderr:true});

;Interp.conf({assertMode:'puts', noStderr:true});

;assert(false,'assert also failed');


Option help can be dump with:

 jsish -u -h:
Run script(s) as unit-tests setting return code to number of failed tests.

	-args	 	""		// Argument string to call script with
	-context 	3		// Number of context lines for DIFF (>3 forces dir diff).
	-debug	 	false		// Enable debugging messages.
	-echo	 	false		// Run with puts/assert output showing file:line number, but don't test.
	-evalFile 	""		// File to source in subinterp before test.
	-exec	 	false		// Use exec instead of running test in a sub-interp.
	-expectFile 	null		// File to use for expected output.
	-failMax 	0		// Quit after this many failed tests.
	-inFile	 	null		// File to use for stdin input.
	-silent	 	false		// Run quietly, showing only failures.
	-update	 	false		// In-place update or create of EXPECT* from a run of test file(s).
	-verbose 	false		// Show gory detail: inputs/outputs/args.

A script can detect unit-test mode using:

if (Interp.conf('unitTest') > 0)
    puts("We are testing...");


When a test fails, -echo can show the source line associated with output:

jsish -u -echo true prob/testfail.js
jsish -u -echo true prob/testfail.js 
Test prob/testfail.js 
/home/user/src/jsi/jsi/tests/prob/testfail.js:7:   "foo passed", 
/home/user/src/jsi/jsi/tests/prob/testfail.js:8:   "bar failed", 
/home/user/src/jsi/jsi/tests/prob/testfail.js:9:   "baz passed", 

Edit the script as follows to run from Geany with F9, so as to click-to-navigate the output:

#!/usr/local/bin/jsish -u -echo true %s

You can also try -verbose for even more detail.

Builtin Tests

Following are links to the javascript test-files.

49.jsi 99bottles.jsi alias.jsi apply.jsi arg.jsi arg2.jsi arguments.jsi argumentshared.jsi array.jsi array2.jsi assert.jsi b64.jsi badfunc.jsi bind.jsi brainfuck.jsi call.jsi callee2.jsi class.jsi construct.jsi delete.jsi do.jsi eval.jsi eval2.jsi eval3.jsi evalthrow.jsi excpt.jsi excpt2.jsi excpt3.jsi excpt4.jsi excpt5.jsi exec.jsi expr.jsi ffi.jsi fib.jsi file.jsi file2.jsi float.jsi foreach.jsi forin.jsi forinstack.jsi format.jsi func.jsi grep.jsi hexnames.jsi in.jsi info.jsi inherit.jsi inherit2.jsi instance.jsi interp.jsi interp2.jsi invoketime.jsi io.jsi json.jsi json2.jsi labeled.jsi lambda.jsi local.jsi logging.jsi map.jsi math.jsi module.jsi number.jsi obj.jsi person1.jsi person2.jsi prime.jsi property.jsi proto2.jsi proto3.jsi prototypes.jsi recurse.jsi redefine.jsi ref.jsi regex.jsi scope.jsi signal.jsi simple.jsi sqlite.jsi strict.jsi string.jsi switch.jsi switch2.jsi syntax.jsi test.jsi test2.jsi this.jsi this2.jsi this3.jsi time.jsi trim.jsi tryreturn.jsi update.jsi util.jsi value.jsi while.jsi while2.jsi with.jsi yhsj.jsi

Note: the self-test run by make test in Jsi uses a bash script testjs.sh, not jsish -u: