I have a ViewModel defined as below:
(function(ko, myApp) {
myApp.HomeViewModel = function () {
this.message = ko.observable("Helloy.....");
this.toolBarIsVisible = ko.observable(true);
this.isDataDirectoryManager = ko.observable(true);
};
myApp.HomeViewModel.prototype = {
sayHi: function () {
this.message("World");
}
};
ko.applyBindings(new myApp.HomeViewModel());
}(window.ko, window.myApp || {}));
How do I write a qunit test that instantiates an instance of myApp.HomeViewModel.
Thanks
Martin
You need to include your app code in the test file. The test code could be something like this:
(function (ko, myApp) {
var vm;
module( "HomdeViewModel", {
setup: function() {
vm = new myApp.HomeViewModel();
},
teardown: function() { }
});
test('Can create HomdeViewModel', function () {
ok(vm instanceof myApp.HomeViewModel);
});
test('Sets default values', function () {
strictEqual(vm.message(), 'Helloy.....');
ok(vm.toolBarIsVisible());
ok(vm.isDataDirectoryManager());
})
test('Can change message', function () {
vm.sayHi();
strictEqual(vm.message(), 'World');
});
})(window.ko, window.myApp)
Here's a jsFiddle with an example: http://jsfiddle.net/danne567/ptW9k/
Related
I have the following services:
DataService.js
app.service("DataService", [
function () {
this.getData = function () { return "original value" }
}
]);
LocationService.js
app.service("LocationService", ["DataService",
function(dataSvc) {
this.getLocationData = function () {
return dataSvc.getData();
}
}
]);
Now for testing LocationService.js, how do mock DataService inside of LocationService?
This is what I currently have for LocationService_tests.js:
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
describe("getLocationData", function () {
it("returns the location data", function () {
var mockLocationDataValue = "mocked value";
// ???
// I want to mock dataSvc.getData within getLocationData
// so it returns "mocked value" instead of "original value"
expect(locationSvc.getLocationData()).toBe(mockLocationDataValue);
});
});
});
You could mock whole service using $provide API's service method, and change your service to returned mock data.
describe("LocationService", function () {
var locationSvc;
beforeEach(module('myModule'));
beforeEach(module(function($provide) {
$provide.service('LocationService', function() {
this.getData = function() {
return "mock value";
}
});
});
beforeEach(inject(function (LocationService) {
locationSvc = LocationService;
}));
...
});
I am having a controller like below
(function () {
var newPlaceController = function ($scope, PlacesService, $mdDialog) {
$scope.newPlace = {
"city": "",
"country": ""
};
$scope.addCity = function () {
$scope.places.push($scope.newPlace);
PlacesService.addCity($scope.newPlace);
$mdDialog.hide();
};
$scope.cancel = function(){
$mdDialog.hide();
};
};
angular.module("module.place")
.controller('NewPlaceController', newPlaceController);
}());
Also I have a test file like below which tests whether the initialization value of newPlace is correct.The code is like below
describe("NewPlaceController", function () {
var $scope, ctrl;
beforeEach(module("module.place"));
beforeEach(
inject(function (_$controller_) {
$scope = {};
controller = _$controller_('NewPlaceController', {
$scope: $scope
});
}));
describe("Initialization", function () {
it("asdasd", function () {
expect($scope.newPlace).toEqual({
city: ''
, country: ''
});
})
});
});
It's working fine. My doubt is how can I test the addCity and cancel functions in the controller.
You can use it like this
it("Should call addCity", function () {
var spy = spyOn(PlacesService, 'addCity');
controller.addCity();
expect(spy).toHaveBeenCalled();
})
it("Should call mdDialog hide", function () {
var spy = spyOn($mdDialog, 'hide');
controller.cancel();
expect(spy).toHaveBeenCalled();
})
I'm trying to figure out how to mock an angular provider for a unit test. In the following snippet I have a 'translate' provider that is used to determine which language will be displayed in a view by default. I'd like to inject a different version of this provider into my tests to ensure my app displays the right thing based on a provider's settings. What I'm doing right now clearly doesn't seem to be working. Thanks in advance for your help.
By the way, if you're wondering why a provider was used instead of something else like a service or a simple value, this is a contrived example that distills a problem I'm having in a larger application. I need to inject something into an application's config method, which means I need to mock a provider.
var app = angular.module('app', []);
app.config(function($provide) {
$provide.provider('translate', function() {
return {
$get: function() {
return {
language: 'en'
};
}
};
});
});
app.controller('ctl', function($scope, translate) {
if (translate.language === 'en') {
$scope.greeting = "Welcome to the application.";
} else {
$scope.greeting = "Velkommen til appen.";
}
});
// ---SPECS-------------------------
describe('App', function() {
beforeEach(angular.mock.module('app'));
describe('by default', function() {
beforeEach(angular.mock.inject(
function(_$compile_, _$rootScope_) {
const viewHtml = $('#view');
$compile = _$compile_;
$rootScope = _$rootScope_;
$rootScope.isOn = false;
elm = $(viewHtml);
$compile(elm)($rootScope);
$rootScope.$digest();
}));
it('shows English', function() {
expect(elm.text()).toMatch(/Welcome/);
});
});
describe('without English specified', function() {
beforeEach(angular.mock.module('app', function ($provide) {
$provide.provider('translate', function () {
return {
$get: function () {
return { preferredLanguage: 'no' };
}
};
});
}));
beforeEach(angular.mock.inject(
function(_$compile_, _$rootScope_) {
const viewHtml = $('#view');
$compile = _$compile_;
$rootScope = _$rootScope_;
$rootScope.isOn = false;
elm = $(viewHtml);
$compile(elm)($rootScope);
$rootScope.$digest();
}));
it('shows Norwegian', function() {
expect(elm.text()).toMatch(/Velkommen/);
});
});
});
// --- Runner -------------------------
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
<link href="http://jasmine.github.io/1.3/lib/jasmine.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="http://code.angularjs.org/1.4.9/angular.js"></script>
<script src="http://code.angularjs.org/1.4.9/angular-mocks.js"></script>
<script src="http://jasmine.github.io/1.3/lib/jasmine.js"></script>
<script src="http://jasmine.github.io/1.3/lib/jasmine-html.js"></script>
<div ng-app="app">
<div id="view" ng-controller="ctl">{{greeting}}</div>
</div>
you can do it like this: -
beforeEach(module('app', function ($provide) {
$provide.provider('translate', function() {
return {
$get: function() {
return {
language: 'fr'
};
}
};
});
}));
you can also put the above code in a util method, that will take the language code as a parameter, so you don't spread above code everywhere.
Can we call the factory functions defined in one module from another module? If so, how?
Let's say my first module is defined in moduleOne.js file as:
var myModule = angular.module('MyServiceModuleOne', []);
myModule.factory('notify', function () {
return {
sampleFun: function () {
// some code to call sampleFunTwo()
},
};
});
And my second module in moduleTwo.js as:
var myModuleTwo = angular.module('MyServiceModuleTwo', []);
myModuleTwo.factory('notifytwo', function () {
return {
sampleFunTwo: function () {
// code
},
};
});
How to call sampleFunTwo() from sampleFun()?
Thanks.
You need to inject MyServiceModuleTwo into MyServiceModule:
var myModuleTwo= angular.module('MyServiceModuleTwo',[]);
var myModule= angular.module('MyServiceModuleOne', ['MyServiceModuleTwo']);
Then inject notifytwo into notify:
myModule.factory('notify', function(notifytwo) {
return {
sampleFun: function() {
notifytwo.sampleFunTwo();
}
};
});
myModuleTwo.factory('notifytwo', function() {
return {
sampleFunTwo: function() {
alert('From notify two');
}
};
});
And the code on plunker
I have a module with a greet factory attached to it:
angular.module('someModule', [])
.factory('greet', function(name) {
return function() {
return 'Hi ' + name + '!';
}
});
This factory injects a name which is a value defined in some other module.
angular.module('someOtherModule', [])
.value('name', 'example');
When testing this module, I would like to be able to change the value of my injectable name multiple times (once for each test) so that my tests can look something like:
// In my test fileā¦
// Initialise the module I am testing `greet` upon, and mock the other module which has a `name` value
beforeEach(mocks.module('someModule', function ($provider) {
$provider.value('name', 'Bob');
}));
var greet
beforeEach(mocks.inject(function ($injector) {
greet = $injector.get('greet');
});
it('should say "Bob"', function () {
expect(greet()).toBe('Hi Bob!');
});
// Now I need to change the `name` value to be "Bar" instead
it('should say "Bar"', function () {
expect(greet()).toBe('Hi Bar!');
});
How is this possible?
The two modules are composed with my app module:
angular.module('app', ['someModule', 'someOtherModule'])
You can use $provide.value('name', 'Bob'); to inject the value.
var myApp = angular.module('myApp', []);
myApp.factory('greet', function (name) {
return function () {
return 'Hi ' + name + '!';
}
});
myApp.value('name', 'example');
describe('myApp', function () {
beforeEach(angular.mock.module('myApp'));
it('should say "Bob"', function () {
module(function ($provide) {
$provide.value('name', 'Bob');
});
angular.mock.inject(function ($injector) {
var greet = $injector.get('greet');
expect(greet()).toBe('Hi Bob!');
})
});
it('should say "Bar"', function () {
module(function ($provide) {
$provide.value('name', 'Bar');
});
angular.mock.inject(function ($injector) {
var greet = $injector.get('greet');
expect(greet()).toBe('Hi Bar!');
})
});
});
I created a demo for you and hope it can shed some light!
Updated: demo
Demo
I was able to get this working, but I had to make a slight change to how the name dependency was injected (pointed out in the comment below). Given the app code:
angular.module("app", ["some", "other"]);
angular.module("some", []).factory('greet', function(name) { // name injected here
return function() { // the name dependency moved from here up one function signature
return 'Hi ' + name + '!';
};
});
angular.module("other", []).value('name', 'example');
This is as DRY as I could make the test:
describe("greet", function() {
var provide = injector = greet = undefined;
beforeEach(function() {
module('app', function($provide) {
provide = $provide;
});
inject(function($injector) {
injector = $injector;
});
greet = function() {
return injector.get('greet')();
};
});
describe("#greet", function() {
it("says Hi Bob", function() {
provide.value('name', 'Bob');
expect(greet()).toBe('Hi Bob!');
});
it("says Hi Biff", function() {
provide.value('name', 'Biff');
expect(greet()).toBe('Hi Biff!');
});
});
});