When writing tests for Backbone/Marionette Views I have noticed that at times, when using setElement in the render or onRender (if a marionette itemView), I cannot later trigger a specific event (i.e click) on an element set in the view's events hash, from my tests.
However when doing element.dispatchEvent('createdEvent') in the test suit, no error is reported, but the method I am spying on with sinon is never called.
If I simply stub the setElement method it returns an error: TypeError: 'undefined' is not an object (evaluating 'this.$el.attr').
I am guessing I need some more setting-up to do in my tests apart from simply instantiating the view and necessarymodelsandcollectionsalong with anyspies,stubs, orfakeServers, or either refactoring the existingviewsand removing thesetElement` method?
Has anyone come across a similar situation before?
How do I get around this?
I am using mocha, chai, sinon and phantomjs for my tests.
I have a more detailed SO question, with a working example, on this topic here: https://stackoverflow.com/questions/33828501/marionette-itemview-click-event-not-firing-when-triggered-from-tests
Related
I've started using Sinon.js to mock a MongoDB library in a Mocha test suite. I'm confused as to why mock.restore() in my afterEach blocks do not actually clear out the mocks & assertions I've set up in other tests. Example:
mockedMongo.expects('updateCustomer').once();
mockedMongo.restore();
mockedMongo.expects('updateCustomer').never();
mockedMongo.verify(); // error here
The last line will throw an Expected updateCustomer([...]) once (never called) ExpectationError. In the documentation it says that mock.restore() "Restores all mocked methods". I'm trying to figure out what that actually means, since it doesn't clear out my previous expectation, even when it seems that I've overwritten the mock on that method with something else. Thoughts?
Summary
If any methods have been wrapped in a proxy by the mock, restore() returns them to their original state. That's all it does.
Details
Looking at the source gives the following info:
calling expects() sets up a proxy for the method if no expectations have been set on it yet, and then adds an expectation
calling verify() cycles the expectations on the proxies and verifies each, then calls restore()
restore() cycles the proxies and restores the original methods
All restore() does is remove any proxies added by expects(), it doesn't affect the expectations stored by the mock.
So for each line in your example code:
create proxy for updateCustomer and add expectation of once
restore original updateCustomer
add expectation of never to updateCustomer
cycle the two expectations on updateCustomer and record that once fails, call restore(), then report that once failed
With Jasmine it is possible to spyOn methods, but I'm not clear on when would it be actually useful. My understanding is that unit tests should not be concerned with implementation details and testing if method is called would be implementation detail.
One place I might think of is spying on scope.$broadcast (Angular) etc but then again this would be implementation detail and not sure if unit tests should even bother with how the code works, as long as it gives expected result.
Obviously there are good reasons to use spyOn so what would be good place to use it?
The spyOn you describe is more commonly known in testing as a MOCK, although to be more clear it allows for 2 operations:
Create a new implementation for a method via createSpy (this is the classical mock)
Instrument an existing method via spyOn (this allows you to see if the method was called and with what args, the return value etc.)
Mocking in probably the most used technique in unit testing. When you are testing a unit of code, you'll often find that there are dependencies to other units of code, and those dependencies have their own dependencies etc. If you try to test everything you'll end up with an module / UI test, which are expensive and difficult to maintain (they are still valuable, but you want as few of those as possible)
This is where mocking comes in. Imagine your unit calls to a REST service for some data. You don't want to take a dependency on a service in your unit test. So you mock the method that calls the service and you provide your own implementation that simply returns some data. Want to check that your unit handles REST errors? Have your mock return an error. etc.
It can sometimes be useful to know if your code actually calls another unit of code - imagine that you want to make sure your code correctly calls a logging module. Just mock (spyOn) that logging module and assert that it was called X number of times with the proper parameters.
You can spy functions and then you will be able to assert a couple of things
about it. You can check if it was called, what parameters it had, if it
returned something or even how many times it was called!
Spies are highly useful when writing tests, so I am going to explain how to
use the most common of them here.
// This is our SUT (Subject under test)
function Post(rest) {
this.rest = rest;
rest.init();
}
We have here our SUT which is a Post constructor. It uses a RestService to
fetch its stuff. Our Post will delegate all the Rest work to the RestService
which will be initialized when we create a new Post object. Let’s start testing
it step by step:
`describe('Posts', function() {
var rest, post;
beforeEach(function() {
rest = new RestService();
post = new Post(rest);
});
});`
Nothing new here. Since we are going to need both instances in every test,
we put the initialization on a beforeEach so we will have a new instance every
time.
Upon Post creation, we initialize the RestService. We want to test that, how
can we do that?:
`it('will initialize the rest service upon creation', function() {
spyOn(rest, 'init');
post = new Post(rest);
expect(rest.init).toHaveBeenCalled();
});`
We want to make sure that init on rest is being called when we create a new
Post object. For that we use the jasmine spyOn function. The first parameter is
the object we want to put the spy and the second parameter is a string which
represent the function to spy. In this case we want to spy the function init
on the spy object. Then we just need to create a new Post object that will call
that init function. The final part is to assert that rest.init have been
called. Easy right? Something important here is that the when you spy a
function, the real function is never called. So here rest.init doesn’t actually
run.
Using sinon and sinon-qunit in our front end unit tests, and I'm struggling to understand the difference in these methods. We are using sinon.sandbox.stub() (literally that is the function, we do not create a sandbox) and these stubs are apparently restored after each test automatically. I just don't see this anywhere in the documentation.
I wouldn't think that this method exists, I would think you would need to explicitly create a sandbox using sinon.sandbox.create(). On that sandbox object you would call the stub function, i.e. mySandbox.stub(), not "sinon.sandbox.stub()".
Could anyone help me understand?
Stubs - Sinon.JS
sinon.stub(); read about from here
Sandboxes - Sinon.JS
sandbox.stub(); read detail from here
Works almost exactly like sinon.stub, only also adds the returned stub to the internal collection of fakes for easy restoring through sandbox.restore().
The sandbox stub method can also be used to stub any kind of property. This is useful if you need to override an object’s property for the duration of a test, and have it restored when the test completes
Despite these two related questions on StackOverflow, I've yet to find an satisfactory answer for this, so I'm posting to find out if there is an accepted best practice among Jasmine-jQuery users.
The basic problem is simple and two examples of it are covered in the two linked questions:
In my Javascript, there is a setup() function that binds event handlers to various selectors on a page, as in $('#someDiv').click(someHandler); this function is passed to $(document).ready
In my Jasmine tests, I use HTML fixtures representing various extracted parts of the page to test AJAX interactions on those elements (I'm running the jasmine-rails "server" version, where you can view Jasmine test reports in browser)
The problem, of course, is that the selectors to which setup() tries to bind handlers will not exist until after the fixture is loaded. As a result, an event triggered explicitly in a Jasmine test will not be picked up by the DOM element in the fixture, because the function that would have bound that handler already ran at $(document).ready time.
If only Jasmine could somehow delay the call to $(document).ready until after the fixtures were loaded, I'd be golden. But apparently it can't.
From the two StackOverflow questions above, I've gleaned various ways to get around this, all unsatisfactory:
Copy the binding code in setup into the HTML fixture(s) themselves. This is non-DRY and almost certainly will cause the fixtures to drift out of sync with reality, plus the fixtures are supposed to represent unobtrusive JS and therefore not mix code and markup.
Explicitly call the setup function in the test cases that require it. This works in simple cases, but would fail if setup did non-idempotent things.
In setup, use something like $(document).on('click', '#someDiv', someHandler) instead of the code I showed above. (I'm on jQuery 1.10.1.) I actually tried this but it doesn't work: even if the loaded fixture contains an element matching #someDiv, triggering 'click' on that element doesn't result in someHandler being called. Even if it did work, it's messy because (if I understand correctly) the value of this when the handler is called will reflect the element that actually handled the event, not necessarily the one that first received it.
In setup, use something like $('#someDiv').live(someHandler), but live was deprecated as of jQuery 1.7 and removed in 1.9.
Is there some other method I'm missing that doesn't require making changes to working code solely to accommodate the testing environment and that doesn't require violating DRY?
I have an example of DOM manipulation with Jasmine using jasmine-jquery here. You will also see a link in the description therein to a github repo you can clone to provide more insight into how SpecRunner.html orders dependencies. Basically I have my html fixtures with their onclick events followed by a jquery click() all in my jasmine beforeEach(). I then have my test expectations also check the DOM for validation. This may be along the lines of your #2 workaround above.
I am having a similar problem as in this question:
node.js - request - How to "emitter.setMaxListeners()"?
the user seemed to have solved their problem, but I'm not sure how they did it. ("process.setMaxListeners(0)"???) what is "process"?
I suppose that 'process' in the context of that question refers just to SOME EventEmitter class. In fact, if you have some object that is EventEmitter and get the same error, you should add to your code something like this (before adding listeners):
request.setMaxListeners(0);
Here can be request, process or any other object that causes the problem. However, sometimes such an error signalizes about design error. If you show your code, it will be possible to give more precise recommendation.
process is the global process. It is an EventEmitter. The node.js api documentation says this:
The process object is a global object and can be accessed from anywhere. It is an instance of EventEmitter. (http://nodejs.org/api/process.html)
You can do things like set global event listeners, remove global event listeners, emit global events, pretty much anything you can do with an EventEmitter.
process.on("GlobalEvent", GlobalEventHandler);
process.emit("GlobalEvent");
do something. . . .
process.removeListener("GlobalEvent", GlobalEventHandler);
I used this to emit events from one module across to another module I was running under same overall process. That allowed me to keep them in nice little functional modules but still have the ability to emit events to one another.