Testing Angular Faster with Jest - Xfive (2024)

Sep 23, 2019 | Michal Pierzchala | Web Development | 32 Comments

Michal Pierzchala | Web Development

Testing Angular Faster with Jest - Xfive (1)

It struck me how painful experience it was to test an Angular app. And then I realized it can be painless with Jest.

This article was last updated on Apr 6, 2023, so the setup works with the latest Angular and Jest versions. If you still have troubles with your project setup, please open an issue in the jest-preset-angularproject.

Note: This article assumes you are using an Angular CLI v1.0 generated project from Angular v4.0.0. But it, too, works on Angular v2.x with CLI in beta.

Despite Angular being a comprehensive framework with lots of default abstractions: e.g., custom JIT andAOT compilers, deepRxJS, andZone.js integration, it’s still possible to work outside of its toolbox. Interestingly, it’s possible to change the default test runner. This post will tell you why and how you can do it.

If you ever felt blue, tired, and hopeless while running your Angular app slow test suite with Karma in your favorite browser (and I’m not talking about injecting every possible component into your test file), keep reading.

What if I tell you that you can:

  • run your Angular tests without a browser
  • run the test suite several times faster
  • rerun instantly only tests related to the latest code changes?

Testing Angular Faster with Jest - Xfive (2)

Meet Jest 🃏

Jest is a painless JavaScript testing platform. If this doesn’t tell you much, it’s probably because you had to spend all your free time running slow Karma tests 😅. Let me introduce it briefly:

  • Jest is a testing platform widely adopted by many large companies and swiftly adopted by the React community.
  • It sits on top of Jasmine, so the API is nearly identical.
  • It has all of its API documented, along with guides, examples, and a helpful community on forums like Reactiflux and Stack Overflow.
  • Focuses on Developer Experience (speed and ease of use are the priority.)
  • Provides meaningful error messages.
  • Runs on Continuous Integration servers without extra tooling (abstracting the DOM with jsdomlibrary.)
  • Provides code coverage out of the box.
  • Integrates with Babel and TypeScript seamlessly.

And what’s most important is that it provides a smart,immersive watch mode. The watch mode runs only tests affected by git file changes – it also runs failed tests first and is able to bail on first error, so the feedback loop is ~10x faster than with Karma, depending on test suite size.

Testing Angular Faster with Jest - Xfive (3)

To the point – I want my Angular tests faster now!

We need to install the necessary dependencies (I’m using yarn, but if you fancy npm, no problems):

$ yarn add -D jest jest-preset-angular @types/jest

where:

  • jest – Jest testing platform
  • jest-preset-angular – configuration preset with common settings setup for you
  • @types/jest – Jest typings

To setup Jest, we will need a few more steps:

In your project root, create a setup-jest.ts file with the following contents:

import 'jest-preset-angular/setup-jest';

Additionally, you’ll need to create the jest.config.js file in your project root directory with the following contents:

