karma/angularjs how to test run block with an asynchronous service -
how can test like:
init.js lama.system module
angular.module('lama.system', []) .config(['$httpprovider', function($httpprovider) { // crossdomain requests not allowed if want cors request see filter.php $httpprovider.defaults.headers.common['x-requested-with'] = 'xmlhttprequest'; }]) .run(['$rootscope', '$state', '$log', 'global',function ($rootscope, $state, $log, global) { $rootscope.$state = $state; $rootscope.$log = $log; $rootscope.global = global; }]);
controllers.js lama.system module
angular.module('lama.system') .controller('systemcontroller', ['$scope', function($scope) { $scope.test =[]; } ]);
services.js lama.system module
angular.module('lama.system') .factory('menus', ['$http', function($http) { return { query : function(menus){ return $http.get('/api/v1/user/menus', { params: { 'menus[]': menus } }); } }; }]);
system.js router
//setting route angular.module('lama.system') .config(['$stateprovider', '$urlrouterprovider', function($stateprovider, $urlrouterprovider) { $urlrouterprovider.otherwise('/'); $stateprovider .state('home', { url: '/', templateurl: 'system/views/home.html', controller:'systemcontroller' }); } ]);
init.js lama module
angular.module('lama', ['ui.router','restangular','lama.system','lama.users']) .run(['$rootscope', 'menus',function ($rootscope, menus) { // default hard coded menu items main menu var menus = [ { 'permission': null, 'title': 'home', 'link': 'home' }, { 'permission': 'users', 'title': 'user', 'link': 'user_actions.list' } ]; $rootscope.menus = []; function querymenu(menus) { menus.query(menus).then( function (result) { $rootscope.menus = result.data; }, function (reason) { throw new error(reason); } ); } // query server menus , check permissions querymenu(menus); $rootscope.$on('loggedin', function(event,user) { console.log('kkk'); querymenu(menus); $rootscope.global = { user: user, authenticated: user.groups.length, isadmin: user.groups.indexof('admins') }; }); }]);
the test
(function() { describe('unit test: system module', function () { describe('systemcontroller', function () { // load controller's module beforeeach(function() { module('lama'); module('statemock'); }); var systemcontroller, $rootscope, $scope, $httpbackend; // initialize controller , mock scope beforeeach(inject(function ($controller, _$rootscope_, _$httpbackend_) { $rootscope = _$rootscope_; $scope = _$rootscope_.$new(); $httpbackend = _$httpbackend_; systemcontroller = $controller('systemcontroller', { $scope: $scope }); $httpbackend.when('get', '/api/v1/user/menus').respond(200,{}); })); it('should attach list of awesomethings scope', function () { expect($scope.test.length).tobe(0); }); it('should expose global scope', function() { expect($rootscope.global).tobetruthy(); }); }); }); }());
that give me :(
grunt test running "karma:unit" (karma) task info [karma]: karma v0.12.21 server started @ http://localhost:9876/ info [launcher]: starting browser phantomjs warn [watcher]: pattern "/home/whisher/public_html/public/users/tests/unit/**/*.js" not match file. info [phantomjs 1.9.7 (linux)]: connected on socket zk1splajthe4x5sam9ew id 16331650 warn [web-server]: 404: /api/v1/user/menus?menus%5b%5d=%7b%22permission%22:null,%22title%22:%22home%22,%22link%22:%22home%22%7d&menus%5b%5d=%7b%22permission%22:%22users%22,%22title%22:%22user%22,%22link%22:%22user_actions.list%22%7d warn [web-server]: 404: /system/views/home.html error: 'error: [object object] @ http://localhost:9876/base/public/init.js?c7a481724bcf81e4810141349c93d0f698a18904:34 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:100 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:100 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:101 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:112 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:109 @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:112 @ h (http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:72) @ x (http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:77) @ http://localhost:9876/base/public/bower_components/angular/angular.min.js?4b4cffd940f7a29168096212664973432d1d7449:78' phantomjs 1.9.7 (linux): executed 2 of 2 success (0.039 secs / 0.065 secs) done, without errors.
nb
i'm using ui-router
i've taken @ source code. primary offending item is:
angular.element(document).ready(function() { angular.bootstrap(document, ['lama']); });
by including manual bootstrap in files karma imports, app un-necessarily being bootstrapped within karma test environment. so, instead, move lama
module separate file, , omit init.js
files included karma.
there couple of other design concerns causing excessive test setup. when testing systemcontroller
there no need include lama.system
module (as controller belongs to). test setup controller can simple as:
var $scope, $rootscope; beforeeach(module('system.lama')); beforeeach(inject(function($controller, _$rootscope_) { $rootscope = _$rootscope_; $scope = $rootscope.$new(); $controller('systemcontroller', {$scope: $scope}); }));
you note in isolating lama.system
module above, error $state
cannot injected (not found). because module definition should instead be:
angular.module('lama.system', ['ui.router'])
(a module should not require presence of module own dependencies, else can never function in isolation).
one final observation on mocking lama
module run
block. strictly speaking should stub service query
method entirely , not part of implementation, else test isolated. therefore, instead, better following:
beforeeach(module(function($provide) { $provide.decorator('menus', function($delegate, $q) { // overwrite query method $delegate.query = function() { return $q.when([{id: 1, name: 'bob'}]); }; return $delegate; }); }));
this way, don't need worry using $httpbackend
@ all.
Comments
Post a Comment