Testing JavaScript code in the browser - part I
Testing user-interface code is hard. I don’t know any tool that makes this easy. The complication comes from the need of simulating what the user will do and asserting the results of that. To be able to test a user-interface in a browser, we need tools to automate it.
These posts are based on what I’ve learned trying to test browser user-interfaces and the content may be very far from ideal. I’m going to use a very simple example to guide these posts: a JavaScript counter widget.
I’ve described previously in another blog post some of the tools I’m going to use: Jasmine, PhantomJS and JQuery. I also mentioned in that post one problem that we have to be aware of: Jasmine will not start from a clean state of PhantomJS each time it runs a test. Let’s put an example:
If we run that code, the tests will pass:
But if we change the order of the tests, executing creates one instance when initializing
before does not create any instance before initializing
. This will happen:
When the test does not create any instance before initializing
is executed, there is a counter in the DOM! Why is that?
I guess that’s because Jasmine and PhantomJS are keeping the same DOM content during all the tests.
Colin Jones explains better than me the consequences of having that in our tests.
We need to do the cleaning of the DOM ourselves. To achieve that, we could add an afterEach
step:
With that, our tests are now independent and will pass.
But if the widget adds more elements that are not inside a counter
element, those are not going to be cleaned. Also, we have another problem: we are always adding the counter to the body
. And we may not want that to be decided by the widget.
There is an alternative that will give us better control and modularity:
So far, I used JQuery for the testing side as well as the production side. But what if we don’t want to use JQuery in our production code? A good outcome of passing the containerId
directly as a string
instead of anything related with JQuery is that we can change the implementation of the production code and keep our implementation of the tests working.
For example we could use plain old JavaScript DOM manipulation:
But I’m going to keep using JQuery to keep things simple.