I have the following code in background.js
var allCookies = [];
function getAllCookies() {
chrome.cookies.getAll({}, function(cookies) {
for (var i in cookies) {
allCookies.push(cookies[i])
}
}
});
}
Now in specs.js, I have written the following code to test the getAllCookies method -
describe('getAllCookies', function() {
beforeEach(function() {
chrome = {
cookies: {
getAll : function() {
return [
'cookie1',
'cookie2'
]
}
}
};
spyOn(chrome.cookies,'getAll');
});
it('should updated global variable allCookies', function() {
getAllCookies();
expect(allCookies).toEqual(['cookie1','cookie2'])
})
})
But the test is failing as allCookies = [] but it should be equal to ['cookie1','cookie2']
Can someone please help me to mock such chrome APIs (say chrome.cookies.getAll) which takes callback function as argument?
Related
I have the following code in a file named options.js. I need to mock it using Jasmine. I need to test whether chrome.storage.local.set is called when save function is called.
In the spec file I have the following code. But it does not call the chrome function in options.js file. Can someone point out the mistake?
beforeEach(function() {
ctrl = new OptionCtrl(scope);
chrome: {
storage: {
local: {
set: function() {
}
}
}
}
});
it('should call storage on save', function() {
spyOn(chrome.storage.local, 'set').and.callThrough();
ctrl.save({data: 'check'}, 'check');
expect(chrome.storage.local.set).toHaveBeenCalled();
});
Update 1: save function implementation
save(data, successMessage) {
chrome.storage.local.set(data, (error) => {
if (error) {
this.status('Error Occurred. Please refresh.', 1000, 100, 'danger');
} else {
this.status(successMessage, 1000, 100, 'success');
}
});
}
Link to the options.js file - Line: 122
Stubbing in Jasmine is easy as:
var chrome = {
storage: {
local: {
set: function() {}
}
}
}
function OptionCtrl() {
this.save = function(data, callbackStr) {
chrome.storage.local.set(data)
}
}
describe('OptionCtrl', function() {
var ctrl;
beforeEach(function() {
ctrl = new OptionCtrl({});
});
it('calls storage on save', function() {
spyOn(chrome.storage.local, 'set').and.callThrough();
var dataStub = {
data: 'check'
}
ctrl.save(dataStub, 'check');
expect(chrome.storage.local.set).toHaveBeenCalledWith(dataStub);
});
})
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>
I'm attempting to test a custom filter I've built. The issue I'm running into is that this filter relies on an asynchronous call through a service. Below is my relevant filter code first, then my current test:
.filter('formatValue', ['serverService', '_', function(serverService, _) {
var available = null;
var serviceInvoked = false;
function formatValue(value, code) {
var details = _.findWhere(available, {code: code});
if (details) {
return details.unitSymbol + parts.join('.');
} else {
return value;
}
}
getAvailable.$stateful = true;
function getAvailable(value, code) {
if (available === null) {
if (!serviceInvoked) {
serviceInvoked = true;
serverService.getAvailable().$promise.then(function(data) {
available = data;
});
}
} else {
return formatValue(value, code);
}
}
return getAvailable;
}])
test:
describe('filters', function() {
beforeEach(function() {
module('underscore');
module('gameApp.filters');
});
beforeEach(module(function($provide) {
$provide.factory('serverService', function() {
var getAvailable = function() {
return {
// mock object here
};
};
return {
getAvailable: getAvailable
};
});
}));
describe('formatValue', function() {
it('should format values', inject(function(formatValueFilter) {
expect(formatValueFilter(1000, 'ABC')).toEqual('å1000');
}));
});
});
The error I'm encountering when running my tests is:
TypeError: 'undefined' is not an object (evaluating 'serverService.getAvailable().$promise.then')
Your mock service needs to return a resolved promise. You can do this by injecting $q and returning $q.when(data)
However, I would think about refactoring this filter first. Filters are intended to be fast computations and probably should not be dependent on an asynchronous call. I would suggest moving your http call to a controller, then pass in the data needed to the filter.
I'm trying to unit test my app built on Angular with Jasmine via Karma. The app involves making a call to the GitHub API and pulling the names of all the repos of a user and filling an array with those names. I'm trying to test that the array is getting filled but I'm having some issues with $httpBackend.
The relevant parts of my controller are:
readmeSearch.controller('ReadMeSearchController', ['RepoSearch', function(RepoSearch) {
var self = this;
self.gitRepoNames = [];
self.doSearch = function() {
var namesPromise =
RepoSearch.query(self.username)
.then(function(repoResponse) {
addRepoNames(repoResponse);
}).catch(function(error) {
console.log('error: ' + error);
});
return namesPromise;
};
addRepoNames = function(response) {
self.repoSearchResult = response.data;
for(var i = 0; i < self.repoSearchResult.length; i++) {
var name = self.repoSearchResult[i]['name']
self.gitRepoNames.push(name);
};
};
}]);
My RepoSearch factory is:
readmeSearch.factory('RepoSearch', ['$http', function($http) {
return {
query: function(searchTerm) {
return $http({
url: 'https://api.github.com/users/' + searchTerm + '/repos',
method: 'GET',
params: {
'access_token': gitAccessToken
}
});
}
};
}]);
And the test in question is this:
describe('ReadMeSearchController', function() {
beforeEach(module('ReadMeter'));
var ctrl;
beforeEach(inject(function($controller) {
ctrl = $controller('ReadMeSearchController');
}));
describe('when searching for a user\'s repos', function() {
var httpBackend;
beforeEach(inject(function($httpBackend) {
httpBackend = $httpBackend
httpBackend
.expectGET('https://api.github.com/users/hello/repos?access_token=' + gitAccessToken)
.respond(
{ data: items }
);
}));
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
var items = [
{
"name": "test1"
},
{
"name": "test2"
}
];
it('adds search results to array of repo names', function() {
ctrl.username = 'hello';
ctrl.doSearch();
httpBackend.flush();
expect(ctrl.gitRepoNames).toEqual(["test1", "test2"]);
});
});
});
When I run the test I get the error
Expected [ ] to equal [ 'test1', 'test2' ].
So evidently this is because self.gitRepoNames is not being filled. When I console log ctrl.repoSearchResult just before the expectation in the test I get
Object{data: [Object{name: ...}, Object{name: ...}]}
Which is where the problem is I feel since self.repoSearchResult.length will be undefined when it is called in the for loop in the addRepoNames function.
So my question is why doesn't response.data return an array when it is called in the addRepoNames function in the test?
Any help would be greatly appreciated.
EDIT: I should mention that the app works fine when run on the server.
ctrl.doSearch is an asynchronous function. You should handle it in an async way. Try:
it('adds search results to array of repo names', function(done) {
ctrl.username = 'hello';
ctrl.doSearch().then(function() {
expect(ctrl.gitRepoNames).toEqual(["test1", "test2"]);
done();
});
httpBackend.flush();
});
I have little Angular Service to store and retrieve data. How do I write Jasmine test spec for testing this service?
angular.module("myServices").factory('dataStore', [
function() {
var DATASTORE;
DATASTORE = {};
return {
get: function(id) {
if (DATASTORE[id] != null) {
return DATASTORE[id];
} else {
return null;
}
},
put: function(id, data) {
return DATASTORE[id] = data;
}
};
}
]);
The below spec doesn't working for me:
"use strict";
describe("Service: dataStore", function() {
var store;
store = null;
beforeEach(function() {
module("myServices").inject([
'dataStore', function(dataStore) {
return store = dataStore;
}
]);
});
it("should return null", function() {
expect(store.get('some')).toBe(null);
});
});
First of all you should load your module within a beforEach block. After that you may use the inject function - angular and jasmin will do the rest for you.
"use strict";
describe("Service: dataStore", function() {
var store;
beforeEach(module('myServices'));
beforeEach(inject(function(dataStore){
store = dataStore;
}));
it("should return null", function() {
expect(store.get('some')).toBe(null);
});
});
Reading this Testing Angular Services Documentation should get you started
As for your problem, inject the myServices module in the beforeEach block and the dataStore service in the it block.
beforeEach(module('myServices'));
it("should return null",
inject(function(dataStore) {
expect(dataStore.get('some')).toBe(null);
}));
I have the following object:
var party =
{
food:
{
serve: function () {
// I want to call turnOff method from here
}
cleanUp: function () {
}
}
music:
{
turnOff: function () {
}
}
}
So as the comment points out, I want to call the turnOff method from the music object, how can I do this? this refers to the food object but I need to access the music object...
var party =
{
food:
{
serve: function () {
party.music.turnOff();
},
cleanUp: function () {
}
},
music:
{
turnOff: function () {
}
}
}
Use a constructor instead of a literal with a variable referencing the parent object
var party = new (function()
{
var self = this;
this.food =
{
serve: function () {
self.music.turnoff();
},
cleanUp: function () {
}
}
this.music =
{
turnOff: function () {
}
}
})();
Call it as party.music.turnOff().
FYI, your above code block isn't valid. You're missing some commas - after the serve and food closing braces.