From 1e65d9cd7e9310c2008708043e71a9cd3017b07e Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Tue, 15 Nov 2016 11:35:23 +0200 Subject: [PATCH 1/3] Add test runner --- README.md | 7 +++++ bower.json | 4 ++- karma.conf.js | 54 ++++++++++++++++++++++++++++++++++++ package.json | 8 +++++- src/http-auth-interceptor.js | 44 +++++++++++++++-------------- tests.js | 50 +++++++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 23 deletions(-) create mode 100644 karma.conf.js create mode 100644 tests.js diff --git a/README.md b/README.md index 52fdb11..7dd9c85 100644 --- a/README.md +++ b/README.md @@ -104,3 +104,10 @@ It is also possible to stop specific request from being retried, by returning `` return false; return config; }) + +###Testing + +``` +npm install +npm test +``` diff --git a/bower.json b/bower.json index 54fac45..59155d3 100644 --- a/bower.json +++ b/bower.json @@ -11,7 +11,9 @@ "angular": "^1.2" }, "ignore": [ - "package.json" + "package.json", + "karma.conf.js", + "test.js" ], "license": "MIT" } diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..2771a8b --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,54 @@ +'use strict'; + +// Karma configuration +module.exports = function(config) { + config.set({ + + basePath: './', + + // List of files / patterns to load in the browser + files: [ + 'node_modules/angular/angular.js', + 'node_modules/angular-mocks/angular-mocks.js', + 'src/http-auth-interceptor.js', + 'tests.js' + ], + + // Test results reporter to use + // Possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'x + reporters: ['progress'], + + // Web server port + port: 9876, + + // Enable / disable colors in the output (reporters and logs) + colors: true, + + // Level of logging + // Possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // Enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + // Frameworks to use + frameworks: ['jasmine'], + + // Start these browsers, currently available: + // - Chrome + // - ChromeCanary + // - Firefox + // - Opera + // - Safari (only Mac) + // - PhantomJS + // - IE (only Windows) + browsers: ['Chrome'], + + // If browser does not capture in given timeout [ms], kill it + captureTimeout: 60000, + + // Continuous Integration mode + // If true, it capture browsers, run tests and exit + singleRun: true + }); +}; diff --git a/package.json b/package.json index 30affc7..0850e7f 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,10 @@ ], "homepage": "https://github.com/witoldsz/angular-http-auth", "devDependencies": { + "angular": "^1.2", + "angular-mocks": "^1.2", + "jasmine-core": "^2.5.2", + "karma": "^1.3.0", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "uglifyjs": "^2.4.10" @@ -28,7 +32,9 @@ "build": "npm run build:minify -s && npm run build:copy -s", "build:minify": "uglifyjs src/http-auth-interceptor.js -o dist/http-auth-interceptor.min.js -c", "build:copy": "cat src/http-auth-interceptor.js > dist/http-auth-interceptor.js", + "preversion": "npm test", "version": "npm run build && git add -A dist", - "postversion": "git push && git push --tags" + "postversion": "git push && git push --tags", + "test": "karma start karma.conf.js" } } diff --git a/src/http-auth-interceptor.js b/src/http-auth-interceptor.js index 0fd9789..5252215 100644 --- a/src/http-auth-interceptor.js +++ b/src/http-auth-interceptor.js @@ -47,29 +47,31 @@ * On 403 response (without 'ignoreAuthModule' option) discards the request * and broadcasts 'event:auth-forbidden'. */ - .config(['$httpProvider', function($httpProvider) { - $httpProvider.interceptors.push(['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) { - return { - responseError: function(rejection) { - var config = rejection.config || {}; - if (!config.ignoreAuthModule) { - switch (rejection.status) { - case 401: - var deferred = $q.defer(); - var bufferLength = httpBuffer.append(config, deferred); - if (bufferLength === 1) - $rootScope.$broadcast('event:auth-loginRequired', rejection); - return deferred.promise; - case 403: - $rootScope.$broadcast('event:auth-forbidden', rejection); - break; - } + .factory('requestService', ['$rootScope', '$q', 'httpBuffer', function($rootScope, $q, httpBuffer) { + return { + responseError: function(rejection) { + var config = rejection.config || {}; + if (!config.ignoreAuthModule) { + switch (rejection.status) { + case 401: + var deferred = $q.defer(); + var bufferLength = httpBuffer.append(config, deferred); + if (bufferLength === 1) + $rootScope.$broadcast('event:auth-loginRequired', rejection); + return deferred.promise; + case 403: + $rootScope.$broadcast('event:auth-forbidden', rejection); + break; } - // otherwise, default behaviour - return $q.reject(rejection); } - }; - }]); + // otherwise, default behaviour + return $q.reject(rejection); + } + }; + }]) + + .config(['$httpProvider', function($httpProvider) { + $httpProvider.interceptors.push('requestService'); }]); /** diff --git a/tests.js b/tests.js new file mode 100644 index 0000000..18e85ed --- /dev/null +++ b/tests.js @@ -0,0 +1,50 @@ +'use strict'; + +describe('http-auth-interceptor Module', function () { + + describe('Test that interceptor is configured', function () { + + var httpProvider; + + beforeEach(module('http-auth-interceptor', function ($httpProvider) { + httpProvider = $httpProvider; + })); + + it('`httpProvider.interceptors` should contain `requestService`', inject(function () { + expect(httpProvider.interceptors).toContain('requestService'); + })); + + }); + + describe('Test `authService`', function () { + + // var rootScope; + + beforeEach(module('http-auth-interceptor')); + + // Setup the mock service in an anonymous module. + // beforeEach(module(function () { + // })); + + /* + beforeEach(inject(function ($injector) { + // rootScope = $rootScope.$new(); + rootScope = $injector.get('$rootScope'); + spyOn(rootScope, '$broadcast').andCallThrough(); + })); + */ + + it('can get an instance of `authService`', inject(function(authService) { + expect(authService).toBeDefined(); + })); + + /* + it('it broadcasts a signal when invoking `loginConfirmed`', inject(function(authService) { + authService.loginConfirmed(); + expect(rootScope.$broadcast).toHaveBeenCalledWith('event:auth-loginConfirmed', undefined); + })); + */ + + }); + +}); From ad5b3825a774c9f6a16638c586658307e4d93618 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Tue, 15 Nov 2016 11:47:51 +0200 Subject: [PATCH 2/3] Fix test+log ignores --- .gitignore | 2 +- bower.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 67a0dad..bfb6505 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules -npm-debug.log bower_components components +*.log diff --git a/bower.json b/bower.json index 59155d3..800c10b 100644 --- a/bower.json +++ b/bower.json @@ -13,7 +13,7 @@ "ignore": [ "package.json", "karma.conf.js", - "test.js" + "tests.js" ], "license": "MIT" } From 6c227595865ff10c912c5fd6c74088758c178916 Mon Sep 17 00:00:00 2001 From: Mikael Korpela Date: Tue, 15 Nov 2016 12:36:52 +0200 Subject: [PATCH 3/3] Refactor and add event tests --- README.md | 7 ++- bower.json | 3 +- package.json | 6 +- spec/http-auth-interceptor.spec.js | 91 +++++++++++++++++++++++++++++ karma.conf.js => spec/karma.conf.js | 15 +++-- tests.js | 50 ---------------- 6 files changed, 113 insertions(+), 59 deletions(-) create mode 100644 spec/http-auth-interceptor.spec.js rename karma.conf.js => spec/karma.conf.js (84%) delete mode 100644 tests.js diff --git a/README.md b/README.md index 7dd9c85..626c740 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,12 @@ It is also possible to stop specific request from being retried, by returning `` ###Testing +Run tests and watch for changes: ``` -npm install npm test ``` + +Run tests only one time: +``` +npm run test-single-run +``` diff --git a/bower.json b/bower.json index 800c10b..a95aa85 100644 --- a/bower.json +++ b/bower.json @@ -12,8 +12,7 @@ }, "ignore": [ "package.json", - "karma.conf.js", - "tests.js" + "spec" ], "license": "MIT" } diff --git a/package.json b/package.json index 0850e7f..f498423 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "angular-mocks": "^1.2", "jasmine-core": "^2.5.2", "karma": "^1.3.0", + "karma-phantomjs-launcher": "~1.0.2", "mkdirp": "^0.5.1", "rimraf": "^2.5.4", "uglifyjs": "^2.4.10" @@ -35,6 +36,9 @@ "preversion": "npm test", "version": "npm run build && git add -A dist", "postversion": "git push && git push --tags", - "test": "karma start karma.conf.js" + "pretest": "npm install", + "test": "karma start spec/karma.conf.js", + "pretest-single-run": "npm install", + "test-single-run": "karma start spec/karma.conf.js --single-run" } } diff --git a/spec/http-auth-interceptor.spec.js b/spec/http-auth-interceptor.spec.js new file mode 100644 index 0000000..931adf3 --- /dev/null +++ b/spec/http-auth-interceptor.spec.js @@ -0,0 +1,91 @@ +'use strict'; + +describe('http-auth-interceptor Module', function () { + + // Load http-auth-interceptor module + beforeEach(module('http-auth-interceptor')); + + describe('Test that interceptor is configured', function () { + + var httpProvider; + + beforeEach(function ($httpProvider) { + httpProvider = $httpProvider; + }); + + it('`$httpProvider.interceptors` should contain `requestService`', inject(function () { + expect(httpProvider.interceptors).toContain('requestService'); + })); + + }); + + describe('Test `authService`', function () { + + it('can get an instance of `authService`', inject(function(authService) { + expect(authService).toBeDefined(); + })); + + describe('Events', function() { + + var authService, $httpBackend, $http, $scope; + var methods = ['GET', 'POST', 'UPDATE', 'DELETE']; + + beforeEach(function() { + // Get services and make them available + inject(function(_authService_, _$httpBackend_, _$http_, _$rootScope_) { + authService = _authService_; + $httpBackend = _$httpBackend_; + $http = _$http_; + $scope = _$rootScope_; + }); + + // Spy on $emit to detect events + spyOn($scope, '$broadcast'); + }); + + it('should broadcast "event:auth-loginRequired" on http 401 respones and "event:auth-loginConfirmed" after calling loginConfirmed', function() { + angular.forEach(methods, function(method) { + // require authentication (http 401) + $httpBackend.expect(method, '/myresource').respond(401); + $http({ method: method, url: '/myresource' }); + $httpBackend.flush(); + expect($scope.$broadcast).toHaveBeenCalledWith('event:auth-loginRequired', jasmine.any(Object)); + + // confirm auth + $httpBackend.expect(method, '/myresource').respond(200); + authService.loginConfirmed(); + expect($scope.$broadcast).toHaveBeenCalledWith('event:auth-loginConfirmed', undefined); + }); + }); + + it('should broadcast "event:auth-loginRequired" on http 401 respones and "event:auth-loginCancelled" after calling loginConfirmed', function() { + angular.forEach(methods, function(method) { + // require authentication (http 401) + $httpBackend.expect(method, '/myresource').respond(401); + $http({ method: method, url: '/myresource' }); + $httpBackend.flush(); + expect($scope.$broadcast).toHaveBeenCalledWith('event:auth-loginRequired', jasmine.any(Object)); + + // confirm auth + authService.loginCancelled(); + expect($scope.$broadcast).toHaveBeenCalledWith('event:auth-loginCancelled', undefined); + }); + }); + + it('should not broadcast any event on responses other than 401', function() { + // most of the following tests don't make sense, but they also don't hurt + for(status = 100; status <= 599; status++) { + angular.forEach(methods, function(method) { + $httpBackend.expect(method, '/myresource').respond(status); + $http({ method: method, url: '/myresource' }); + $httpBackend.flush(); + expect($scope.$broadcast).not.toHaveBeenCalled(); + }); + } + }); + + }); + + }); + +}); diff --git a/karma.conf.js b/spec/karma.conf.js similarity index 84% rename from karma.conf.js rename to spec/karma.conf.js index 2771a8b..056d5ac 100644 --- a/karma.conf.js +++ b/spec/karma.conf.js @@ -4,14 +4,14 @@ module.exports = function(config) { config.set({ - basePath: './', + basePath: '../', // List of files / patterns to load in the browser files: [ 'node_modules/angular/angular.js', 'node_modules/angular-mocks/angular-mocks.js', 'src/http-auth-interceptor.js', - 'tests.js' + 'spec/*.spec.js' ], // Test results reporter to use @@ -34,6 +34,11 @@ module.exports = function(config) { // Frameworks to use frameworks: ['jasmine'], + plugins: [ + 'karma-jasmine', + 'karma-phantomjs-launcher' + ], + // Start these browsers, currently available: // - Chrome // - ChromeCanary @@ -42,13 +47,13 @@ module.exports = function(config) { // - Safari (only Mac) // - PhantomJS // - IE (only Windows) - browsers: ['Chrome'], + browsers: ['PhantomJS'], // If browser does not capture in given timeout [ms], kill it captureTimeout: 60000, // Continuous Integration mode - // If true, it capture browsers, run tests and exit - singleRun: true + // If true, will capture browsers, run tests and exit + singleRun: false }); }; diff --git a/tests.js b/tests.js deleted file mode 100644 index 18e85ed..0000000 --- a/tests.js +++ /dev/null @@ -1,50 +0,0 @@ -'use strict'; - -describe('http-auth-interceptor Module', function () { - - describe('Test that interceptor is configured', function () { - - var httpProvider; - - beforeEach(module('http-auth-interceptor', function ($httpProvider) { - httpProvider = $httpProvider; - })); - - it('`httpProvider.interceptors` should contain `requestService`', inject(function () { - expect(httpProvider.interceptors).toContain('requestService'); - })); - - }); - - describe('Test `authService`', function () { - - // var rootScope; - - beforeEach(module('http-auth-interceptor')); - - // Setup the mock service in an anonymous module. - // beforeEach(module(function () { - // })); - - /* - beforeEach(inject(function ($injector) { - // rootScope = $rootScope.$new(); - rootScope = $injector.get('$rootScope'); - spyOn(rootScope, '$broadcast').andCallThrough(); - })); - */ - - it('can get an instance of `authService`', inject(function(authService) { - expect(authService).toBeDefined(); - })); - - /* - it('it broadcasts a signal when invoking `loginConfirmed`', inject(function(authService) { - authService.loginConfirmed(); - expect(rootScope.$broadcast).toHaveBeenCalledWith('event:auth-loginConfirmed', undefined); - })); - */ - - }); - -});