
function sum(x, y) {
return x + y;
}
it('should add the values of x and y', function() {
var x = 5;
var y = 6;
expect(sum(x, y)).toBe(11);
});" A test is not a unit test if :
It talks to the database
It communicates across the network
It touches the file system
It can't run at the same time as any of your other unit tests
You have to do special things to your environment (such as editing config files) to run it."
http://www.artima.com/weblogs/viewpost.jsp?thread=126923
//Given
function sum(x, y) {
return x + 1 + y;
}
//Test
it('should calculate the sum of x and y', function() {
var x = 5;
var y = 6;
expect(sum(x, y)).toBe(11); //FAILED! The sum ended up being 12...
});
Test Runner

Test Framework

Task Runner

'use strict';
module.exports = function (config) {
var files = [
'vendors/angular.js',
'vendors/scripts/angular-mocks.js',
'vendors/scripts/jquery-1.10.2.min.js',
'test/myApp/someAppTest.js',
];
config.set({
basePath: '../', //The path which the test will run from
browsers: ['Chrome'] //The browser which the tests will run in
frameworks: ['jasmine'], //The JS test framework to use
files: files //The files that will be used for the test
});
};karma.config.js
$ karma start <your_karma_config_filename>$ grunt karma:myTest
'use strict';
module.exports = function (config) {
var libs = [
'vendors/angular.js',
'vendors/scripts/ui-utils.min.js',
'vendors/scripts/angular-mocks.js',
'vendors/scripts/jquery-1.10.2.min.js',
'scripts/common/commonFiles.js',
{pattern: 'vendors/scripts/ui-bootstrap-*.js', included: true},
{pattern: 'vendors/scripts/angular-*.js', included: true}
];
return {
basePath: '../../',
frameworks: ['jasmine'],
files: libs,
//This function will be executed by karma to set the test configs
setConfig: function(files) {
config.set({
basePath: '../',
frameworks: ['jasmine'],
files: libs.concat(files)
});
}
}
};karma.shared.config.js
//Import your test modules here.
var feature1Module = require('./karma.feature1.config.js'),
feature2Module = require('./karma.feature2.config.js'),
sharedModule = require('./karma.shared.config.js');
module.exports = function (config) {
var feature1 = feature1Module(config),
feature2 = feature2Module(config),
shared = sharedModule(config);
//We are concating test files together to be inserted into the test.
var files = shared.files.concat(feature1.files, feature2.files);
//Set the main test suite's configuration
config.set({
basePath: shared.basePath,
frameworks: shared.frameworks,
files: files
});
};karma.main.config.js
'use strict';
module.exports = function (config) {
var sharedConfigModule = require('./karma.shared.config.js');
var sharedConfig = sharedConfigModule(config);
var feature1Files = [
{pattern: 'scripts/feature1/**.js', included: true},
{pattern: 'scripts/feature1/**/*.js', included: true},
{pattern: 'test/specs/feature1/*.js'}
];
//Set the configuration for feature1
sharedConfig.setConfig(feature1Files);
return {
files: feature1Files
}
};karma.feature1.config.js

//A random "class" we want to test against
function MyMathClass() {
return {
sum: function(a, b) {
return a + b;
}
}
}
describe('A suite which tests simple arithmetic', function() {
var myMathClass;
//Before each test is executed, run this block of code
beforeEach(function() {
myMathClass = new MyMathClass();
});
//Your test scenario
it('should sum the values of two numbers', function() {
var x = 6,
y = 3;
var sum = myMathClass.sum(x, y);
expect(sum).toBe(9);
});
});it('should display the button')E2E
Unit test
it('should set isBtnDisplayed to true') it('should join a manual mission', function () {
expect(scope.joinCard(scope.card, null)).toEqual(scope.joinManual(scope.card, null));
}); it('should join a manual mission', function () {
var missionSpy = spyOn(mockMissionsApiService, 'joinMission')
.and.callFake(ServiceFixtures.joinMissionsSuccess);
var emitSpy = spyOn($scope, '$emit').and.callThrough();
//Execution of the function that is being tested
$scope.joinManual(Fixtures.missionsInd10Card, Fixtures.deckOfCards);
$scope.$digest();
expect(missionSpy).toHaveBeenCalled();
expect(emitSpy).toHaveBeenCalledWith('CARD_JOINED',
[Fixtures.missionsInd10Card, Fixtures.deckOfCards]);
expect($scope.card.joined).toBeTruthy();
expect($scope.card.instanceId).toBe(
Fixtures.missionInd10Response.data.instance.instanceId);
});Vague and unable to understand
Descriptive

Grunt can execute the karma test runners into your CI build process. This allows CI builds to pass or fail depending on your unit test status
grunt.initConfig({
karma: {
options: {
browsers: ['PhantomJS'],
singleRun: true
},
main: {
configFile: 'test/conf/karma.main.config.js'
}
}
});
grunt.registerTask('test', ['karma']);$ grunt testYou can also run your Grunt task within IntelliJ


