Angular TestBed and tests execution

First of all, Angular monkey patches our testing framework like this:

As we can see — Angular resets your testing module for you before you run each and every one of your tests.

But what does the TestBed.resetTestingModule function actually do?

It cleans up all your overrides, modules, module factories and disposes all active fixtures as well. If only we could keep the compiled factories, and just re-create components and services without re-compilation.

Now we are ready to define the problem — we would like to compile angular components only once per suite, however angular forces the policy of testing module reset which leads to eventual re-compilation. It would be great to prevent angular from cleaning compilation results and just reuse them, but still clean up all the rest to keep tests in isolation.

If we take a closer look at other TestBed methods we might notice the usage of _instantiated flag (or _initIfNeeded method which checks the flag eventually) in most public methods.

If we imagine that we actually preserve our factories from the previous run, then _initIfNeeded seems to do exactly what we are missing. If the flag is false TestBed will re-create components required for the test, create a new zone and testing module, but it won’t recompile anything if moduleFactory is in place.

We considered all of the above with our frontend team and we were also inspired by this TestBed performance discussion, so at the end of the day we came up with the following “patch” for TestBed to meet our requirements:

So let’s do a small demo for comparison. I have a test suite prepared. It has 9 tests in it and its configuration section looks like this:

My machine’s specs are:

Machine specs

And it takes ~24 seconds to complete this test suite with the current setup:

tests execution time before patch

Now let’s apply our patch finally and see how it performs. In 2 words: we need to call a setupTestSuite function inside our suite and replace beforeEach call with beforeAll for our suite configuration method. And after these changes code should look like this:

And now it takes ~8 seconds.

tests execution time after patch

It is at least 3 times faster roughly speaking, but you should keep in mind that your results will highly depend on the number of tests in the suite. The more tests you have per suite the more beneficial this technique will be for you.