Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to define a Jasmine spec inside a function and still have beforeEach apply to it?

I have a lot of tests which are virtually the same. In the interests of DRY and scanability I'd like to abstract the tests into a single function and then call that function with a few parameters. The function would then call it and add the spec to the suite.

It seems to work, except the specs don't get run in the same way as the other specs and beforeEach is not called before the specs defined in the common function.

define(['modules/MyModule','jasmine/jasmine'], function(MyModule) {

    describe('myModule', function() {

        function commonTests(params) {
            it('should pass this test OK', function() {
                expect(true).toBe(true);
            });

            it('should fail because module is undefined', function() {
                expect(module[params.method]()).toBe('whatever');
            });
        }

        var module;

        beforeEach(function() {
            module = new MyModule();
        });

        describe('#function1', function() {
            commonTests({
                method: 'function1'
            });
        });

        describe('#function2', function() {
            commonTests({
                method: 'function2'
            });
        });

    });

});

Is there any way of doing this and maintaining the functionality of beforeEach and afterEach?

UPDATE:

Looks like I got my example wrong, sorry. Here's the case that fails:

define(['modules/MyModule'], function(MyModule) {

    function commonTests(params) {
        it('will fail because params.module is undefined', function() {
            expect(typeof params.module).toBe('object');
            expect(typeof params.module[params.method]).toBe('function');
        });

        it('has a few tests in here', function() {
            expect(true).toBe(true);
        });
    }


    describe('MyModule', function() {

        var module;

        beforeEach(function() {
            module = new MyModule();
        });

        describe('#function1', function() {
            commonTests({
                module: module,
                method: 'function1'
            });
        });

        describe('#function2', function() {
            commonTests({
                module: module,
                method: 'function2'
            });
        });

    });
});

I think it fails because the value of module is preserved as part of the call to commonTests instead of always using the current value of module as in the first example. I'll post my solution when I get there...

like image 996
Mark Stickley Avatar asked Oct 30 '12 13:10

Mark Stickley


1 Answers

Thanks to Andreas for pointing out that my first example actually worked! The final solution I'm using is very similar:

define(['modules/MyModule'], function(MyModule) {

    var module;

    function commonTests(params) {
        it('will not fail because module is shared', function() {
            expect(typeof module).toBe('object');
            expect(typeof module[params.method]).toBe('function');
        });

        it('has a few tests in here', function() {
            expect(true).toBe(true);
        });
    }


    describe('MyModule', function() {

        beforeEach(function() {
            module = new MyModule();
        });

        describe('#function1', function() {
            commonTests({
                method: 'function1'
            });
        });

        describe('#function2', function() {
            commonTests({
                method: 'function2'
            });
        });

    });
});

Although if you needed to have the ability to pass in module as an argument to commonTests you would have to take a slightly different approach and have a different function for each it block:

define(['modules/MyModule'], function(MyModule) {

    var module;

    function commonTest1(params) {
        expect(typeof module).toBe('object');
        expect(typeof module[params.method]).toBe('function');
    }

    function commonTest2(params) {
        expect(true).toBe(true);
    }


    describe('MyModule', function() {

        beforeEach(function() {
            module = new MyModule();
        });

        describe('#function1', function() {

            it('will not fail because module is shared', function() {
                commonTest1({ method: 'function1' });
            });

            it('has a few tests in here', function() {
                commonTest2({ method: 'function1' });
            });

        });

        describe('#function2', function() {

            it('will not fail because module is shared', function() {
                commonTest1({ method: 'function2' });
            });

            it('has a few tests in here', function() {
                commonTest2({ method: 'function2' });
            });

        });

    });
});

This way the executions of the functions containing the common tests is delayed until after beforeEach has run its callback.

like image 117
Mark Stickley Avatar answered Sep 28 '22 06:09

Mark Stickley