module.exports = { preset: 'jest-preset-angular', setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'], globalSetup: 'jest-preset-angular/global-setup',};

Adjust your tsconfig.spec.json to be:

{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec","module": "CommonJs","types": ["jest"] }, "include": ["src/**/*.spec.ts", "src/**/*.d.ts"]};

This is most likely all configuration you'll need. I've extracted common configuration options into the jest-preset-angular package, which should just work™ for most cases. Please go to the library documentation for up-to-date instructions on how to set it up correctly for your project.

You’re now ready to add this to your npm scripts:

"test": "jest --verbose","test:watch": "jest --watch",

...and change the way you test Angular apps forever.

Oh, one more thing. Forget about installing PhantomJS on your CI:

"test:ci": "jest --runInBand",

It's worth noting that CI servers usually run your code on a single core so parallelization may slow your tests down. If you're experiencing such behavior, use --runInBand flag to tell Jest explicitly that you want to run tests one-by-one (just like Karma or Mocha).

Caveats

Of course, there are some. But surprisingly, not many.

Migration from Jasmine

We’ll need to migrate some of Jasmine calls to Jest. Mostof the API is similar, but there are slight differences.

Below are listed the required changes to be made in your codebase.

  • jasmine.createSpyObj('name', ['key'])--> jest.fn({key: jest.fn()})
  • remove @types/jasminemodule (duplicate TS declarations from @types/jest)

After portingjasmine.createSpyObj(), you can come back later to migrate the rest of the functions, which are optional at the time of writing (this may change in the future):

  • jasmine.createSpy('name')--> jest.fn()
  • and.returnValue()--> mockReturnValue()
  • spyOn(...).and.callFake(() => {})--> jest.spyOn(...).mockImplementation(() => {})
  • Asymmetric matchers: jasmine.any, jasmine.objectContaining, etc. --> expect.any, expect.objectContaining

Farewell browser, our tests now run in jsdom

You can also bump into APIs available in browsers but not in jsdom, like htmlElement.closest or window.localStorage (which we just mocked in jestGlobalMocks.ts).

Zone.js messy error stack trace

I couldn't force Zone to output shorter and more meaningful error stack traces. As a workaround, you can add Error.stackTraceLimit = 2; to your setupJest.ts or whatever number suits you. I find it useful in most cases.

IDE integrations

Be sure also to check these awesome extensions to ease the testing experience even more:

Summary

I was truly amazed that it’s possible to integrate a 3rd party testing tool not running in a browser, like Jest, into Angular. A couple of days ago, I still thought it would be impossible to do so within a reasonable amount of time, and it was not worth the effort, but it turned out it was so worth it.

Our app's whole test suite of 35 files with ~100 tests executed 2.5x faster than with Karma. We can also usesnapshot testing. What’s most important, though, we now have a powerful watch mode, rerunning tests instantly. And all of this without compiling the app or running a dev server.

So if you care about your testing experience, do yourself a favor and run Angular tests with Jest. You’ll love it.

And don't forget to star it on GitHub!

If you find problems with the setup presented or spot a bug, please file an issue in the jest-preset-angular GitHub repository.

About the author

Testing Angular Faster with Jest - Xfive (4)

Michal Pierzchala | LinkedIn

Michal Pierzchala has been a member of Xfive since 2013. Part of the Jest core team. Passionate about modern web technologies, enthusiast of traveling, sailing and future space exploration.

More from Michal More from Michal

Comments (32)

Write a comment

Wilgert Velinga

Jest looks like a big improvement over Karma. But actually something exists that is even better into terms of feedback speed and quality: wallabyjs. Try it out!

Apr 01, 2017

kpax

I can't seem to figure out how to get webpack to run through it's loaders first, like angular2-template-loader to do what your preprocessor is doing. Is there a way to get jest to kick off a webpack bundle first?

Apr 03, 2017

Michal Pierzchala

kpax Running your code through Jest and Webpack are two different things. One doesn’t know about the other. Here you’ll find a Webpack tutorial on official Jest docs. You’ll probably need to adjust moduleNameMapper to suite your needs. You can also submit an issue on jest-preset-angular and we’ll see what can be done. Good luck!

Apr 04, 2017

Dominic Watson

Feel like I'm being dumb and missing something, but is this for ejected CLIs?
Using on a project out of the box I get: `SyntaxError: Unexpected token import` as it runs through each of the tests.

Apr 04, 2017

Brady Isom

I was excited about trying to add Jest to my Angular 4.x/AngularCli project. Thank you for the post. However, In following the instructions, I am seeing an error when Jest tries to load the setupJest.ts file:

/Users/bradyisom/Development/buzz/src/setupJest.ts:1
({"Object.":function(module,exports,require,__dirname,__filename,global,jest){require('ts-jest').install();import 'jest-preset-angular';
^^^^^^
SyntaxError: Unexpected token import

at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:320:12)
at handle (node_modules/worker-farm/lib/child/index.js:41:8)
at process. (node_modules/worker-farm/lib/child/index.js:47:3)
at emitTwo (events.js:106:13)

Any ideas on what is wrong here?

Apr 04, 2017

Michal Pierzchala

Dominic, Brady, just for the record, this was resolved in jest-preset-angular repo: https://github.com/thymikee/jest-preset-angular/issues/4

Apr 05, 2017

hotelyorba

Do you have a github repo where we can see some examples of how to test angular components and services using Jest?

Apr 05, 2017

Michal Pierzchala

hotelyorba, I have an example directory in jest-preset-angular repo:
https://github.com/thymikee/jest-preset-angular/tree/master/example
But in general you can test components, services, reducers, etc the same way as with Jasmine, provided that you're not using unsupported methods (like jasmine.createSpyObj()).

Apr 08, 2017

danAnderl

Hello there,
very nice article. i manage to execute 208 tests in around 30 secs in the best case. which is quite good, but i want it even faster. the problem seems to be in some initial step, as only the first tests take long (6 - 10 secs -> each worker ) and the following up are really quick.

-> watch mode 2 specs changed:

PASS src/app/features/geofencing/geofencing.component.spec.ts (5.593s)

PASS src/app/features/geofencing/geo-definition/geo-definition.component.spec.ts (9.75s)

Test Suites: 2 passed, 2 total
Tests: 16 passed, 16 total
Snapshots: 0 total
Time: 10.709s, estimated 11s

-> watchAll -w=8

Test Suites: 5 failed, 41 passed, 46 total
Tests: 202 passed, 202 total
Snapshots: 0 total
Time: 31.418s

do you have any idea to investigate what takes so long initially? i am using uptodate versions of ng (4.0.1) and ng-cli (1.0.0)

Cheers Andi

Apr 15, 2017

Michal Pierzchala

Hey danAnderl!
The following runs are faster, because the cache is "warm". On the first run Jest scans all necessary files and transform them from TypeScript to JS. Transforming takes some time, so the results (JS files) are cached – this way the files are only transformed through tsc (or any other transformer, e.g. babel) only once, and after they're changed.
Glad it works for you!

Apr 18, 2017

Jan

Thanks for the great article and project ... I still have a question concerning Snapshot testing ... is there an equivalent to the react-renderer i can use in Angular projects?

Apr 20, 2017

Michal Pierzchala

Jan, working on it!

Apr 22, 2017

Michal Pierzchala

Hey folks, it's now possible to snapshot your Angular components: https://github.com/thymikee/jest-preset-angular/pull/24
Happy testing! :)

Apr 22, 2017

Eniep Yrekcaz

Thank you so much for the post. Your approach and the Jest framework look very interesting. I have my own Angular* skeleton project that I've been working on. I tried to integrate your approach, but am running into some issues. Namely, I keep getting an error trying to run the tests relating to zone-node.js. If you would be willing to look, the repository is on GitHub: https://github.com/PdUi/angular-aspnet-skeletons/tree/jest-integration/ng-custom
I assume you ran into a similar issue and would greatly appreciate any help you could offer.

Thanks again for the very informative post!!!

May 08, 2017

Michal Pierzchala

Eniep Yrekcaz, checkout the PR I sent you :)

May 10, 2017

Eniep Yrekcaz

You are awesome. I really appreciate it!!!

May 10, 2017

Andrew Krueger

Michal Pierzchala, what's the benefit of using Jest with Webpack rather than running it normally?

May 17, 2017

Michal Pierzchala

Andrew Krueger, I'm sorry, but I don't know what are you referring to. Please be more specific.

May 18, 2017

Jon Caris

when trying to configure jest to run with coverage I get an error :
Failed to write coverage reports:
ERROR: RangeError: Maximum call stack size exceeded
STACK: RangeError: Maximum call stack size exceeded

May 25, 2017

Michal Pierzchala

Jon Caris, that doesn't tell much. But if you can provide a repository with the reproduction of the problem, please post it on Jest issue tracker

May 26, 2017

David Atencia

Awesome! I have been able to integrate Jest into an Ionic2 project with a little change following the instructions in this article. Really easy to set-up.

Many thanks for the article

May 27, 2017

YuJM

i using material2
i could not test ( dependency material2 components files )
how do i do?

Jun 15, 2017

Carl

This article is awesome and the angular jest preset is great. I'm having one little issue that I hope you can help with. When I change one file, jest runs all of my tests rather than the tests relating to the file that changed, do you know why this is?

Jul 22, 2017

Thomas

Nice article. Any suggestion why the paths in the tsconfig seem not to be resolved?
My tests are crashing when using absolute imports based on the paths defined there.

Aug 10, 2017

Derek Lin

Do you have an example of how to set up jest in a multi-app environment in angular-cli?

Dec 16, 2017

Marian Zburlea

Bad day:
FAIL src/app/app.component.spec.ts
● Test suite failed to run

TypeError: Cannot read property 'clearImmediate' of undefined

at new FakeTimers (node_modules/jest-util/build/fake_timers.js:106:29)
at new JSDOMEnvironment (node_modules/jest-preset-angular/testEnvironment.js:27:23)

Test Suites: 2 failed, 2 total
Tests: 0 total
Snapshots: 0 total
Time: 0.56s, estimated 1s
Ran all test suites.
npm ERR! Test failed. See above for more details.

Dec 20, 2017

Kornel Dva

Well, this works fine for simple setups. As soon as you have some 3rd-party modules, the "painless" becomes "nightmare". Jest babel ignores, by default, everything in node_modules and you can either hack it to stop ignoring specific modules, or you have to mock all the stuff in the modules, otherwise you get errors like "SyntaxError: Unexpected token export". Good luck with the mocking.

Jan 25, 2018

Jon

Does anyone know of any tutorials or links about testing Angular routing with Jest? I have a really simple sample project with e2e and test coverage plus reporting for a CI/CD. Currently all the tests work except routing to an unknown route.

const routes = AppRoutingModule.applicationRoutes;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule.withRoutes(routes)],
declarations: [HomeComponent, AppComponent, PageNotFoundComponent]
});

