This is the second post in the series about Angular unit testing. If you are unfamiliar with using Angular CLI, please read the first post in the series.
In the previous post, we learned how to pass parameters into Angular CLI to run unit tests. In this post, we'll dive into Karma configuration and make the test runner more snazzy by configuring it for our unique needs. It's time to level up your testing game and get pumped up to unit test!
Follow Along
We're using Angular CLI to test the application and using code from a previous post I wrote.
Intercepting Http Requests-- Using And Testing Angular's HttpClient
Alisa ・ Aug 28 '17
You can clone the tutorial-angular-httpclient and run tests too. All the level ups discussed in the posts are found in "test-configuration" branch.
Karma Configuration
In your Angular app, find $/src/karma.config.js
. This is the config file Karma uses to run tests. Let's start editing it!
Reporters
Out of the box, Angular CLI enables 'progress' and 'kjhtml' reporters. In v7 and v5, you can configure reporters via commandline but sadly, that option was removed in v6. We can still make changes via the config file for v6 though!
If you are using Angular v5 or v7, pass in a comma separated list of reporters using the reporters
flag.
To change karma.config.js, in the reporters
array, remove 'progress' and replace it with 'dots'. Now when you run tests, the output to the console uses the dot reporter instead of the progress reporter.
Add A New Reporter
But our test output could be way better. It's nothing to write home about yet. Let's try adding a reporter.
Add the 'karma-spec-reporter' npm package
npm install karma-spec-reporter --save-dev
Require the reporter in karma.conf.js by adding the require statement to the plugins
array
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular-devkit/build-angular/plugins/karma'),
require('karma-spec-reporter')
],
Add to the reporters
array
reporters: ['kjhtml', 'spec']
Now when you run tests, you'll see an output like this
There's all sorts of reporters available for Karma. If you want unit test output available in your CI environment, you can add a reporter for JUnit output and configure Jenkins to consume JUnit reports as an example. If you need some more flair in your life, add the nyan cat progress reporter.
Code Coverage
Now that you know how to run tests and set it up to get the output format you like, it's time to measure coverage.
Keep in mind test coverage metrics can't determine if an application is working as intended or if the tests you have are "good" by testing the important things.
Angular CLI automatically adds and configures Istanbul as a coverage reporter. In karma.conf.js there's a section for coverageIstanbulReporter
and it's already set up to generate reports. Prior to v7 of Angular, it only had 'html' and 'lcov' enabled out of the box. Add 'text-summary' to the array if it's not already there.
Run test with the coverage flag enabled. In v6, use --code-coverage
.
ng test --watch false --browsers ChromeHeadless --codeCoverage
Now you have nice output in the console for coverage summary.
Running coverage with 'html' report creates a visual overview of coverage in html format. You can view coverage results for the entire app broken down per file.
And step into coverage report for a single file and see the number of times each line of code was executed.
Add native report formats such as 'text', 'json', 'Cobertura', 'TeamCity', or use the 'lcov' report as part of your CI process so you can show test coverage trend lines per build.
Maintaining Thresholds
If you want to ensure a certain level of coverage, you can configure coverageIstanbulReporter
object in karma.conf.js to add thresholds
.
To the thresholds
object, fill in keys for statements
, lines
, branches
, and functions
.
coverageIstanbulReporter: {
dir: require('path').join(__dirname, '../coverage'),
reports: ['html', 'lcovonly', 'text-summary'],
fixWebpackSourcePaths: true,
thresholds: {
statements: 80,
lines: 80,
branches: 80,
functions: 80
}
},
Now when you run tests with code coverage, your tests will complete with failure if your project doesn't meet the thresholds of coverage.
Setting Up angular.json For Defaults
Sure, we can create npm scripts to wrap all the parameters we send in while running unit tests, but there's cases where we always want a certain configuration set. An example might be code coverage. Despite watch
or browsers
configurations, we always want to run coverage. We can set that up in angular.json.
In $/angular.json
file, find the configuration for "test". It has an "options" property. Add a new property for "codeCoverage" and set the value to true.
You can set more properties than just coverage. All parameters that you pass in to Angular CLI can be configured. Check out the schema for angular.json for more details.
Add A Git Hook
Want to make sure every push to the repo has passing unit tests and adequate coverage? Add the npm package 'husky' and add the pre-push
step that runs unit tests following their instructions.
Now people can't push code into the repo without passing unit tests that meet code coverage. Applied to all branches, this requirement might make it difficult for teams to collaborate so you might want to target only master branch following a method posted in this GitHub issue.
Apply husky git hook to specific branch only #186
Is there a way to configure husky to apply a specific git hook, i.e. prepush
ONLY to a specific branch i.e. master
?
I know I can modify the hooks in the package, but that makes it more complicated because husky installs its own hooks, then I have to go overwrite it with a modified version using some scripts.
Mainly the purpose is to only run e2e or unit tests before pushing to master, but not every time I push to dev (which gets annoying waiting and seeing the browsers popup every time).
In the next post, we'll learn about ways to target tests to run and dive a little deeper into custom solutions.
Top comments (2)
Great article! Thanks for sharing these, they're very helpful.
Thank you!