1
0
mirror of https://github.com/moparisthebest/mail synced 2024-11-26 19:02:20 -05:00
mail/test/unit/mail-list-ctrl-test.js
Tankred Hase 6a0ae4d55d Performance improvements and fixes for mail-list
* Use same list style in desktop as mobile
* Bugfix: don't download all body when list not displayed
* Use ng-infinite-scroll to load DOM nodes on demand
* Custom search filter for FTS and reomve angular filters
* Rubber band scrolling on iOS
* Add CSP support in cordova via html meta tag
2014-07-17 17:43:51 +02:00

465 lines
16 KiB
JavaScript

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'),
notification = require('js/util/notification');
chai.Assertion.includeStack = true;
describe('Mail List controller unit test', function() {
var scope, ctrl, origEmailDao, emailDaoMock, keychainMock, deviceStorageMock,
emailAddress, notificationClickedHandler, emails,
hasChrome, hasSocket, hasRuntime, hasIdentity;
beforeEach(function() {
hasChrome = !!window.chrome;
hasSocket = !!window.chrome.socket;
hasIdentity = !!window.chrome.identity;
if (!hasChrome) {
window.chrome = {};
}
if (!hasSocket) {
window.chrome.socket = {};
}
if (!hasRuntime) {
window.chrome.runtime = {
getURL: function() {}
};
}
if (!hasIdentity) {
window.chrome.identity = {};
}
sinon.stub(notification, 'setOnClickedListener', function(func) {
notificationClickedHandler = func;
});
emails = [{
unread: true
}, {
unread: true
}, {
unread: true
}];
appController._outboxBo = {
pendingEmails: emails
};
origEmailDao = appController._emailDao;
emailDaoMock = sinon.createStubInstance(EmailDAO);
appController._emailDao = emailDaoMock;
emailAddress = 'fred@foo.com';
emailDaoMock._account = {
emailAddress: emailAddress,
};
keychainMock = sinon.createStubInstance(KeychainDAO);
appController._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 = {
read: {
toggle: function() {}
}
};
scope.loadVisibleBodies = function() {};
ctrl = $controller(MailListCtrl, {
$scope: scope
});
});
});
afterEach(function() {
notification.setOnClickedListener.restore();
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('displayMore', function() {
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
});
it('should not do anything when display length equals messages length', function() {
scope.displayMessages = ['a', 'b'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
it('should append next message interval', function() {
scope.displayMessages = ['a'];
scope.displayMore();
expect(scope.displayMessages.length).to.equal(scope.state.nav.currentFolder.messages.length);
});
});
describe('displaySearchResults', function() {
var clock;
beforeEach(function() {
scope.state.nav = {
currentFolder: {
messages: ['a', 'b']
}
};
scope.watchMessages();
scope.watchOnline();
clock = sinon.useFakeTimers();
});
afterEach(function() {
clock.restore();
});
it('should show initial message on empty', function() {
scope.displaySearchResults();
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Online');
expect(scope.displayMessages.length).to.equal(2);
});
it('should show initial message on empty', function() {
var searchStub = sinon.stub(scope, 'search');
searchStub.returns(['a']);
scope.displaySearchResults('query');
expect(scope.searching).to.be.true;
expect(scope.lastUpdateLbl).to.equal('Searching ...');
clock.tick(500);
expect(scope.displayMessages).to.deep.equal(['a']);
expect(scope.searching).to.be.false;
expect(scope.lastUpdateLbl).to.equal('Matches in this folder');
});
});
describe('search', function() {
var message1 = {
to: [{
name: 'name1',
address: 'address1'
}],
subject: 'subject1',
body: 'body1',
html: 'html1'
},
message2 = {
to: [{
name: 'name2',
address: 'address2'
}],
subject: 'subject2',
body: 'body2',
html: 'html2'
},
message3 = {
to: [{
name: 'name3',
address: 'address3'
}],
subject: 'subject3',
body: 'body1',
html: 'html1',
encrypted: true
},
message4 = {
to: [{
name: 'name4',
address: 'address4'
}],
subject: 'subject4',
body: 'body1',
html: 'html1',
encrypted: true,
decrypted: true
},
testMessages = [message1, message2, message3, message4];
it('return same messages array on empty query string', function() {
var result = scope.search(testMessages, '');
expect(result).to.equal(testMessages);
});
it('return message1 on matching subject', function() {
var result = scope.search(testMessages, 'subject1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching name', function() {
var result = scope.search(testMessages, 'name1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return message1 on matching address', function() {
var result = scope.search(testMessages, 'address1');
expect(result.length).to.equal(1);
expect(result[0]).to.equal(message1);
});
it('return plaintext and decrypted messages on matching body', function() {
var result = scope.search(testMessages, 'body1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
it('return plaintext and decrypted messages on matching html', function() {
var result = scope.search(testMessages, 'html1');
expect(result.length).to.equal(2);
expect(result[0]).to.equal(message1);
expect(result[1]).to.equal(message4);
});
});
describe('scope variables', function() {
it('should be set correctly', function() {
expect(scope.select).to.exist;
expect(scope.remove).to.exist;
expect(scope.state.mailList).to.exist;
});
});
describe('push notification', function() {
beforeEach(function() {
scope._stopWatchTask();
});
it('should succeed for single mail', function(done) {
var mail = {
uid: 123,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
};
sinon.stub(notification, 'create', function(opts) {
expect(opts.id).to.equal('' + mail.uid);
expect(opts.title).to.equal(mail.from[0].address);
expect(opts.message).to.equal(mail.subject);
notification.create.restore();
done();
});
emailDaoMock.onIncomingMessage([mail]);
});
it('should succeed for multiple mails', function(done) {
var mails = [{
uid: 1,
from: [{
address: 'asd'
}],
subject: 'this is the subject!',
unread: true
}, {
uid: 2,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: true
}, {
uid: 3,
from: [{
address: 'qwe'
}],
subject: 'this is the other subject!',
unread: false
}];
sinon.stub(notification, 'create', function(opts) {
expect(opts.id).to.equal('' + mails[0].uid);
expect(opts.title).to.equal('2 new messages');
expect(opts.message).to.equal(mails[0].subject + '\n' + mails[1].subject);
notification.create.restore();
done();
});
emailDaoMock.onIncomingMessage(mails);
});
it('should focus mail when clicked', function() {
var mail = {
uid: 123,
from: [{
address: 'asd'
}],
subject: 'asdasd',
unread: true
};
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: [mail]
}
};
notificationClickedHandler('123');
expect(scope.state.mailList.selected).to.equal(mail);
});
it('should not change focus mail when popup id is NaN', function() {
scope.state.nav = {
currentFolder: {
type: 'asd',
messages: []
}
};
var focus = scope.state.mailList.selected = {};
notificationClickedHandler('');
expect(scope.state.mailList.selected).to.equal(focus);
});
});
describe('getBody', function() {
it('should get the mail content', function() {
scope.state.nav = {
currentFolder: {
type: 'asd',
}
};
scope.getBody();
expect(emailDaoMock.getBody.calledOnce).to.be.true;
});
});
describe('select', function() {
it('should decrypt, focus mark an unread mail as read', function() {
var mail = {
from: [{
address: 'asd'
}],
unread: true,
};
scope.state = {
nav: {
currentFolder: {
type: 'asd'
}
},
mailList: {},
read: {
toggle: function() {}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
});
it('should decrypt and focus a read mail', function() {
var mail = {
from: [{
address: 'asd'
}],
unread: false
};
scope.state = {
mailList: {},
read: {
toggle: function() {}
},
nav: {
currentFolder: {
type: 'asd'
}
}
};
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
scope.select(mail);
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.equal(mail);
});
});
describe('remove', function() {
it('should not delete without a selected mail', function() {
scope.remove();
});
it('should delete the selected mail', function() {
var uid, mail, currentFolder;
scope._stopWatchTask();
scope.account = {};
uid = 123;
mail = {
uid: uid,
from: [{
address: 'asd'
}],
subject: '[whiteout] asdasd',
unread: true
};
currentFolder = {
type: 'Inbox',
path: 'INBOX',
messages: [mail]
};
scope.account.folders = [currentFolder];
scope.state.nav = {
currentFolder: currentFolder
};
emailDaoMock.deleteMessage.yields();
scope.remove(mail);
expect(emailDaoMock.deleteMessage.calledOnce).to.be.true;
expect(scope.state.mailList.selected).to.not.exist;
});
});
});
});