CLI Typescript project setup for Wallaby , Mocha, Chai, and Sinon

So I wanted to put this out here for others that might want to use this tooling set.

What this is for:
Aurelia CLI Typescript Project
This is my setup for creating a cli project and using WallabyJS, Mocha, Chai, and Sinon.
You can add Jasmine (I assume Jest as well) using the cli options if desired as I haven’t found it interferred with anything.

Result should be:
Ability to run you unit tests live using WallabyJS and run the tests from the command line using ‘npm run test’.

Things to do:
Getting tests to run using ‘au test’

Requirements:
You need to npm install the following modules:

npm i mocha @types/mocha chai @types/chai sinon @types/sinon ts-node -D

Next steps:
You will need to create the following files. These are referenced from your projects base directory. Each files contents will follow:

wallaby.js (can also use wallaby.config.js)
tsconfig.test.json
test/mocha.opts
test/tshook.js

test/unit/app.spec.ts (updated with some simple tests to make sure everything is linked up)

wallaby.js contents

module.exports = function (wallaby)
{
    return {

        debug: true,

        files: [
            { pattern: 'node_modules/chai/chai.js', instrument: false, load: true },
            { pattern: 'node_modules/sinon/pkg/sinon.js', instrument: false, load: true },
            { pattern: 'tsconfig.json' },
            { pattern: 'src/**/*.ts' },
            { pattern: 'src/**/*.html' },
            { pattern: 'test/**/*.ts' },
            { pattern: '!test/unit/**/*.spec.ts' }
        ],

        tests: ['test/unit/**/*.spec.ts'],

        env: {
            type: 'node',
            runner: 'node'
        },

        testFramework: 'mocha',

        compilers: {
            '**/*.ts': wallaby.compilers.typeScript({
                module: 'commonjs'
            })
        },

		//executed in test framework context
        setup: function (wallaby) 
        {
        }
    };
};

tsconfig.test.json contents (copy of base tsconfig.json with target and module type changed)

{
    "compileOnSave": false,
    "compilerOptions": {
        "sourceMap": true,
        "target": "es6",
        "module": "commonjs",
        "declaration": false,
        "noImplicitAny": false,
        "removeComments": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "allowJs": true,
        "moduleResolution": "node",
        "lib": [
            "es2017",
            "dom"
        ],
        "baseUrl": "src"
    },
    "include": [
        "./src/**/*.ts",
        "./test/**/*.ts",
        "./custom_typings/**/*.d.ts"
    ],
    "atom": {
        "rewriteTsconfig": false
    }
}

test/mocha.opts contents

--require ./test/tshook
--timeout 6000
--slow 1500
--watch-extensions ts
./test/unit/**/*.spec.ts

test/tshook.js contents

require("ts-node").register({
    project: "tsconfig.test.json",
});

test/unit/app.spec.ts content

import { App } from '../../src/app';
import { expect } from 'chai';
import { SinonStatic } from 'sinon';
let sinon: SinonStatic = require('sinon');


describe('the app', () =>
{
    it('says hello with chai expect', () =>
    {
        expect(new App().message).to.equal('Hello World!');
    });
});

function once(fn)
{
    var returnValue, called = false;
    return function ()
    {
        if (!called)
        {
            called = true;
            returnValue = fn.apply(this, arguments);
        }
        return returnValue;
    };
}

describe('sinon accessable test', () =>
{
    it('calls the original function', function ()
    {
        var callback = sinon.fake();
        var proxy = once(callback);

        proxy();

        expect(callback.called).to.equal(true);
    });
});

Starting WallabyJS:
I am using VS Code so the instructions are for that environment.
Open the project in code.
Use CTL-SHIFT-P to open the Command Palette and selet ‘wallaby.js: Start’
It might prompt you to select a configuration file, though it should just auto-select it. If not select the wallaby.js file we created earlier.
In the lower right of VS Code you should see the Wallaby activity indicator and eventually the failing and passing test count, which if you used my sample above should display 0 failing, 2 passing.