router = TestBed.get(Router);
location = TestBed.get(Location);

fixture = TestBed.createComponent(AppComponent);
router.initialNavigation();
});

it(
'navigate to "/abcdefghij" redirects you to /pagenotfound',
fakeAsync(() => {
router.navigate(['abcdefghij']).then(
() => {
expect(router.url).toBe('/pagenotfound');
},
() => {
fail('Failed to open page');
}
);
})
);

Thanks

https://github.com/zebslc/angular5mat

Apr 26, 2018

Bhargav

After adding your jestGlobalMocks.ts to setupJest.ts and importing the setupJest.ts like below:
setupTestFrameworkScriptFile: "/src/setup-jest.ts",
I am expecting sessionStorage.getItem to have been called like below:
global.sessionStorage.setItem('appInitData', JSON.stringify(plContext));
expect(service.plContext).not.toBeNull();
expect(global.sessionStorage.getItem).toHaveBeenCalled();

But, I get an error saying:
expect(jest.fn())[.not).toHaveBeenCalled()

jest.fn() value must be a mock function or spy.
Received:
function: [Function getItem]

Can you please help? I feel like I am close to getting it resolved. I am not using any jest.mock() or jest.spyOn() for sessionStorage since I believe it's already mocked in the jestGlobalMocks.ts. Correct me if I am wrong. Thanks in advance.

