Ember is truly an awesome framework. The exciting community and the quality of the code has brought joy to front-end development. That said, testing (more importantly integration testing) is a part of the framework that isn’t quite there yet, and for various reasons:
- Lack of well defined best practices
- Few complete examples
- Debugging issues during tests is hard
The guide on the Ember website is a good start but it’s not enough. It won’t tell you anything about how to handle the run loop during tests, how to work with timers or how to configure the store. If you look around for examples they are either outdated or don’t work with the framework you are using (Mocha, QUnit).
Towards a viable stack
After spending some time trying and failing I believe I’ve reached a stack that makes me happy and that I consider solid enough:
- Rails (asset pipeline)
- Konacha (Chai and Mocha)
Rails might seem an overkill for just the asset pipeline, but currently it’s the most convenient way to build Ember applications. I’ve tried ember-app-kit and although it’s going in the right direction with the ES6 module system-aware resolver, it still has some rough edges like slow compilation times and a vast API surface.
Once you go with Rails you can draw from a nice pool of libraries built around it. Konacha is one of them. If you too think that testing like this is cool, keep reading:
Konacha uses Mocha and Chai in combo. These libraries will make if you feel at home if you’re coming from the RSpec world. It also spins up a web server on the port 3500 that you can visit to run your tests (don’t worry there is still a command for your CI).
The main problem is that Konacha uses Mocha to run tests and Ember supports only QUnit for integration testing out of the box; fortunately teddyzeenny built an adapter for this purpose. Include it in the spec_helper file like this:
1 2 3 4 5 6 7
Now you can use Ember test helpers like
click without worrying about asynchronous behavior. Just chain them or call
then if you want to execute some code after asynchronous actions have been performed.
1 2 3 4 5 6 7 8
There are some other important things to add to the spec_helper file:
1 2 3 4 5 6 7 8 9 10 11 12
The first 4 lines will make Konacha play nicely with Ember. They will tell it to ignore leaks on globals and to avoid clearing the body of the application after each test, which is something that Ember doesn’t like.
Removing animations is always a good idea during testing, it will improve speed and cause less accidental problems.
We also tell Mocha to reset the App after each test, which will destroy and reload everything bringing the router to its initial status.
The last lines are important if you have to setup your application before loading it. When you visit localhost:3500 Konacha will load the page and Ember will run App initializers and advance App readiness on document ready. In order to have full control over this process remember to add
App.deferReadiness() at the end of the application.coffee file, after creating the App.
If you need to perform some setup before resetting (
setup is a custom method I’ve added), override the reset method like this:
1 2 3 4 5 6 7
Under the hood
There are some things that this spec_helper will do under the hood. First of all it will set
true. This will stop the auto-run feature of the Ember RunLoop during tests to give you control over what can run with async side effects and what cannot.
For example if you want to create a fixture you need to wrap it in a
Ember.run block or it won’t execute all the async operation that will be scheduled by the application model adapter, like this:
1 2 3 4
I strongly suggest to read about how the Ember loop works because sooner or later you will need that knowledge in order to debug tests. There is a good SO answer about it.
Ember.Test.MochaAdapter will also enable the bdd interface for you, so you can use stuff like
it during tests.
Stubbing the server
In order to test interactions with a web server some people suggest to switch to FixtureAdapters during tests, but I don’t like this approach because you wouldn’t be testing the actual code of your application and some features, like associations, are implemented properly only on RESTAdapters.
What I’ve found useful instead is mocking the xhr object itself with the sinon.fakeServer. Suppose you want to stub the
/api/notices endpoint, which should return a list of
notices, you can do it like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
This way you won’t need to change your adapter at runtime and tests will run superfast.
Beware of timers. If your application has long running or self scheduling timers, every function that uses
wait under the hood, like
visit, will never resolve. It has been discussed that you should be able to explicitly avoid waiting for specific timers during tests, but in the meanwhile you can use the following hack:
1 2 3 4 5 6
1 2 3 4 5 6 7 8
This way you won’t use the Ember internal setTimeout (which is not optimal), but you won’t risk of executing async code outside of the run loop while allowing your tests to pass.
Ember is still a relatively young framework which means that you will have to work more to get simple stuff done. However I believe the community is very conscious of this and it’s pushing towards a common and strong approach for getting started quickly and testing.