Using the command line:
Open a command line shell.
Type in ‘npm run test’
The tests will run and display the results showing passing and failing tests.

If you find any errors, or suggestions let me know.

Shoutout to @zewa666 for the mocha setup.

3 Likes

So I have revisited this with the new cli version 1.2.2 and its appears its much simpler, or I just over complicated the first version. (That wouldn’t suprise me)

Anyways, here is how I have:

  • Mocha
  • Chai
  • Sinon
  • Wallaby

now running both using a command line, and the standard Wallaby interface.

So wind up the Aurelia CLI and create a new project.

I used the following prompt selections:

    • Custom App
    • CLI’s built-in bundler
    • Alameda
    • Web
    • Typescript
    • Maximum Minification
    • Sass
    • Typical
    • None
    • None
    • Visual Studio Code
    • Minimum
    • No
    • Yes

Change into your project directory.

Add the following npm modules:

  • npm i mocha @types/mocha chai @types/chai sinon @types/sinon chai-datetime @types/chai-datetime -D
  • npm i ts-node ts-mocha tsconfig-paths -D

Once those are installed add/update the following files:

  • /package.json
  • /wallaby.js
  • /.mocharc.json
  • /test/tsconfig.cjs.json
  • /test/unit/test.spec.ts

I originally had the chai initialization inside of the wallaby config, but of course if you used the command line it would error out not finding it. So I moved it into the mocha setup() function, which does create more boilerplate noise. There is probably a way to seperate that out, but I haven’t looked into that yet.

I override the default module type selection for testing only using a parameter to ts-mocha, which extends the root tsconfig.json.

You should now be able to run Wallaby in VS Code if you have it installed

  • [shift][control]-p and select wallaby start

or

Using the ts-mocha wrapper, run tests on the command line using:

  • npm run test

Here are the file changes/contents:

package.json - add test script

"test": "ts-mocha -p test/tsconfig.cjs.json"

wallaby.js - New File

module.exports = function (wallaby)
{
    var path = require('path');

    process.env.NODE_PATH += path.delimiter + wallaby.projectCacheDir + path.delimiter + 'src';

    return {

        debug: false,

        files: [
            { pattern: 'node_modules/chai/chai.js', instrument: false, load: true },
            { pattern: 'node_modules/sinon/pkg/sinon.js', instrument: false, load: true },
            { pattern: 'src/**/*.ts' },
        ],

        tests: ['test/unit/**/*.spec.ts'],

        env: {
            type: 'node',
            runner: 'node'
        },

        testFramework: 'mocha',

        compilers: {
            '**/*.ts': wallaby.compilers.typeScript({
                module: 'commonjs',
                baseUrl: './src'
            })
        },

        //executed in test framework context
        setup: function (wallaby) 
        {
            //chai.use(require('chai-datetime'));
            //var should = chai.should();
        }
    };
};

.mocharc.json

{
  "extension": ["ts"],
  "spec": "test/unit/**/*.spec.ts",
  "require": "tsconfig-paths/register"
}

tsconfig.cjs.json

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "module": "commonjs"
  }
}

test.spec.ts

import * as chai from 'chai';
import { expect, assert } from 'chai';
import { setup } from 'mocha';

import { App } from "app";

setup(() =>
{
    chai.should();
    chai.use(require('chai-datetime'));
});

describe('Sayings Greeter', () =>
{
    it('should be defined', () =>
    {        
        assert(expect !== undefined, "expect undefined");
        expect(this.should, "should is undefined").to.not.be.undefined;
        'foo'.should.equal('foo');
    });

    it('should greet', () =>
    {
        var greeter = {name: 'John'};
        expect(greeter.name).to.equal('John');
    });
});

describe('App message', () =>
{
    var app = new App();
    
    it('should be defined', () =>
    {
        assert(app.message !== undefined, "expect undefined");
    });

    it('should equal', () =>
    {
        expect(app.message).to.equal('Hello World!');
    });
});
2 Likes

I created a project for those that might find that easier to examine versus code blocks.

4 Likes