Basically, I'm quite experienced with Mocha (written thousands of unit tests), and I'm quite new to AngularJS (written just my first project).
Now I am wondering how I might unit test all the AngularJS stuff using Mocha.
I know that Mocha runs in the browser, and I have already done this. But how do I structure and setup things?
I guess I need to:
- Load AngularJS
- Load Mocha
- Load my tests
Within each of the tests, I need to load a controller, a service, ... to test. How do I do that? I am not using require.js or something like that, the files are just script files with basically the following content:
angular.controller('fooController', [ '$scope', function ($scope) {
// ...
}]);
How do I reference and instantiate that controller within a test?
The same holds true for services, directives, ...
Do I need to create mocks for $scope
, $http
& co. for myself, or is there some help?
Please note that I am aware that there is the Karma test runner (formerly known as Testacular), but I do not want to switch my test runner completely.
One way of doing that is to use Angular
$injector
in your tests:
myModule_test.js
suite('myModule', function(){
setup(function(){
var app = angular.module('myModule', []);
var injector = angular.injector(['myModule', 'ng']);
var service = injector.get('myService');
});
suite('myService', function(){
test('should return correct value', function(){
// perform test with an instance of service here
});
});
});
your html
should look similar to this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>myModule tests</title>
<link rel="stylesheet" media="all" href="vendor/mocha.css">
</head>
<body>
<div id="mocha"><p><a href=".">Index</a></p></div>
<div id="messages"></div>
<div id="fixtures"></div>
<script src="vendor/mocha.js"></script>
<script src="vendor/chai.js"></script>
<script src="angular.min.js"></script>
<script src="myModule.js"></script>
<script>mocha.setup('tdd')</script>
<script src="myModule_test.js"></script>
<script>mocha.run();</script>
</body>
</html>
If you're creating an angular service that doesn't have any dependencies and isn't necessarily angular specific, you can write your module in an angular-agnostic way, then either write a separate small angular wrapper for it, or test for the presence of angular, and conditionally create a service for it.
Here's an example of an approach that I use to create modules that can be used both in angular, the browser, and node modules, including for mocha tests:
(function(global) {
//define your reusable component
var Cheeseburger = {};
if (typeof angular != 'undefined') {
angular.module('Cheeseburger', [])
.value('Cheeseburger', Cheeseburger);
}
//node module
else if (typeof module != 'undefined' && module.exports) {
module.exports = Cheeseburger
}
//perhaps you'd like to use this with a namespace in the browser
else if (global.YourAppNamespace) {
global.YourAppNamespace.Cheeseburger = Cheeseburger
}
//or maybe you just want it to be global
else {
global.Cheeseburger = Cheeseburger
}
})(this);