Unit testing JavaScript with Karma in 2021. Starting point
Tags: karma, testing, jest, javascript
Published: 2021-03-27 23:12:51

---
title: Unit testing JavaScript with Karma in 2021. Starting point
published: true
date: 2021-01-30 13:43:42 UTC
tags: karma,testing,jest,javascript
canonical_url: 
---

[Karma](https://karma-runner.github.io/) was born in the era of [AngularJS](https://en.wikipedia.org/wiki/AngularJS). This was a significant improvement of existed test tooling on the Web and was one of the reasons for the spread of [TDD](https://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530) in the JavaScript community. Karma still **the best test runner** for web JavaScript after almost 10 years thanks to the [architecture and principles it’s based on](https://www.youtube.com/watch?v=MVw8N3hTfCI).

Let's set up it for a test project and try to understand how it works. The first step is to install it via NPM

```
npm install karma
```

After successful installation, we would have Karma binary inside the local node\_modules folder. Now let’s create the Karma configuration file for our project using the init command

```
npx karma init
```

Here we could select the testing framework from the list of popular frameworks like “[Jasmine](https://jasmine.github.io/)”, “[Mocha](https://mochajs.org/)” etc. In our example, we would use “[**Jasmine**](https://jasmine.github.io/)” so just press [Enter] to move to the next question.

```
Do you want to use Require.js ?
no
```

[Require.js](https://requirejs.org/) was popular 10 years ago for management dependencies when we didn’t have Webpack. Now it’s mostly rudiment so here we select [no]

```
Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome
```

We would use Chrome as a default browser for our tests because this is one of the popular browsers nowadays and works on most of operating systems

```
What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.
> src/**/*.test.js
> src/**/*.js
```

Here we should tell Karma where we keep our source and test files. In our example, we would use src/\*\*/\*.test.js patter for test files which are widespread now, and src/\*\*/\*.js for source files

```
Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.
>
```

Leaves it empty

```
Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.
> yes
```

Karma can be run in two modes “single run” or “watch”. Single run means that when tests are finished karma would stop and to rerun our tests we should do run tests manually again. In the “ **watch** ” mode Karma would automatically rerun our tests when we change either the source or test files. This pretty handy feature **saves our time** , so we select [yes] here

```
Config file generated at "/<project>/karma.conf.js".
```

We have finished the configuration and Karma says that the result is a karma.conf.js file. But this is not all. Karma also has installed necessary dependencies based on our choices and updated package.json

```
+ "karma-chrome-launcher": "^3.1.0",
+ "karma-jasmine": "^4.0.1",
```

In our case these were

- karma-chrome-launcher the plugin which helps run tests in Chrome
- karma-jasmine an adapter for jasmine

Karma has a plugin architecture. Most of the language and frameworks specific functionality provided by plugins. Karma itself as a runner provides only functionality to run arbitrary JavaScript in a browser via Karma HTTP server. Also, Karma gives you the possibility to process your test and source files before they would be sent to the browser. So roughly say Karma is a mediator between your test/source files, frameworks, browsers, and operating system. Thus, this architecture allows karma to do only one thing but do it well and be open for extension without changing the Karma source itself. I highly encourage you to watch this [video](https://www.youtube.com/watch?v=MVw8N3hTfCI) and look at the [Karma source code](https://github.com/karma-runner/karma) itself as an example of a good product that stood the test of time.

Let’s move back to our test project and finish the Karma setup. Because we decided to use Jasmine as a test framework we should install it too.

```
npm install jasmine
```

karma-jasmine only a Karma adapter for Jasmine itself so this is why we should install Jasmine alongside karma-jasmine.

Now we are ready to write our first test. Let’s create a file src/foo.test.js and write a test case

```
describe('My first Karma test', function() {
  it('should be true', function() {
    expect(true).toEqual(true);
  });
});
```

Before start Karma make sure that you have installed Chrome which we select as our default browser for tests. Now we are ready to run our tests

```
npx karma start
```

This command would start the Karma server, open the Chrome browser, and run our tests. The result of tests would be printed in the terminal

```
30 01 2021 14:59:09.329:WARN [karma]: No captured browser, open [http://localhost:9876/](http://localhost:9876/)
30 01 2021 14:59:09.353:INFO [karma-server]: **Karma v6.0.3 server started at** [**http://localhost:9876/**](http://localhost:9876/)
30 01 2021 14:59:09.353:INFO [launcher]: Launching browsers Chrome with concurrency unlimited
30 01 2021 14:59:09.358:INFO [launcher]: Starting browser Chrome
30 01 2021 14:59:10.799:INFO [Chrome 88.0.4324.96 (Mac OS 11.1.0)]: Connected on socket kj6wu3FYg7XPKEKCAAAB with id 15222593
Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 1 of 1 SUCCESS (0.002 secs / 0.002 secs)
**TOTAL: 1 SUCCESS**
```

Here you can notice several interesting points

1. Karma starts the server
2. Open [http://localhost:9876](http://localhost:9876C) in Chrome
3. Run tests and print the result

When tests finished Karma would not stop and wait for changes to rerun tests automatically. Let’s change our test to see how it works

```
it('should be true', function() {
  expect(true).toEqual( **false** );
});
```

And now look at the result

```
30 01 2021 15:02:37.443:INFO [filelist]: Changed file "/playground/src/foo.test.js".
Chrome 88.0.4324.96 (Mac OS 11.1.0) **My first Karma test should be true FAILED**
        Error: **Expected true to equal false**.
            at <Jasmine>
            at UserContext.<anonymous> ( **src/foo.test.js:3:18** )
            at <Jasmine>
Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 1 of 1 (1 FAILED) (6.226 secs / 0.001 secs)
**TOTAL: 1 FAILED, 0 SUCCESS**
```

You can see that Karma automatically rerun the test and told us that now we have 1 failed test. Also, the result contains useful information about the error. The error message contains

- Name of a test suite. In our case My first Karma test
- Name of a test case — test should be true
- Expectation/assert error message — Expected true to equal false
- Exception stack trace

Because Karma runs tests inside a browser you can use the browser’s developer tools to debug your tests. For this purpose, you can set a breakpoint in a test and open developer tools in Chrome. Also, you can open [http://localhost:9876](http://localhost:9876C)/debug page where tests would be run in the main window and don’t produce the result in the terminal. If you want to run your tests in another browser you can easily do it without stopping tests and changing configuration by open [http://localhost:9876](http://localhost:9876C)/ in an interesting browser. It would attach the browser to the Karma server and run tests on it too. This approach also **allows you to run tests on any device and any browser** just by opening Karma server URL.

Ok. Let’s fix our test by reverting to the previous change. **To stop tests press [Ctrl-C] in the terminal** where Karma is running. Now let’s change the Karma configuration file so that test runs without “watch” by default. To do this open karma.conf.js and change singleRun from false to true

```
singleRun: **true** ,
```

Now if we run tests again by npx karma start you can see Karma stops after tests finished. To run tests in watch mode we should pass --no-single-run parameter

```
npx karma start **--no-single-run**
```

When karma running in watch mode you can rerun tests without changing source and test files by run command. To do this we should open a **new terminal window** without terminating karma start process and run

```
npx karma run
```

This command mostly useful for the integration of different tools with Karma.

Now let’s talk about source files. In the example above we have added the test file that contains all logic inside itself. Let’s create the file src/foo.js and write function multiply

```
function multiply(x, y) {
  return x * y;
}
```

now let’s change add test inside src/foo.test.js so that it would check the result of function multiply

```
it('should multiply 2 on 2', function() {
  expect(multiply(2, 2)).toEqual(4);
});
```

If you don’t stop Karma server you can see that it automatically detect new file and test

```
Chrome 88.0.4324.96 (Mac OS 11.1.0): Executed 2 of 2 SUCCESS (0.006 secs / 0 secs)
TOTAL: 2 SUCCESS
```

Now we have two tests. You can see that function multiply available in the test file this is because **all files are loaded and executed in the same context (on the same page)**. We had not restricted visibility of our function multiply thus it’s available globally, and we can use it in our test.

Here I finish the article. This is a **basic setup of Karma and starting point for advanced configuration**. I recommend starting from the basic setup and when you are sure that it works correctly move towards advanced configuration which usually includes preprocessing step for web projects in our days.