angular.module('myApp')
.controller('myController', function($scope) {
$scope.sqrt = function(num) {
if (num < 0) throw new Error('Number must not be negative');
return Math.exp(Math.log(num) / 2);
};
});describe('MyCtrl test', function() {
var $scope;
//Declare the myApp module that will be used before each test is ran
beforeEach(module('myApp'));
//Inject the built in ngProviders of $rootScope and $controller. You can also
//inject any services that are part of myApp or angular.
beforeEach(inject(function($rootScope, $controller) {
//We are setting our local $scope to be a new scope from the rootScope
$scope = $rootScope.$new();
//Instantiate the controller and set its $scope to the local $scope for this test.
//This means that any functions or properties on the controller's $scope will now
//be accessible to the test's local $scope.
$controller('myCtrl', { $scope: $scope });
//Run a digest cycle before each test to update or reinitialize any values on $scope.
$scope.$digest();
}));
it('should be able to calculate the square root of numbers',
var result = $scope.sqrt(64);
expect(result).toBe(8);
});
});angular.module('myApp')
.factory('myFactory', function($http) {
return {
someAjaxGet: function() {
return $http.get('/someUrl');
};
};
});angular.module('myApp')
.controller('myCtrl', function($scope, myFactory) {
$scope.data = undefined;
$scope.makeServiceCall = function() {
myFactory.someAjaxGet().then(function(data) {
$scope.data = data;
});
};
});myFactory.js
myCtrl.js
Is this a valid test?
it('should get the response from the service', function() {
var result = $scope.makeServiceCall();
expect($scope.data.success).toBe(result.success)
});
And error will be thrown where it doesn't know what $http is because myFactory uses it and was never injected into the test. Another issue is fact that the service call returns a promise. So how can we capture a successful callback when JavaScript runs asynchronously?
1. We need to mock out the service and spy on the service call
var $scope, $q, myFactoryMock;
//mock out the function call for myFactoryMock
var Fixtures = {
ajaxCallGetSuccess: function() {
var deferred = $q.defer();
deferred.resolve({success: true});
return deferred.promise;
}
};
beforeEach(module('myApp'));
beforeEach(inject(function($rootScope, $q, myFactory) {
$scope = $rootScope.$new();
//Set myFactoryMock to be myFactory
myFactoryMock = myFactory;
$controller('myCtrl', {$scope: $scope, myFactory: myFactoryMock});
$scope.$digest();
}));2. Create a spy on the service call. A spy stubs out a function call that is being tracked. Think of it as "when(someFunction.isCalled).then(doSomething)"
it('should set the data when the service is called', function() {
//We are spying on the 'someAjaxGet' function from myFactoryMock.
//When that function is called, call a fake success function
//that we stubbed out earlier. Be sure that the fake function
//being called returns what is return in the real world.
//Don't make up data just to make the test pass.
var spy = spyOn(myFactoryMock, 'someAjaxGet').and.callFake(ajaxCallSuccess);
$scope.makeServiceCall();
//Running the digest cycle will ensure that the promise has been returned.
$scope.$digest();
expect(spy).toHaveBeenCalled();
expect($scope.data.success).toBeTruthy();
})var mockMyFactory;
beforeEach(inject(function(myFactory) {
mockMyFactory = myFactory;
));
it('should make a HTTP GET request', inject(function($httpBacked, $q) {
var deferred = $q.defer();
var expectedResult = { success : true };
//Think of this like a spyOn for $http
$httpBackend.whenGET('/someUrl').respond(expectedResult);
spyOn(mockMyFactory, 'someAjaxGet').and.returnValue(deferred.promise);
mockMyFactory.someAjaxGet();
deferred.resolve(expectedResult);
$httpBackend.expectGET('/someUrl').respond(expectedResult);
$httpBackend.flush();
));angular.module('myApp')
.directive('numberOnly', function() {
var linker = function($scope, $elem, $attr) {
//implementation will detect if a value is a number
var value = elem.val();
return isNaN(value);
};
return {
require: '^ngModel',
restrict: 'A',
scope: {
'value': '=ngModel',
},
link: linker
};
});<input number-only class="inputClass">Template
myDirective.js
//compiles the template with the associated $scope
element = $compile(template)($scope);
//retrieves the model controller from the template
ngModelController = element.data('$ngModelController');
//run the digest cycle to update what's in $scope
$scope.$digest();
//Update the model controller's values and render it onto the template
ngModelController.$setViewValue(value);
ngModelController.$render();var $scope, $compile, template, element, ngModelController;
/**
* Helper function to compile a template and update the model and directive's view
*/
function compileTemplateAndDigest(value) {
$scope.model = value;
//compiles the template with the associated $scope
element = $compile(template)($scope);
//retrieves the model controller from the template
ngModelController = element.data('$ngModelController');
//run the digest cycle to update what's in #scope
$scope.$digest();
//Update the model controller's values and render it onto the template
ngModelController.$setViewValue(value);
ngModelController.$render();
}
beforeEach(module('numberOnly'));
beforeEach(inject(function($rootScope, _$compile_) {
$scope = $rootScope.$new();
$compile = _$compile_;
$scope.model = '';
template = '<input type="text" name="myInput" number-only precision="1" ng-model="model" />';
}));
it('should have the value of a whole number', function() {
compileTemplateAndDigest('123');
expect(element.val()).toBe('123');
});
it('should have the value of a decimal number', function() {
compileTemplateAndDigest('123.1');
expect(element.val()).toBe('123.1');
});