Karma needs an adapter to know about the Jasmine testing framework. It also needs a browser launcher to run the tests within a browser environment.
Update export
Karma will run the tests inside the operating system's Chrome browser which was in my case Chrome v74. The browser environment does not know about module.exports, so we will use the window namespace to export our afterTwoSeconds function:
Note: We still export our code for Node.js environments, to make our code work in both worlds. That's why we keep setTimeout because it is available in Node.js and browser environments. If we would write window.setTimeout it would only work in browsers but fail in Node.js.
Update test
Our tests will run in the browser so we cannot import code with a require statement (CommonJS syntax) anymore and need to use the window namespace:
Add Karma configuration
A Karma configuration can be interactively created by running npx karma init. In our case we reuse the file paths from our Jasmine configuration.
For a successful Karma test run it is important to declare the source code and test code within the files property.
Karma can be equipped with a custom test reporter but for now we are good with the standard progress reporter:
Add Webpack
Update dependencies
We need to add webpack-karma so that Karma can use webpack to preprocess files. This also requires us to include webpack in our list of dependencies as it is a peer dependency of webpack-karma:
Common mistake
ERROR [preprocess]: Can not load "webpack", it is not registered! Perhaps you are missing some plugin?
This happens when you run karma start and you forgot to install webpack.
Add Webpack configuration
Thanks to webpack's zero configuration mode and its default settings, we don't need to specify much. All we do is defining a "development" mode to get detailed messages in case of preprocessing errors:
Using a "development" mode will decrypt error messages like TypeError: r is not a function.
Update Karma configuration
In the previous Karma setup, our test code was relying that our business logic is exposed to the window namespace (window.afterTwoSeconds). Having webpack in place we will now load our business logic through our test code. That's why we don't need to declare our business logic anymore within Karma's files pattern. It's sufficient if we just point Karma to our test code because the tests will import the main source code for us. We can also reuse our webpack configuration by requiring it. To activate webpack, we need to declare it as a preprocessor for our test code. We also need to add the webpack configuration to our Karma configuration:
Update imports
Our test code will now be preprocessed by webpack which means that we can use Node.js features like require statements to import code. Webpack will make sure that the require statements get processed into something that can be understood by our Browser environment:
Add Babel
Babel 7 ships with TypeScript support and can be used to preprocess code with TypeScript's compiler. You might not need Babel to compile your code with TypeScript but using Babel's ecosystem (with presets like @babel/preset-env) can bring enormous benefits if you want to ship code for various environments. That's why it is the preferred setup in this tutorial, so let's get started with a Babel setup:
Update dependencies
Add Babel configuration
We will start with a very basic Babel configuration which does not define any plugin our sets of plugins (called presets). Without plugins Babel won't do much which is okay for now and will be changed once we add TypeScript to our Babel toolchain.
Update webpack configuration
With the babel-loader we are telling webpack to process files ending on .js or .jsx (/\.jsx?$/) through Babel:
Add TypeScript
Update dependencies
Add TypeScript configuration
Update webpack configuration
Update Babel configuration
Migrate test code
We need to rename main.test.js to main.test.ts. Thanks to the allowJsTypeScript compiler option we can still import our JavaScript business logic within our test code:
Update Karma configuration
Our Karma setup now needs to load our migrated test code:
Migrate source code
Update export
Update import
Adjust start script
Add code coverage
Note: Every package prefixed with karma- will be automatically added to Karma's plugin section, so no need to define it.
Update dependencies
Update Karma configuration
Update webpack configuration
Update Karma configuration
Bonus: TypeScript everything!
Since Webpack 5 you can turn the webpack.config.js into a TypeScript file called webpack.config.ts. If you are using Webpack 4, you will have to add @types/webpack to get type definitions for Webpack's configuration file.