I’ve been developing a LOT of Angular applications lately. Some of them are hybrid projects (Angular w/ MVC); some of my projects have been completely separated (Angular for client-side, with a separate project for an API). Regardless, I always want to ensure that my code has been thoroughly tested with unit tests and acceptance (E2E) tests. When developing hybrid projects, my preferred IDE is Visual Studio. When developing a pure, client-side project, my preferred IDE is Visual Studio Code as it has a lot less remnants/artifacts tied to a solution (.vs, .xproj, .csproj, etc.) eliminating the need for a ridiculously large .gitignore file. Additionally, I will use WebStorm depending on the need.
Jasmine is a great framework for providing both unit testing and end-to-end, acceptance testing. Coupled with Karma, Jasmine can monitor file changes to our client-side code and execute tests on every file change in order to ensure that all tests are always passing. In this blog post, I will demonstrate how to set up and use Karma and Jasmine in both development environments.
NOTE: This tutorial is for a Windows environment as PowerShell is required to fork a child process. However, if you are using VS Code in a Linux environment (including Mac), the instructions can easily be adapted to using a bash script.
Installation
In order to run Karma and Jasmine, you’ll need to install a couple of things.
Node.js
Node.js is a lightweight JavaScript engine which Karma and Jasmine both require in order to run. Node.js will be what our task runner uses under the hood to execute Karma (and Jasmine).
If you are using Visual Studio 2015 with ASP.NET 5, you can skip installing Node.js as it’s included in the Visual Studio installation. You’ll simply need to right-click on your project and add the NPM Configuration File which creates a package.json file in your project’s main folder.
If you are using code, or would like a little more practice doing this manually, you’ll need to visit the Node.js website to download and install it.
After Node.js has been installed, you’ll need to initialize it within your project. Head over to your project’s main directory and type the following:
npm init
“npm” is the command for Node.js’s package manager. By issuing this command you will be adding the Node.js configuration file package.json to your project.
When you run the above command, you will be asked a couple of questions. You can simply accept the defaults or answer to the best of your knowledge. If you’ve added the configuration file via Visual Studio, then you can edit the file and set the properties manually. The configuration file is nothing more than a json file.
Also, once you start adding dependencies in your project, Node.js will create a node_modules folder. If you are using TFS, you’ll want to exclude this folder from source control. If you are using GIT, you’ll need to add this folder to your .gitignore file. The dependencies will be re-downloaded every time you check out a file. If you want to update/re-install your dependencies, you can simply go to your project’s command line and type: npm install or, in Visual Studio 2015, you can right-click on your project and select “Restore Packages.”
Karma
Now that Node.js has been installed, it’s time to add Karma to your project. You can do this in two ways (depending on which IDE you are using):
Visual Studio
- Open your package.json file in Visual Studio
- Inside of the “devDependencies” section, add the following:
"devDependencies": { "karma": "0.3.15" }
- Save the file
- Visual Studio, at this point, should download the package automatically. But, if necessary, right-click on your project and select “Restore Packages.
Visual Studio Code
- Open your package.json file in Visual Studio Code
- Inside the “devDependencies” object, add the above code
- Save the file
- In your command prompt at your project’s home directory, type the following:
npm install
Visual Studio Code (alternative)
- Open your command prompt and go to your project’s home directory
- Type the following at the command prompt:
npm install karma --save-dev
- This will install the Karma dependency and add it to the package.json file for you.
Jasmine + Additional Requirements
Now that you’ve got a little experience adding a Node.js dependency to your project, let’s add a couple more. You can follow any one of the three ways covered in the previous section for Karma, but the dependencies you will need are the following (I’ve include current version numbers and descriptions of what they do)…
- gulp (3.9.0) – our Task Runner. Gulp is very simply to a batch file, but offers the ability to define specific tasks. These tasks can run pre-build, post-build, or simultaneously while debugging our application.
- gulp-shell (0.5.1) – allows Gulp to run shell commands
- jasmine-core (2.4.1) – the core libraries for Jasmine, our unit testing framework
- karma (0.13.15) – installed above. Is executed by our task runner and is the execution environment for Jasmine and reporting
- karma-jasmine (0.3.6) – the plugin for “hooking up” Karma and Jasmine
- phantomjs (1.9.19) – a “headless” browser. Unlike trying to use Chrome, Firefox, Safari or the like for running our tests, PhantomJS is a lightweight browser that is platform agnostic. PhantomJS will be the browser that Jasmine uses to test our application.
- karma-phantomjs-launcher (0.2.1) – the plugin for integrating Karma and PhantomJS
- karma-html-detailed-reporter (1.1.8) – a plugin for Karma that is used by Jasmine to output test results to an html file creating a reporting dashboard.
Once you’ve added all of the dependencies, your package.json file, should look like the following:
"devDependencies": { "gulp": "^3.9.0", "gulp-shell": "^0.5.1", "jasmine-core": "^2.4.1", "karma": "^0.13.15", "karma-jasmine": "^0.3.6", "karma-phantomjs-launcher": "^0.2.1", "karma-html-detailed-reporter": "^1.1.8", "phantomjs": "^1.9.19" }
NOTE: If you used the 3rd, alternative, way for adding dependency modules, you may see a caret (“^”) prefacing the version number. That’s okay, it’s simply a version helper for Node.js and you can keep the caret or remove it.
Finally, if you’ll need to ensure all modules have been downloaded successfully by restoring packages in Visual Studio, or issuing npm install at the command prompt in project’s home directory. This will download all of the files (and versions) listed in the devDependencies section.
Hi, I found this very useful in setting up my tests. A simple test will work fine. I am using typescript however and it starts to add systemjs calls into the transpiled javascript if i try to add an imoprt {} statement for example. This causes an error. Any ideas how I can get that working together?
Ehh, a little more in-depth than the purpose of the post, but a few things to consider when using TypeScript:
import
statements and other ES* directivesI realize this isn’t that much insight, but hopefully it gets you going in the right direction. I’ll try to blog about how to do this in another post.
i think you meant “Task” Runner Explorer and not “Test” Runner Explorer.
In the ‘Visual Studio’ section I think the ‘Test Runner Explorer ‘ should be ‘Task Runner Explorer’, right?
yes, I mistakenly put “Test Runner Explorer” which refers to MSTest and other testing extensions. Instead, I want to view the results of my gulp tasks. Thanks for pointing it out.
Thank you Joshua,
It is first time when I configured the VS so quickly 🙂
Awesome! Glad it helped you out.
On running karma task from Task Runner Explorer window, I got error:
“karma.ps1 cannot be loaded because running scripts is disabled on this system.”
To fix this, in powershell, I had to run this (My LocalMachine was already set to RemoveSigned, only changing CurrentUser made a difference):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Typically, you shouldn’t have to do this if you are creating the .ps file locally. Setting the policy for RemoteSigned is only needed if 1) you are downloading my source from the blog, thus, downloading code from an untrusted location; or, 2) you have local policies prohibiting the running of scripts. What I normally do, is open PowerShell as an Administrator and run VS Code from the PS prompt (as compared to running it from the DOS prompt or Windows Explorer extension). For my local admin account, I’ve set the execution policy to Bypass. By doing this, I’m running VS Code in the context of a PowerShell administrator and my local scripts run fine without restrictions. Nonetheless, I’m glad you got it working.
Great tutorial! Lots of other guides out there aren’t really for VS so it’s great to find one which is so clearly explained
Awesome! Glad it helped.
In VS 2013 you also have to install gulp
Yes. Good point. Thanks!
The karma task never stops running, what do I do about that? I’d like it to stop when I’m done debugging.
You’ll need to configure a shortcut key to terminate the tasks.
keybindings.json
add the following:{
"key": "ctrl+shift+alt+t",
"command": "workbench.action.tasks.terminate"
}
Now, while your task is running, press and hold Ctrl+Shift+Alt+T to cancel your task.
‘include’ directive in C# ???
Not sure if I understand your question. In C#, the directive is
using
, compared to C++’sinclude
.I think he meant in your guide you’ve written C# ‘include’ directive, where it should have been C++.
Ahh, fixed. Thanks for the clarity!
Joshua, first of all, excellent work. I’ve been following along with your visual studio track using a little TS Angular App of my own. I haven’t touched Karma in a couple years, so I’m catching back. But a few questions.
Configuration: Visual Studio 2015 Update 3, Win 7 Update 2, Firefox Browser:
App: Typescript/Angular
Issue 1.
Task Runner Errors on Karma
C:\Users\jim\documents\visual studio 2015\Projects\TypeScriptHTMLApp1\TypeScriptHTMLApp1> cmd.exe /c gulp -b “C:\Users\jim\documents\visual studio 2015\Projects\TypeScriptHTMLApp1\TypeScriptHTMLApp1” –color –gulpfile “C:\Users\jim\documents\visual studio 2015\Projects\TypeScriptHTMLApp1\TypeScriptHTMLApp1\Gulpfile.js” karma
[11:33:19] Using gulpfile ~\documents\visual studio 2015\Projects\TypeScriptHTMLApp1\TypeScriptHTMLApp1\Gulpfile.js
[11:33:19] Starting ‘karma’…
events.js:141
throw er; // Unhandled ‘error’ event
^
Error: spawn powershell -Command “./karma.ps1” ENOENT
at exports._errnoException (util.js:856:11)
at Process.ChildProcess._handle.onexit (internal/child_process.js:178:32)
at onErrorNT (internal/child_process.js:344:16)
at nextTickCallbackWith2Args (node.js:474:9)
at process._tickCallback (node.js:388:17)
at Function.Module.runMain (module.js:431:11)
at startup (node.js:139:18)
at node.js:999:3
Process terminated with code 1.
Issue 2.
Debug Renders but never shows any Data
Issue 3.
Karma renders in the browser, but never shows any data, but data does show from the command line
Issue 4.
Detailed reporter pops a browser with no url or data, but it does show data if I go dig into the temp folder and open it
Files:
#
# karma.ps1
#
Start-Process “C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe” -Argument “node_modules/.bin/karma start karma.conf.js”
Start-Process “firefox” -Argument “.\_reports\\html-results.html”
Gulp
///
‘use strict’;
var gulp = require(‘gulp’),
shell = require(‘gulp-shell’);
gulp.task(‘server’, [‘node’, ‘karma’]);
gulp.task(‘node’, shell.task(‘node app.js’));
gulp.task(‘karma’, shell.task(‘powershell -Command “./karma.ps1″‘));
gulp.task(‘default’, function () {
// place code for your default task here
});
karma.conf.js
// Karma configuration
// Generated on Tue Aug 15 2017 17:05:31 GMT-0400 (Eastern Daylight Time)
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: ”,
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: [‘jasmine’],
// list of files / patterns to load in the browser
files: [
‘./test/**/*.js’
],
// list of files to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: ‘dots’, ‘progress’
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: [‘progress’],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_DEBUG,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: [‘Firefox’],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false,
// Concurrency level
// how many browser should be started simultaneous
concurrency: Infinity,
// notify karma of the available plugins
plugins: [
‘karma-firefox-launcher’,
‘karma-jasmine’,
‘karma-phantomjs-launcher’,
‘karma-html-detailed-reporter’
],
// add ‘htmlDetailed’
reporters: [‘progress’, ‘htmlDetailed’],
// configure the HTML-Detailed-Reporter to put all results in one file
htmlDetailed: {
splitResults: false
}
})
}
Ignore my previous comment. I have everything figured out except one issue.
The Task Runner in Visual Studio 2015-3 doesn’t like the configuration of the Karma task in the gulpfile.
I did this in the pre-build even command line in the Project Properties:
Powershell.exe -ExecutionPolicy Unrestricted -file “$(ProjectDir)karma.ps1”
Which worked, but no combination seems to work out of Gulp to appear correctly in the Task Runner Explorer output window
Is the Task Runner Explorer showing you anything? Is Gulp even running correctly from within VS?
Hi there, awesome post!
I am trying to setup this environment on a Mac. Any replacement for the powershell?
I haven’t tested this, but something like the following should work.
karma.ps1
, create akarma.command
file./node_modules/.bin/karma start karma.conf.js
open -a "Google Chrome" ./_reports/html-results.html
chmod +x karma.command
gulpfile.js
, replace the PowerShell task with the following:gulp.task('karma', shell.task('open karma.command'));
Like I said, I haven’t tested this, but it should work. You may have to fiddle with it a bit.
In Output Screen at tasks.json
Its displaying as
“‘gulp’ is not recognized as an internal or external command,
operable program or batch file.”
Even when I tried to run (ctrl+shift+B) in the Sample Application (downloaded solution here), its giving the same error
I have downloaded gulp.. everything . I am not understanding why am I still getting the same message as gulp is not recognized !!
1 more doubt in the problems section besides output in tasks.json
Its showing as
“‘Warning’ message: ‘Problems loading reference ‘http://json.schemastore.org/package’: Unable to load schema from ‘http://json.schemastore.org/package’: Unable to to connect to http://json.schemastore.org/package. Error: getaddrinfo EAI_AGAIN json.schemastore.org:80′
at: ‘1,1’
source: ””
Btw I’m using Angular 4
Correct me if I’m wrong, but it appears that you are running Visual Studio? In cases like this, I would take a look at your
package.json
and make sure it’s formatted correctly as this is often the case for this error message and why VS cannot download npm packages.Hi, This looks promising. I went through all the steps but in the end, Task Runner Explorer shows “No tasks found” under Glupfile.js.
Also, you wrote: “You’ll notice that the ‘karma’ task executes a PowerShell script. Here’s the contents of the karma.ps1 script (save the contents below into a file named karma.ps1 in your project’s main directory)”
However, I didn’t see any powershell script run (I checked too!). What would trigger a run of that karma.ps1 script? Simply saving the gulfile file? (Btw, “Gulfile.js” in the Task Runner Explorer shows with a capital G. Is that normal?)
Based on what you’ve said, with the Task Runner Explorer giving you the message “No tasks found” and you not seeing any PowerShell script run, at first glances I would think you may have a typo. Additionally, I haven’t tested it, but perhaps Gulp doesn’t like the fact that your
gulpfile.js
is capitalized. Typically (and common practice), is this filename is lowercase.