Aug 15, 2018

James

This article is educational but misses one vital example. An example test with angular using Jest. Wasn't that what this article was all about...?

May 27, 2020

Neutrino

jest.fn({ key: jest.fn()})

That's not even valid

Error: "Argument of type '{ key: jest.Mock; }' is not assignable to parameter of type '(...args: any[]) => unknown'.
Object literal may only specify known properties, and 'key' does not exist in type '(...args: any[]) => unknown'.ts(2345)"

Mar 31, 2021

Kris

Not sure if I missed something or if its just a mistake here, but was brought here by the Jest documentation and found one part kind of confusing. For the setup file, you said to put it in my root directory and name it "setup-jest.ts" but then in the jest.config.js file you specify '/src/setupJest.ts'.

This was a bit hard to figure out what was needed, I tried to change it to remove /src/ and rename the config reference to '/setup-jest.ts' but then I was getting a bunch of errors. I just tried again by moving the setup-jest.ts into the /src/ folder and that seemed to solve all my issues.

So does the article need to be fixed to say "put setup-jest into your src folder" instead of root folder? and then the file name be fixed?

Apr 24, 2023

Would you like to add something?

All fields are required. Your email address will not be published.

Testing Angular Faster with Jest - Xfive (2024)

FAQs

How can I make my Jest test run faster? ›

While Jest may be fast on modern multi-core computers with fast IOs, it may be slow on certain setups. As prescribed by Jest, one way to mitigate this issue and improve the speed by up to 50% is to run tests sequentially. Another alternative is to set the max worker pool to ~4.

Why do my Jest tests take so long? ›

Populating the cache. The first time we run tests in our application, Jest will need to take a bit longer as it can't take advantage of cached data. Jest spends the majority of the first time it runs transpiling TypeScript.

