Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make "npm test" run Karma tests #140

Merged
merged 15 commits into from
Jul 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ module.exports = function (grunt) {
proxies: [
{
context: '/v2',
host: 'path-to-your-registry-v2',
port: 5000,
host: process.env.DOCKER_REGISTRY_HOST,
port: process.env.DOCKER_REGISTRY_PORT,
https: false,
xforward: false,
headers: {
Expand Down
174 changes: 174 additions & 0 deletions app/app.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
'use strict';

describe('docker-registry-frontend', function() {
var $route, $location, $rootScope, $httpBackend, $controller;

beforeEach(module('docker-registry-frontend'));
beforeEach(inject(function(_$route_, _$location_, _$rootScope_, _$httpBackend_, _$controller_) {
$route = _$route_;
$location = _$location_;
$rootScope = _$rootScope_;
$httpBackend = _$httpBackend_;
$controller = _$controller_;
}));

it('/home should display home page', function() {
$httpBackend.expectGET('home.html').respond(200);
$location.path('/home');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('home.html');
expect($route.current.controller).toBe('HomeController');
var scope = {};
var expectedAppMode = {
"browseOnly": true,
"defaultRepositoriesPerPage": 20,
"defaultTagsPerPage": 10
}
$controller('HomeController', {$scope: scope});
$httpBackend.expectGET('/app-mode.json').respond(expectedAppMode);
$httpBackend.flush();
jasmine.addCustomEqualityTester(angular.equals);
expect(scope.appMode).toEqual(expectedAppMode);
});

it('/repositories should display repository list page', function() {
$httpBackend.expectGET('repository/repository-list.html').respond(200);
$location.path('/repositories');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-list.html');
expect($route.current.controller).toBe('RepositoryListController');
var scope = {};
$controller('RepositoryListController', {$scope: scope});
expect(scope.reposPerPage).toBeUndefined();
});

it('/repositories/10 should display repository list page', function() {
$httpBackend.expectGET('repository/repository-list.html').respond(200);
$location.path('/repositories/10');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-list.html');
expect($route.current.controller).toBe('RepositoryListController');
var scope = {};
$controller('RepositoryListController', {$scope: scope});
// expect(scope.reposPerPage).toBe(10);
});

it('/repositories/20 should display repository list page', function() {
$httpBackend.expectGET('repository/repository-list.html').respond(200);
$location.path('/repositories/20');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-list.html');
expect($route.current.controller).toBe('RepositoryListController');
var scope = {};
$controller('RepositoryListController', {$scope: scope});
// expect(scope.reposPerPage).toBe(20);
});

it('URL with repositoryUser and repositoryName and no tagsPerPage should display repository detail page', function() {
$httpBackend.expectGET('repository/repository-detail.html').respond(200);
$location.path('/repository/owner/name');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-detail.html');
expect($route.current.controller).toBe('RepositoryDetailController');
var scope = {};
$controller('RepositoryDetailController', {$scope: scope});
expect(scope.repositoryUser).toBe('owner');
expect(scope.repositoryName).toBe('name');
expect(scope.repository).toBe('owner/name');
expect(scope.maxTagsPage).toBeUndefined();
});

it('URL with repositoryUser and repositoryName and tagsPerPage should display repository detail page', function() {
$httpBackend.expectGET('repository/repository-detail.html').respond(200);
$location.path('/repository/owner/name/10');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-detail.html');
expect($route.current.controller).toBe('RepositoryDetailController');
var scope = {};
$controller('RepositoryDetailController', {$scope: scope});
expect(scope.repositoryUser).toBe('owner');
expect(scope.repositoryName).toBe('name');
expect(scope.repository).toBe('owner/name');
});

// This test currently fails; this URL is incorrectly routing to the home page
// @todo @FIXME
//
// it('URL with repositoryName but no repositoryUser and no tagsPerPage should display repository detail page', function() {
// $httpBackend.expectGET('repository/repository-detail.html').respond(200);
// $location.path('/repository/cx');
// $rootScope.$digest();
// expect($route.current.templateUrl).toBe('repository/repository-detail.html');
// expect($route.current.controller).toBe('RepositoryDetailController');
// });

it('URL with repositoryName but no repositoryUser and tagsPerPage should display repository detail page', function() {
$httpBackend.expectGET('repository/repository-detail.html').respond(200);
$location.path('/repository/cx/10');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('repository/repository-detail.html');
expect($route.current.controller).toBe('RepositoryDetailController');
var scope = {};
$controller('RepositoryDetailController', {$scope: scope});
// expect(scope.repositoryUser).toBeUndefined();
// expect(scope.repositoryName).toBe('cx');
// expect(scope.repository).toBe('cx');
});

it('/about should display about page', function() {
$httpBackend.expectGET('about.html').respond(200);
$location.path('/about');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('about.html');
});

it('/tag/repositoryUser/repositoryName/latest should display tag detail page', function() {
$httpBackend.expectGET('tag/tag-detail.html').respond(200);
$location.path('/tag/repositoryUser/repositoryName/latest');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('tag/tag-detail.html');
expect($route.current.controller).toBe('TagController');
var scope = {};
$controller('TagController', {$scope: scope});
expect(scope.repositoryUser).toBe('repositoryUser');
expect(scope.repositoryName).toBe('repositoryName');
expect(scope.repository).toBe('repositoryUser/repositoryName');
expect(scope.tagName).toBe('latest');
});

// This test currently fails; this URL is incorrectly routing to the home page
// @todo @FIXME
//
// it('/tag/repositoryName/latest should display tag detail page', function() {
// $httpBackend.expectGET('tag/tag-detail.html').respond(200);
// $location.path('/tag/repositoryName/latest');
// $rootScope.$digest();
// expect($route.current.templateUrl).toBe('tag/tag-detail.html');
// expect($route.current.controller).toBe('TagController');
// });

it('/image/88e37c7099fa should display image detail page', function() {
$httpBackend.expectGET('tag/image-detail.html').respond(200);
$location.path('/image/88e37c7099fa');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('tag/image-detail.html');
expect($route.current.controller).toBe('ImageController');
});

it('/image/88e37c7099fa/tag should display create tag page', function() {
$httpBackend.expectGET('tag/create-tag.html').respond(200);
$location.path('/image/88e37c7099fa/tag');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('tag/create-tag.html');
expect($route.current.controller).toBe('CreateTagController');
});

it('/unknown-url should display home page', function() {
$httpBackend.expectGET('home.html').respond(200);
$location.path('/unknown-url');
$rootScope.$digest();
expect($route.current.templateUrl).toBe('home.html');
expect($route.current.controller).toBe('HomeController');
});

});
4 changes: 2 additions & 2 deletions app/main-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
* # MainController
* Controller of the docker-registry-frontend
*/
angular.module('main-controller', [])
angular.module('main-controller', ['ngRoute', 'app-version-services', 'registry-services'])
.controller('MainController', ['$scope', '$route', '$routeParams', '$location', 'AppVersion', 'RegistryHost',
function($scope, $route, $routeParams, $location, AppVersion, RegistryHost){
this.$route = $route;
this.$location = $location;
this.$routeParams = $routeParams;
$scope.appVersion = AppVersion.query();
$scope.registryHost = RegistryHost.query();
}]);
}]);
3 changes: 2 additions & 1 deletion app/repository/repository-list-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* # RepositoryListController
* Controller of the docker-registry-frontend
*/
angular.module('repository-list-controller', ['registry-services', 'app-mode-services'])
angular.module('repository-list-controller', ['ngRoute', 'ui.bootstrap', 'registry-services', 'app-mode-services'])
.controller('RepositoryListController', ['$scope', '$route', '$routeParams', '$location', '$modal', 'Repository', 'AppMode',
function($scope, $route, $routeParams, $location, $modal, Repository, AppMode){

Expand Down Expand Up @@ -47,6 +47,7 @@ angular.module('repository-list-controller', ['registry-services', 'app-mode-ser
// To watch for changes on a property inside the object "repositories"
// we first have to make sure the promise is ready.
$scope.repositories.$promise.then(function(data) {
$scope.repositories = data;
$scope.$watch('repositories.repos|filter:{selected:true}', function(nv) {
$scope.selectedRepositories = nv.map(function (repo) {
return repo.name;
Expand Down
49 changes: 49 additions & 0 deletions app/repository/repository-list-controller.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

describe('RepositoryListController', function() {

// load the controller's module
beforeEach(module('repository-list-controller'));

var $controller, $httpBackend, $q, $rootScope;

beforeEach(inject(function(_$controller_, _$httpBackend_, _$q_, _$rootScope_) {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$q = _$q_;
$rootScope = _$rootScope_;
}));

it('should attach some keys to the scope', function() {
var $scope = $rootScope.$new();
var route = {
'current': {
'params': {
'lastNamespace': 'lastNamespace',
'lastRepository': 'lastRepository',
'reposPerPage': 10
}
}
};

var mockRepositoryReturnValue = {
repos: [{username: 'username', name: 'name', selected: true}],
lastNamespace: 'lastNamespace',
lastRepository: 'lastRepository'
};
var mockRepository = {query: null};
spyOn(mockRepository, 'query').and.returnValue({$promise: $q.when(mockRepositoryReturnValue)});

var expectedAppMode = {"browseOnly": true, "defaultRepositoriesPerPage": 20, "defaultTagsPerPage": 10};
$httpBackend.expectGET('/app-mode.json').respond(expectedAppMode);
var ctrl = $controller('RepositoryListController', {$scope: $scope, $route: route, Repository: mockRepository});
$httpBackend.flush();
expect($scope.reposPerPage).toBe(10);
expect($scope.lastNamespace).toEqual('lastNamespace');
expect($scope.lastRepository).toEqual('lastRepository');
expect($scope.selectedRepositories).toEqual(['name']);
expect(mockRepository.query).toHaveBeenCalled();
expect($scope.repositories).toEqual(mockRepositoryReturnValue);
});
});

11 changes: 0 additions & 11 deletions app/services/registry-host-services.js

This file was deleted.

12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,25 @@
"grunt-svgmin": "^3.1.2",
"grunt-usemin": "^3.1.1",
"grunt-wiredep": "^2.0.0",
"jasmine": "^2.4.1",
"jasmine-core": "^2.4.1",
"jshint-stylish": "^2.1.0",
"karma": "^1.1.1",
"karma-jasmine": "^1.0.2",
"karma-junit-reporter": "^1.1.0",
"karma-phantomjs-launcher": "^1.0.1",
"karma-spec-reporter": "0.0.26",
"load-grunt-tasks": "^3.4.0",
"time-grunt": "^1.3.0"
},
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"test": "grunt test"
"postinstall": "bower install",
"pretest": "npm install",
"test": "karma start test/karma.conf.js",
"test-single-run": "karma start test/karma.conf.js --single-run"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msabramo Maybe this is a dump question but how can I trigger this test-single-run? Just npm test-single-run won't work. As you can see here, travis will stuck after a while when running npm test. I know that this is normal and that it allows me open various browsers to run my tests.

Copy link
Contributor Author

@msabramo msabramo Jul 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kwk There are no dumb questions. Use npm run test-single-run (note run in there). npm test is a special case, but in general you need to use npm run (or npm run-script) to execute the scripts that you define in package.json.

$ npm run test-single-run

> docker-registry-frontend@0.0.2 test-single-run /Users/marca/dev/git-repos/docker-registry-frontend_2
> karma start test/karma.conf.js --single-run

19 07 2016 06:29:24.145:WARN [karma]: Port 8080 in use
19 07 2016 06:29:24.148:WARN [karma]: Port 8081 in use
19 07 2016 06:29:24.148:INFO [karma]: Karma v1.1.1 server started at http://localhost:8082/
19 07 2016 06:29:24.149:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
19 07 2016 06:29:24.157:INFO [launcher]: Starting browser PhantomJS
19 07 2016 06:29:24.613:INFO [PhantomJS 2.1.1 (Mac OS X 0.0.0)]: Connected on socket /#L0dobW7vCDANyy35AAAA with id 59001397

  docker-registry-frontend
    ✓ /home should display home page
    ✓ /repositories should display repository list page
    ✓ /repositories/10 should display repository list page
    ✓ /repositories/20 should display repository list page
    ✓ URL with repositoryUser and repositoryName and no tagsPerPage should display repository detail page
    ✓ URL with repositoryUser and repositoryName and tagsPerPage should display repository detail page
    ✓ URL with repositoryName but no repositoryUser and no tagsPerPage should display repository detail page
    ✓ URL with repositoryName but no repositoryUser and tagsPerPage should display repository detail page
    ✓ /about should display about page
    ✓ /tag/repositoryUser/repositoryName/latest should display tag detail page
    ✓ /image/88e37c7099fa should display image detail page
    ✓ /image/88e37c7099fa/tag should display create tag page
    ✓ /unknown-url should display home page

  RepositoryListController
    ✓ should attach some keys to the scope

  MainController
    ✓ should attach an appVersion and registryHost to the scope

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 15 of 15 SUCCESS (0.008 secs / 0.077 secs)
TOTAL: 15 SUCCESS

See https://docs.npmjs.com/cli/run-script for more info on this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to submit a PR to change it in .travis.yml but I see that you are a step ahead of me.

Crossing my fingers and hoping that the Travis CI build passes!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@msabramo Thank you for this. I totally forgot about run. It probably will not pass because in pretest you do an npm install which I have to do before running the single test as well, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm yeah, you are probably right. And I don't know if there is a way to have a pre step for a script. I guess the easiest thing to do is to have the .travis.yml do npm install.

Copy link
Contributor Author

@msabramo msabramo Jul 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might work on Travis perhaps, because maybe the default for a node_js project is to do npm install for the install step.

That seems to be what they are saying (I think) at https://docs.travis-ci.com/user/languages/javascript-with-nodejs#Travis-CI-uses-npm

Copy link
Contributor Author

@msabramo msabramo Jul 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just found this:

https://karma-runner.github.io/latest/plus/travis.html

Though that will work, it doesn't seem ideal because then npm test won't run continuously, which is kind of nice for development. I guess one could use a script for that, like test-continuously or something.

Copy link
Contributor Author

@msabramo msabramo Jul 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's what angular-seed does:

https://github.com/angular/angular-seed/blob/master/.travis.yml

script:
  - node_modules/.bin/karma start karma.conf.js --no-auto-watch --single-run --reporters=dots --browsers=Firefox

Copy link
Contributor Author

@msabramo msabramo Jul 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From #146:

screen shot 2016-07-19 at 6 54 06 am

Awesome!

},
"description": "A pure web-based frontend to a docker-registry",
"main": "Gruntfile.js",
Expand Down
21 changes: 14 additions & 7 deletions test/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,25 @@ module.exports = function(config) {
// testing framework to use (jasmine/mocha/qunit/...)
frameworks: ['jasmine'],

reporters: ['junit', 'spec'],

// list of files / patterns to load in the browser
files: [
'bower_components/angular/angular.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-animate/angular-animate.js',
'bower_components/angular-bootstrap/ui-bootstrap.js',
'bower_components/angular-bootstrap-checkbox/angular-bootstrap-checkbox.js',
'bower_components/angular-cookies/angular-cookies.js',
'bower_components/angular-filter/dist/angular-filter.js',
'bower_components/angular-loading-bar/src/loading-bar.js',
'bower_components/angular-mocks/angular-mocks.js',
'bower_components/angular-moment/angular-moment.js',
'bower_components/angular-resource/angular-resource.js',
'bower_components/angular-route/angular-route.js',
'bower_components/angular-sanitize/angular-sanitize.js',
'bower_components/angular-smart-table/src/smart-table.module.js',
'bower_components/angular-touch/angular-touch.js',
'app/scripts/**/*.js',
'test/mock/**/*.js',
'app/**/*.js',
'test/spec/**/*.js'
],

Expand All @@ -50,10 +57,10 @@ module.exports = function(config) {
],

// Which plugins to enable
plugins: [
'karma-phantomjs-launcher',
'karma-jasmine'
],
// plugins: [
// 'karma-phantomjs-launcher',
// 'karma-jasmine'
// ],

// Continuous Integration mode
// if true, it capture browsers, run tests and exit
Expand Down
22 changes: 0 additions & 22 deletions test/spec/controllers/about.js

This file was deleted.

Loading