Jasmine describe override

Say you want to test your Angular application.

To do that you’ll be implementing Unit tests (with the Jasmine + Karma + PhantomJS stack) or E2E tests (with the Jasmine + Protractor stack).
You could choose any other stack using Cucumber, mocha, chai or any other testing framework – the principle of today’s topic remains the same.

The scenario is this:
There’s this piece of setup code that needs to be executed before each spec in every suite (performing login, for example).
I chose before each spec for the sake of the argument, but the same concept could be applied to before all specs in the suite and/or after each and after all specs in the suite.

for the sake of the post: describe = suite and it = spec.

The obvious option would be to copy and paste the snippet in every spec. This is also the worst option possible, for many conceptual and architectural reasons, but the most obvious one would be that on every change to the setup code snippet we would have to apply it to every single occurrence.
Someone bring me a bucket cause I’m barfing all over the place here! 🙂

Another, slightly better option, is to implement the snippet once in each suite by using Jasmine’s beforeEach function inside every suite. While this is better since the snippet is now implemented only once per suite, it is still being duplicated across different suites.
Now, I’m feeling only slightly sick, anyone got an advil?

So, what we would really like, is a way to implement the beforeEach only once, and have it applied to all specs in all suites.

It is easier to explain the concept using the E2E stack (Jasmine + Protractor) but it can just as easily be applied to the Unit stack (Jasmine + Karma + PhantomJS).

So, down to business!

First, let’s inspect how Jasmine is implemented. Jasmine’s suite is implemented by the describe function that accepts 2 arguments: the suite name, and a function reference that includes all the specs implementations and creates the Suite internal class.

However, the code is implemented in such a way that it is not as simple as overriding the describe function and adding our code snippet. Let’s see why.

If you examine Env.js code, you’ll find the code for describe:

Screen Shot 2016-05-06 at 18.36.11

As you can see, it creates a Suite instance using the suiteFactory function and then adds the specs to the suite from the specDefinitions (which is actually the reference to the function that contains all the spec implementations).
Without going into too much detail – this implementation includes internal private variables and functions that make the override way to complicated and forces a very big change to the framework code. We don’t want to go that deep into the framework code just to be able to have a single beforeEach

But fear not! There is still a way!
(by using wrappers instead of overrides)

Since we’re using Protractor for the example, we can use NodeJS global:

Screen Shot 2016-05-06 at 18.56.34So, basically we added our myDescribe wrapper to the global namespace, so it can easily be used inside our spec files.

The wrapper signature includes: the suite name, one or more arguments (you can omit those if they are not needed) and the suite function reference.
Then, we call Jasmine’s original describe implementation with the name and a new function reference that calls our private internal describe logic with the additional arguments.

Let’s examine our myDescribeLogic:

Screen Shot 2016-05-06 at 19.02.09

As you can see, it is pretty straight forward. Since this code is run inside the scope of Jasmine’s original describe, we can simply call before*/after* and have access to the additional arguments, and then just invoke the suite function reference.

We can also extend it to support xdescribe and fdescribe like this:

Screen Shot 2016-05-06 at 19.05.11

Note, that for myxDescribe we simply invoke jasmine’s xdescribe. Since it basically prevents the suite from running, there’s no need to add the before*/after* code.

The last piece of the puzzle is to make sure this code is invoked. Protractor has a built in feature in it’s configuration file called onPrepare, we can use it to reference to this file and it will be executed on protractor’s prepare stage:

Screen Shot 2016-05-06 at 19.09.04

Now, we can use our new overrides in the spec files just like we would have used Jasmine’s original implementations, we don’t need to copy paste the setup/teardown code and our spec files are neat and tidy:

Screen Shot 2016-05-06 at 19.19.34

Hope you will find this useful,
As always, feel free to use and abuse 🙂
If you modify jsBlackBelt code, please let me know or submit a pull request for the benefit of others.

2 thoughts on “Jasmine describe override

Leave a comment