mirror of
https://github.com/moparisthebest/mail
synced 2024-11-29 12:22:22 -05:00
Merge remote-tracking branch 'origin/dev/unittest'
This commit is contained in:
commit
61b02c8175
@ -151,7 +151,7 @@ module.exports = function(grunt) {
|
|||||||
expand: true,
|
expand: true,
|
||||||
flatten: true,
|
flatten: true,
|
||||||
cwd: 'node_modules/',
|
cwd: 'node_modules/',
|
||||||
src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js'],
|
src: ['requirejs/require.js', 'mocha/mocha.css', 'mocha/mocha.js', 'chai/chai.js', 'sinon/pkg/sinon.js', 'angularjs/src/ngMock/angular-mocks.js'],
|
||||||
dest: 'test/lib/'
|
dest: 'test/lib/'
|
||||||
},
|
},
|
||||||
cryptoLib: {
|
cryptoLib: {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"requirejs": "2.1.8"
|
"requirejs": "2.1.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"angular": "https://github.com/angular/angular.js/tarball/v1.2.0",
|
||||||
"grunt": "0.4.1",
|
"grunt": "0.4.1",
|
||||||
"mocha": "1.13.0",
|
"mocha": "1.13.0",
|
||||||
"phantomjs": "1.9.1-9",
|
"phantomjs": "1.9.1-9",
|
||||||
|
@ -37,7 +37,7 @@ define(function(require) {
|
|||||||
$scope.exportKeyFile = function() {
|
$scope.exportKeyFile = function() {
|
||||||
emailDao._crypto.exportKeys(function(err, keys) {
|
emailDao._crypto.exportKeys(function(err, keys) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
$scope.onError(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,16 +46,14 @@ define(function(require) {
|
|||||||
content: keys.publicKeyArmored + keys.privateKeyArmored,
|
content: keys.publicKeyArmored + keys.privateKeyArmored,
|
||||||
filename: id + '.asc',
|
filename: id + '.asc',
|
||||||
contentType: 'text/plain'
|
contentType: 'text/plain'
|
||||||
}, onSave);
|
}, function onSave(err) {
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function onSave(err) {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
$scope.onError(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return AccountCtrl;
|
return AccountCtrl;
|
||||||
|
@ -31,16 +31,16 @@ define(function(require) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(states.PROCESSING);
|
$scope.setState(states.PROCESSING);
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
emailDao.unlock({}, passphrase, function(err) {
|
emailDao.unlock({}, passphrase, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
setState(states.IDLE, true);
|
$scope.setState(states.IDLE, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(states.DONE, true);
|
$scope.setState(states.DONE, true);
|
||||||
});
|
});
|
||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
@ -75,13 +75,13 @@ define(function(require) {
|
|||||||
$location.path('/desktop');
|
$location.path('/desktop');
|
||||||
};
|
};
|
||||||
|
|
||||||
function setState(state, async) {
|
$scope.setState = function(state, async) {
|
||||||
$scope.state.ui = state;
|
$scope.state.ui = state;
|
||||||
|
|
||||||
if (async) {
|
if (async) {
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return LoginInitialCtrl;
|
return LoginInitialCtrl;
|
||||||
|
@ -27,12 +27,6 @@
|
|||||||
angular: {
|
angular: {
|
||||||
exports: 'angular'
|
exports: 'angular'
|
||||||
},
|
},
|
||||||
openpgp: {
|
|
||||||
exports: 'window'
|
|
||||||
},
|
|
||||||
iscroll: {
|
|
||||||
exports: 'IScroll'
|
|
||||||
},
|
|
||||||
angularRoute: {
|
angularRoute: {
|
||||||
exports: 'angular',
|
exports: 'angular',
|
||||||
deps: ['angular']
|
deps: ['angular']
|
||||||
@ -41,6 +35,12 @@
|
|||||||
exports: 'angular',
|
exports: 'angular',
|
||||||
deps: ['angular']
|
deps: ['angular']
|
||||||
},
|
},
|
||||||
|
openpgp: {
|
||||||
|
exports: 'window'
|
||||||
|
},
|
||||||
|
iscroll: {
|
||||||
|
exports: 'IScroll'
|
||||||
|
},
|
||||||
lawnchair: {
|
lawnchair: {
|
||||||
exports: 'Lawnchair'
|
exports: 'Lawnchair'
|
||||||
},
|
},
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<h1>Keypair generated</h1>
|
<h1>Keypair generated</h1>
|
||||||
<p>Your personal keypair has been generated. You can export it (e.g. to a USB flash drive) to setup whiteout on another computer or as a backup.</p>
|
<p>Your personal keypair has been generated. You can export it (e.g. to a USB flash drive) to setup whiteout on another computer or as a backup.</p>
|
||||||
<button ng-click="exportKeypair()" class="btn" tabindex="4">Export now</button>
|
<button ng-click="exportKeypair()" class="btn" tabindex="4">Export now</button>
|
||||||
<button ng-click="proceed()" class="btn" tabindex="5">Do it later</button>
|
<button ng-click="forward()" class="btn" tabindex="5">Do it later</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div><!--/content-->
|
</div><!--/content-->
|
||||||
|
115
test/new-unit/account-ctrl-test.js
Normal file
115
test/new-unit/account-ctrl-test.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
AccountCtrl = require('js/controller/account'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
PGP = require('js/crypto/pgp'),
|
||||||
|
dl = require('js/util/download'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Account Controller unit test', function() {
|
||||||
|
var scope, accountCtrl, origEmailDao, emailDaoMock,
|
||||||
|
dummyFingerprint, expectedFingerprint,
|
||||||
|
dummyKeyId, expectedKeyId,
|
||||||
|
emailAddress,
|
||||||
|
keySize,
|
||||||
|
cryptoMock;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
cryptoMock = sinon.createStubInstance(PGP);
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
emailDaoMock._crypto = cryptoMock;
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
dummyFingerprint = '3A2D39B4E1404190B8B949DE7D7E99036E712926';
|
||||||
|
expectedFingerprint = '3A2D 39B4 E140 4190 B8B9 49DE 7D7E 9903 6E71 2926';
|
||||||
|
dummyKeyId = '9FEB47936E712926';
|
||||||
|
expectedKeyId = '6E712926';
|
||||||
|
cryptoMock.getFingerprint.returns(dummyFingerprint);
|
||||||
|
cryptoMock.getKeyId.returns(dummyKeyId);
|
||||||
|
emailAddress = 'fred@foo.com';
|
||||||
|
keySize = 1234;
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
asymKeySize: keySize
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.module('accounttest', []);
|
||||||
|
mocks.module('accounttest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
accountCtrl = $controller(AccountCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scope variables', function() {
|
||||||
|
it('should be set correctly', function() {
|
||||||
|
expect(scope.eMail).to.equal(emailAddress);
|
||||||
|
expect(scope.keyId).to.equal(expectedKeyId);
|
||||||
|
expect(scope.fingerprint).to.equal(expectedFingerprint);
|
||||||
|
expect(scope.keysize).to.equal(keySize);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('export to key file', function() {
|
||||||
|
it('should work', function() {
|
||||||
|
var createDownloadMock = sinon.stub(dl, 'createDownload');
|
||||||
|
cryptoMock.exportKeys.yields(null, {
|
||||||
|
publicKeyArmored: 'a',
|
||||||
|
privateKeyArmored: 'b',
|
||||||
|
keyId: dummyKeyId
|
||||||
|
});
|
||||||
|
createDownloadMock.withArgs(sinon.match(function(arg) {
|
||||||
|
return arg.content === 'ab' && arg.filename === expectedKeyId + '.asc' && arg.contentType === 'text/plain';
|
||||||
|
})).yields();
|
||||||
|
|
||||||
|
scope.exportKeyFile();
|
||||||
|
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
expect(dl.createDownload.calledOnce).to.be.true;
|
||||||
|
dl.createDownload.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when key export failed', function(done) {
|
||||||
|
cryptoMock.exportKeys.yields(new Error('asdasd'));
|
||||||
|
scope.onError = function() {
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.exportKeyFile();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when create download failed', function(done) {
|
||||||
|
var createDownloadMock = sinon.stub(dl, 'createDownload');
|
||||||
|
cryptoMock.exportKeys.yields(null, {
|
||||||
|
publicKeyArmored: 'a',
|
||||||
|
privateKeyArmored: 'b',
|
||||||
|
keyId: dummyKeyId
|
||||||
|
});
|
||||||
|
createDownloadMock.withArgs(sinon.match(function(arg) {
|
||||||
|
return arg.content === 'ab' && arg.filename === expectedKeyId + '.asc' && arg.contentType === 'text/plain';
|
||||||
|
})).yields(new Error('asdasd'));
|
||||||
|
scope.onError = function() {
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
expect(dl.createDownload.calledOnce).to.be.true;
|
||||||
|
dl.createDownload.restore();
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.exportKeyFile();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
50
test/new-unit/dialog-ctrl-test.js
Normal file
50
test/new-unit/dialog-ctrl-test.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
DialogCtrl = require('js/controller/dialog');
|
||||||
|
|
||||||
|
describe('Dialog Controller unit test', function() {
|
||||||
|
var scope, dialogCtrl;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
angular.module('dialogtest', []);
|
||||||
|
mocks.module('dialogtest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {
|
||||||
|
dialog: {}
|
||||||
|
};
|
||||||
|
dialogCtrl = $controller(DialogCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {});
|
||||||
|
|
||||||
|
describe('confirm', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
scope.state.dialog.callback = function(confirmed) {
|
||||||
|
expect(confirmed).to.be.true;
|
||||||
|
expect(scope.state.dialog.open).to.be.false;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
scope.confirm(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancel', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
scope.state.dialog.callback = function(confirmed) {
|
||||||
|
expect(confirmed).to.be.false;
|
||||||
|
expect(scope.state.dialog.open).to.be.false;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
scope.confirm(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
192
test/new-unit/login-ctrl-test.js
Normal file
192
test/new-unit/login-ctrl-test.js
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
LoginCtrl = require('js/controller/login'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Login Controller unit test', function() {
|
||||||
|
var scope, location, ctrl, origEmailDao, emailDaoMock,
|
||||||
|
emailAddress = 'fred@foo.com',
|
||||||
|
oauthToken = 'foobarfoobar',
|
||||||
|
startAppStub,
|
||||||
|
checkForUpdateStub,
|
||||||
|
fetchOAuthStub,
|
||||||
|
initStub;
|
||||||
|
|
||||||
|
describe('initialization', function() {
|
||||||
|
var hasChrome, hasIdentity;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
hasChrome = !!window.chrome;
|
||||||
|
hasIdentity = !!window.chrome.identity;
|
||||||
|
window.chrome = window.chrome || {};
|
||||||
|
window.chrome.identity = window.chrome.identity || {};
|
||||||
|
|
||||||
|
// remember original module to restore later, then replace it
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the browser
|
||||||
|
if (!hasIdentity) {
|
||||||
|
delete window.chrome.identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasChrome) {
|
||||||
|
delete window.chrome;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the app controller module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
appController.start.restore && appController.start.restore();
|
||||||
|
appController.checkForUpdate.restore && appController.checkForUpdate.restore();
|
||||||
|
appController.fetchOAuthToken.restore && appController.fetchOAuthToken.restore();
|
||||||
|
appController.init.restore && appController.init.restore();
|
||||||
|
location.path.restore && location.path.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward to existing user login', function(done) {
|
||||||
|
startAppStub = sinon.stub(appController, 'start');
|
||||||
|
startAppStub.yields();
|
||||||
|
checkForUpdateStub = sinon.stub(appController, 'checkForUpdate');
|
||||||
|
fetchOAuthStub = sinon.stub(appController, 'fetchOAuthToken');
|
||||||
|
fetchOAuthStub.yields(null, {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
token: oauthToken
|
||||||
|
});
|
||||||
|
initStub = sinon.stub(appController, 'init');
|
||||||
|
initStub.yields(null, {
|
||||||
|
privateKey: 'a',
|
||||||
|
publicKey: 'b'
|
||||||
|
});
|
||||||
|
|
||||||
|
emailDaoMock.imapLogin.yields();
|
||||||
|
|
||||||
|
angular.module('logintest', []);
|
||||||
|
mocks.module('logintest');
|
||||||
|
mocks.inject(function($controller, $rootScope, $location) {
|
||||||
|
location = $location;
|
||||||
|
sinon.stub(location, 'path', function(path) {
|
||||||
|
expect(path).to.equal('/login-existing');
|
||||||
|
expect(emailDaoMock.imapLogin.calledOnce).to.be.true;
|
||||||
|
expect(startAppStub.calledOnce).to.be.true;
|
||||||
|
expect(checkForUpdateStub.calledOnce).to.be.true;
|
||||||
|
expect(fetchOAuthStub.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(LoginCtrl, {
|
||||||
|
$location: location,
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward to new device login', function(done) {
|
||||||
|
startAppStub = sinon.stub(appController, 'start');
|
||||||
|
startAppStub.yields();
|
||||||
|
checkForUpdateStub = sinon.stub(appController, 'checkForUpdate');
|
||||||
|
fetchOAuthStub = sinon.stub(appController, 'fetchOAuthToken');
|
||||||
|
fetchOAuthStub.yields(null, {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
token: oauthToken
|
||||||
|
});
|
||||||
|
initStub = sinon.stub(appController, 'init');
|
||||||
|
initStub.yields(null, {
|
||||||
|
publicKey: 'b'
|
||||||
|
});
|
||||||
|
|
||||||
|
emailDaoMock.imapLogin.yields();
|
||||||
|
|
||||||
|
angular.module('logintest', []);
|
||||||
|
mocks.module('logintest');
|
||||||
|
mocks.inject(function($controller, $rootScope, $location) {
|
||||||
|
location = $location;
|
||||||
|
sinon.stub(location, 'path', function(path) {
|
||||||
|
expect(path).to.equal('/login-new-device');
|
||||||
|
expect(emailDaoMock.imapLogin.calledOnce).to.be.true;
|
||||||
|
expect(startAppStub.calledOnce).to.be.true;
|
||||||
|
expect(checkForUpdateStub.calledOnce).to.be.true;
|
||||||
|
expect(fetchOAuthStub.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(LoginCtrl, {
|
||||||
|
$location: location,
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should forward to initial login', function(done) {
|
||||||
|
startAppStub = sinon.stub(appController, 'start');
|
||||||
|
startAppStub.yields();
|
||||||
|
checkForUpdateStub = sinon.stub(appController, 'checkForUpdate');
|
||||||
|
fetchOAuthStub = sinon.stub(appController, 'fetchOAuthToken');
|
||||||
|
fetchOAuthStub.yields(null, {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
token: oauthToken
|
||||||
|
});
|
||||||
|
initStub = sinon.stub(appController, 'init');
|
||||||
|
initStub.yields();
|
||||||
|
|
||||||
|
emailDaoMock.imapLogin.yields();
|
||||||
|
|
||||||
|
angular.module('logintest', []);
|
||||||
|
mocks.module('logintest');
|
||||||
|
mocks.inject(function($controller, $rootScope, $location) {
|
||||||
|
location = $location;
|
||||||
|
sinon.stub(location, 'path', function(path) {
|
||||||
|
expect(path).to.equal('/login-initial');
|
||||||
|
expect(emailDaoMock.imapLogin.calledOnce).to.be.true;
|
||||||
|
expect(startAppStub.calledOnce).to.be.true;
|
||||||
|
expect(checkForUpdateStub.calledOnce).to.be.true;
|
||||||
|
expect(fetchOAuthStub.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(LoginCtrl, {
|
||||||
|
$location: location,
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fall back to dev mode', function(done) {
|
||||||
|
var chromeIdentity;
|
||||||
|
|
||||||
|
chromeIdentity = window.chrome.identity;
|
||||||
|
delete window.chrome.identity;
|
||||||
|
|
||||||
|
startAppStub = sinon.stub(appController, 'start');
|
||||||
|
startAppStub.yields();
|
||||||
|
|
||||||
|
angular.module('logintest', []);
|
||||||
|
mocks.module('logintest');
|
||||||
|
mocks.inject(function($controller, $rootScope, $location) {
|
||||||
|
location = $location;
|
||||||
|
sinon.stub(location, 'path', function(path) {
|
||||||
|
expect(path).to.equal('/desktop');
|
||||||
|
window.chrome.identity = chromeIdentity;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(LoginCtrl, {
|
||||||
|
$location: location,
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
105
test/new-unit/login-existing-ctrl-test.js
Normal file
105
test/new-unit/login-existing-ctrl-test.js
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
LoginExistingCtrl = require('js/controller/login-existing'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Login (existing user) Controller unit test', function() {
|
||||||
|
var scope, location, ctrl, origEmailDao, emailDaoMock,
|
||||||
|
emailAddress = 'fred@foo.com',
|
||||||
|
passphrase = 'asd',
|
||||||
|
keychainMock;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
// remember original module to restore later
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||||
|
emailDaoMock._keychain = keychainMock;
|
||||||
|
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.module('loginexistingtest', []);
|
||||||
|
mocks.module('loginexistingtest');
|
||||||
|
mocks.inject(function($rootScope, $controller, $location) {
|
||||||
|
location = $location;
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(LoginExistingCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initial state', function() {
|
||||||
|
it('should be well defined', function() {
|
||||||
|
expect(scope.buttonEnabled).to.be.true;
|
||||||
|
expect(scope.incorrect).to.be.false;
|
||||||
|
expect(scope.change).to.exist;
|
||||||
|
expect(scope.confirmPassphrase).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('functionality', function() {
|
||||||
|
describe('change', function() {
|
||||||
|
it('should set incorrect to false', function() {
|
||||||
|
scope.incorrect = true;
|
||||||
|
|
||||||
|
scope.change();
|
||||||
|
expect(scope.incorrect).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('confirm passphrase', function() {
|
||||||
|
it('should unlock crypto and start', function() {
|
||||||
|
var keypair = {},
|
||||||
|
pathSpy = sinon.spy(location, 'path');
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, keypair);
|
||||||
|
emailDaoMock.unlock.withArgs(keypair, passphrase).yields(null);
|
||||||
|
|
||||||
|
|
||||||
|
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('/desktop')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not do anything without passphrase', function() {
|
||||||
|
var pathSpy = sinon.spy(location, 'path');
|
||||||
|
scope.passphrase = '';
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
expect(pathSpy.callCount).to.equal(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when keypair unavailable', function(done) {
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(new Error('asd'));
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
171
test/new-unit/login-initial-ctrl-test.js
Normal file
171
test/new-unit/login-initial-ctrl-test.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
LoginInitialCtrl = require('js/controller/login-initial'),
|
||||||
|
dl = require('js/util/download'),
|
||||||
|
PGP = require('js/crypto/pgp'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Login (initial user) Controller unit test', function() {
|
||||||
|
var scope, ctrl, location, origEmailDao, emailDaoMock,
|
||||||
|
emailAddress = 'fred@foo.com',
|
||||||
|
passphrase = 'asd',
|
||||||
|
keyId, expectedKeyId,
|
||||||
|
cryptoMock;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
// remember original module to restore later
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
keyId = '9FEB47936E712926';
|
||||||
|
expectedKeyId = '6E712926';
|
||||||
|
cryptoMock = sinon.createStubInstance(PGP);
|
||||||
|
emailDaoMock._crypto = cryptoMock;
|
||||||
|
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.module('logininitialtest', []);
|
||||||
|
mocks.module('logininitialtest');
|
||||||
|
mocks.inject(function($rootScope, $controller, $location) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
location = $location;
|
||||||
|
scope.state = {
|
||||||
|
ui: {}
|
||||||
|
};
|
||||||
|
ctrl = $controller(LoginInitialCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initial state', function() {
|
||||||
|
it('should be well defined', function() {
|
||||||
|
expect(scope.proceed).to.exist;
|
||||||
|
expect(scope.exportKeypair).to.exist;
|
||||||
|
expect(scope.confirmPassphrase).to.exist;
|
||||||
|
expect(scope.state.ui).to.equal(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('confirm passphrase', function() {
|
||||||
|
var setStateStub;
|
||||||
|
|
||||||
|
it('should unlock crypto', function(done) {
|
||||||
|
scope.state.passphrase = passphrase;
|
||||||
|
scope.state.confirmation = passphrase;
|
||||||
|
emailDaoMock.unlock.withArgs({}, passphrase).yields();
|
||||||
|
setStateStub = sinon.stub(scope, 'setState', function(state) {
|
||||||
|
if (setStateStub.calledOnce) {
|
||||||
|
expect(state).to.equal(2);
|
||||||
|
} else if (setStateStub.calledTwice) {
|
||||||
|
expect(state).to.equal(4);
|
||||||
|
expect(emailDaoMock.unlock.calledOnce).to.be.true;
|
||||||
|
scope.setState.restore();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not do anything matching passphrases', function() {
|
||||||
|
scope.state.passphrase = 'a';
|
||||||
|
scope.state.confirmation = 'b';
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when keypair generation fails', function(done) {
|
||||||
|
scope.state.passphrase = passphrase;
|
||||||
|
scope.state.confirmation = passphrase;
|
||||||
|
emailDaoMock.unlock.withArgs({}, passphrase).yields(new Error('asd'));
|
||||||
|
setStateStub = sinon.stub(scope, 'setState', function(state) {
|
||||||
|
if (setStateStub.calledOnce) {
|
||||||
|
expect(state).to.equal(2);
|
||||||
|
} else if (setStateStub.calledTwice) {
|
||||||
|
expect(state).to.equal(1);
|
||||||
|
expect(emailDaoMock.unlock.calledOnce).to.be.true;
|
||||||
|
scope.setState.restore();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('proceed', function() {
|
||||||
|
it('should forward', function() {
|
||||||
|
var locationSpy = sinon.spy(location, 'path');
|
||||||
|
|
||||||
|
scope.proceed();
|
||||||
|
|
||||||
|
expect(locationSpy.calledWith('/desktop')).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('export keypair', function() {
|
||||||
|
it('should work', function() {
|
||||||
|
var locationSpy, createDownloadMock;
|
||||||
|
|
||||||
|
createDownloadMock = sinon.stub(dl, 'createDownload');
|
||||||
|
cryptoMock.exportKeys.yields(null, {
|
||||||
|
publicKeyArmored: 'a',
|
||||||
|
privateKeyArmored: 'b',
|
||||||
|
keyId: keyId
|
||||||
|
});
|
||||||
|
createDownloadMock.withArgs(sinon.match(function(arg) {
|
||||||
|
return arg.content === 'ab' && arg.filename === expectedKeyId + '.asc' && arg.contentType === 'text/plain';
|
||||||
|
})).yields();
|
||||||
|
|
||||||
|
locationSpy = sinon.spy(location, 'path');
|
||||||
|
|
||||||
|
scope.exportKeypair();
|
||||||
|
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
expect(createDownloadMock.calledOnce).to.be.true;
|
||||||
|
expect(locationSpy.calledWith('/desktop')).to.be.true;
|
||||||
|
dl.createDownload.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when download fails', function() {
|
||||||
|
var createDownloadMock = sinon.stub(dl, 'createDownload');
|
||||||
|
cryptoMock.exportKeys.yields(null, {
|
||||||
|
publicKeyArmored: 'a',
|
||||||
|
privateKeyArmored: 'b',
|
||||||
|
keyId: keyId
|
||||||
|
});
|
||||||
|
createDownloadMock.yields({
|
||||||
|
errMsg: 'snafu.'
|
||||||
|
});
|
||||||
|
scope.exportKeypair();
|
||||||
|
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
expect(createDownloadMock.calledOnce).to.be.true;
|
||||||
|
dl.createDownload.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when export fails', function() {
|
||||||
|
cryptoMock.exportKeys.yields(new Error('snafu.'));
|
||||||
|
|
||||||
|
scope.exportKeypair();
|
||||||
|
|
||||||
|
expect(cryptoMock.exportKeys.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
142
test/new-unit/login-new-device-ctrl-test.js
Normal file
142
test/new-unit/login-new-device-ctrl-test.js
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
LoginNewDeviceCtrl = require('js/controller/login-new-device'),
|
||||||
|
KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Login (new device) Controller unit test', function() {
|
||||||
|
var scope, ctrl, origEmailDao, emailDaoMock,
|
||||||
|
emailAddress = 'fred@foo.com',
|
||||||
|
passphrase = 'asd',
|
||||||
|
keyId,
|
||||||
|
keychainMock;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
// remember original module to restore later
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
keyId = '9FEB47936E712926';
|
||||||
|
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||||
|
emailDaoMock._keychain = keychainMock;
|
||||||
|
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
angular.module('loginnewdevicetest', []);
|
||||||
|
mocks.module('loginnewdevicetest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {
|
||||||
|
ui: {}
|
||||||
|
};
|
||||||
|
ctrl = $controller(LoginNewDeviceCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initial state', function() {
|
||||||
|
it('should be well defined', function() {
|
||||||
|
expect(scope.incorrect).to.be.false;
|
||||||
|
expect(scope.confirmPassphrase).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('confirm passphrase', function() {
|
||||||
|
it('should unlock crypto', function() {
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
scope.key = {
|
||||||
|
privateKeyArmored: 'b'
|
||||||
|
};
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
|
||||||
|
_id: keyId,
|
||||||
|
publicKey: 'a'
|
||||||
|
});
|
||||||
|
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
|
||||||
|
keychainMock.putUserKeyPair.yields();
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(emailDaoMock.unlock.calledOnce).to.be.true;
|
||||||
|
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not do anything without passphrase', function() {
|
||||||
|
scope.state.passphrase = '';
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(scope.incorrect).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when keypair upload fails', function() {
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
scope.key = {
|
||||||
|
privateKeyArmored: 'b'
|
||||||
|
};
|
||||||
|
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
|
||||||
|
_id: keyId,
|
||||||
|
publicKey: 'a'
|
||||||
|
});
|
||||||
|
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields();
|
||||||
|
keychainMock.putUserKeyPair.yields({
|
||||||
|
errMsg: 'yo mamma.'
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoMock.unlock.calledOnce).to.be.true;
|
||||||
|
expect(keychainMock.putUserKeyPair.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when unlock fails', function() {
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
scope.key = {
|
||||||
|
privateKeyArmored: 'b'
|
||||||
|
};
|
||||||
|
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields(null, {
|
||||||
|
_id: keyId,
|
||||||
|
publicKey: 'a'
|
||||||
|
});
|
||||||
|
emailDaoMock.unlock.withArgs(sinon.match.any, passphrase).yields({
|
||||||
|
errMsg: 'yo mamma.'
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(scope.incorrect).to.be.true;
|
||||||
|
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoMock.unlock.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when keypair retrieval', function() {
|
||||||
|
scope.passphrase = passphrase;
|
||||||
|
|
||||||
|
keychainMock.getUserKeyPair.withArgs(emailAddress).yields({
|
||||||
|
errMsg: 'yo mamma.'
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.confirmPassphrase();
|
||||||
|
|
||||||
|
expect(keychainMock.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
253
test/new-unit/mail-list-ctrl-test.js
Normal file
253
test/new-unit/mail-list-ctrl-test.js
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
MailListCtrl = require('js/controller/mail-list'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||||
|
KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Mail List controller unit test', function() {
|
||||||
|
var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock,
|
||||||
|
emailAddress, notificationClickedHandler,
|
||||||
|
hasChrome, hasNotifications, hasSocket, hasRuntime, hasIdentity;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
hasChrome = !! window.chrome;
|
||||||
|
hasNotifications = !! window.chrome.notifications;
|
||||||
|
hasSocket = !! window.chrome.socket;
|
||||||
|
hasIdentity = !! window.chrome.identity;
|
||||||
|
if (!hasChrome) {
|
||||||
|
window.chrome = {};
|
||||||
|
}
|
||||||
|
if (!hasNotifications) {
|
||||||
|
window.chrome.notifications = {
|
||||||
|
onClicked: {
|
||||||
|
addListener: function(handler) {
|
||||||
|
notificationClickedHandler = handler;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
create: function() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!hasSocket) {
|
||||||
|
window.chrome.socket = {};
|
||||||
|
}
|
||||||
|
if (!hasRuntime) {
|
||||||
|
window.chrome.runtime = {
|
||||||
|
getURL: function() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (!hasIdentity) {
|
||||||
|
window.chrome.identity = {};
|
||||||
|
}
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
emailAddress = 'fred@foo.com';
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||||
|
emailDaoMock._keychain = keychainMock;
|
||||||
|
|
||||||
|
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
|
emailDaoMock._devicestorage = deviceStorageMock;
|
||||||
|
|
||||||
|
angular.module('maillisttest', []);
|
||||||
|
mocks.module('maillisttest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(MailListCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
if (!hasNotifications) {
|
||||||
|
delete window.chrome.notifications;
|
||||||
|
}
|
||||||
|
if (!hasSocket) {
|
||||||
|
delete window.chrome.socket;
|
||||||
|
}
|
||||||
|
if (!hasRuntime) {
|
||||||
|
delete window.chrome.runtime;
|
||||||
|
}
|
||||||
|
if (!hasChrome) {
|
||||||
|
delete window.chrome;
|
||||||
|
}
|
||||||
|
if (!hasIdentity) {
|
||||||
|
delete window.chrome.identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scope variables', function() {
|
||||||
|
it('should be set correctly', function() {
|
||||||
|
expect(scope.select).to.exist;
|
||||||
|
expect(scope.synchronize).to.exist;
|
||||||
|
expect(scope.remove).to.exist;
|
||||||
|
expect(scope.state.mailList).to.exist;
|
||||||
|
expect(emailDaoMock.onIncomingMessage).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('push notification', function() {
|
||||||
|
it('should focus mail and not mark it read', function(done) {
|
||||||
|
var uid, mail, currentFolder;
|
||||||
|
|
||||||
|
uid = 123;
|
||||||
|
mail = {
|
||||||
|
uid: uid,
|
||||||
|
from: [{
|
||||||
|
address: 'asd'
|
||||||
|
}],
|
||||||
|
subject: '[whiteout] asdasd',
|
||||||
|
unread: true
|
||||||
|
};
|
||||||
|
currentFolder = 'asd';
|
||||||
|
scope.state.nav = {
|
||||||
|
currentFolder: currentFolder
|
||||||
|
};
|
||||||
|
scope.state.read = {
|
||||||
|
toggle: function() {}
|
||||||
|
};
|
||||||
|
scope.emails = [mail];
|
||||||
|
emailDaoMock.imapMarkMessageRead.withArgs({
|
||||||
|
folder: currentFolder,
|
||||||
|
uid: uid
|
||||||
|
}).yields();
|
||||||
|
emailDaoMock.unreadMessages.yieldsAsync(null, 10);
|
||||||
|
emailDaoMock.imapSync.yieldsAsync();
|
||||||
|
emailDaoMock.listMessages.yieldsAsync(null, [mail]);
|
||||||
|
window.chrome.notifications.create = function(id, opts) {
|
||||||
|
expect(id).to.equal('123');
|
||||||
|
expect(opts.type).to.equal('basic');
|
||||||
|
expect(opts.message).to.equal('asdasd');
|
||||||
|
expect(opts.title).to.equal('asd');
|
||||||
|
expect(scope.state.mailList.selected).to.deep.equal(mail);
|
||||||
|
expect(emailDaoMock.imapMarkMessageRead.callCount).to.equal(0);
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
emailDaoMock.onIncomingMessage(mail);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('clicking push notification', function() {
|
||||||
|
it('should focus mail and mark it read', function() {
|
||||||
|
var uid, mail, currentFolder;
|
||||||
|
|
||||||
|
uid = 123;
|
||||||
|
mail = {
|
||||||
|
uid: uid,
|
||||||
|
from: [{
|
||||||
|
address: 'asd'
|
||||||
|
}],
|
||||||
|
subject: '[whiteout] asdasd',
|
||||||
|
unread: true
|
||||||
|
};
|
||||||
|
currentFolder = 'asd';
|
||||||
|
scope.state.nav = {
|
||||||
|
currentFolder: currentFolder
|
||||||
|
};
|
||||||
|
scope.state.read = {
|
||||||
|
toggle: function() {}
|
||||||
|
};
|
||||||
|
scope.emails = [mail];
|
||||||
|
emailDaoMock.imapMarkMessageRead.withArgs({
|
||||||
|
folder: currentFolder,
|
||||||
|
uid: uid
|
||||||
|
}).yields();
|
||||||
|
|
||||||
|
notificationClickedHandler('123'); // first select, irrelevant
|
||||||
|
notificationClickedHandler('123');
|
||||||
|
|
||||||
|
expect(scope.state.mailList.selected).to.deep.equal(mail);
|
||||||
|
expect(emailDaoMock.imapMarkMessageRead.callCount).to.be.at.least(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('remove', function() {
|
||||||
|
it('should not delete without a selected mail', function() {
|
||||||
|
scope.remove();
|
||||||
|
|
||||||
|
expect(emailDaoMock.imapDeleteMessage.called).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should delete the selected mail from trash folder after clicking ok', function() {
|
||||||
|
var uid, mail, currentFolder;
|
||||||
|
|
||||||
|
uid = 123;
|
||||||
|
mail = {
|
||||||
|
uid: uid,
|
||||||
|
from: [{
|
||||||
|
address: 'asd'
|
||||||
|
}],
|
||||||
|
subject: '[whiteout] asdasd',
|
||||||
|
unread: true
|
||||||
|
};
|
||||||
|
scope.emails = [mail];
|
||||||
|
currentFolder = {
|
||||||
|
type: 'Trash'
|
||||||
|
};
|
||||||
|
scope.folders = [currentFolder];
|
||||||
|
scope.state.nav = {
|
||||||
|
currentFolder: currentFolder
|
||||||
|
};
|
||||||
|
emailDaoMock.imapDeleteMessage.yields();
|
||||||
|
|
||||||
|
scope.remove(mail);
|
||||||
|
scope.state.dialog.callback(true);
|
||||||
|
|
||||||
|
expect(emailDaoMock.imapDeleteMessage.calledOnce).to.be.true;
|
||||||
|
expect(scope.state.mailList.selected).to.not.exist;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move the selected mail to the trash folder', function() {
|
||||||
|
var uid, mail, currentFolder, trashFolder;
|
||||||
|
|
||||||
|
uid = 123;
|
||||||
|
mail = {
|
||||||
|
uid: uid,
|
||||||
|
from: [{
|
||||||
|
address: 'asd'
|
||||||
|
}],
|
||||||
|
subject: '[whiteout] asdasd',
|
||||||
|
unread: true
|
||||||
|
};
|
||||||
|
scope.emails = [mail];
|
||||||
|
currentFolder = {
|
||||||
|
type: 'Inbox',
|
||||||
|
path: 'INBOX'
|
||||||
|
};
|
||||||
|
trashFolder = {
|
||||||
|
type: 'Trash',
|
||||||
|
path: 'TRASH'
|
||||||
|
};
|
||||||
|
scope.folders = [currentFolder, trashFolder];
|
||||||
|
scope.state.nav = {
|
||||||
|
currentFolder: currentFolder
|
||||||
|
};
|
||||||
|
emailDaoMock.imapMoveMessage.withArgs({
|
||||||
|
folder: currentFolder,
|
||||||
|
uid: uid,
|
||||||
|
destination: trashFolder.path
|
||||||
|
}).yields();
|
||||||
|
|
||||||
|
scope.remove(mail);
|
||||||
|
|
||||||
|
expect(emailDaoMock.imapMoveMessage.calledOnce).to.be.true;
|
||||||
|
expect(scope.state.mailList.selected).to.not.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -2,9 +2,19 @@
|
|||||||
|
|
||||||
require(['../../src/require-config'], function() {
|
require(['../../src/require-config'], function() {
|
||||||
require.config({
|
require.config({
|
||||||
baseUrl: '../../src/lib'
|
baseUrl: '../../src/lib',
|
||||||
|
paths: {
|
||||||
|
angularMocks: '../../test/lib/angular-mocks'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
angularMocks: {
|
||||||
|
exports: 'angular.mock',
|
||||||
|
deps: ['angular']
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Start the main app logic.
|
// Start the main app logic.
|
||||||
require(['js/app-config', 'cordova'], function(app) {
|
require(['js/app-config', 'cordova'], function(app) {
|
||||||
window.Worker = undefined; // disable web workers since mocha doesn't support them
|
window.Worker = undefined; // disable web workers since mocha doesn't support them
|
||||||
@ -27,7 +37,17 @@ function startTests() {
|
|||||||
'test/new-unit/publickey-dao-test',
|
'test/new-unit/publickey-dao-test',
|
||||||
'test/new-unit/lawnchair-dao-test',
|
'test/new-unit/lawnchair-dao-test',
|
||||||
'test/new-unit/keychain-dao-test',
|
'test/new-unit/keychain-dao-test',
|
||||||
'test/new-unit/devicestorage-dao-test'
|
'test/new-unit/devicestorage-dao-test',
|
||||||
|
'test/new-unit/dialog-ctrl-test',
|
||||||
|
'test/new-unit/account-ctrl-test',
|
||||||
|
'test/new-unit/login-existing-ctrl-test',
|
||||||
|
'test/new-unit/login-initial-ctrl-test',
|
||||||
|
'test/new-unit/login-new-device-ctrl-test',
|
||||||
|
'test/new-unit/login-ctrl-test',
|
||||||
|
'test/new-unit/read-ctrl-test',
|
||||||
|
'test/new-unit/navigation-ctrl-test',
|
||||||
|
'test/new-unit/mail-list-ctrl-test',
|
||||||
|
'test/new-unit/write-ctrl-test'
|
||||||
], function() {
|
], function() {
|
||||||
//Tests loaded, run tests
|
//Tests loaded, run tests
|
||||||
mocha.run();
|
mocha.run();
|
||||||
|
120
test/new-unit/navigation-ctrl-test.js
Normal file
120
test/new-unit/navigation-ctrl-test.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
NavigationCtrl = require('js/controller/navigation'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Navigation Controller unit test', function() {
|
||||||
|
var scope, ctrl, origEmailDao, emailDaoMock, deviceStorageMock, tempChrome;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
if (window.chrome.identity) {
|
||||||
|
tempChrome = window.chrome.identity;
|
||||||
|
delete window.chrome.identity;
|
||||||
|
}
|
||||||
|
// remember original module to restore later
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
|
||||||
|
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
|
appController._emailDao._devicestorage = deviceStorageMock;
|
||||||
|
|
||||||
|
angular.module('navigationtest', []);
|
||||||
|
mocks.module('navigationtest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(NavigationCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
if (tempChrome) {
|
||||||
|
window.chrome.identity = tempChrome;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('initial state', function() {
|
||||||
|
it('should be well defined', function() {
|
||||||
|
expect(scope.state).to.exist;
|
||||||
|
expect(scope.state.nav.open).to.be.false;
|
||||||
|
expect(scope.folders).to.not.be.empty;
|
||||||
|
|
||||||
|
expect(scope.onError).to.exist;
|
||||||
|
expect(scope.openFolder).to.exist;
|
||||||
|
expect(scope.emptyOutbox).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('open/close nav view', function() {
|
||||||
|
it('should open/close', function() {
|
||||||
|
expect(scope.state.nav.open).to.be.false;
|
||||||
|
scope.state.nav.toggle(true);
|
||||||
|
expect(scope.state.nav.open).to.be.true;
|
||||||
|
scope.state.nav.toggle(false);
|
||||||
|
expect(scope.state.nav.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('open folder', function() {
|
||||||
|
it('should work', function() {
|
||||||
|
scope.state.nav.open = true;
|
||||||
|
|
||||||
|
scope.openFolder('asd');
|
||||||
|
expect(scope.state.nav.currentFolder).to.equal('asd');
|
||||||
|
expect(scope.state.nav.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('empty outbox', function() {
|
||||||
|
it('should work', function() {
|
||||||
|
deviceStorageMock.listItems.yields(null, [{
|
||||||
|
id: 1
|
||||||
|
}, {
|
||||||
|
id: 2
|
||||||
|
}, {
|
||||||
|
id: 3
|
||||||
|
}]);
|
||||||
|
emailDaoMock.smtpSend.yields();
|
||||||
|
deviceStorageMock.removeList.yields();
|
||||||
|
|
||||||
|
scope.emptyOutbox();
|
||||||
|
|
||||||
|
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoMock.smtpSend.calledThrice).to.be.true;
|
||||||
|
expect(deviceStorageMock.removeList.calledThrice).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when device storage errors', function() {
|
||||||
|
deviceStorageMock.listItems.yields({errMsg: 'error'});
|
||||||
|
|
||||||
|
scope.emptyOutbox();
|
||||||
|
|
||||||
|
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work when smtp send fails', function() {
|
||||||
|
deviceStorageMock.listItems.yields(null, [{
|
||||||
|
id: 1
|
||||||
|
}]);
|
||||||
|
emailDaoMock.smtpSend.yields({errMsg: 'error'});
|
||||||
|
|
||||||
|
scope.emptyOutbox();
|
||||||
|
|
||||||
|
expect(deviceStorageMock.listItems.calledOnce).to.be.true;
|
||||||
|
expect(emailDaoMock.smtpSend.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
44
test/new-unit/read-ctrl-test.js
Normal file
44
test/new-unit/read-ctrl-test.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
ReadCtrl = require('js/controller/read');
|
||||||
|
|
||||||
|
describe('Read Controller unit test', function() {
|
||||||
|
var scope, ctrl;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
angular.module('readtest', []);
|
||||||
|
mocks.module('readtest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(ReadCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {});
|
||||||
|
|
||||||
|
describe('scope variables', function() {
|
||||||
|
it('should be set correctly', function() {
|
||||||
|
expect(scope.state.read).to.exist;
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
expect(scope.state.read.toggle).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('open/close read view', function() {
|
||||||
|
it('should open/close', function() {
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
scope.state.read.toggle(true);
|
||||||
|
expect(scope.state.read.open).to.be.true;
|
||||||
|
scope.state.read.toggle(false);
|
||||||
|
expect(scope.state.read.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
205
test/new-unit/write-ctrl-test.js
Normal file
205
test/new-unit/write-ctrl-test.js
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var expect = chai.expect,
|
||||||
|
angular = require('angular'),
|
||||||
|
mocks = require('angularMocks'),
|
||||||
|
WriteCtrl = require('js/controller/write'),
|
||||||
|
EmailDAO = require('js/dao/email-dao'),
|
||||||
|
DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||||
|
KeychainDAO = require('js/dao/keychain-dao'),
|
||||||
|
appController = require('js/app-controller');
|
||||||
|
|
||||||
|
describe('Write controller unit test', function() {
|
||||||
|
var ctrl, scope, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock, emailAddress;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
origEmailDao = appController._emailDao;
|
||||||
|
emailDaoMock = sinon.createStubInstance(EmailDAO);
|
||||||
|
appController._emailDao = emailDaoMock;
|
||||||
|
emailAddress = 'fred@foo.com';
|
||||||
|
emailDaoMock._account = {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||||
|
emailDaoMock._keychain = keychainMock;
|
||||||
|
|
||||||
|
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
|
emailDaoMock._devicestorage = deviceStorageMock;
|
||||||
|
|
||||||
|
angular.module('writetest', []);
|
||||||
|
mocks.module('writetest');
|
||||||
|
mocks.inject(function($rootScope, $controller) {
|
||||||
|
scope = $rootScope.$new();
|
||||||
|
scope.state = {};
|
||||||
|
ctrl = $controller(WriteCtrl, {
|
||||||
|
$scope: scope
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function() {
|
||||||
|
// restore the module
|
||||||
|
appController._emailDao = origEmailDao;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scope variables', function() {
|
||||||
|
it('should be set correctly', function() {
|
||||||
|
expect(scope.state.writer).to.exist;
|
||||||
|
expect(scope.state.writer.open).to.be.false;
|
||||||
|
expect(scope.state.writer.write).to.exist;
|
||||||
|
expect(scope.state.writer.close).to.exist;
|
||||||
|
expect(scope.verifyTo).to.exist;
|
||||||
|
expect(scope.updatePreview).to.exist;
|
||||||
|
expect(scope.sendToOutbox).to.exist;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('close', function() {
|
||||||
|
it('should close the writer', function() {
|
||||||
|
scope.state.writer.open = true;
|
||||||
|
|
||||||
|
scope.state.writer.close();
|
||||||
|
|
||||||
|
expect(scope.state.writer.open).to.be.false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('write', function() {
|
||||||
|
it('should prepare write view', function() {
|
||||||
|
var verifyToMock = sinon.stub(scope, 'verifyTo');
|
||||||
|
|
||||||
|
scope.state.writer.write();
|
||||||
|
|
||||||
|
expect(scope.writerTitle).to.equal('New email');
|
||||||
|
expect(scope.to).to.equal('');
|
||||||
|
expect(scope.subject).to.equal('');
|
||||||
|
expect(scope.body).to.equal('');
|
||||||
|
expect(scope.ciphertextPreview).to.equal('');
|
||||||
|
expect(verifyToMock.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
scope.verifyTo.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prefill write view for response', function() {
|
||||||
|
var verifyToMock = sinon.stub(scope, 'verifyTo'),
|
||||||
|
address = 'pity@dafool',
|
||||||
|
subject = 'Ermahgerd!',
|
||||||
|
body = 'so much body!',
|
||||||
|
re = {
|
||||||
|
from: [{
|
||||||
|
address: address
|
||||||
|
}],
|
||||||
|
subject: subject,
|
||||||
|
sentDate: new Date(),
|
||||||
|
body: body
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.state.writer.write(re);
|
||||||
|
|
||||||
|
expect(scope.writerTitle).to.equal('Reply');
|
||||||
|
expect(scope.to).to.equal(address);
|
||||||
|
expect(scope.subject).to.equal('Re: ' + subject);
|
||||||
|
expect(scope.body).to.contain(body);
|
||||||
|
expect(scope.ciphertextPreview).to.not.be.empty;
|
||||||
|
expect(verifyToMock.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
scope.verifyTo.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should prevent markup injection', function() {
|
||||||
|
var address = 'pity@dafool',
|
||||||
|
subject = 'Ermahgerd!',
|
||||||
|
body = '<div>markup</div><div>moreMarkup<div>',
|
||||||
|
re = {
|
||||||
|
from: [{
|
||||||
|
address: address
|
||||||
|
}],
|
||||||
|
subject: subject,
|
||||||
|
sentDate: new Date(),
|
||||||
|
body: body,
|
||||||
|
html: false
|
||||||
|
};
|
||||||
|
|
||||||
|
sinon.stub(scope, 'verifyTo');
|
||||||
|
|
||||||
|
scope.state.writer.write(re);
|
||||||
|
|
||||||
|
expect(scope.body).to.contain('<br>markupmoreMarkup');
|
||||||
|
|
||||||
|
scope.verifyTo.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('verifyTo', function() {
|
||||||
|
it('should verify the recipient as secure', function() {
|
||||||
|
var id = scope.to = 'pity@da.fool';
|
||||||
|
keychainMock.getReceiverPublicKey.withArgs(id).yields(null, {
|
||||||
|
userId: id
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.verifyTo();
|
||||||
|
|
||||||
|
expect(scope.toSecure).to.be.true;
|
||||||
|
expect(scope.sendBtnText).to.equal('Send securely');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should verify the recipient as not secure', function() {
|
||||||
|
var id = scope.to = 'pity@da.fool';
|
||||||
|
keychainMock.getReceiverPublicKey.withArgs(id).yields({
|
||||||
|
errMsg: '404 not found yadda yadda'
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.verifyTo();
|
||||||
|
|
||||||
|
expect(scope.toSecure).to.be.false;
|
||||||
|
expect(scope.sendBtnText).to.equal('Invite & send securely');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset display if there is no recipient', function() {
|
||||||
|
scope.to = undefined;
|
||||||
|
scope.verifyTo();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('send to outbox', function() {
|
||||||
|
it('should work', function(done) {
|
||||||
|
scope.state.writer.open = true;
|
||||||
|
scope.to = 'a, b, c';
|
||||||
|
scope.body = 'asd';
|
||||||
|
scope.subject = 'yaddablabla';
|
||||||
|
|
||||||
|
deviceStorageMock.storeList.withArgs(sinon.match(function(mail) {
|
||||||
|
return mail[0].from[0].address === emailAddress && mail[0].to.length === 3;
|
||||||
|
})).yieldsAsync();
|
||||||
|
scope.emptyOutbox = function() {
|
||||||
|
expect(scope.state.writer.open).to.be.false;
|
||||||
|
expect(deviceStorageMock.storeList.calledOnce).to.be.true;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.sendToOutbox();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not work and not close the write view', function() {
|
||||||
|
scope.state.writer.open = true;
|
||||||
|
scope.to = 'a, b, c';
|
||||||
|
scope.body = 'asd';
|
||||||
|
scope.subject = 'yaddablabla';
|
||||||
|
|
||||||
|
deviceStorageMock.storeList.withArgs(sinon.match(function(mail) {
|
||||||
|
return mail[0].from[0].address === emailAddress && mail[0].to.length === 3;
|
||||||
|
})).yields({
|
||||||
|
errMsg: 'snafu'
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.sendToOutbox();
|
||||||
|
|
||||||
|
expect(scope.state.writer.open).to.be.true;
|
||||||
|
expect(deviceStorageMock.storeList.calledOnce).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user