Hi,
As you can see in the following Plunkr, the way most AngularJs unit tests and documentations are written is wrong when it's about loading a module in a beforeEach() function.
Most of the documentation refers to
beforeEach(module('aModule'));
while the right way of loading a module _before each_ "it" spec is the following:
beforeEach(function() {
module('aModule');
});
This is particularly annoying when you rely on stateful singleton (service, factory), that can have side effects since the module is not entirely reloaded after each it.
I would then say, for the sake of lisibility, that the first way of writing should be replaced by the second one, or at least to clearly explain in the documentation the fast that the first method, even if shorter, might have side effects.
I totally agree. Also it can cause a lot for troubles when you're dealing with stubs, mocks etc. Check my gist https://gist.github.com/lucassus/41b9a1651229745fa34c it's an example written in mocha and sinon.js
Thanks for your support ;)
while the right way of loading a module before each "it" spec is the following:
...
Mmm, not quite. So what happens is, beforeEach will add functions to a collection, to be run before each spec in a suite (at least, in test frameworks which are supported --- and you are using a supported framework, because window.module or window.inject would not be exposed otherwise!).
The ngMock module() helper returns a function if it's being called before a spec is actually running, and this allows jasmine or mocha to do the right thing with it.
The alternative method proposed here essentially does the same thing, you're giving jasmine or mocha a function to run when the spec starts, and your function does the same magic that would have otherwise happened.
The fact is, it doesn't make a huge difference which one you use, most of the time.
I am curious what the confusion around this is, because I'm not seeing it demonstrated in the plunkr. The reason the plunkr doesn't work is because your wrappedModule() function is not returning the result of the mock module function.
This seems to come from a fundamental misunderstanding of how the test frameworks work, and how ngMock's module and inject helpers work. so I think we can close this.
Hi,
You are right, it is clearly a misunderstanding of the way ngMock module() was working, thanks for the explanation, and sorry for having used your time.
Sorry, I didn't mean to sound dismissive! I'm just hoping that the explanation makes sense.
module('myModule') will return a function if run before the spec, or will execute a function when run during a spec.
That function will just add an item to the set of modules to be loaded when the injector is created using the inject() helper. So regardless of which style of call to beforeEach you use (provided the wrapped module function returns a function which does the real work, as angular.mock.module() does), then there's no real difference between the two. So the short-hand is just nice =)
It is a bit hard to explain this stuff on github, but I hope that it makes a bit of sense to you, and I'm definitely not trying to sound dismissive and say that peoples concerns aren't real, lol. It's totally understandable for a JS api to be a bit confusing.
No worries, @caitp, it was clearly a misunderstanding from me (I retried without the wrappedModule and using a run block, and indeed, it works as expected).
I had troubles using the syntax I was complaining about with some module mocking, but defining the whole declaration in a single beforeEach() was okay, and I immediately thought it was because the module declaration was executed immediately , while it is deferred.
Seeing the code of ngMock.module(), this is now clear, maybe the only room for improvements is some additional documentation about the mechanism ;)
Thanks again.
@caitp could you check this plunkr http://plnkr.co/edit/ukE3jhwaY68orwczdZhz?p=preview
This example clearly demonstrates the issue. For some reason beforeEach(module(...)); syntax is execute only once before each spec, whereas beforeEach(function() { module(...) }); is executed every time.
I believe that there's a bug in angular-mocks module or the documentation ins't clear enough.
@lucassus when you pass an object to angular.mock.module(), here's what happens: It adds a "config" block, and the config block in turn registers each key in the object as a value factory.
So yes, sinon.mock() only gets called once when this value is registered with DI, at the start of each spec.
However, even though this isn't doing what you want, it is doing exactly what you're telling it to do. In order to make it do what you want, you should give it better instructions.
got it, you're right. The following syntaxt works fine
beforeEach(module('angularjsTddRecipesApp', function($provide) {
$provide.value('loadComments', sinon.mock());
}));
Most helpful comment
Mmm, not quite. So what happens is,
beforeEachwill add functions to a collection, to be run before each spec in a suite (at least, in test frameworks which are supported --- and you are using a supported framework, because window.module or window.inject would not be exposed otherwise!).The ngMock
module()helper returns a function if it's being called before a spec is actually running, and this allows jasmine or mocha to do the right thing with it.The alternative method proposed here essentially does the same thing, you're giving jasmine or mocha a function to run when the spec starts, and your function does the same magic that would have otherwise happened.
The fact is, it doesn't make a huge difference which one you use, most of the time.
I am curious what the confusion around this is, because I'm not seeing it demonstrated in the plunkr. The reason the plunkr doesn't work is because your
wrappedModule()function is not returning the result of the mock module function.