Skip to content

Commit 2bda7d8

Browse files
committed
Adding unit tests, coverage at 100%
Fixing some things that had issues, found during testing
1 parent 1ee6342 commit 2bda7d8

4 files changed

Lines changed: 351 additions & 3 deletions

File tree

client/controllers/instance/controllerInstanceHome.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function ControllerInstanceHome(
1818
if (!instanceName) {
1919
$scope.loading = true;
2020
fetchInstances(userName, false, function(err, instances, account) {
21-
if (account === $rootScope.dataApp.data.activeAccount.oauthName()) {
21+
if (account === keypather.get($rootScope, 'dataApp.data.activeAccount.oauthName()')) {
2222
$scope.loading = false;
2323
var models = $filter('orderBy')(instances.models, 'attrs.name');
2424
var name = keypather.get(models, '[0].attrs.name');

client/services/serviceFetchInstances.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ function fetchInstances(
77
var currentInstances;
88
var currentAccountName;
99
return function (activeAccountName, forceQuery, cb) {
10-
if (activeAccountName === currentAccountName && !forceQuery) {
10+
if (activeAccountName === currentAccountName && !forceQuery && currentInstances) {
1111
return cb(null, currentInstances, activeAccountName);
1212
} else {
1313
currentAccountName = activeAccountName;
1414
fetchUser(function (err, user) {
1515
currentInstances = user.fetchInstances({
1616
githubUsername: currentAccountName
1717
}, function (err) {
18-
cb(err, currentInstances, activeAccountName);
18+
if (currentAccountName === activeAccountName) {
19+
cb(err, currentInstances, activeAccountName);
20+
}
1921
});
2022
});
2123
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
var $controller,
2+
$rootScope,
3+
$timeout,
4+
$scope,
5+
$localStorage,
6+
keypather,
7+
$state;
8+
var apiMocks = require('../apiMocks/index');
9+
/**
10+
* Things to test:
11+
* Since this controller is pretty simple, we only need to test it's redirection
12+
*/
13+
describe('ControllerInstanceHome'.bold.underline.blue, function () {
14+
var ctx = {};
15+
function setup(activeAccountUsername, localStorageData) {
16+
angular.mock.module('app');
17+
ctx.fakeuser = {
18+
attrs: angular.copy(apiMocks.user),
19+
oauthName: function () {
20+
return 'user';
21+
}
22+
};
23+
ctx.fakeOrg1 = {
24+
attrs: angular.copy(apiMocks.user),
25+
oauthName: function () {
26+
return 'org1';
27+
}
28+
};
29+
ctx.fakeOrg2 = {
30+
attrs: angular.copy(apiMocks.user),
31+
oauthName: function () {
32+
return 'org2';
33+
}
34+
};
35+
36+
ctx.userList = {
37+
user: ctx.fakeuser,
38+
org1: ctx.fakeOrg1,
39+
org2: ctx.fakeOrg2
40+
};
41+
42+
ctx.instanceLists = {
43+
user: {
44+
models: [{
45+
attrs: angular.copy(apiMocks.instances.running)
46+
}, {
47+
attrs: angular.copy(apiMocks.instances.stopped)
48+
}]
49+
},
50+
org1: {
51+
models: [{
52+
attrs: angular.copy(apiMocks.instances.building)
53+
}]
54+
},
55+
org2: {
56+
models: []
57+
}
58+
};
59+
ctx.setupInstanceResponse = function(username, cb) {
60+
return function (overrideUsername) {
61+
cb(null, ctx.instanceLists[overrideUsername || username], overrideUsername || username);
62+
};
63+
};
64+
ctx.fireInstanceResponse = {};
65+
ctx.fetchInstancesMock = sinon.spy(function (username, force, cb) {
66+
ctx.fireInstanceResponse[username] = ctx.setupInstanceResponse(username, cb);
67+
});
68+
ctx.stateParams = {
69+
userName: activeAccountUsername || 'user'
70+
};
71+
angular.mock.module('app', function ($provide) {
72+
$provide.value('fetchInstances', ctx.fetchInstancesMock);
73+
$provide.value('$stateParams', ctx.stateParams);
74+
$provide.value('$localStorage', localStorageData || {});
75+
});
76+
angular.mock.inject(function (
77+
_$controller_,
78+
_$rootScope_,
79+
_$localStorage_,
80+
_keypather_,
81+
_$timeout_,
82+
_$state_
83+
) {
84+
keypather = _keypather_;
85+
$controller = _$controller_;
86+
$rootScope = _$rootScope_;
87+
$scope = $rootScope.$new();
88+
$localStorage = _$localStorage_;
89+
$timeout = _$timeout_;
90+
$state = _$state_;
91+
$rootScope.safeApply = function(cb) {
92+
$timeout(function() {
93+
$scope.$digest();
94+
});
95+
};
96+
});
97+
98+
if (activeAccountUsername) {
99+
keypather.set($rootScope, 'dataApp.data.activeAccount', ctx.userList[activeAccountUsername]);
100+
}
101+
102+
ctx.fakeGo = sinon.stub($state, 'go');
103+
var ca = $controller('ControllerInstanceHome', {
104+
'$scope': $scope,
105+
'$rootScope': $rootScope,
106+
'$state': $state,
107+
'$stateParams': ctx.stateParams,
108+
'$localStorage': $localStorage
109+
});
110+
$rootScope.$digest();
111+
}
112+
describe('No local storage options'.blue, function () {
113+
it('should navigate to the first (alphabetical) instance for user', function () {
114+
setup('user');
115+
expect($scope.loading).to.be.true;
116+
ctx.fireInstanceResponse['user']();
117+
expect($scope.loading).to.be.false;
118+
sinon.assert.calledWith(ctx.fakeGo, 'instance.instance', {
119+
userName: 'user',
120+
instanceName: 'spaaace'
121+
});
122+
});
123+
it('should navigate to new for org2', function () {
124+
setup('org2');
125+
expect($scope.loading).to.be.true;
126+
ctx.fireInstanceResponse['org2']();
127+
expect($scope.loading).to.be.false;
128+
sinon.assert.calledWith(ctx.fakeGo, 'instance.new', {
129+
userName: 'org2'
130+
});
131+
});
132+
});
133+
describe('local storage options'.blue, function () {
134+
it('should navigate based on local storage', function () {
135+
var lsData = {};
136+
keypather.set(lsData, 'lastInstancePerUser.user', 'space');
137+
setup('user', lsData);
138+
sinon.assert.calledWith(ctx.fakeGo, 'instance.instance', {
139+
userName: 'user',
140+
instanceName: 'space'
141+
});
142+
expect($scope.loading).to.be.undefined;
143+
});
144+
});
145+
describe('multiple requests for different active accounts'.blue, function () {
146+
it('should only care about the last requested user, even when the responses are out of order', function () {
147+
setup('org1');
148+
ctx.stateParams.userName = 'org2';
149+
var ca = $controller('ControllerInstanceHome', {
150+
'$scope': $scope,
151+
'$rootScope': $rootScope,
152+
'$state': $state,
153+
'$stateParams': ctx.stateParams,
154+
'$localStorage': $localStorage
155+
});
156+
keypather.set($rootScope, 'dataApp.data.activeAccount', ctx.userList['org2']);
157+
$rootScope.$digest();
158+
expect($scope.loading).to.be.true;
159+
// This should still be connected to the old controller, but it should fail
160+
ctx.fireInstanceResponse['org1']();
161+
162+
sinon.assert.neverCalledWith(ctx.fakeGo, 'instance.instance', {
163+
userName: 'org1',
164+
instanceName: 'spaaace'
165+
});
166+
ctx.fireInstanceResponse['org2']();
167+
expect($scope.loading).to.be.false;
168+
169+
sinon.assert.calledWith(ctx.fakeGo, 'instance.new', {
170+
userName: 'org2'
171+
});
172+
});
173+
});
174+
});
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
var $state, user, fetchInstances, ctx;
2+
describe('serviceFetchUser'.bold.underline.blue, function () {
3+
var apiMocks = require('../apiMocks/index');
4+
beforeEach(function () {
5+
user = {};
6+
ctx = {};
7+
angular.mock.module('app');
8+
angular.mock.module(function ($provide) {
9+
$provide.value('user', user);
10+
$provide.value('fetchUser', function(cb) {
11+
cb(null, user);
12+
});
13+
});
14+
angular.mock.inject(function (_fetchInstances_, _$state_) {
15+
$state = _$state_;
16+
fetchInstances = _fetchInstances_;
17+
});
18+
ctx.fakeuser = {
19+
attrs: angular.copy(apiMocks.user),
20+
oauthName: function () {
21+
return 'user';
22+
}
23+
};
24+
ctx.fakeOrg1 = {
25+
attrs: angular.copy(apiMocks.user),
26+
oauthName: function () {
27+
return 'org1';
28+
}
29+
};
30+
ctx.fakeOrg2 = {
31+
attrs: angular.copy(apiMocks.user),
32+
oauthName: function () {
33+
return 'org2';
34+
}
35+
};
36+
37+
ctx.userList = {
38+
user: ctx.fakeuser,
39+
org1: ctx.fakeOrg1,
40+
org2: ctx.fakeOrg2
41+
};
42+
43+
ctx.instanceLists = {
44+
user: {
45+
models: [{
46+
attrs: angular.copy(apiMocks.instances.running)
47+
}, {
48+
attrs: angular.copy(apiMocks.instances.stopped)
49+
}]
50+
},
51+
org1: {
52+
models: [{
53+
attrs: angular.copy(apiMocks.instances.building)
54+
}]
55+
},
56+
org2: {
57+
models: []
58+
}
59+
};
60+
});
61+
62+
/**
63+
* Things to check
64+
*
65+
* Make sure forceQuery works
66+
* Make sure it always performs the query when changing active accounts
67+
*
68+
*/
69+
70+
it('should fetch the instances the first time', function(done) {
71+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
72+
expect(opts).to.deep.equal({
73+
githubUsername: 'user'
74+
});
75+
setTimeout(innerCb, 10);
76+
return ctx.instanceLists['user'];
77+
});
78+
var cb = sinon.spy(function (err, instances, username) {
79+
sinon.assert.called(user.fetchInstances);
80+
expect(instances).to.equal(ctx.instanceLists['user']);
81+
expect(username).to.equal('user');
82+
done();
83+
});
84+
fetchInstances('user', false, cb);
85+
});
86+
it('should use its own cache when refetching', function(done) {
87+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
88+
expect(opts).to.deep.equal({
89+
githubUsername: 'user'
90+
});
91+
setTimeout(innerCb, 10);
92+
return ctx.instanceLists['user'];
93+
});
94+
var cb = sinon.spy(function (err, instances, username) {
95+
sinon.assert.calledOnce(user.fetchInstances);
96+
97+
expect(instances).to.equal(ctx.instanceLists['user']);
98+
expect(username).to.equal('user');
99+
part2();
100+
});
101+
fetchInstances('user', false, cb);
102+
function part2() {
103+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
104+
innerCb(null, ctx.instanceLists['user'], 'user');
105+
});
106+
cb = sinon.spy(function (err, instances, username) {
107+
sinon.assert.notCalled(user.fetchInstances);
108+
expect(instances).to.equal(ctx.instanceLists['user']);
109+
expect(username).to.equal('user');
110+
done();
111+
});
112+
fetchInstances('user', false, cb);
113+
}
114+
});
115+
it('should skip its own cache when forced', function(done) {
116+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
117+
expect(opts).to.deep.equal({
118+
githubUsername: 'user'
119+
});
120+
setTimeout(innerCb, 10);
121+
return ctx.instanceLists['user'];
122+
});
123+
var cb = sinon.spy(function (err, instances, username) {
124+
sinon.assert.calledOnce(user.fetchInstances);
125+
126+
expect(instances).to.equal(ctx.instanceLists['user']);
127+
expect(username).to.equal('user');
128+
part2();
129+
});
130+
fetchInstances('user', false, cb);
131+
function part2() {
132+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
133+
innerCb(null, ctx.instanceLists['user'], 'user');
134+
});
135+
cb = sinon.spy(function (err, instances, username) {
136+
sinon.assert.calledOnce(user.fetchInstances);
137+
expect(instances).to.equal(ctx.instanceLists['user']);
138+
expect(username).to.equal('user');
139+
done();
140+
});
141+
fetchInstances('user', true, cb);
142+
}
143+
});
144+
it('should return the correct user with the correct instances when they come out of order', function(done) {
145+
var cb1, cb2;
146+
var isUser = true;
147+
user.fetchInstances = sinon.spy(function (opts, innerCb) {
148+
if (opts.githubUsername === 'user') {
149+
expect(isUser).to.be.true;
150+
isUser = false;
151+
cb1 = innerCb;
152+
} else {
153+
expect(isUser).to.be.false;
154+
cb2 = innerCb;
155+
}
156+
return ctx.instanceLists[opts.githubUsername];
157+
});
158+
var doneCb = sinon.spy(function (err, instances, username) {
159+
});
160+
var doneCb2 = sinon.spy(function (err, instances, username) {
161+
sinon.assert.notCalled(doneCb);
162+
expect('org1').to.deep.equal(username);
163+
expect(instances).to.not.deep.equal(ctx.instanceLists['user']);
164+
expect(instances).to.deep.equal(ctx.instanceLists[username]);
165+
done();
166+
});
167+
fetchInstances('user', false, doneCb);
168+
fetchInstances('org1', false, doneCb2);
169+
cb2();
170+
cb1();
171+
});
172+
});

0 commit comments

Comments
 (0)