Begin conrtoller unit tests

This commit is contained in:
Tankred Hase 2014-12-17 22:41:57 +01:00
parent eab07041f0
commit 6beddf4760
9 changed files with 284 additions and 234 deletions

View File

@ -51,7 +51,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, $timeout, $q, mai
callback: function(granted) {
if (granted) {
// query oauth token
getOAuthToken();
return getOAuthToken();
} else {
// use normal user/password login
$scope.setCredentials();
@ -61,7 +61,7 @@ var AddAccountCtrl = function($scope, $location, $routeParams, $timeout, $q, mai
function getOAuthToken() {
// fetches the email address from the chrome identity api
auth.getOAuthToken().then(function() {
return auth.getOAuthToken().then(function() {
// continue to setting credentials
return $scope.setCredentials();

View File

@ -1,30 +1,33 @@
'use strict';
var LoginCtrl = function($scope, $timeout, $location, updateHandler, account, auth, email, keychain, dialog) {
var LoginCtrl = function($scope, $timeout, $location, updateHandler, account, auth, email, keychain, dialog, appConfig) {
// check for app update
updateHandler.checkForUpdate();
//
// Scope functions
//
// initialize the user account
auth.init().then(function() {
// get email address
return auth.getEmailAddress();
$scope.init = function() {
// initialize the user account
return auth.init().then(function() {
// get email address
return auth.getEmailAddress();
}).then(function(info) {
// check if account needs to be selected
if (!info.emailAddress) {
return $scope.goTo('/add-account');
}
}).then(function(info) {
// check if account needs to be selected
if (!info.emailAddress) {
return $scope.goTo('/add-account');
}
// initiate the account by initializing the email dao and user storage
return account.init({
emailAddress: info.emailAddress,
realname: info.realname
}).then(function(availableKeys) {
return redirect(availableKeys);
});
// initiate the account by initializing the email dao and user storage
return account.init({
emailAddress: info.emailAddress,
realname: info.realname
}).then(function(availableKeys) {
return redirect(availableKeys);
});
}).catch(dialog.error);
}).catch(dialog.error);
};
function redirect(availableKeys) {
if (availableKeys && availableKeys.publicKey && availableKeys.privateKey) {
@ -32,15 +35,16 @@ var LoginCtrl = function($scope, $timeout, $location, updateHandler, account, au
return email.unlock({
keypair: availableKeys,
passphrase: undefined
}).then(function() {
// no passphrase set... go to main screen
return auth.storeCredentials().then(function() {
return $scope.goTo('/account');
});
}).catch(function() {
// passphrase set... ask for passphrase
return $scope.goTo('/login-existing');
}).then(function() {
// no passphrase set... go to main screen
return auth.storeCredentials();
}).then(function() {
return $scope.goTo('/account');
});
} else if (availableKeys && availableKeys.publicKey && !availableKeys.privateKey) {
@ -69,6 +73,19 @@ var LoginCtrl = function($scope, $timeout, $location, updateHandler, account, au
$location.path(location);
});
};
//
// Start the app
//
// check for app update
updateHandler.checkForUpdate();
// init the app
if (!appConfig.preventAutoStart) {
$scope.init();
}
};
module.exports = LoginCtrl;

View File

@ -49,6 +49,10 @@ require('../src/js/email');
// Global mocks
//
window.qMock = function(res, rej) {
return new Promise(res, rej);
};
window.resolves = function(val) {
return new Promise(function(res) {
res(val);

View File

@ -116,16 +116,17 @@ describe('Add Account Controller unit test', function() {
setCredentialsStub.restore();
});
it('should use oauth', function() {
it('should use oauth', function(done) {
dialogStub.confirm = function(options) {
options.callback(true);
options.callback(true).then(function() {
expect(setCredentialsStub.calledOnce).to.be.true;
expect(authStub.getOAuthToken.calledOnce).to.be.true;
done();
});
};
authStub.getOAuthToken.yields();
authStub.getOAuthToken.returns(resolves());
scope.oauthPossible();
expect(setCredentialsStub.calledOnce).to.be.true;
expect(authStub.getOAuthToken.calledOnce).to.be.true;
});
it('should not use oauth', function() {
@ -139,25 +140,29 @@ describe('Add Account Controller unit test', function() {
expect(authStub.getOAuthToken.called).to.be.false;
});
it('should not forward to login when oauth fails', function() {
it('should not forward to login when oauth fails', function(done) {
dialogStub.error = function(err) {
expect(err).to.exist;
expect(setCredentialsStub.called).to.be.false;
done();
};
dialogStub.confirm = function(options) {
options.callback(true);
};
authStub.getOAuthToken.yields(new Error());
authStub.getOAuthToken.returns(rejects(new Error()));
scope.oauthPossible();
expect(dialogStub.error.calledOnce).to.be.true;
expect(setCredentialsStub.called).to.be.false;
});
});
describe('setCredentials', function() {
it('should work', function() {
scope.setCredentials();
it('should work', inject(function($timeout) {
scope.setCredentials().then();
$timeout.flush();
expect(location.path.calledWith('/login-set-credentials')).to.be.true;
});
}));
});
});

View File

@ -29,6 +29,7 @@ describe('Create Account Controller unit test', function() {
$location: location,
$scope: scope,
$routeParams: {},
$q: window.qMock,
auth: authStub,
admin: adminStub
});
@ -54,16 +55,15 @@ describe('Create Account Controller unit test', function() {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync(new Error('asdf'));
adminStub.createUser.returns(rejects(new Error('asdf')));
scope.$apply = function() {
scope.createWhiteoutAccount().then(function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.equal('asdf');
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
});
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
@ -71,16 +71,15 @@ describe('Create Account Controller unit test', function() {
scope.form.$invalid = false;
scope.betaCode = 'asfd';
scope.phone = '12345';
adminStub.createUser.yieldsAsync();
adminStub.createUser.returns(resolves());
scope.$apply = function() {
scope.createWhiteoutAccount().then(function() {
expect(scope.busy).to.be.false;
expect(scope.errMsg).to.be.undefined;
expect(adminStub.createUser.calledOnce).to.be.true;
done();
};
});
scope.createWhiteoutAccount();
expect(scope.busy).to.be.true;
});
});

View File

@ -26,17 +26,13 @@ describe('Login Controller unit test', function() {
};
authMock.emailAddress = emailAddress;
});
function createController() {
angular.module('login-test', ['woServices', 'woEmail', 'woUtil']);
angular.mock.module('login-test');
angular.mock.inject(function($rootScope, $controller) {
scope = $rootScope.$new();
scope.state = {};
scope.form = {};
scope.goTo = function() {};
goToStub = sinon.stub(scope, 'goTo');
ctrl = $controller(LoginCtrl, {
$scope: scope,
@ -46,151 +42,167 @@ describe('Login Controller unit test', function() {
auth: authMock,
email: emailMock,
keychain: keychainMock,
dialog: dialogMock
dialog: dialogMock,
appConfig: {
preventAutoStart: true
}
});
});
}
scope.goTo = function() {};
goToStub = sinon.stub(scope, 'goTo');
});
afterEach(function() {});
it('should fail for auth.getEmailAddress', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(new Error());
it('should fail for auth.getEmailAddress', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(rejects(new Error()));
createController();
expect(updateHandlerMock.checkForUpdate.calledOnce).to.be.true;
expect(authMock.init.calledOnce).to.be.true;
expect(dialogMock.error.calledOnce).to.be.true;
});
it('should fail for auth.init', function() {
authMock.init.yields(new Error());
authMock.getEmailAddress.yields(null, {
emailAddress: emailAddress
scope.init().then(function() {
expect(updateHandlerMock.checkForUpdate.calledOnce).to.be.true;
expect(authMock.init.calledOnce).to.be.true;
expect(dialogMock.error.calledOnce).to.be.true;
done();
});
createController();
expect(authMock.init.calledOnce).to.be.true;
expect(accountMock.init.called).to.be.false;
expect(dialogMock.error.calledOnce).to.be.true;
});
it('should redirect to /add-account', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {});
createController();
expect(goToStub.withArgs('/add-account').calledOnce).to.be.true;
});
it('should redirect to /login-existing', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should fail for auth.init', function(done) {
authMock.init.returns(rejects(new Error()));
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
}));
scope.init().then(function() {
expect(authMock.init.calledOnce).to.be.true;
expect(accountMock.init.called).to.be.false;
expect(dialogMock.error.calledOnce).to.be.true;
done();
});
accountMock.init.yields(null, {
});
it('should redirect to /add-account', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({}));
scope.init().then(function() {
expect(goToStub.withArgs('/add-account').calledOnce).to.be.true;
done();
});
});
it('should redirect to /login-existing', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey',
privateKey: 'privateKey'
}));
emailMock.unlock.returns(rejects(new Error()));
scope.init().then(function() {
expect(goToStub.withArgs('/login-existing').calledOnce).to.be.true;
done();
});
emailMock.unlock.yields(new Error());
createController();
expect(goToStub.withArgs('/login-existing').calledOnce).to.be.true;
});
it('should fail for auth.storeCredentials', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should fail for auth.storeCredentials', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
});
accountMock.init.yields(null, {
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey',
privateKey: 'privateKey'
}));
emailMock.unlock.returns(resolves());
authMock.storeCredentials.returns(rejects(new Error()));
scope.init().then(function() {
expect(dialogMock.error.calledOnce).to.be.true;
done();
});
emailMock.unlock.yields();
authMock.storeCredentials.yields(new Error());
createController();
expect(dialogMock.error.calledOnce).to.be.true;
});
it('should redirect to /account', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should redirect to /account', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
});
accountMock.init.yields(null, {
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey',
privateKey: 'privateKey'
}));
emailMock.unlock.returns(resolves());
authMock.storeCredentials.returns(resolves());
scope.init().then(function() {
expect(goToStub.withArgs('/account').calledOnce).to.be.true;
done();
});
emailMock.unlock.yields();
authMock.storeCredentials.yields();
createController();
expect(goToStub.withArgs('/account').calledOnce).to.be.true;
});
it('should fail for keychain.requestPrivateKeyDownload', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should fail for keychain.requestPrivateKeyDownload', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
});
accountMock.init.yields(null, {
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey'
}));
keychainMock.requestPrivateKeyDownload.returns(rejects(new Error()));
scope.init().then(function() {
expect(dialogMock.error.calledOnce).to.be.true;
done();
});
keychainMock.requestPrivateKeyDownload.yields(new Error());
createController();
expect(dialogMock.error.calledOnce).to.be.true;
});
it('should redirect to /login-privatekey-download', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should redirect to /login-privatekey-download', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
});
accountMock.init.yields(null, {
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey'
}));
keychainMock.requestPrivateKeyDownload.returns(resolves(true));
scope.init().then(function() {
expect(goToStub.withArgs('/login-privatekey-download').calledOnce).to.be.true;
done();
});
keychainMock.requestPrivateKeyDownload.yields(null, true);
createController();
expect(goToStub.withArgs('/login-privatekey-download').calledOnce).to.be.true;
});
it('should redirect to /login-new-device', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should redirect to /login-new-device', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
});
accountMock.init.yields(null, {
}));
accountMock.init.returns(resolves({
publicKey: 'publicKey'
}));
keychainMock.requestPrivateKeyDownload.returns(resolves());
scope.init().then(function() {
expect(goToStub.withArgs('/login-new-device').calledOnce).to.be.true;
done();
});
keychainMock.requestPrivateKeyDownload.yields();
createController();
expect(goToStub.withArgs('/login-new-device').calledOnce).to.be.true;
});
it('should redirect to /login-initial', function() {
authMock.init.yields();
authMock.getEmailAddress.yields(null, {
it('should redirect to /login-initial', function(done) {
authMock.init.returns(resolves());
authMock.getEmailAddress.returns(resolves({
emailAddress: emailAddress
}));
accountMock.init.returns(resolves({}));
scope.init().then(function() {
expect(goToStub.withArgs('/login-initial').calledOnce).to.be.true;
done();
});
accountMock.init.yields(null, {});
createController();
expect(goToStub.withArgs('/login-initial').calledOnce).to.be.true;
});
});

View File

@ -28,6 +28,7 @@ describe('Login (existing user) Controller unit test', function() {
ctrl = $controller(LoginExistingCtrl, {
$scope: scope,
$routeParams: {},
$q: window.qMock,
email: emailDaoMock,
auth: authMock,
keychain: keychainMock
@ -44,32 +45,35 @@ describe('Login (existing user) Controller unit test', function() {
});
describe('confirm passphrase', function() {
it('should unlock crypto and start', function() {
it('should unlock crypto and start', function(done) {
var keypair = {},
pathSpy = sinon.spy(location, 'path');
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair);
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(resolves(keypair));
emailDaoMock.unlock.withArgs({
keypair: keypair,
passphrase: passphrase
}).yields();
authMock.storeCredentials.yields();
}).returns(resolves());
authMock.storeCredentials.returns(resolves());
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(pathSpy.calledOnce).to.be.true;
expect(pathSpy.calledWith('/account')).to.be.true;
scope.confirmPassphrase().then(function() {
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailDaoMock.unlock.calledOnce).to.be.true;
expect(pathSpy.calledOnce).to.be.true;
expect(pathSpy.calledWith('/account')).to.be.true;
done();
});
});
it('should not work when keypair unavailable', function() {
it('should not work when keypair unavailable', function(done) {
scope.passphrase = passphrase;
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd'));
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(rejects(new Error('asd')));
scope.confirmPassphrase();
expect(scope.errMsg).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
scope.confirmPassphrase().then(function() {
expect(scope.errMsg).to.exist;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
});
});
});
});

View File

@ -30,6 +30,7 @@ describe('Login (initial user) Controller unit test', function() {
ctrl = $controller(LoginInitialCtrl, {
$scope: scope,
$routeParams: {},
$q: window.qMock,
newsletter: newsletter,
email: emailMock,
auth: authMock
@ -74,36 +75,38 @@ describe('Login (initial user) Controller unit test', function() {
expect(newsletterStub.called).to.be.false;
});
it('should fail due to error in emailDao.unlock', function() {
it('should fail due to error in emailDao.unlock', function(done) {
scope.agree = true;
emailMock.unlock.withArgs({
passphrase: undefined
}).yields(new Error('asdf'));
authMock.storeCredentials.yields();
}).returns(rejects(new Error('asdf')));
authMock.storeCredentials.returns(resolves());
scope.generateKey();
expect(scope.errMsg).to.exist;
expect(scope.state.ui).to.equal(1);
expect(newsletterStub.called).to.be.true;
scope.generateKey().then(function() {
expect(scope.errMsg).to.exist;
expect(scope.state.ui).to.equal(1);
expect(newsletterStub.called).to.be.true;
done();
});
});
it('should unlock crypto', function() {
it('should unlock crypto', function(done) {
scope.agree = true;
emailMock.unlock.withArgs({
passphrase: undefined
}).yields();
authMock.storeCredentials.yields();
}).returns(resolves());
authMock.storeCredentials.returns(resolves());
scope.generateKey();
expect(scope.errMsg).to.not.exist;
expect(scope.state.ui).to.equal(2);
expect(newsletterStub.called).to.be.true;
expect(location.$$path).to.equal('/account');
expect(emailMock.unlock.calledOnce).to.be.true;
scope.generateKey().then(function() {
expect(scope.errMsg).to.not.exist;
expect(scope.state.ui).to.equal(2);
expect(newsletterStub.called).to.be.true;
expect(location.$$path).to.equal('/account');
expect(emailMock.unlock.calledOnce).to.be.true;
done();
});
});
});
});

View File

@ -35,6 +35,7 @@ describe('Login (new device) Controller unit test', function() {
ctrl = $controller(LoginNewDeviceCtrl, {
$scope: scope,
$routeParams: {},
$q: window.qMock,
email: emailMock,
auth: authMock,
pgp: pgpMock,
@ -53,7 +54,7 @@ describe('Login (new device) Controller unit test', function() {
});
describe('confirm passphrase', function() {
it('should unlock crypto with a public key on the server', function() {
it('should unlock crypto with a public key on the server', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
@ -64,20 +65,21 @@ describe('Login (new device) Controller unit test', function() {
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(resolves({
_id: keyId,
publicKey: 'a'
}));
emailMock.unlock.withArgs(sinon.match.any, passphrase).returns(resolves());
keychainMock.putUserKeyPair.returns(resolves());
scope.confirmPassphrase().then(function() {
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
});
emailMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
scope.confirmPassphrase();
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
});
it('should unlock crypto with no key on the server', function() {
it('should unlock crypto with no key on the server', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b',
@ -89,17 +91,18 @@ describe('Login (new device) Controller unit test', function() {
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields();
emailMock.unlock.withArgs(sinon.match.any, passphrase).yields();
keychainMock.putUserKeyPair.yields();
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(resolves());
emailMock.unlock.withArgs(sinon.match.any, passphrase).returns(resolves());
keychainMock.putUserKeyPair.returns(resolves());
scope.confirmPassphrase();
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
scope.confirmPassphrase().then(function() {
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
done();
});
});
it('should not work when keypair upload fails', function() {
it('should not work when keypair upload fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
@ -110,24 +113,25 @@ describe('Login (new device) Controller unit test', function() {
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(resolves({
_id: keyId,
publicKey: 'a'
});
emailMock.unlock.yields();
keychainMock.putUserKeyPair.yields({
}));
emailMock.unlock.returns(resolves());
keychainMock.putUserKeyPair.returns(rejects({
errMsg: 'yo mamma.'
}));
scope.confirmPassphrase().then(function() {
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.putUserKeyPair.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
done();
});
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailMock.unlock.calledOnce).to.be.true;
expect(keychainMock.putUserKeyPair.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
});
it('should not work when unlock fails', function() {
it('should not work when unlock fails', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
@ -138,36 +142,38 @@ describe('Login (new device) Controller unit test', function() {
userIds: []
});
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(resolves({
_id: keyId,
publicKey: 'a'
});
emailMock.unlock.yields({
}));
emailMock.unlock.returns(rejects({
errMsg: 'yo mamma.'
}));
scope.confirmPassphrase().then(function() {
expect(scope.incorrect).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailMock.unlock.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
done();
});
scope.confirmPassphrase();
expect(scope.incorrect).to.be.true;
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(emailMock.unlock.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
});
it('should not work when keypair retrieval', function() {
it('should not work when keypair retrieval', function(done) {
scope.passphrase = passphrase;
scope.key = {
privateKeyArmored: 'b'
};
keychainMock.getUserKeyPair.withArgs(emailAddress).yields({
keychainMock.getUserKeyPair.withArgs(emailAddress).returns(rejects({
errMsg: 'yo mamma.'
}));
scope.confirmPassphrase().then(function() {
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
done();
});
scope.confirmPassphrase();
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
expect(scope.errMsg).to.equal('yo mamma.');
});
});
});