Is it possible to define a Jasmine spec inside a function and still have beforeEach apply to it?
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.
Comments
-
Mark Stickley almost 2 years
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
andafterEach
?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 tocommonTests
instead of always using the current value ofmodule
as in the first example. I'll post my solution when I get there... -
Mark Stickley over 11 yearsInteresting, well you are right of course: it is require.js. The thing is I know MyModule is getting loaded OK because there are other tests that use it that aren't in
commonTests
(which I left out for brevity) and they pass just fine. When I run the debugger incommonTests
and check the value ofmodule
it isundefined
. It has the correct value in tests outside ofcommonTests
... Thanks for looking into this! -
Andreas over 11 yearsI suppose that the other tests are located in the two
describe
calls at the bottom, right? I remember that I've read something aboutvar
scopes in JS. In some cases the variables defined withvar
in functions are available only after thevar
statement. If that's the case here you would try to access the globalmodule
(which doesn't exist) incommonTests
. Perhaps you can try to move thevar module;
and thebeforeEach
to the top of the surroundingdescribe
. -
Mark Stickley over 11 yearsThanks Andreas, I had a look and compared the example to my code and it was slightly different. I've posted an update in the question...
-
Mark Stickley over 11 yearsThat's basically what I've ended up doing. If it's absolutely necessary to pass in the module in the params there's another solution which I'll write up shortly. Thanks!