paint-brush
Migration From Karma/Jasmine to Jest - Why, When, and the Resultsby@amirankou
7,971 reads
7,971 reads

Migration From Karma/Jasmine to Jest - Why, When, and the Results

by Aliaksandr MirankouDecember 6th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Karma had been deprecated since Apr 2023, and we were in the preparation stage to write unit tests for our project. There are several arguments, but the main ones are: Karma had been deprecated since Apr 2023, and we were in the preparation stage to write unit tests for our project.
featured image - Migration From Karma/Jasmine to Jest - Why, When, and the Results
Aliaksandr Mirankou HackerNoon profile picture

Recently, I had a chance to participate in migration from Karma and Jasmine to Jest. If you are an Angular developer, you might be wondering why you did so. But give me some time, and in this article, I will tell you why we did that, why you should do it, and our results.

Let’s Revise the Things That We Are Talking About

  • Karma. Karma is nothing but a simple HTTP server, which runs your tests and generates the test runner HTML page. One of the main disadvantages of Karma is launching in a real browser. When you have a lot of unit tests, it can be problematic to run the server, and you will always be trying to reconnect to this server and waste your time.


  • Jasmine. Jasmine is the JavaScript testing framework, which is usually used by most Angular developers. It’s lightweight (it doesn’t have any external dependencies), simple, and has the obvious syntax.


  • Jest. Jest is another popular JavaScript testing framework which usually used in React. Provides high performance and simplicity.

Why Have We Migrated From Karma/Jasmine to Jest?

There are several arguments, but the main ones are: Karma had been deprecated since Apr 2023, and we were in the preparation stage to write unit tests for our project.


We thought that it’s better to migrate to Jest now (while we don’t have a huge amount of unit tests) than in the future Angular versions. Let’s look at the steps of migration.


  1. Install all necessary packages:

    npm install --save-dev jest @types/jest @jest/globals @angular-builders/jest jest-preset-angular
    


  2. Create a setup-jest.ts file, and import this module. This file is necessary if you want to specify some code that runs before all test suits but after Jest has set up its testing environment.


    It can be helpful if you have some package, that requires global configuration (ex day.js) or setup mocks:

    import 'jest-preset-angular/setup-jest';
    // other imports if you need
    


  3. Create a jest.config.js file:

    module.exports = {
        preset: 'jest-preset-angular',
        globalSetup: 'jest-preset-angular/global-setup',
        setupFilesAfterEnv: ['<rootDir>/setup-jest.ts'],
        transform: {
            '^.+\\.(ts|js|html)$': 'jest-preset-angular',
        },
        globals: {
            'ts-jest': {
                tsconfig: './tsconfig.spec.json',
                stringifyContentPathRegex: '\\.html$',
                astTransformers: ['jest-preset-angular/InlineHtmlStripStylesTransformer'],
                isolatedModules: true,
                preserveSymlinks: true,
            },
        },
        moduleFileExtensions: ['ts', 'html', 'js', 'json'],
        moduleDirectories: ['node_modules', 'src'],
        modulePaths: ['<rootDir>'],
        moduleNameMapper: {
            '^@app/(.*)$': ['<rootDir>/src/app/$1'],
        },
    };
    


  4. Update your tsconfig.spec.json

    {
        "extends": "../tsconfig.json",
        "compilerOptions": {
            "outDir": "../out-tsc/spec",
            "types": ["node", "jest"]
        },
        "include": ["../src/**/*.spec.ts", "../src/**/*.ts", "../src/**/*.mock.ts"]
    }
    
  5. Remove all files and configurations (and dependencies in package.json) which depend on Karma and Jasmine - karma.conf.js, test.ts (usually located in the src folder)


  6. Update your angular.json

    "test": {
        "builder": "@angular-builders/jest:run",
    },
    


  7. Update your test scripts in the package.json

    "test": "ng test",
    "test-coverage": "ng test --coverage=true",
    


After completion of these steps, you have to slightly edit your existing tests. There are some points that you should revise:


  • Jest doesn’t have some function that Jasmine does (ex: toBeTrue/toBeFalse). It means that you should use other functions - they exist but have other names (toBe(true)/toBe(false))


  • If you want to make a spy on a function, you should use the following syntax: jest.spyOn(class, ‘functionName’) instead of spyOn(class, ‘functionName’)


  • If you want to mock the returning function’s value, you should use the following syntax: jest.fn().mockReturnValue(yourValue) instead of jasmine.createSpy(‘functionNname’).and.returnValue(yourValue)


  • The total time spent on these changes depends on the amount of unit tests and can vary from project to project.

When Should You Consider This Migration?

Well, it depends, and there is no simple answer. If you just started your new project and don’t have a huge amount of unit tests - yes, you can migrate from the start. If you have a legacy project or just a project without unit tests and you want to start writing them - it’s also a good opportunity to migrate to Jest. If you have a lot of unit tests - it can take some time to migrate all of them

What About the Results?

It’s important to mention that Jest requires a lot of your resources. If you want to run your test faster - increase the number of streams (each stream can take around 2 GB of RAM and one core). I want to pay attention to what you have on your CI server, and how much capacity you have.


If you have 8GB of RAM and several cores on your server - it’s not a good idea to run Jest in 4 streams because you can get out of allowed memory allocation.


There are some options to configure your runner in the CI environment:

  • Configure --maxWorkers option. This flag determines how many cores can be used for test running (all available cores minus one for the main thread)


  • Use --runInBand option. With this flag, your tests will be running serially. Sometimes, it can be faster than with --maxWorkers If you want to run all your tests fast - just run the jest command for the root directory without any flags. It will take all of your available resources (your workstation can be a little bit laggy at this moment, but your test will pass faster).


    What about time comparison? Well, when we have several thousands of tests it can be challenging even to run the karma server (it can take more than several minutes) but when the server has started - all tests are passing quite fast. In Jest's case, we don’t need to wait for a server, but tests running take a lot of resources.


    I can say, that on a local machine, it will be faster than with Karma/Jasmine setup, but in CI - it depends on your server. In my case, it becomes worse over several minutes.

Conclusion

I’d like to say that such a kind of migration fully depends on your project setup and needs. There is no silver bullet, and I can’t push you to perform this migration - just think twice, think about your setup, performance perspectives, and future support.


In the next articles, I will tell you about test optimizations and how to increase the speed of your test in your CI environment