What is the fastest Jest test runner? ›

Wallaby is the fastest available JavaScript test runner. Jest in watch mode (in the best case scenario) re-runs all tests in all test files related to changed files based on hg/git uncommitted files.

Can I use Jest with Angular? ›

Several existing community projects have successfully brought Jest to Angular applications and proved the approach can work at scale for many applications.

What is the disadvantage of Jest testing? ›

Limitations of Jest Framework
  • People who worked with other testing libraries may find it hard to learn Jest.
  • Jest is not supported by all IDE. ...
  • Compared to other similar libraries, Jest lacks the library and tooling support.
  • The auto mocking feature makes Jest slower.

What are the disadvantages of Jest? ›

The primary drawbacks of Jest are due to its youth and lack of popularity among JavaScript developers. This kind of technology can be really helpful at times, such as when you can run and debug your tests in an IDE like WebStorm. WebStorm didn't even support running Jest tests till recently.

Is Jest good for end-to-end testing? ›

js development, you can use a combination of the Chrome API Puppeteer and the JavaScript testing framework Jest to automate e2e testing, allowing you to ensure that the user interface (UI) of your application is still functioning as you fix bugs and add new features.

Is Jest good for unit testing? ›

Fast: Jest tests run in parallel – this in turn greatly reduces the test execution time. Built-in code coverage: Jest supports code coverage out of the box – this is a very useful metric for all CI-based delivery pipelines and overall test effectiveness of a project.

How fast is the fastest Jest? ›

The Lockheed SR-71 Blackbird is the fastest jet aircraft in the world, reaching speeds of Mach 3.3--that's more than 3,500 kph (2,100 mph) and almost four times as fast as the average cruising speed of a commercial airliner. Key elements of the SR-71's design made this possible.

Are Jest tests run sequentially? ›

Once the describe blocks are complete, by default Jest runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.

What is the test runner for Jest? ›

Overview. Jest is a javascript testing framework which is used to easily write unit tests whereas Nightwatch. js is an integrated test framework for performing automated end-to-end testing on web applications and websites, across all major browsers.

Is Jest faster than karma? ›

Jest is 2 to 3 times faster than karma testing

This is particularly important when using CI-CD ( Continous Integration/Continous Delivery).

Why not to use Angular? ›

The short-term projects (up to a month) or startups with limited budgets and resources would not benefit from Angular. Plus, the technology is difficult to manage with a team of few developers, since the front-end framework's complexity may be hard to overcome.

Why Jest is better than Jasmine? ›

Jest is a more modern and comprehensive testing framework than Jasmine. Jest includes features like snapshot testing, code coverage analysis, and parallel test execution, which are unavailable in Jasmine.

How long should unit tests take to run? ›

Typically the response I get when I ask this question is each test should take anywhere from 0.01 seconds to 1 second max to run in isolation. As we all know, that isn't always the case! I've even seen some that take 7.6 seconds to run….

How long should a test suite take? ›

Some developers will be happy to run their extensive test suite in three minutes, while others want to go the more radical route and keep it under 60 seconds.

How long should E2E tests take? ›

End-to-End Testing vs Integration Testing
AspectIntegration TestingEnd-to-End Testing
Time neededFaster than E2E testing (about less than 1 hour for 200 tests)Longer than Integration testing (may take up to 4 - 8 hours)
4 more rows

How do you make a Jest test wait? ›

For async/await, developers can declare their test function as async and use the await keyword to wait for asynchronous operations to complete. Jest will automatically detect when the test function returns a promise and wait for it to resolve or reject.

References

Top Articles
Latest Posts
Article information

Author: Chrissy Homenick

Last Updated:

Views: 6533

Rating: 4.3 / 5 (54 voted)

Reviews: 93% of readers found this page helpful

Author information

Name: Chrissy Homenick

Birthday: 2001-10-22

Address: 611 Kuhn Oval, Feltonbury, NY 02783-3818

Phone: +96619177651654

Job: Mining Representative

Hobby: amateur radio, Sculling, Knife making, Gardening, Watching movies, Gunsmithing, Video gaming

Introduction: My name is Chrissy Homenick, I am a tender, funny, determined, tender, glorious, fancy, enthusiastic person who loves writing and wants to share my knowledge and understanding with you.