Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run Mocha tests in a defined order

Tags:

Background

I am working on a program in Node.js and writing my test suites in Mocha with Chai and SinonJS. I have core graphics module which controls access to a node-webgl context.

Due to how node-webgl works, I only wish to initialize a context once for the entire test run. I have some tests I wish to run prior to the initialization of the core module, like so:

describe('module:core', function () {
    describe('pre-init', function () {
        describe('.isInitialized', function () {
            it('should return false if the module is not initialized', function () {
                expect(core.isInitialized()).to.be.false;
            });
        });
        describe('.getContext', function () {
            it('should error if no context is available', function () {
                expect(function () {
                    core.getContext();
                }).to.throw(/no context/i);
            });
        });
    });
    describe('.init', function () {
        it('should error on an invalid canvas', function () {
            expect(function () {
                core.init(null);
            }).to.throw(/undefined or not an object/i);
            expect(function () {
                core.init({});
            }).to.throw(/missing getcontext/i);
        });
        it('should error if the native context could not be created', function () {
            var stub = sinon.stub(global._canvas, 'getContext').returns(null);
            expect(function () {
                core.init(global._canvas);
            }).to.throw(/returned null/i);
            stub.restore();
        });
        it('should initialize the core module', function () {
            expect(function () {
                core.init(global._canvas);
            }).not.to.throw();
        });
    });
    describe('post-init', function () {
        describe('.isInitialized', function () {
            it('should return true if the module is initialized', function () {
                expect(core.isInitialized()).to.be.true;
            });
        });
        describe('.getContext', function () {
            it('should return the current WebGL context', function () {
                var gl = null;
                expect(function () {
                    gl = core.getContext();
                }).not.to.throw();
                // TODO Figure out if it's actually a WebGL context.
                expect(gl).to.exist;
            });
        });
    });
});

Then I can run the remaining tests.

Problem

When I run this through Mocha, everything is fine since the core test suite is the first thing to be run. My concern is that if any test suites get run before the core test suite, then those test suites will fail as the core is not initialized yet.

What is the best way to ensure the core test suite is always run before any other test suites?

like image 956
M. Damian Mulligan Avatar asked Mar 29 '16 12:03

M. Damian Mulligan


2 Answers

In the end I refactored my code to permit the core module to be torn down without affecting node-webgl and using a before block to initialize it, like so:

// Run this before all tests to ensure node-webgl is initialized
before(function () {
    if (!global._document) {
        global._document = WebGL.document();
        global._document.setTitle('Machination Graphics Test Suite');
    }
    if (!global._canvas) {
        global._canvas = global._document.createElement('canvas', 640, 480);
    }
});

describe('test suite goes here', function () {
    // Ensure core is ready for us before testing (except when testing core)
    before(function () {
        if (!core.isInitialized()) {
            core.init(global._canvas);
        }
    });
    // Tear down core after all tests are run
    after(function () {
        core.deinit();
    });
    ...
});
like image 142
M. Damian Mulligan Avatar answered Oct 12 '22 13:10

M. Damian Mulligan


Use before() as described in their documentation.

describe('hooks', function() {
    before(function() {
        // runs before all tests in this block
    });
    ......
});

the function in before will run first and everything else int he describe after it.

hope this helps.

like image 29
Pavel Zlatanov Avatar answered Oct 12 '22 12:10

Pavel Zlatanov