summaryrefslogtreecommitdiff
path: root/web-ui/test
diff options
context:
space:
mode:
Diffstat (limited to 'web-ui/test')
-rw-r--r--web-ui/test/spec/dispatchers/left_pane_dispatcher.spec.js79
-rw-r--r--web-ui/test/spec/dispatchers/middle_pane_dispatchers.spec.js27
-rw-r--r--web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js90
-rw-r--r--web-ui/test/spec/helpers/view_helper.spec.js76
-rw-r--r--web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js136
-rw-r--r--web-ui/test/spec/mail_list/ui/mail_items/mail_item.spec.js40
-rw-r--r--web-ui/test/spec/mail_list/ui/mail_list.spec.js275
-rw-r--r--web-ui/test/spec/mail_list_actions/ui/compose_trigger.spec.js16
-rw-r--r--web-ui/test/spec/mail_list_actions/ui/mail_actions.spec.js9
-rw-r--r--web-ui/test/spec/mail_list_actions/ui/pagination_trigger.spec.js26
-rw-r--r--web-ui/test/spec/mail_view/data/mail_builder.spec.js110
-rw-r--r--web-ui/test/spec/mail_view/data/mail_sender.spec.js70
-rw-r--r--web-ui/test/spec/mail_view/ui/compose_box.spec.js132
-rw-r--r--web-ui/test/spec/mail_view/ui/draft_box.spec.js67
-rw-r--r--web-ui/test/spec/mail_view/ui/draft_save_status.spec.js26
-rw-r--r--web-ui/test/spec/mail_view/ui/forward_box.spec.js90
-rw-r--r--web-ui/test/spec/mail_view/ui/mail_actions.spec.js63
-rw-r--r--web-ui/test/spec/mail_view/ui/mail_view.spec.js247
-rw-r--r--web-ui/test/spec/mail_view/ui/recipients/recipients.spec.js36
-rw-r--r--web-ui/test/spec/mail_view/ui/recipients/recipients_input.spec.js104
-rw-r--r--web-ui/test/spec/mail_view/ui/recipients/recipients_iterator.spec.js101
-rw-r--r--web-ui/test/spec/mail_view/ui/reply_box.spec.js105
-rw-r--r--web-ui/test/spec/mail_view/ui/reply_section.spec.js97
-rw-r--r--web-ui/test/spec/mail_view/ui/send_button.spec.js91
-rw-r--r--web-ui/test/spec/mixins/with_mail_edit_base.spec.js94
-rw-r--r--web-ui/test/spec/page/pane_contract_expand.spec.js67
-rw-r--r--web-ui/test/spec/page/router.spec.js70
-rw-r--r--web-ui/test/spec/page/router/url_params.spec.js68
-rw-r--r--web-ui/test/spec/search/search_trigger.spec.js78
-rw-r--r--web-ui/test/spec/services/delete_service.spec.js54
-rw-r--r--web-ui/test/spec/services/mail_service.spec.js307
-rw-r--r--web-ui/test/spec/services/model/mail.spec.js116
-rw-r--r--web-ui/test/spec/tags/data/tags.spec.js39
-rw-r--r--web-ui/test/spec/tags/ui/tag.spec.js151
-rw-r--r--web-ui/test/spec/tags/ui/tag_list.spec.js75
-rw-r--r--web-ui/test/spec/tags/ui/tag_shortcut.spec.js35
-rw-r--r--web-ui/test/spec/user_alerts/ui/user_alerts.spec.js23
-rw-r--r--web-ui/test/test-main.js57
-rw-r--r--web-ui/test/test_data.js170
39 files changed, 3517 insertions, 0 deletions
diff --git a/web-ui/test/spec/dispatchers/left_pane_dispatcher.spec.js b/web-ui/test/spec/dispatchers/left_pane_dispatcher.spec.js
new file mode 100644
index 00000000..fb5b169a
--- /dev/null
+++ b/web-ui/test/spec/dispatchers/left_pane_dispatcher.spec.js
@@ -0,0 +1,79 @@
+/*global Smail */
+
+describeComponent('dispatchers/left_pane_dispatcher', function () {
+ 'use strict';
+
+ describe('initialize', function () {
+ it('asks for tags', function () {
+ var tagWantEvent = spyOnEvent(document, Smail.events.tags.want);
+
+ setupComponent();
+
+ expect(tagWantEvent).toHaveBeenTriggeredOn(document);
+ expect(tagWantEvent.mostRecentCall.data.caller[0]).toEqual(this.$node[0]);
+ });
+ });
+
+ describe('after initialization', function () {
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ it('pushes the url state when a tag is selected but not for the first tag', function () {
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'Drafts'});
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'inbox'});
+
+ expect(pushStateEvent).toHaveBeenTriggeredOn(document, { tag: 'inbox'});
+ });
+
+ it('fetches mails by tag when a tag is selected', function () {
+ var fetchByTagEvent = spyOnEvent(document, Smail.events.ui.mails.fetchByTag);
+
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'Drafts'});
+
+ expect(fetchByTagEvent).toHaveBeenTriggeredOn(document, { tag: 'Drafts'});
+ });
+
+ it('doesnt fetch mails by tag when skipMailListRefresh is sent on tag.selected', function () {
+ var fetchByTagEvent = spyOnEvent(document, Smail.events.ui.mails.fetchByTag);
+
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'Drafts', skipMailListRefresh: true});
+
+ expect(fetchByTagEvent).not.toHaveBeenTriggeredOn(document, { tag: 'Drafts'});
+ });
+
+ it('asks for more tags when refreshTagList is fired', function () {
+ var tagWantEvent = spyOnEvent(document, Smail.events.tags.want);
+
+ $(document).trigger(Smail.events.dispatchers.tags.refreshTagList);
+
+ expect(tagWantEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('fires tagLoad when the tags are received', function () {
+ var tagListLoadEvent = spyOnEvent(document, Smail.events.ui.tagList.load);
+
+ this.$node.trigger(Smail.events.tags.received, { tags: ['tags']});
+
+ expect(tagListLoadEvent).toHaveBeenTriggeredOn(document, { tags: ['tags']});
+ });
+
+ it('on tags loaded selects the inbox tag if no data is provided', function () {
+ var selectTagEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+
+ $(document).trigger(Smail.events.ui.tags.loaded);
+
+ expect(selectTagEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'inbox' });
+ });
+
+ it('on tags loaded selects the a different tag if tag is provided', function () {
+ var selectTagEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+
+ $(document).trigger(Smail.events.ui.tags.loaded, { tag: 'Drafts' });
+
+ expect(selectTagEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'Drafts' });
+ });
+ });
+});
diff --git a/web-ui/test/spec/dispatchers/middle_pane_dispatchers.spec.js b/web-ui/test/spec/dispatchers/middle_pane_dispatchers.spec.js
new file mode 100644
index 00000000..2dd0de2e
--- /dev/null
+++ b/web-ui/test/spec/dispatchers/middle_pane_dispatchers.spec.js
@@ -0,0 +1,27 @@
+/*global Smail */
+
+describeComponent('dispatchers/middle_pane_dispatcher', function () {
+ 'use strict';
+
+ beforeEach(function() {
+ setupComponent('<div><div id="middle-pane" style="height: 200px; overflow-y: scroll;"><div style="height: 400px"></div></div></div>');
+ });
+
+ it ('listens to refresh mail list event', function() {
+ var mailsListRefreshEventSpy = spyOnEvent(document, Smail.events.ui.mails.fetchByTag);
+ this.component.trigger(document, Smail.events.dispatchers.middlePane.refreshMailList);
+ expect(mailsListRefreshEventSpy).toHaveBeenTriggeredOn(document);
+ });
+
+ it ('listens to unselect event', function() {
+ var mailListUnselectEvent = spyOnEvent(document, Smail.events.ui.mails.cleanSelected);
+ this.component.trigger(document, Smail.events.dispatchers.middlePane.cleanSelected);
+ expect(mailListUnselectEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('resets the scrollTop value when asked to', function() {
+ this.component.select('middlePane').scrollTop(200);
+ this.component.trigger(document, Smail.events.dispatchers.middlePane.resetScroll);
+ expect(this.component.select('middlePane').scrollTop()).toEqual(0);
+ });
+});
diff --git a/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js b/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js
new file mode 100644
index 00000000..5fc7ecd7
--- /dev/null
+++ b/web-ui/test/spec/dispatchers/right_pane_dispatcher.spec.js
@@ -0,0 +1,90 @@
+/*global Smail */
+
+describeComponent('dispatchers/right_pane_dispatcher', function () {
+ 'use strict';
+
+ describe('after initialization', function () {
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ it('listens to open compose box event and creates a compose box', function () {
+ var composeBox = require('mail_view/ui/compose_box');
+ spyOn(composeBox, 'attachTo');
+
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openComposeBox);
+
+ expect(composeBox.attachTo).toHaveBeenCalled();
+ });
+
+ describe('no message selected', function () {
+ var noMessageSelectedPane;
+ beforeEach(function () {
+ noMessageSelectedPane = require('mail_view/ui/no_message_selected_pane');
+ spyOn(noMessageSelectedPane, 'attachTo');
+ });
+
+ it('listen to open no message selected event and creates a no-message-selected-pane', function () {
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ expect(noMessageSelectedPane.attachTo).toHaveBeenCalled();
+ });
+
+ it('sends an dispatchers.middlePane.unselect event', function () {
+ var unselectEvent = spyOnEvent(document, Smail.events.dispatchers.middlePane.cleanSelected);
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ expect(unselectEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('pushes the current state with the current tag', function () {
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ this.component.attr.currentTag = 'sometag';
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ expect(pushStateEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({tag: this.component.attr.currentTag }));
+ });
+
+ it('pushes the current state stating that it meant to close the right pane', function () {
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ this.component.attr.currentTag = 'sometag';
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ expect(pushStateEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ isDisplayNoMessageSelected: true }));
+ });
+
+
+ });
+
+ it('listens to open a draft and creates it', function () {
+ var draftBox = require('mail_view/ui/draft_box');
+ spyOn(draftBox, 'attachTo');
+
+ this.component.trigger(document, Smail.events.dispatchers.rightPane.openDraft, { ident: '1' });
+
+ expect(draftBox.attachTo).toHaveBeenCalled();
+ });
+ });
+
+ describe('on initialization', function () {
+ var noMessageSelectedPane;
+
+ beforeEach(function () {
+ noMessageSelectedPane = require('mail_view/ui/no_message_selected_pane');
+ spyOn(noMessageSelectedPane, 'attachTo');
+ });
+
+ it('opens the no message selected pane but doesnt push the state', function () {
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ setupComponent();
+
+ expect(noMessageSelectedPane.attachTo).toHaveBeenCalled();
+ expect(pushStateEvent).not.toHaveBeenTriggeredOn(document);
+
+ });
+ });
+
+});
diff --git a/web-ui/test/spec/helpers/view_helper.spec.js b/web-ui/test/spec/helpers/view_helper.spec.js
new file mode 100644
index 00000000..7fa10e56
--- /dev/null
+++ b/web-ui/test/spec/helpers/view_helper.spec.js
@@ -0,0 +1,76 @@
+/*global Smail */
+
+define(['helpers/view_helper'], function (viewHelper) {
+ 'use strict';
+
+ var testData;
+ describe('view helper', function() {
+ beforeEach(function () {
+ testData = Smail.testData();
+ });
+
+ describe('quote email', function() {
+ it('should add > to body text', function() {
+ testData.rawMail.mail.body = 'First Line\nSecond Line';
+
+ var quotedMail = viewHelper.quoteMail(testData.rawMail.mail);
+
+ expect(quotedMail).toContain('> First Line\n> Second Line');
+ });
+ });
+
+ describe('getFormmattedDate', function() {
+ it('formats correctly a Date for today', function() {
+ var d = new Date();
+ var dtest = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 14, 2, 36);
+
+ var res = viewHelper.getFormattedDate(dtest);
+
+ expect(res).toEqual('14:02');
+
+ });
+
+ it('formats correctly a Date for a specific day', function() {
+ var dtest = new Date(2013, 2, 13, 7, 56, 1);
+
+ var res = viewHelper.getFormattedDate(dtest);
+
+ // This expectation is weird for the month - JS Dates have date numbers be zero-indexed, thus the discrepency
+ // Specifically, the 2 in the constructor DOES match the 3 in the expectation below.
+ expect(res).toEqual('2013-03-13');
+ });
+ });
+
+ describe('format status classes', function () {
+ it('formats all the status of the email to css classes', function () {
+ var statuses = ['read', 'banana'];
+
+ expect(viewHelper.formatStatusClasses(statuses)).toEqual('status-read status-banana');
+ });
+
+ it('formats a single status of the email to a css class', function () {
+ var statuses = ['read'];
+
+ expect(viewHelper.formatStatusClasses(statuses)).toEqual('status-read');
+ });
+ });
+
+ it('formats the body of a multipart email', function () {
+ expect(viewHelper.formatMailBody(testData.parsedMail.html)).toContainHtml('<p>Hello everyone!</p>');
+ });
+
+ it('decodes a quoted-printable email body', function () {
+ var result = viewHelper.formatMailBody(testData.parsedMail.htmlQuotedPrintable);
+
+ expect(result).toContainHtml('<p style="border: 5px;">Hello everyone!</p>');
+ });
+
+ it('move caret to the end of text after 1ms', function () {
+ spyOn(window, 'setTimeout');
+
+ viewHelper.moveCaretToEndOfText();
+
+ expect(window.setTimeout.calls[0].args[1]).toEqual(1);
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js b/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js
new file mode 100644
index 00000000..b49bc7f0
--- /dev/null
+++ b/web-ui/test/spec/mail_list/ui/mail_items/generic_mail_item.spec.js
@@ -0,0 +1,136 @@
+describeComponent('mail_list/ui/mail_items/generic_mail_item', function () {
+ 'use strict';
+
+ var mail;
+
+ beforeEach(function () {
+ mail = Smail.testData().parsedMail.simpleTextPlain;
+ mail.tags = ['inbox'];
+
+ setupComponent('<li></li>', {
+ mail: mail,
+ selected: false,
+ tag: 'inbox'
+ });
+ });
+
+ it('should trigger ui:openMail on click', function () {
+ var spyEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+
+ this.component.$node.find('a').click();
+
+ expect(spyEvent).toHaveBeenTriggeredOn(document);
+ expect(spyEvent.mostRecentCall.data).toEqual({ ident: mail.ident });
+ });
+
+ it('should add selected class when selecting', function () {
+ this.$node.find('a').click();
+
+ expect(this.$node).toHaveClass('selected');
+ });
+
+ it('should remove selected class when selecting a different mail', function () {
+ $(document).trigger(Smail.events.ui.mail.updateSelected, { ident: 2 });
+
+ expect(this.$node).not.toHaveClass('selected');
+ });
+
+ it('should remove selected class when enabling compose box', function () {
+ this.$node.find('a').click();
+
+ $(document).trigger(Smail.events.ui.composeBox.newMessage);
+
+ expect(this.$node).not.toHaveClass('selected');
+ });
+
+ it('should have the href link with mail ident and tag name', function () {
+ expect(this.$node.find('a')[0].href).toMatch('inbox/mail/' + mail.ident);
+ });
+
+ describe('clicking on a mail', function () {
+
+ function createClickEvent(options) {
+ var clickEvent = $.Event('click');
+ _.merge(clickEvent, options);
+ spyOn(clickEvent, 'preventDefault');
+ return clickEvent;
+ }
+
+ it('triggers mail open and pushes the state', function () {
+ var clickEvent = createClickEvent();
+ var mailOpenEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ $(this.$node.find('a')).trigger(clickEvent);
+
+ expect(mailOpenEvent).toHaveBeenTriggeredOnAndWith(document, { ident: mail.ident });
+ expect(pushStateEvent).toHaveBeenTriggeredOnAndWith(document, { mailIdent: mail.ident });
+ expect(clickEvent.preventDefault).toHaveBeenCalled();
+ });
+
+ describe('when opening on a new tab', function () {
+
+ _.each([
+ {metaKey: true},
+ {which: 2},
+ {ctrlKey: true}
+ ], function (specialKey) {
+ it('doesnt trigger mail open and nor pushes the state', function () {
+ var clickEvent = createClickEvent(specialKey);
+ var mailOpenEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+ var pushStateEvent = spyOnEvent(document, Smail.events.router.pushState);
+
+ $(this.$node.find('a')).trigger(clickEvent);
+
+ expect(mailOpenEvent).not.toHaveBeenTriggeredOnAndWith(document, { ident: mail.ident });
+ expect(pushStateEvent).not.toHaveBeenTriggeredOnAndWith(document, { mailIdent: mail.ident });
+ expect(clickEvent.preventDefault).not.toHaveBeenCalled();
+ });
+
+ it('marks the email as read', function () {
+ debugger;
+ var mailReadEvent = spyOnEvent(document, Smail.events.mail.read);
+ var clickEvent = createClickEvent(specialKey);
+
+ $(this.$node.find('a')).trigger(clickEvent);
+
+ expect(this.component.attr.mail.status).toContain(this.component.status.READ);
+ expect(this.$node.attr('class')).toMatch('status-read');
+ expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, { ident: mail.ident, tags: ['inbox'] });
+ });
+
+ });
+
+ });
+
+ });
+
+ describe('marking emails as read', function () {
+ it('should trigger mail:read event when unread is clicked', function () {
+ var mailReadEvent = spyOnEvent(document, Smail.events.mail.read);
+
+ this.$node.find('a').click();
+
+ expect(mailReadEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ident: mail.ident}));
+ });
+
+ it('should not trigger mail:read event when clicking mail that is already read', function () {
+ var mailReadEvent = spyOnEvent(document, Smail.events.mail.read);
+ this.component.attr.mail.status.push(this.component.status.READ);
+
+ this.$node.find('a').click();
+
+ expect(mailReadEvent).not.toHaveBeenTriggeredOnAndWith(document, {ident: mail.ident});
+ });
+
+ it('should add status-read class to email when clicking an unread email', function () {
+ this.$node.find('a').click();
+
+ expect(this.$node).toHaveClass('status-read');
+ });
+
+ it('should not have status-read class when initializing email without read status', function () {
+ expect(this.$node).not.toHaveClass('status-read');
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_list/ui/mail_items/mail_item.spec.js b/web-ui/test/spec/mail_list/ui/mail_items/mail_item.spec.js
new file mode 100644
index 00000000..1b5899a1
--- /dev/null
+++ b/web-ui/test/spec/mail_list/ui/mail_items/mail_item.spec.js
@@ -0,0 +1,40 @@
+/*global Smail */
+
+describeMixin('mail_list/ui/mail_items/mail_item', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ var mail = Smail.testData().parsedMail.simpleTextPlain;
+ mail.tags = ['inbox'];
+
+ setupComponent('<li><input type="checkbox"></input></li>', {
+ mail: mail,
+ selected: false,
+ tag: 'inbox'
+ });
+ });
+
+ describe('mail checkbox', function () {
+ var mailCheckedEvent, mailUncheckedEvent, checkbox;
+ beforeEach(function () {
+ mailCheckedEvent = spyOnEvent(document, Smail.events.ui.mail.checked);
+ mailUncheckedEvent = spyOnEvent(document, Smail.events.ui.mail.unchecked);
+ checkbox = this.component.$node.find('input[type=checkbox]');
+ });
+
+ it('checkCheckbox checks it and triggers events.ui.mail.checked', function () {
+ this.component.checkCheckbox();
+
+ expect(checkbox.prop('checked')).toBe(true);
+ expect(mailCheckedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('uncheckCheckbox checks it and triggers events.ui.mail.checked', function () {
+ checkbox.prop('checked', true);
+ this.component.uncheckCheckbox();
+
+ expect(checkbox.prop('checked')).toBe(false);
+ expect(mailUncheckedEvent).toHaveBeenTriggeredOn(document);
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_list/ui/mail_list.spec.js b/web-ui/test/spec/mail_list/ui/mail_list.spec.js
new file mode 100644
index 00000000..f383d540
--- /dev/null
+++ b/web-ui/test/spec/mail_list/ui/mail_list.spec.js
@@ -0,0 +1,275 @@
+/*global Smail */
+
+describeComponent('mail_list/ui/mail_list', function () {
+ 'use strict';
+
+ var mailList;
+
+ beforeEach(function () {
+ setupComponent('<div id="mails"></div>', {
+ urlParams: {
+ hasMailIdent: function () {
+ return false;
+ }
+ }
+ });
+ mailList =
+ [
+ createMail('the mail subject', 'from@mail.com', '1', '2012-12-26T01:38:46-08:00'),
+ createMail('another mail subject', 'from_another@mail.com', '2', '2012-12-28T01:38:46-08:00')
+ ];
+ });
+
+
+ it('should open mail at first mail:available if there is a mailIdent in the url hash', function () {
+ this.component.attr.urlParams = {
+ hasMailIdent: function () {
+ return true;
+ },
+ getMailIdent: function () {
+ return '10';
+ }
+ };
+ var openMailEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+
+ this.$node.trigger(Smail.events.mails.available, { mails: mailList });
+ expect(openMailEvent).toHaveBeenTriggeredOnAndWith(document, { ident: '10' });
+
+ this.$node.trigger(Smail.events.mails.available, { mails: mailList });
+ expect(openMailEvent.calls.length).toEqual(1);
+ });
+
+ it('should push the state if there is a mail ident in the hash url', function () {
+ this.component.attr.urlParams = {
+ hasMailIdent: function () {
+ return true;
+ },
+ getMailIdent: function () {
+ return '10';
+ }
+ };
+ var pushState = spyOnEvent(document, Smail.events.router.pushState);
+ this.component.attr.currentTag = 'inbox';
+
+ this.$node.trigger(Smail.events.mails.available, { mails: mailList });
+
+ expect(pushState).toHaveBeenTriggeredOnAndWith(document, { tag: 'inbox', mailIdent: '10' });
+ });
+
+ describe('checking/unchecking mails in the list', function () {
+
+ it('keeps a list with the currently checked mails', function () {
+ var checkedMails = {};
+
+ this.component.attr.checkedMails = {};
+
+ $(document).trigger(Smail.events.ui.mail.checked, {mail: mailList[0]});
+
+ checkedMails[mailList[0].ident] = mailList[0];
+
+ expect(this.component.attr.checkedMails).toEqual(checkedMails);
+ });
+
+ it('returns the list of checked mails to whomever requests them', function () {
+ var caller = {};
+ this.component.attr.checkedMails = {'1': {}};
+ var mailHereCheckedEvent = spyOnEvent(caller, Smail.events.ui.mail.hereChecked);
+
+ $(document).trigger(Smail.events.ui.mail.wantChecked, caller);
+
+ expect(mailHereCheckedEvent).toHaveBeenTriggeredOnAndWith(caller, { checkedMails: {'1': {} }});
+ });
+
+ it('returns an empty list to whomever requests the checked mails if there are no checked mails', function () {
+ var caller = {};
+ var mailHereCheckedEvent = spyOnEvent(caller, Smail.events.ui.mail.hereChecked);
+
+ $(document).trigger(Smail.events.ui.mail.wantChecked, caller);
+
+ expect(mailHereCheckedEvent).toHaveBeenTriggeredOnAndWith(caller, { checkedMails: {} });
+ });
+
+ it('removes for the checked mails when mail is unchecked', function () {
+ this.component.attr.checkedMails = {
+ '1': {},
+ '2': {},
+ '3': {}
+ };
+
+ $(document).trigger(Smail.events.ui.mail.unchecked, {mail: {ident: '1'}});
+
+ expect(this.component.attr.checkedMails).toEqual({'2': {}, '3': {} });
+ });
+
+ it('checks the check all checkbox if at least one mail is checked', function () {
+ var setCheckAllCheckboxEvent = spyOnEvent(document, Smail.events.ui.mails.hasMailsChecked);
+
+ $(document).trigger(Smail.events.ui.mail.checked, {mail: mailList[0]});
+
+ expect(setCheckAllCheckboxEvent).toHaveBeenTriggeredOnAndWith(document, true);
+ });
+
+ it('unchecks the check all checkbox if no mail is left checked', function () {
+ this.component.attr.checkedMails = {1: {}};
+
+ var setCheckAllCheckboxEvent = spyOnEvent(document, Smail.events.ui.mails.hasMailsChecked);
+
+ $(document).trigger(Smail.events.ui.mail.unchecked, {mail: {ident: '1'}});
+
+ expect(setCheckAllCheckboxEvent).toHaveBeenTriggeredOnAndWith(document, false);
+ });
+ });
+
+ describe('when mails are available', function () {
+ it('should open email if popstate event happened (when mailIdent isnt undefined)', function () {
+ var openMailEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList, mailIdent: '30' });
+
+ expect(openMailEvent).toHaveBeenTriggeredOnAndWith(document, { ident: '30'});
+ });
+
+ it('should open draft in popstate event if tag is Drafts', function () {
+ var openDraftEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openDraft);
+
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList, mailIdent: '30', tag: 'drafts' });
+
+ expect(openDraftEvent).toHaveBeenTriggeredOnAndWith(document, { ident: '30'});
+ });
+ });
+
+ it('should not append emails when another mails:available event is triggered', function () {
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList });
+
+ expect(this.component.$node.find('a').length).toEqual(2);
+
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList });
+
+ expect(this.component.$node.find('a').length).toEqual(2);
+ });
+
+ it('resets scroll when opening a new tag or choosing a new tag', function () {
+ var eventSpy = spyOnEvent(document, Smail.events.dispatchers.middlePane.resetScroll);
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList });
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ });
+
+ describe('rendering the mails', function () {
+
+ describe('when mails are available for refreshing', function () {
+ it('renders the new mails', function () {
+ this.component.$node.trigger(Smail.events.mails.availableForRefresh, { mails: mailList });
+
+ matchMail(mailList[0], this.component.$node);
+ matchMail(mailList[1], this.component.$node);
+ });
+
+ });
+
+ it('should render all mails sent in ui:mails:show event', function () {
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList });
+
+ matchMail(mailList[0], this.component.$node);
+ matchMail(mailList[1], this.component.$node);
+ });
+
+ it('should select the current email when mails are available', function () {
+ this.component.attr.currentMailIdent = '1';
+
+ this.component.trigger(Smail.events.mails.available, { mails: mailList });
+
+ matchSelectedMail(mailList[0], this.component.$node);
+ matchMail(mailList[1], this.component.$node);
+ });
+
+ it('should keep the mail checked when it was previously checked (so refresh works)', function () {
+ var checkbox, mailIdent;
+
+ mailIdent = mailList[0].ident;
+ this.component.attr.checkedMails[mailIdent] = mailList[0];
+ this.component.$node.trigger(Smail.events.mails.available, { mails: [mailList[0]] });
+ checkbox = this.$node.find('input[type=checkbox]');
+
+ expect(checkbox.prop('checked')).toBe(true);
+ });
+
+ it('should render links for the emails', function () {
+ this.component.$node.trigger(Smail.events.mails.available, { mails: mailList, tag: 'inbox' });
+
+ expect(this.$node.html()).toMatch('href="/#/inbox/mail/1');
+ expect(this.$node.html()).toMatch('href="/#/inbox/mail/2');
+ });
+
+ it('should clean the selected email', function () {
+ this.component.attr.currentMailIdent = '1';
+ this.component.trigger(Smail.events.ui.mails.cleanSelected);
+
+ expect(this.component.attr.currentMailIdent).toEqual('');
+ });
+
+ function matchMail(mail, node) {
+ expect(node.html()).toMatch('id="mail-' + mail.ident + '"');
+ expect(node.html()).toMatch('<div class="subject-and-tags">');
+ expect(node.html()).toMatch('<div class="from">' + mail.header.from + '</div>');
+ expect(node.html()).toMatch('<span class="received-date">' + mail.header.formattedDate + '</span>');
+ }
+
+ function matchSelectedMail(mail, node) {
+ expect(node.html()).toMatch(['id="mail-', mail.ident, '" class="selected"'].join(''));
+ }
+ });
+
+ describe('when saving a draft', function () {
+ it('refreshes the list if the current tag is drafts', function () {
+ this.component.attr.currentTag = 'drafts';
+ var spyRefresh = spyOnEvent(document, Smail.events.ui.mails.refresh);
+ var spyScroll = spyOnEvent(document, Smail.events.dispatchers.middlePane.resetScroll);
+ this.component.trigger(Smail.events.mail.draftSaved, {ident: 1});
+ expect(spyRefresh).toHaveBeenTriggeredOn(document);
+ expect(spyScroll).toHaveBeenTriggeredOn(document);
+ });
+
+ it('does not refresh the list if the current tag is not drafts', function() {
+ this.component.attr.currentTag = 'sent';
+ var spyRefresh = spyOnEvent(document, Smail.events.ui.mails.refresh);
+ var spyScroll = spyOnEvent(document, Smail.events.dispatchers.middlePane.resetScroll);
+ this.component.trigger(Smail.events.mail.draftSaved, {ident: 1});
+ expect(spyRefresh).not.toHaveBeenTriggeredOn(document);
+ expect(spyScroll).not.toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('when sending a mail', function () {
+ it('refreshes the list if the current tag is drafts', function () {
+ this.component.attr.currentTag = 'drafts';
+ var spyRefresh = spyOnEvent(document, Smail.events.ui.mails.refresh);
+ var spyScroll = spyOnEvent(document, Smail.events.dispatchers.middlePane.resetScroll);
+ this.component.trigger(Smail.events.mail.sent);
+ expect(spyRefresh).toHaveBeenTriggeredOn(document);
+ expect(spyScroll).toHaveBeenTriggeredOn(document);
+ });
+
+ it('refreshes the list if the current tag is sent', function() {
+ this.component.attr.currentTag = 'sent';
+ var spyRefresh = spyOnEvent(document, Smail.events.ui.mails.refresh);
+ var spyScroll = spyOnEvent(document, Smail.events.dispatchers.middlePane.resetScroll);
+ this.component.trigger(Smail.events.mail.sent);
+ expect(spyRefresh).toHaveBeenTriggeredOn(document);
+ expect(spyScroll).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ function createMail(subject, from, ident, date) {
+ var mail = Smail.testData().parsedMail.simpleTextPlain;
+
+ return _.merge(mail, {
+ header: {
+ subject: subject,
+ from: from,
+ date: date
+ },
+ ident: ident,
+ tags: ['inbox']
+ });
+ }
+});
diff --git a/web-ui/test/spec/mail_list_actions/ui/compose_trigger.spec.js b/web-ui/test/spec/mail_list_actions/ui/compose_trigger.spec.js
new file mode 100644
index 00000000..4942b5b6
--- /dev/null
+++ b/web-ui/test/spec/mail_list_actions/ui/compose_trigger.spec.js
@@ -0,0 +1,16 @@
+describeComponent('mail_list_actions/ui/compose_trigger', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent('<div></div>');
+ });
+
+ it('triggers the enableComposebox event when clicked', function () {
+ var spyEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openComposeBox);
+
+ this.component.trigger('click');
+
+ expect(spyEvent).toHaveBeenTriggeredOn(document);
+ });
+
+});
diff --git a/web-ui/test/spec/mail_list_actions/ui/mail_actions.spec.js b/web-ui/test/spec/mail_list_actions/ui/mail_actions.spec.js
new file mode 100644
index 00000000..f7a0ed72
--- /dev/null
+++ b/web-ui/test/spec/mail_list_actions/ui/mail_actions.spec.js
@@ -0,0 +1,9 @@
+describeComponent('mail_list_actions/ui/mail_actions', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent();
+ });
+
+
+});
diff --git a/web-ui/test/spec/mail_list_actions/ui/pagination_trigger.spec.js b/web-ui/test/spec/mail_list_actions/ui/pagination_trigger.spec.js
new file mode 100644
index 00000000..67c2f3ef
--- /dev/null
+++ b/web-ui/test/spec/mail_list_actions/ui/pagination_trigger.spec.js
@@ -0,0 +1,26 @@
+describeComponent('mail_list_actions/ui/pagination_trigger', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ it('triggers the ui:page:previous event when the left arrow is clicked', function () {
+ var eventSpy = spyOnEvent(document, Smail.events.ui.page.previous);
+ this.component.select('previous').click();
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ });
+
+
+ it('triggers the ui:page:next event when the right arrow is clicked', function () {
+ var eventSpy = spyOnEvent(document, Smail.events.ui.page.next);
+ this.component.select('next').click();
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ });
+
+ it('re-renders with current page number when page changes', function () {
+ this.component.trigger(document, Smail.events.ui.page.changed, {currentPage: 0});
+
+ expect(this.component.select('currentPage').text()).toBe('1');
+ });
+});
diff --git a/web-ui/test/spec/mail_view/data/mail_builder.spec.js b/web-ui/test/spec/mail_view/data/mail_builder.spec.js
new file mode 100644
index 00000000..bf17d598
--- /dev/null
+++ b/web-ui/test/spec/mail_view/data/mail_builder.spec.js
@@ -0,0 +1,110 @@
+define(['mail_view/data/mail_builder'], function (mailBuilder) {
+ describe('mail builder', function () {
+ 'use strict';
+
+ it('sets ident if passed to constructor', function() {
+ var mail = mailBuilder.newMail('12345').build();
+
+ expect(mail.ident).toBe('12345');
+ });
+
+ it('sets ident to empty if not passed to constructor', function() {
+ var mail = mailBuilder.newMail().build();
+
+ expect(mail.ident).toBe('');
+ });
+
+ it('sets the subject', function() {
+ var mail = mailBuilder.newMail().subject("subject").build();
+
+ expect(mail.header.subject).toBe("subject");
+ });
+
+ it('sets the body', function() {
+ var mail = mailBuilder.newMail().body("some body text").build();
+
+ expect(mail.body).toBe("some body text");
+ });
+
+ describe('to field', function() {
+ it('adds a single address', function() {
+ var mail = mailBuilder.newMail().to('foo@bar.com').build();
+
+ expect(mail.header.to).toContain('foo@bar.com');
+ });
+
+ it('adds multiple addresses', function() {
+ var mail = mailBuilder.newMail().to('foo@bar.com bar@foo.com').build();
+
+ expect(mail.header.to).toContain('foo@bar.com');
+ expect(mail.header.to).toContain('bar@foo.com');
+ });
+
+ it('accepts undefined without breaking', function() {
+ var mail = mailBuilder.newMail().to(undefined).build();
+
+ expect(mail.header.to).toEqual([]);
+ });
+ });
+
+ describe('cc field', function() {
+ it('adds a single address', function() {
+ var mail = mailBuilder.newMail().cc('foo@bar.com').build();
+
+ expect(mail.header.cc).toContain('foo@bar.com');
+ });
+
+ it('adds multiple addresses', function() {
+ var mail = mailBuilder.newMail().cc('foo@bar.com bar@foo.com').build();
+
+ expect(mail.header.cc).toContain('foo@bar.com');
+ expect(mail.header.cc).toContain('bar@foo.com');
+ });
+
+ it('accepts undefined without breaking', function() {
+ var mail = mailBuilder.newMail().cc(undefined).build();
+
+ expect(mail.header.cc).toEqual([]);
+ });
+ });
+
+ describe('bcc field', function() {
+ it('adds a single address', function() {
+ var mail = mailBuilder.newMail().bcc('foo@bar.com').build();
+
+ expect(mail.header.bcc).toContain('foo@bar.com');
+ });
+
+ it('adds multiple addresses', function() {
+ var mail = mailBuilder.newMail().bcc('foo@bar.com bar@foo.com').build();
+
+ expect(mail.header.bcc).toContain('foo@bar.com');
+ expect(mail.header.bcc).toContain('bar@foo.com');
+ });
+
+ it('accepts undefined without breaking', function() {
+ var mail = mailBuilder.newMail().bcc(undefined).build();
+
+ expect(mail.header.bcc).toEqual([]);
+ });
+ });
+
+ it('adds arbitrary headers', function() {
+ var mail = mailBuilder.newMail()
+ .header('Reply-To', 'something')
+ .header('In-Reply-To', '12345')
+ .build();
+
+ expect(mail.header['Reply-To']).toBe('something');
+ expect(mail.header['In-Reply-To']).toBe('12345');
+ });
+
+ it('adds tag', function() {
+ var mail = mailBuilder.newMail()
+ .tag('tag1')
+ .build();
+
+ expect(mail.tags).toContain('tag1');
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_view/data/mail_sender.spec.js b/web-ui/test/spec/mail_view/data/mail_sender.spec.js
new file mode 100644
index 00000000..3bdc1934
--- /dev/null
+++ b/web-ui/test/spec/mail_view/data/mail_sender.spec.js
@@ -0,0 +1,70 @@
+/*global Smail */
+
+describeComponent('mail_view/data/mail_sender', function () {
+ 'use strict';
+
+ var mailBuilder;
+ var mail;
+
+ beforeEach(function () {
+ mailBuilder = require('mail_view/data/mail_builder');
+ mail = Smail.testData().parsedMail.simpleTextPlain;
+ setupComponent();
+ });
+
+ it('sends mail data with a POST to the server when asked to send email', function() {
+ var mailSentEventSpy = spyOnEvent(document, Smail.events.mail.sent);
+ var g;
+
+ spyOn($, 'ajax').andReturn({done: function(f) { g = f; return {fail: function(){}};}});
+
+ this.component.trigger(Smail.events.mail.send, mail);
+
+ g();
+
+ expect(mailSentEventSpy).toHaveBeenTriggeredOn(document);
+
+ expect($.ajax.mostRecentCall.args[0]).toEqual('/mails');
+ expect($.ajax.mostRecentCall.args[1].type).toEqual('POST');
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).header).toEqual(mail.header);
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).body).toEqual(mail.body);
+ });
+
+ it('save draft data with a POST to the server when asked to save draft for the first time', function() {
+ var draftSavedEventSpy = spyOnEvent(document, Smail.events.mail.draftSaved);
+ var g;
+
+ spyOn($, 'ajax').andReturn({done: function(f) { g = f; return {fail: function(){}};}});
+
+ mail.ident = '';
+ this.component.trigger(Smail.events.mail.saveDraft, mail);
+
+ g();
+
+ expect(draftSavedEventSpy).toHaveBeenTriggeredOn(document);
+
+ expect($.ajax.mostRecentCall.args[0]).toEqual('/mails');
+ expect($.ajax.mostRecentCall.args[1].type).toEqual('POST');
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).header).toEqual(mail.header);
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).body).toEqual(mail.body);
+ });
+
+ it('save draft data with a PUT to the server when asked to save draft for the second time', function() {
+ var draftSavedEventSpy = spyOnEvent(document, Smail.events.mail.draftSaved);
+ var g;
+
+ spyOn($, 'ajax').andReturn({done: function(f) { g = f; return {fail: function(){}};}});
+
+ mail.ident = 0;
+ this.component.trigger(Smail.events.mail.saveDraft, mail);
+
+ g();
+
+ expect(draftSavedEventSpy).toHaveBeenTriggeredOn(document);
+
+ expect($.ajax.mostRecentCall.args[0]).toEqual('/mails');
+ expect($.ajax.mostRecentCall.args[1].type).toEqual('PUT');
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).header).toEqual(mail.header);
+ expect(JSON.parse($.ajax.mostRecentCall.args[1].data).body).toEqual(mail.body);
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/compose_box.spec.js b/web-ui/test/spec/mail_view/ui/compose_box.spec.js
new file mode 100644
index 00000000..a131d2cf
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/compose_box.spec.js
@@ -0,0 +1,132 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('mail_view/ui/compose_box', function () {
+ 'use strict';
+ beforeEach(function () {
+ Smail.mockBloodhound();
+ setupComponent('<div style="display:none"></div>');
+ });
+
+
+ describe('compose new mail', function() {
+
+ it('only sends if all the recipients are valid emails', function() {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['valid@email.example']});
+
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ });
+
+ it('sends the recipient entered', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['fox@somewhere.com']});
+
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ to: ['fox@somewhere.com']
+ }));
+ });
+
+ it('sends the multiple recipients entered', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['fox@somewhere.com', 'blarg@someone.com', 'fox2@google.se']});
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ to: ['fox@somewhere.com', 'blarg@someone.com', 'fox2@google.se']
+ }));
+ });
+
+ it('sends the subject line entered', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['aa@aa.com']});
+ this.component.select('subjectBox').val('A new fancy subject!');
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ subject: 'A new fancy subject!'
+ }));
+ });
+
+ it('sends the multiple CCs entered', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'cc', newRecipients: ['cc1@foo.bar', 'cc2@bar.foo', 'cc3@zz.top']});
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ cc: ['cc1@foo.bar', 'cc2@bar.foo', 'cc3@zz.top']
+ }));
+ });
+
+ it('sends the multiple BCCs entered', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'bcc', newRecipients: ['bcc1@foo.bar', 'bcc2@bar.foo', 'bcc3@zz.top']});
+ var eventSpy = spyOnEvent(document, Smail.events.mail.send);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ bcc: ['bcc1@foo.bar', 'bcc2@bar.foo', 'bcc3@zz.top']
+ }));
+ });
+
+ it('shows no message selected pane when deleting the email being composed', function() {
+ var openNoMessageSelectedPaneEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+ var mails = [{ident: 123}];
+ this.component.attr.ident = 123;
+
+ this.component.trigger(document, Smail.events.mail.deleted, {mails: mails});
+
+ expect(openNoMessageSelectedPaneEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('does not show no message selected pane when deleting a different set of emails', function() {
+ var openNoMessageSelectedPaneEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+ var mails = [{ident: 321}];
+ this.component.attr.ident = 123;
+
+ this.component.trigger(document, Smail.events.mail.deleted, {mails: mails});
+
+ expect(openNoMessageSelectedPaneEvent).not.toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('close button behavior', function() {
+
+ it('should fire Show no message selected if the close button is clicked', function() {
+ var spy = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+ this.component.select('closeButton').click();
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+
+ });
+
+ describe('draft compose box', function() {
+ it('should save a draft when click on draft button', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['fox@somewhere.com']});
+
+ this.component.select('subjectBox').val('A new fancy subject!');
+ var eventSpy = spyOnEvent(document, Smail.events.mail.saveDraft);
+
+ this.component.select('draftButton').click();
+
+ expect(eventSpy).toHaveBeenTriggeredOn(document);
+ expect(eventSpy.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ to: ['fox@somewhere.com']
+ }));
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/draft_box.spec.js b/web-ui/test/spec/mail_view/ui/draft_box.spec.js
new file mode 100644
index 00000000..3e02f752
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/draft_box.spec.js
@@ -0,0 +1,67 @@
+/* global Smail */
+
+describeComponent('mail_view/ui/draft_box', function () {
+ 'use strict';
+
+ var mail;
+
+ beforeEach(function () {
+ Smail.mockBloodhound();
+ mail = Smail.testData().parsedMail.simpleTextPlain;
+ });
+
+ describe('when initializing', function () {
+ it('fetches the email to draft', function () {
+ var mailWantEvent = spyOnEvent(document, Smail.events.mail.want);
+
+ setupComponent({mailIdent: '1'});
+
+ expect(mailWantEvent).toHaveBeenTriggeredOnAndWith(document, {
+ mail: '1', caller: this.component
+ });
+ });
+ });
+
+ describe('after initialize', function () {
+ beforeEach(function () {
+ setupComponent({mailIdent: '1'});
+ });
+
+ it('renders the compose box when mail is received', function () {
+ var templates = require('views/templates');
+
+ spyOn(this.component, 'render');
+
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mail});
+
+ expect(this.component.render).toHaveBeenCalledWith(templates.compose.box, {
+ recipients: { to: mail.header.to, cc: mail.header.cc, bcc: mail.header.bcc },
+ subject: mail.header.subject,
+ body: mail.body
+ });
+ });
+
+ });
+
+ it('sending a draft sends the correct mailIdent', function () {
+ setupComponent({mailIdent: mail.ident});
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mail});
+
+ var sendDraftEvent = spyOnEvent(document, Smail.events.mail.saveDraft);
+ this.component.select('draftButton').click();
+
+ expect(sendDraftEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ident: mail.ident}));
+ });
+
+ it('shows no message selected pane when draft is sent', function() {
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ setupComponent({mailIdent: mail.ident});
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mail});
+
+ this.component.trigger(document, Smail.events.mail.sent);
+
+ expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/ui/draft_save_status.spec.js b/web-ui/test/spec/mail_view/ui/draft_save_status.spec.js
new file mode 100644
index 00000000..fb989f4c
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/draft_save_status.spec.js
@@ -0,0 +1,26 @@
+/* global Smail */
+
+describeComponent('mail_view/ui/draft_save_status', function () {
+ 'use strict';
+
+ beforeEach(setupComponent);
+
+ it('should be empty on initialization', function() {
+ expect(this.$node.text()).toBe('');
+ });
+
+ it('should display status when saving a draft', function() {
+ $(document).trigger(Smail.events.mail.saveDraft);
+ expect(this.$node.text()).toBe('Saving to Drafts...');
+ });
+
+ it('should display status when draft is saved', function() {
+ $(document).trigger(Smail.events.mail.draftSaved);
+ expect(this.$node.text()).toBe('Draft Saved.');
+ });
+
+ it('should reset status when mail is changed since last save', function() {
+ $(document).trigger(Smail.events.ui.mail.changedSinceLastSave);
+ expect(this.$node.text()).toBe('');
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/forward_box.spec.js b/web-ui/test/spec/mail_view/ui/forward_box.spec.js
new file mode 100644
index 00000000..fc878447
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/forward_box.spec.js
@@ -0,0 +1,90 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('mail_view/ui/forward_box', function () {
+ 'use strict';
+
+ var attrs;
+ var testMail;
+ beforeEach(function () {
+ testMail = Smail.testData().parsedMail.simpleTextPlain;
+
+ Smail.mockBloodhound();
+ });
+
+ it('should have a subject of Fwd: <original_message>', function() {
+ testMail.header.subject = 'Very interesting';
+ setupComponent({ mail: testMail });
+
+ expect(this.component.select('subjectDisplay').text()).toEqual('Fwd: '+ testMail.header.subject);
+ });
+
+ it('should have no recipients', function () {
+ var Recipients = require('mail_view/ui/recipients/recipients');
+ spyOn(Recipients, 'attachTo');
+
+ setupComponent({ mail: testMail });
+
+ expect(Recipients.attachTo.calls[0].args[1]).toEqual({name: 'to', addresses: []});
+ expect(Recipients.attachTo.calls[1].args[1]).toEqual({name: 'cc', addresses: []});
+ expect(Recipients.attachTo.calls[2].args[1]).toEqual({name: 'bcc', addresses: []});
+ });
+
+ it('should populate body text area with quote of email being forwarded', function() {
+ var viewHelper = require('helpers/view_helper');
+ spyOn(viewHelper, 'quoteMail').andReturn('quoted email');
+
+ setupComponent({ mail: testMail });
+
+ expect(viewHelper.quoteMail).toHaveBeenCalledWith(testMail);
+ expect(this.component.select('bodyBox').val()).toBe('quoted email');
+ });
+
+ it('should show subject field when clicking on subject display', function() {
+ setupComponent({ mail: testMail });
+
+ this.component.select('subjectDisplay').click();
+
+ expect(this.component.select('subjectInput')).not.toBeHidden();
+ expect(this.component.select('subjectDisplay')).toBeHidden();
+ });
+
+ it('should copy original message headers', function() {
+ var mailSendEvent = spyOnEvent(document, Smail.events.mail.send);
+
+ testMail.header.bcc = 'original_bcc@email.com';
+ testMail.header.cc = 'original_cc@email.com';
+ testMail.header.date = 'original_date';
+ testMail.header.from = 'original_from';
+ testMail.header.message_id = 'original_message_id';
+ testMail.header.reply_to = 'original_reply_to@email.com';
+ testMail.header.sender = 'original_sender';
+ testMail.header.to = 'original_to@email.com';
+
+ setupComponent({ mail: testMail });
+
+ this.component.attr.recipientValues.to.push('forward_to@email.com');
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(mailSendEvent).toHaveBeenTriggeredOn(document);
+ var sentMail = mailSendEvent.mostRecentCall.data;
+
+ expect(sentMail.header).toEqual(jasmine.objectContaining({
+ resent_bcc: 'original_bcc@email.com',
+ resent_cc: 'original_cc@email.com',
+ resent_date: 'original_date',
+ resent_from: 'original_from',
+ resent_message_id: 'original_message_id',
+ resent_reply_to: 'original_reply_to@email.com',
+ resent_sender: 'original_sender',
+ resent_to: 'original_to@email.com'
+ }));
+ });
+
+ it('triggers openMail when email is sent', function() {
+ var eventSpy = spyOnEvent(document, Smail.events.ui.mail.open);
+ setupComponent({ mail: testMail });
+ $(document).trigger(Smail.events.mail.sent, {ident: testMail.ident});
+ expect(eventSpy).toHaveBeenTriggeredOnAndWith(document, {ident: testMail.ident});
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/mail_actions.spec.js b/web-ui/test/spec/mail_view/ui/mail_actions.spec.js
new file mode 100644
index 00000000..93db0193
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/mail_actions.spec.js
@@ -0,0 +1,63 @@
+/*global Smail */
+
+describeComponent('mail_view/ui/mail_actions', function () {
+ 'use strict';
+
+ var testData;
+
+ beforeEach(function(){
+ testData = Smail.testData();
+ setupComponent(testData);
+ });
+
+ it('verifies if more actions list is hidden when rendering mail view', function() {
+
+ var moreActionsComponent = this.component.select('moreActions');
+ expect(moreActionsComponent.attr('style').trim()).toEqual('display: none;');
+
+ });
+
+ it('show more actions list when click on view more actions button', function(){
+
+ this.component.select('viewMoreActions').click();
+
+ var moreActionsComponent = this.component.select('moreActions');
+ expect(moreActionsComponent.attr('style').trim()).not.toEqual('display: none;');
+ });
+
+ it('triggers a show reply box event when clicking on reply-button-top', function(){
+
+ var showReplyBoxEvent = spyOnEvent(document, Smail.events.ui.replyBox.showReply);
+
+ this.component.select('replyButtonTop').click();
+
+ expect(showReplyBoxEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('triggers a show reply all box event when clicking on reply-button-top and hide more actions list', function(){
+
+ var showReplyAllEvent = spyOnEvent(document, Smail.events.ui.replyBox.showReplyAll);
+
+ this.component.select('viewMoreActions').click();
+ this.component.select('replyAllButtonTop').click();
+
+ expect(showReplyAllEvent).toHaveBeenTriggeredOn(document);
+
+ var moreActionsComponent = this.component.select('moreActions');
+ expect(moreActionsComponent.attr('style').trim()).toEqual('display: none;');
+ });
+
+ it('triggers a delete event when clicking on delete-button-top', function(){
+
+ var deleteEvent = spyOnEvent(document, Smail.events.ui.mail.delete);
+
+ this.component.select('viewMoreActions').click();
+ this.component.select('deleteButtonTop').click();
+
+ expect(deleteEvent).toHaveBeenTriggeredOnAndWith(document, {mail: testData.mail});
+
+ var moreActionsComponent = this.component.select('moreActions');
+ expect(moreActionsComponent.attr('style').trim()).toEqual('display: none;');
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/ui/mail_view.spec.js b/web-ui/test/spec/mail_view/ui/mail_view.spec.js
new file mode 100644
index 00000000..80f253e0
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/mail_view.spec.js
@@ -0,0 +1,247 @@
+/*global Smail */
+
+describeComponent('mail_view/ui/mail_view', function () {
+ 'use strict';
+
+ var mail;
+
+ var testData;
+
+ beforeEach(function () {
+ mail = {ident: 1, header: { date: '12/12/12T12:12' }, tags: ['inbox']};
+ testData = {mail: Smail.testData().parsedMail.simpleTextPlain};
+ Smail.mockBloodhound();
+ setupComponent('<div></div>', {mail: mail});
+ });
+
+ it('triggers mail:want on ui:openMail', function () {
+ var spyEvent = spyOnEvent(document, Smail.events.mail.want);
+
+ setupComponent('<div></div>', {ident: mail.ident });
+
+ expect(spyEvent).toHaveBeenTriggeredOn(document);
+ expect(spyEvent.mostRecentCall.data.mail).toEqual(1);
+ });
+
+ it('triggers dispatchers.rightPane.openNoMessageSelected when getting mail.notFound', function () {
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ this.component.trigger(this.component, Smail.events.mail.notFound);
+
+ expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+
+ it('removes the tag from the mail when the tag label is clicked', function() {
+ var updateSpy = spyOnEvent(document, Smail.events.mail.tags.update);
+
+ this.component.displayMail({}, testData);
+ this.component.removeTag('inbox');
+
+ expect(updateSpy).toHaveBeenTriggeredOn(document);
+ });
+
+ it('verifies if new tag input is hidden when rendering mail view', function() {
+
+ this.component.displayMail({}, testData);
+
+ var newTagInputComponent = this.component.select('newTagInput');
+ expect(newTagInputComponent.attr('style').trim()).toEqual('display: none;');
+ });
+
+ it('verifies if new tag input is shown when clicking on new tag button ', function() {
+ this.component.displayMail({}, testData);
+
+ var newTagInputComponent = this.component.select('newTagInput');
+ var addNewComponent = this.component.select('addNew');
+
+ this.component.select('newTagButton').click();
+
+ expect(newTagInputComponent.attr('style').trim()).not.toEqual('display: none;');
+ expect(addNewComponent.attr('style').trim()).toEqual('display: none;');
+ });
+
+ it('hides new tag button when pressing esc key', function(){
+ this.component.displayMail({}, testData);
+ this.component.select('newTagButton').click();
+
+ var e = creatingEvent("keydown", 27);
+ var newTagInputComponent = this.component.select('newTagInput');
+ var addNewComponent = this.component.select('addNew');
+
+ newTagInputComponent.trigger(e);
+
+ expect(newTagInputComponent.attr('style').trim()).toEqual('display: none;');
+ expect(addNewComponent.attr('style').trim()).not.toEqual('display: none;');
+ });
+
+ it('assumes that the mail is encrypted and valid if at least one of the locks are valid', function() {
+ var email = testData;
+ email.security_casing = {locks: [{state: 'valid'}, {state: 'failure'}]};
+ expect(this.component.checkEncrypted(email)).toEqual('encrypted encryption-valid');
+ });
+
+ it('assumes that the mail is encrypted and failure if all the locks are failed', function() {
+ var email = testData;
+ email.security_casing = {locks: [{state: 'failure'}, {state: 'failure'}]};
+ expect(this.component.checkEncrypted(email)).toEqual('encrypted encryption-failure');
+ });
+
+ it('assumes that the mail is not encrypted if it doesn\'t have any locks', function() {
+ var email = testData;
+ email.security_casing = {locks: []};
+ expect(this.component.checkEncrypted(email)).toEqual('not-encrypted');
+ });
+
+ it('assumes that the mail is signed only if all imprints are valid', function() {
+ var email = testData;
+ email.security_casing = {imprints: [{state: 'valid', seal: {trust: 'marginal', validity: 'marginal'}}, {state: 'valid', seal: {trust: 'marginal', validity: 'marginal'}}]};
+ expect(this.component.checkSigned(email)).toEqual('signed');
+ });
+
+ it('assumes that the mail is signed with failures if there is a revoke or expire', function() {
+ var email = testData;
+ email.security_casing = {imprints: [{state: 'valid', seal: {trust: 'marginal', validity: 'marginal'}}, {state: 'from_revoked', seal: {trust: 'marginal', validity: 'marginal'}}]};
+ expect(this.component.checkSigned(email)).toEqual('signed signature-revoked');
+ });
+
+ it('assumes that mail is not trusted if its signature contains no_trust from the user', function() {
+ var email = testData;
+ email.security_casing = {imprints: [{seal: {trust: "no_trust", validity: "ultimate"}}]};
+ expect(this.component.checkSigned(email)).toEqual('signed signature-not-trusted');
+ });
+
+ it('uses validity when trust is not present', function() {
+ var email = testData;
+ email.security_casing = {imprints: [{seal: { validity: "no_trust"}}]};
+ expect(this.component.checkSigned(email)).toEqual('signed signature-not-trusted');
+ });
+
+ it('assumes not trusted when the signature is not found', function(){
+ var email = testData;
+ email.security_casing = {imprints: [{seal: null}]};
+ expect(this.component.checkSigned(email)).toEqual('signed signature-not-trusted');
+ });
+
+ it('assumes that the mail is not signed if there are no imprints', function() {
+ var email = testData
+ email.security_casing = {imprints: []}
+ expect(this.component.checkSigned(email)).toEqual('not-signed');
+ });
+
+ it('shows that mail is encrypted if it is', function() {
+ spyOn(this.component, 'checkEncrypted').andReturn('encrypted');
+ this.component.displayMail({}, testData);
+ expect(this.component.$node.find('.encrypted')).toExist();
+ });
+
+ it('shows that mail is signed if it is', function() {
+ spyOn(this.component, 'checkSigned').andReturn('signed');
+ this.component.displayMail({}, testData);
+ expect(this.component.$node.find('.signed')).toExist();
+ });
+
+ it('shows that mail is not encrypted if it isn\'t', function() {
+ spyOn(this.component, 'checkEncrypted').andReturn('not-encrypted');
+ this.component.displayMail({}, testData);
+ expect(this.component.$node.find('.not-encrypted')).toExist();
+ });
+
+ it('shows that mail is not signed if it isn\'t', function() {
+ spyOn(this.component, 'checkEncrypted').andReturn('not-signed');
+ this.component.displayMail({}, testData);
+ expect(this.component.$node.find('.not-signed')).toExist();
+ });
+
+ it('creates new tag when pressing Enter key on new tag input', function(){
+ var tagsUpdateEvent = spyOnEvent(document, Smail.events.mail.tags.update);
+ var tagListRefreshEvent = spyOnEvent(document, Smail.events.dispatchers.tags.refreshTagList);
+ var e = creatingEvent("keydown", 13);
+
+ this.component.displayMail({}, testData);
+ this.component.select('newTagButton').click();
+
+ var newTagInputComponent = this.component.select('newTagInput');
+ newTagInputComponent.val('Test');
+ newTagInputComponent.trigger(e);
+
+ var tags = testData.mail.tags.slice();
+ tags.push('Test');
+
+ expect(tagListRefreshEvent).toHaveBeenTriggeredOn(document);
+ expect(tagsUpdateEvent).toHaveBeenTriggeredOnAndWith(document, { ident: testData.mail.ident, tags: tags});
+ });
+
+ it('trigger mail delete event when moving email to trash', function(){
+ var mailDeleteEvent = spyOnEvent(document, Smail.events.ui.mail.delete);
+
+ Foundation.global.namespace = '';
+ $(document).foundation();
+
+ this.component.displayMail({}, testData);
+ this.component.moveToTrash();
+
+ expect(mailDeleteEvent).toHaveBeenTriggeredOnAndWith(document, { mail: this.component.attr.mail });
+ });
+
+ it('shows no message selected pane when deleting the email being composed', function() {
+ var openNoMessageSelectedPaneEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+ var mails = [{ident: 123}];
+ this.component.attr.mail = mails[0];
+
+ this.component.trigger(document, Smail.events.mail.deleted, {mails: mails});
+
+ expect(openNoMessageSelectedPaneEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('does not show no message selected pane when deleting a different set of emails', function() {
+ var openNoMessageSelectedPaneEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+ var mails = [{ident: 321}];
+ this.component.attr.mail = {ident: 123};
+
+ this.component.trigger(document, Smail.events.mail.deleted, {mails: mails});
+
+ expect(openNoMessageSelectedPaneEvent).not.toHaveBeenTriggeredOn(document);
+ });
+
+ describe('archiving email', function() {
+ it('trigger tag updates events with no tags', function(){
+ var tagsUpdateEvent = spyOnEvent(document, Smail.events.mail.tags.update);
+
+ Foundation.global.namespace = '';
+ $(document).foundation();
+
+ this.component.displayMail({}, testData);
+ this.component.archiveIt();
+
+ expect(tagsUpdateEvent).toHaveBeenTriggeredOnAndWith(document, { ident: testData.mail.ident, tags: []});
+ });
+
+ it('opens no message selected pane', function() {
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ Foundation.global.namespace = '';
+ $(document).foundation();
+
+ this.component.displayMail({}, testData);
+ this.component.archiveIt();
+
+ expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ it('opens the no message selected pane when clicking the close button', function() {
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ this.component.displayMail({}, testData);
+ this.component.select('closeMailButton').click();
+
+ expect(openNoMessageSelectedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ function creatingEvent(event, keyCode) {
+ var e = $.Event(event);
+ e.which = keyCode;
+ return e;
+ }
+});
diff --git a/web-ui/test/spec/mail_view/ui/recipients/recipients.spec.js b/web-ui/test/spec/mail_view/ui/recipients/recipients.spec.js
new file mode 100644
index 00000000..692bf0eb
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/recipients/recipients.spec.js
@@ -0,0 +1,36 @@
+/* global Smail */
+
+describeComponent('mail_view/ui/recipients/recipients',function () {
+ 'use strict';
+ var recipientsUpdatedEvent;
+
+ describe('initialization', function() {
+ it('adds recipients', function() {
+ setupComponent({name: 'to', addresses: ['foobar@gmail.com'] });
+ expect(this.component.attr.recipients.length).toBe(1);
+ });
+
+ it('does not trigger recipients updated events on initialization', function() {
+ recipientsUpdatedEvent = spyOnEvent(document, Smail.events.ui.recipients.updated);
+
+ setupComponent({name: 'to', addresses: ['foobar@gmail.com'] });
+ expect(recipientsUpdatedEvent).not.toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('adding recipients from the ui', function() {
+ beforeEach(function () {
+ setupComponent();
+ recipientsUpdatedEvent = spyOnEvent(document, Smail.events.ui.recipients.updated);
+ this.component.trigger(Smail.events.ui.recipients.entered, {name: 'to', addresses: ['foobar@gmail.com'] });
+ });
+
+ it('triggers recipients updated', function() {
+ expect(recipientsUpdatedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('adds recipients', function() {
+ expect(this.component.attr.recipients.length).toBe(1);
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/recipients/recipients_input.spec.js b/web-ui/test/spec/mail_view/ui/recipients/recipients_input.spec.js
new file mode 100644
index 00000000..0f98d007
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/recipients/recipients_input.spec.js
@@ -0,0 +1,104 @@
+/* global Smail */
+
+describeComponent('mail_view/ui/recipients/recipients_input',function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent({name: 'to'});
+ });
+
+ describe('keys that finish address input', function () {
+
+ _.each([
+ [186, 'semicolon'],
+ [188, 'comma'],
+ [32, 'space']
+
+ ], function (keycode) {
+
+ it(': ' + keycode[1], function () {
+ var addressEnteredEvent = spyOnEvent(this.$node, Smail.events.ui.recipients.entered);
+
+ var enterAddressKeyPressEvent = $.Event('keydown', { which: keycode[0] });
+ this.$node.val('a@b.c');
+ this.$node.trigger(enterAddressKeyPressEvent);
+
+ expect(addressEnteredEvent).toHaveBeenTriggeredOnAndWith(this, { name: 'to', address: 'a@b.c' });
+ });
+
+ it('wont add address if val is empty: ' + keycode[1], function () {
+ var addressEnteredEvent = spyOnEvent(this.$node, Smail.events.ui.recipients.entered);
+
+ var enterAddressKeyPressEvent = $.Event('keydown', { which: keycode[0] });
+ this.$node.val('');
+ this.$node.trigger(enterAddressKeyPressEvent);
+
+ expect(addressEnteredEvent).not.toHaveBeenTriggeredOnAndWith(this, { name: 'to', address: '' });
+ });
+
+ it('prevents event default regardless on input val when key is ' + keycode[1], function () {
+ var enterAddressKeyPressEvent = $.Event('keydown', { which: keycode[0] });
+ spyOn(enterAddressKeyPressEvent, 'preventDefault');
+
+ this.$node.val('')
+ this.$node.trigger(enterAddressKeyPressEvent);
+ expect(enterAddressKeyPressEvent.preventDefault).toHaveBeenCalled();
+
+ enterAddressKeyPressEvent.preventDefault.reset();
+ this.$node.val('anything')
+ this.$node.trigger(enterAddressKeyPressEvent);
+ expect(enterAddressKeyPressEvent.preventDefault).toHaveBeenCalled();
+ });
+
+ });
+
+ describe('when tab is pressed', function () {
+ it('enters an address and prevents event default if there is an input val', function () {
+ var addressEnteredEvent = spyOnEvent(this.$node, Smail.events.ui.recipients.entered);
+
+ var tabKeyPressEvent = $.Event('keydown', { which: 9});
+ spyOn(tabKeyPressEvent, 'preventDefault');
+
+ this.$node.val('a@b.c');
+ this.$node.trigger(tabKeyPressEvent);
+
+ expect(tabKeyPressEvent.preventDefault).toHaveBeenCalled();
+ expect(addressEnteredEvent).toHaveBeenTriggeredOnAndWith(this, { name: 'to', address: 'a@b.c'});
+ });
+
+ it('doesnt enter an address and doesnt prevent event default if input val is empty (so tab moves it to the next input)', function () {
+ var addressEnteredEvent = spyOnEvent(this.$node, Smail.events.ui.recipients.entered);
+
+ var tabKeyPressEvent = $.Event('keydown', { which: 9});
+ spyOn(tabKeyPressEvent, 'preventDefault');
+
+ this.$node.val('');
+ this.$node.trigger(tabKeyPressEvent);
+
+ expect(tabKeyPressEvent.preventDefault).not.toHaveBeenCalled();
+ expect(addressEnteredEvent).not.toHaveBeenTriggeredOnAndWith(this, { name: 'to', address: ''});
+ });
+ });
+ });
+
+ describe('on keyup', function () {
+ it('triggers inputHasNoMail if input is empty', function () {
+ var inputHasNoMailEvent = spyOnEvent(document, Smail.events.ui.recipients.inputHasNoMail);
+ this.$node.val('');
+
+ this.$node.trigger('keyup');
+
+ expect(inputHasNoMailEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('triggers inputHasMail if input is not empty', function () {
+ var inputHasMailEvent = spyOnEvent(document, Smail.events.ui.recipients.inputHasMail);
+ this.$node.val('lalala');
+
+ this.$node.trigger('keyup');
+
+ expect(inputHasMailEvent).toHaveBeenTriggeredOn(document, { name: 'to' });
+ });
+ });
+
+});
diff --git a/web-ui/test/spec/mail_view/ui/recipients/recipients_iterator.spec.js b/web-ui/test/spec/mail_view/ui/recipients/recipients_iterator.spec.js
new file mode 100644
index 00000000..480ea256
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/recipients/recipients_iterator.spec.js
@@ -0,0 +1,101 @@
+/* global Smail */
+
+define(['mail_view/ui/recipients/recipients_iterator'], function (RecipientsIterator) {
+ 'use strict';
+
+ function createRecipient() {
+ return jasmine.createSpyObj('recipient', ['select', 'unselect', 'destroy']);
+ }
+
+ var recipientsIterator,
+ exitInput;
+
+ function createIterator(elements) {
+ return recipientsIterator = new RecipientsIterator({ elements: elements, exitInput: exitInput });
+ }
+
+ function resetMock(m) {
+ m.destroy.reset();m.select.reset();m.unselect.reset();
+ }
+
+ beforeEach(function () {
+ exitInput = $('<input>');
+ });
+
+ describe('moving left', function () {
+ it('unselects the current element and selects the element in the left if there is one', function () {
+ var elements = _.times(2, createRecipient);
+
+ recipientsIterator = createIterator(elements);
+ recipientsIterator.moveLeft();
+
+ expect(elements[0].select).toHaveBeenCalled();
+ expect(elements[1].unselect).toHaveBeenCalled();
+ });
+
+ it('doesnt do anything if there are no elements in the left', function () {
+ var elements = _.times(2, createRecipient);
+ recipientsIterator = createIterator(elements);
+ recipientsIterator.moveLeft();
+ _.each(elements, resetMock);
+
+ recipientsIterator.moveLeft();
+
+ expect(elements[0].select).not.toHaveBeenCalled();
+ expect(elements[0].unselect).not.toHaveBeenCalled();
+ expect(elements[1].select).not.toHaveBeenCalled();
+ expect(elements[1].unselect).not.toHaveBeenCalled();
+ });
+
+ });
+
+ describe('moving right', function () {
+ it('unselects the current element and selects the one in the right if there is one', function () {
+ var elements = _.times(2, createRecipient);
+ recipientsIterator = createIterator(elements);
+ recipientsIterator.moveLeft();
+ _.each(elements, resetMock);
+
+ recipientsIterator.moveRight();
+
+ expect(elements[0].unselect).toHaveBeenCalled();
+ expect(elements[1].select).toHaveBeenCalled();
+ });
+
+ it('unselects current element and focus on exit input if there are no elements on the right', function () {
+ var elements = _.times(2, createRecipient);
+ spyOn(exitInput, 'focus');
+
+ recipientsIterator = createIterator(elements);
+ recipientsIterator.moveRight();
+
+ expect(elements[1].unselect).toHaveBeenCalled();
+ expect(exitInput.focus).toHaveBeenCalled();
+ });
+ });
+
+ describe('delete current', function () {
+ it('selects what is left in the right after deleting the current element', function () {
+ var elements = _.times(2, createRecipient);
+ var toBeDeleted = elements[0];
+ recipientsIterator = createIterator(elements);
+ recipientsIterator.moveLeft();
+
+ recipientsIterator.deleteCurrent();
+
+ expect(toBeDeleted.destroy).toHaveBeenCalled();
+ expect(elements[0].select).toHaveBeenCalled();
+ });
+
+ it('focus on the input if there are no more elements', function () {
+ recipientsIterator = createIterator([createRecipient()]);
+ spyOn(exitInput, 'focus');
+
+ recipientsIterator.deleteCurrent();
+
+ expect(exitInput.focus).toHaveBeenCalled();
+ });
+ });
+
+
+}); \ No newline at end of file
diff --git a/web-ui/test/spec/mail_view/ui/reply_box.spec.js b/web-ui/test/spec/mail_view/ui/reply_box.spec.js
new file mode 100644
index 00000000..c6db4de3
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/reply_box.spec.js
@@ -0,0 +1,105 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('mail_view/ui/reply_box', function () {
+ 'use strict';
+
+ var attrs, i18n;
+ beforeEach(function () {
+ attrs = {
+ mail: Smail.testData().parsedMail.simpleTextPlain
+ };
+ setupComponent(attrs);
+ i18n = require('views/i18n');
+ });
+
+ describe('reply compose box', function() {
+ it('should display subject of the reply', function() {
+ expect(this.component.select('subjectDisplay').text()).toBe(i18n('Re: ') + attrs.mail.header.subject);
+ });
+
+ it('should show recipient fields when clicking on recipient display', function() {
+ this.component.select('recipientsDisplay').click();
+
+ expect(this.component.select('recipientsFields')).not.toBeHidden();
+ expect(this.component.select('recipientsDisplay')).toBeHidden();
+ });
+
+ it('should show subject field when clicking on subject display', function() {
+ this.component.select('subjectDisplay').click();
+
+ expect(this.component.select('subjectInput')).not.toBeHidden();
+ expect(this.component.select('subjectDisplay')).toBeHidden();
+ });
+
+ it('should use the from field when Reply-To header does not exist', function() {
+ attrs.mail.header.reply_to = undefined;
+
+ setupComponent(attrs);
+
+ expect(this.component.attr.recipientValues['to']).toEqual([attrs.mail.header.from]);
+ });
+
+ it('should have a subject of Re: <original_message>', function() {
+ attrs.mail.header.subject = 'Very interesting';
+
+ setupComponent(attrs);
+
+ expect(this.component.select('subjectDisplay').text()).toEqual(i18n('Re: ')+ attrs.mail.header.subject);
+ });
+
+ it('should use set In-Reply-To header when Message-Id header is set', function() {
+ var mailSendEvent = spyOnEvent(document, Smail.events.mail.send);
+
+ attrs.mail.header.message_id = '12345';
+ setupComponent(attrs);
+
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(mailSendEvent).toHaveBeenTriggeredOn(document);
+ expect(mailSendEvent.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ in_reply_to: '12345'
+ }));
+ });
+
+ it('keeps the List-Id header when it exists', function() {
+ var mailSendEvent = spyOnEvent(document, Smail.events.mail.send);
+ attrs.mail.header.list_id = 'somelist';
+
+ setupComponent(attrs);
+ $(document).trigger(Smail.events.ui.mail.send);
+
+ expect(mailSendEvent.mostRecentCall.data.header).toEqual(jasmine.objectContaining({
+ list_id: 'somelist'
+ }));
+ });
+
+ it('populates body text area with quote of email being replied', function() {
+ var viewHelper = require('helpers/view_helper');
+ spyOn(viewHelper, 'quoteMail').andReturn('quoted email');
+
+ setupComponent(attrs);
+
+ expect(viewHelper.quoteMail).toHaveBeenCalledWith(attrs.mail);
+ expect(this.component.select('bodyBox').val()).toBe('quoted email');
+ });
+
+ it('triggers mail when cancelling a reply', function () {
+ var mailSaveEvent = spyOnEvent(document, Smail.events.mail.save);
+
+ this.component.select('trashButton').click();
+
+ expect(mailSaveEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('reopens the mail after the reply is sent', function () {
+ var mailOpenEvent = spyOnEvent(document, Smail.events.ui.mail.open);
+
+ this.component.trigger(document, Smail.events.mail.sent);
+
+ expect(mailOpenEvent).toHaveBeenTriggeredOnAndWith(document, {
+ ident: this.component.attr.mail.ident
+ });
+ });
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/reply_section.spec.js b/web-ui/test/spec/mail_view/ui/reply_section.spec.js
new file mode 100644
index 00000000..e5571e2c
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/reply_section.spec.js
@@ -0,0 +1,97 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('mail_view/ui/reply_section', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ describe('clicking reply buttons', function() {
+ var mailWantEvent, expectEventData;
+
+ beforeEach(function () {
+ mailWantEvent = spyOnEvent(document, Smail.events.mail.want);
+ expectEventData = {
+ mail: '12345',
+ caller: this.component
+ };
+ this.component.attr.ident = '12345';
+ });
+
+ it('should ask for email when clicking on reply button', function() {
+ this.component.select('replyButton').click();
+
+ expect(mailWantEvent).toHaveBeenTriggeredOnAndWith(document, expectEventData);
+ });
+
+ it('should ask for email when clicking on replyAll button', function() {
+ this.component.select('replyAllButton').click();
+
+ expect(mailWantEvent).toHaveBeenTriggeredOnAndWith(document, expectEventData);
+ });
+ });
+
+ describe('creating reply box when getting email back', function() {
+ var mailData, ReplyBox, ForwardBox;
+
+ beforeEach(function () {
+ mailData = Smail.testData().mail;
+ ReplyBox = require('mail_view/ui/reply_box');
+ ForwardBox = require('mail_view/ui/forward_box');
+ spyOn(ReplyBox, 'attachTo');
+ spyOn(ForwardBox, 'attachTo');
+ });
+
+ it('for normal reply', function() {
+ this.component.attr.replyType = 'reply';
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mailData });
+
+ expect(ReplyBox.attachTo).toHaveBeenCalledWith(jasmine.any(Object), {
+ mail: mailData,
+ replyType: 'reply'
+ });
+ });
+
+ it('for reply to all', function() {
+ this.component.attr.replyType = 'replyall';
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mailData });
+
+ expect(ReplyBox.attachTo).toHaveBeenCalledWith(jasmine.any(Object), {
+ mail: mailData,
+ replyType: 'replyall'
+ });
+ });
+
+ it('creates a forward box', function() {
+ this.component.attr.replyType = 'forward';
+ this.component.trigger(this.component, Smail.events.mail.here, { mail: mailData });
+
+ expect(ForwardBox.attachTo).toHaveBeenCalledWith(jasmine.any(Object), {
+ mail: mailData
+ });
+ });
+ });
+
+ it('hides the buttons when clicked', function() {
+ this.component.attr.mailIdent = 12345;
+
+ this.component.select('replyButton').click();
+
+ expect(this.component.select('replyButton')).toBeHidden();
+ expect(this.component.select('replyAllButton')).toBeHidden();
+ expect(this.component.select('forwardButton')).toBeHidden();
+ });
+
+ it('shows the buttons when reply is cancelled', function() {
+ this.component.attr.mailIdent = 12345;
+ this.component.select('replyButton').click();
+
+ $(document).trigger(Smail.events.ui.composeBox.trashReply);
+
+ expect(this.component.select('replyButton')).not.toBeHidden();
+ expect(this.component.select('replyAllButton')).not.toBeHidden();
+ expect(this.component.select('forwardButton')).not.toBeHidden();
+ });
+});
diff --git a/web-ui/test/spec/mail_view/ui/send_button.spec.js b/web-ui/test/spec/mail_view/ui/send_button.spec.js
new file mode 100644
index 00000000..27bee0f3
--- /dev/null
+++ b/web-ui/test/spec/mail_view/ui/send_button.spec.js
@@ -0,0 +1,91 @@
+describeComponent('mail_view/ui/send_button', function () {
+
+ describe('send button', function () {
+ beforeEach(function () {
+ setupComponent('<button />');
+ });
+
+ describe('when it is disabled', function () {
+ beforeEach(function () {
+ this.$node.prop('disabled', true);
+ });
+
+ it('gets enabled in a inputHasMail event', function () {
+ $(document).trigger(Smail.events.ui.recipients.inputHasMail, { name: 'to' });
+
+ expect(this.$node).not.toBeDisabled();
+ });
+
+ it('gets enabled in a recipients:updated where there are new recipients', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, { newRecipients: ['a@b.c']});
+
+ expect(this.$node).not.toBeDisabled();
+ });
+ });
+
+ describe('multiple events', function () {
+ it('gets enabled and remains enabled when a inputHasMail is followed by a recipients:updated with NO new recipients', function () {
+ this.$node.prop('disabled', true);
+
+ $(document).trigger(Smail.events.ui.recipients.inputHasMail, { name: 'to' });
+ $(document).trigger(Smail.events.ui.recipients.updated, { newRecipients: [] });
+
+ expect(this.$node).not.toBeDisabled();
+ });
+
+ it('gets enabled and remains enabled when a recipients:updated with recipients is followed by a inputHasNoMail', function () {
+ this.$node.prop('disabled', true);
+
+ $(document).trigger(Smail.events.ui.recipients.updated, { newRecipients: ['a@b.c']});
+ $(document).trigger(Smail.events.ui.recipients.inputHasNoMail, { name: 'to' });
+
+ expect(this.$node).not.toBeDisabled();
+ });
+ });
+
+ describe('when it is enabled', function () {
+ beforeEach(function () {
+ this.$node.prop('disabled', false);
+ });
+
+ it('gets disabled in a inputHasNoMail', function () {
+ $(document).trigger(Smail.events.ui.recipients.inputHasNoMail, { name: 'to' });
+
+ expect(this.$node).toBeDisabled();
+ });
+
+ it('gets disabled in a recipients:updated without new recipients', function () {
+ $(document).trigger(Smail.events.ui.recipients.updated, { newRecipients: []});
+
+ expect(this.$node).toBeDisabled();
+ });
+ });
+
+ describe('on click', function () {
+
+ it ('asks for the recipients input to complete its current input', function () {
+ var doCompleteInputEvent = spyOnEvent(document, Smail.events.ui.recipients.doCompleteInput);
+
+ this.$node.click();
+
+ expect(doCompleteInputEvent).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('after clicking', function () {
+ beforeEach(function () {
+ this.$node.click();
+ });
+
+ it('waits for ui:mail:recipientsUpdated to happen 3 times in the mail then sends the mail then stops listening to ui:mail:recipientsUpdated', function () {
+ var sendMailEvent = spyOnEvent(document, Smail.events.ui.mail.send);
+ spyOn(this.component, 'off');
+
+ _.times(3, function () { $(document).trigger(Smail.events.ui.mail.recipientsUpdated) });;
+
+ expect(sendMailEvent).toHaveBeenTriggeredOn(document);
+ expect(this.component.off).toHaveBeenCalledWith(document, Smail.events.ui.mail.recipientsUpdated);
+ });
+ });
+ });
+});
diff --git a/web-ui/test/spec/mixins/with_mail_edit_base.spec.js b/web-ui/test/spec/mixins/with_mail_edit_base.spec.js
new file mode 100644
index 00000000..43d3b7cd
--- /dev/null
+++ b/web-ui/test/spec/mixins/with_mail_edit_base.spec.js
@@ -0,0 +1,94 @@
+/*global Smail */
+/*global jasmine */
+/*global runs */
+/*global waits */
+
+describeMixin('mixins/with_mail_edit_base', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent();
+ // Stubing mixing wrongly!!! 'deprecated' while waiting for draft component extraction
+ this.component.buildMail = function (tag) {
+ return { header: { to: ['a@smth.com'], from: 'b@smth.com', subject: 'Sbject' } };
+ };
+ });
+
+ describe('initialization', function() {
+ it('should enable send button when rendering with recipients', function() {
+ var enableSendButtonEvent = spyOnEvent(document, Smail.events.ui.sendbutton.enable);
+
+ this.component.render(function() {}, {
+ recipients: { to: ['foobar@mail.com'], cc: [] }
+ });
+
+ expect(enableSendButtonEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('should not enable send button when rendering without recipients', function() {
+ var enableSendButtonEvent = spyOnEvent(document, Smail.events.ui.sendbutton.enable);
+
+ this.component.render(function() {}, {
+ recipients: { to: [], cc: [] }
+ });
+
+ expect(enableSendButtonEvent).not.toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('when the user is typing in subject or body', function() {
+ beforeEach(function () {
+ this.component.attr.saveDraftInterval = 10;
+ });
+
+ it('saves the draft after the save draft interval number of seconds', function() {
+ var saveDraftSpy = spyOnEvent(document, Smail.events.mail.saveDraft);
+ runs(function () {
+ this.component.monitorInput();
+ expect(saveDraftSpy).not.toHaveBeenTriggeredOn(document);
+ });
+ waits(10);
+ runs(function () {
+ expect(saveDraftSpy).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ it('does not save if mail is sent before the save draft interval number of seconds', function() {
+ var saveDraftSpy = spyOnEvent(document, Smail.events.mail.saveDraft);
+ runs(function () {
+ this.component.monitorInput();
+ this.component.sendMail();
+ });
+ waits(10);
+ runs(function () {
+ expect(saveDraftSpy).not.toHaveBeenTriggeredOn(document);
+ });
+ });
+ });
+
+ describe('when a mail is sent', function () {
+ it('displays a message of mail sent', function () {
+ var spy = spyOnEvent(document, Smail.events.ui.userAlerts.displayMessage);
+ this.component.trigger(document, Smail.events.mail.sent);
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('when user asks to trash the mail', function() {
+ it('triggers mail delete for this mail', function() {
+ var spy = spyOnEvent(document, Smail.events.mail.save);
+ this.component.trashMail();
+ expect(spy).toHaveBeenTriggeredOn(document);
+ });
+ });
+
+ describe('when recipients are updated', function () {
+ it('triggers an event to let the send button know that the recipients in the mail are updated', function () {
+ var uiMailRecipientsUpdated = spyOnEvent(document, Smail.events.ui.mail.recipientsUpdated);
+
+ $(document).trigger(Smail.events.ui.recipients.updated, {recipientsName: 'to', newRecipients: ['fox@somewhere.com']});
+
+ expect(uiMailRecipientsUpdated).toHaveBeenTriggeredOn(document);
+ });
+ });
+});
diff --git a/web-ui/test/spec/page/pane_contract_expand.spec.js b/web-ui/test/spec/page/pane_contract_expand.spec.js
new file mode 100644
index 00000000..803f688c
--- /dev/null
+++ b/web-ui/test/spec/page/pane_contract_expand.spec.js
@@ -0,0 +1,67 @@
+/*global Smail */
+/*global afterEach */
+
+'use strict';
+
+describeComponent('page/pane_contract_expand', function () {
+
+ var fixture;
+
+ beforeEach(function () {
+ fixture = $('<div>')
+ .append($('<div>', { id: 'middle-pane-container' }))
+ .append($('<div>', { id: 'right-pane' }));
+
+ $('body').append(fixture);
+
+
+ });
+
+ afterEach(function () {
+ fixture.remove();
+ });
+
+ describe('after initialization', function () {
+ beforeEach(function () {
+ setupComponent(document);
+ });
+
+ it('contracts middle pane and expands right pane on mail open', function () {
+ $(document).trigger(Smail.events.ui.mail.open);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_CONTRACT_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_EXPAND_CLASSES);
+ });
+
+ it('contracts middle pane and expands right pane on open compose box', function () {
+ $(document).trigger(Smail.events.dispatchers.rightPane.openComposeBox);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_CONTRACT_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_EXPAND_CLASSES);
+ });
+
+ it('contracts middle pane and expands right pane on open draft', function () {
+ $(document).trigger(Smail.events.dispatchers.rightPane.openDraft);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_CONTRACT_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_EXPAND_CLASSES);
+ });
+
+ it('expands middle pane and contracts right pane on event on open no message selected pane', function () {
+ $(document).trigger(Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_EXPAND_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_CONTRACT_CLASSES);
+ });
+ });
+
+ describe('on initialization', function () {
+ it('expands middle pane and contracts right pane', function () {
+ setupComponent(document);
+
+ expect($('#middle-pane-container').attr('class')).toEqual(this.component.attr.MIDDLE_PANE_EXPAND_CLASSES);
+ expect($('#right-pane').attr('class')).toEqual(this.component.attr.RIGHT_PANE_CONTRACT_CLASSES);
+ });
+ });
+
+});
diff --git a/web-ui/test/spec/page/router.spec.js b/web-ui/test/spec/page/router.spec.js
new file mode 100644
index 00000000..0b5b6b32
--- /dev/null
+++ b/web-ui/test/spec/page/router.spec.js
@@ -0,0 +1,70 @@
+/*global Smail */
+/*global jasmine */
+describeComponent('page/router', function () {
+ 'use strict';
+
+ var fakeHistory;
+
+ describe('on router:pushState coming from a tag selection', function () {
+ beforeEach(function () {
+ fakeHistory = jasmine.createSpyObj('history', ['pushState']);
+ setupComponent({history: fakeHistory});
+ });
+
+ it('pushes the state with the tag and the url', function () {
+ $(document).trigger(Smail.events.router.pushState, { tag: 'inbox'});
+
+ expect(fakeHistory.pushState).toHaveBeenCalledWith(jasmine.objectContaining({ tag: 'inbox' }), '', '/#/inbox');
+ });
+
+ it('pushes the state with mailIdent', function () {
+ $(document).trigger(Smail.events.router.pushState, { tag: 'inbox', mailIdent: 1});
+
+ expect(fakeHistory.pushState).toHaveBeenCalledWith(jasmine.objectContaining({ tag: 'inbox', mailIdent: 1 }), '', '/#/inbox/mail/1');
+ });
+
+ it('pushes the state with mailIdent even if mail ident is 0 (that happens for drafts)', function () {
+ $(document).trigger(Smail.events.router.pushState, { tag: 'inbox', mailIdent: 0});
+
+ expect(fakeHistory.pushState).toHaveBeenCalledWith(jasmine.objectContaining({ tag: 'inbox', mailIdent: 0 }), '', '/#/inbox/mail/0');
+ });
+
+ it('pushes the state with the displayNoMessage boolean forwarded from the event', function () {
+ $(document).trigger(Smail.events.router.pushState, { tag: 'inbox', mailIdent: 0});
+
+ expect(fakeHistory.pushState).toHaveBeenCalledWith(jasmine.objectContaining({ isDisplayNoMessageSelected: false}), '', '/#/inbox/mail/0');
+
+ $(document).trigger(Smail.events.router.pushState, { tag: 'inbox', mailIdent: 0, isDisplayNoMessageSelected: true});
+
+ expect(fakeHistory.pushState).toHaveBeenCalledWith(jasmine.objectContaining({ isDisplayNoMessageSelected: true}), '', '/#/inbox/mail/0');
+ });
+
+ it('when popping a state with no tag should select tag from url', function () {
+ var urlParams = require("page/router/url_params");
+ spyOn(urlParams, 'getTag').andReturn('tag');
+
+ var selectTagEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+
+ this.component.smailPopState({ state: {tag: undefined} });
+
+ expect(selectTagEvent).toHaveBeenTriggeredOnAndWith(document, jasmine.objectContaining({ tag: "tag"}))
+ });
+
+ it('when popping a state triggers the displayNoMessage pane if required', function () {
+ var urlParams = require("page/router/url_params");
+ spyOn(urlParams, 'getTag').andReturn('tag');
+
+ var displayNoMessageEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelectedWithoutPushState);
+
+ this.component.smailPopState({ state: {tag: undefined, isDisplayNoMessageSelected: false} });
+
+ expect(displayNoMessageEvent).not.toHaveBeenTriggeredOn(document)
+
+ this.component.smailPopState({ state: {tag: undefined, isDisplayNoMessageSelected: true} });
+
+ expect(displayNoMessageEvent).toHaveBeenTriggeredOn(document)
+ });
+
+ });
+
+});
diff --git a/web-ui/test/spec/page/router/url_params.spec.js b/web-ui/test/spec/page/router/url_params.spec.js
new file mode 100644
index 00000000..a14ba1ba
--- /dev/null
+++ b/web-ui/test/spec/page/router/url_params.spec.js
@@ -0,0 +1,68 @@
+require(['page/router/url_params'], function (urlParams) {
+
+ describe('urlParams', function () {
+
+ beforeEach(function () {
+ //preventing the hash change to fire the onpopstate event in other components
+ //in this case in the router component
+ window.onpopstate = function () {};
+ });
+
+ afterEach(function () {
+ document.location.hash = '';
+ });
+
+ describe('getTag', function () {
+ it('returns inbox if there is no tag in the url hash', function () {
+ expect(urlParams.getTag()).toEqual('inbox');
+ });
+
+ it('returns the tag in the hash if there is one', function () {
+ document.location.hash = '/Drafts';
+
+ expect(urlParams.getTag()).toEqual('Drafts');
+ });
+
+ it('returns tag with slash', function () {
+ document.location.hash = '/Events/2011';
+
+ expect(urlParams.getTag()).toEqual('Events/2011');
+ });
+
+ it('returns tag even if there is an mail ident', function () {
+ document.location.hash = '/Events/2011/mail/1';
+
+ expect(urlParams.getTag()).toEqual('Events/2011');
+ });
+
+ it('returns the tag even if there is a trailing slash', function () {
+ document.location.hash = '/Events/';
+
+ expect(urlParams.getTag()).toEqual('Events');
+ });
+ });
+
+ describe('hasMailIdent', function () {
+ it('is true if hash has mailIdent', function () {
+ document.location.hash = '/inbox/mail/1';
+
+ expect(urlParams.hasMailIdent()).toBeTruthy();
+ });
+
+ it('is false if hash has no mail ident', function () {
+ document.location.hash = '/Drafts';
+
+ expect(urlParams.hasMailIdent()).toBeFalsy();
+ });
+ });
+
+ describe('getMailIdent', function () {
+ it('returns the mail ident that is in the hash', function () {
+ document.location.hash = '/inbox/mail/123';
+
+ expect(urlParams.getMailIdent()).toEqual('123');
+ });
+ });
+ });
+
+});
diff --git a/web-ui/test/spec/search/search_trigger.spec.js b/web-ui/test/spec/search/search_trigger.spec.js
new file mode 100644
index 00000000..aaeba3b1
--- /dev/null
+++ b/web-ui/test/spec/search/search_trigger.spec.js
@@ -0,0 +1,78 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('search/search_trigger', function () {
+ 'use strict';
+ var self;
+
+ beforeEach(function () {
+ setupComponent();
+ self = this;
+ });
+
+ function submitSearch(queryString) {
+ self.component.select('input').val(queryString);
+ self.component.select('form').submit();
+ }
+
+ it('should trigger search when the submit occurs', function () {
+ var spy = spyOnEvent(document, Smail.events.search.perform);
+
+ submitSearch('tanana');
+ expect(spy).toHaveBeenTriggeredOnAndWith(document, { query: 'tanana' });
+ });
+
+ it('should select the "all" tag when submit occurs but should skip mail list refresh', function (){
+ var tagSelectEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+
+ submitSearch('tanana');
+
+ expect(tagSelectEvent).toHaveBeenTriggeredOnAndWith(document, {
+ tag: 'all',
+ skipMailListRefresh: true
+ });
+ });
+
+ it('should select the "all" tag when an empty submit occurs and shoud refresh mail list', function() {
+ var tagSelectEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+ var emptySearchEvent = spyOnEvent(document, Smail.events.search.empty);
+
+ submitSearch('');
+
+ expect(emptySearchEvent).toHaveBeenTriggeredOn(document);
+ expect(tagSelectEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'all'});
+
+ });
+
+ it('should clear input when selecting a new tag', function(){
+ submitSearch('tanana');
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'inbox'});
+ expect(self.component.select('input').val()).toBe('');
+ });
+
+ it('should add place holder on input value after doing a search', function(){
+ submitSearch('teste');
+ expect(self.component.select('input').val()).toBe('Search results for: teste');
+ });
+
+ it('should remove place holder on input value when input is on focus', function(){
+ submitSearch('teste');
+ this.component.select('input').focus();
+ expect(self.component.select('input').val()).toBe('teste');
+ });
+
+ it('should remove place holder on input value when input is not on focus', function(){
+ submitSearch('teste');
+ this.component.select('input').focus();
+ this.component.select('input').blur();
+ expect(self.component.select('input').val()).toBe('Search results for: teste');
+ });
+
+ it('should not change input value when input is empty', function(){
+ submitSearch('');
+ this.component.select('input').focus();
+ expect(self.component.select('input').val()).toBe('');
+ });
+
+
+});
diff --git a/web-ui/test/spec/services/delete_service.spec.js b/web-ui/test/spec/services/delete_service.spec.js
new file mode 100644
index 00000000..3e098877
--- /dev/null
+++ b/web-ui/test/spec/services/delete_service.spec.js
@@ -0,0 +1,54 @@
+/*global jasmine */
+/*global Smail */
+
+describeComponent('services/delete_service', function () {
+ 'use strict';
+
+ var i18n;
+
+ beforeEach( function () {
+ setupComponent();
+ i18n = require('views/i18n');
+ });
+
+ var mailWithoutTrashTag = {
+ ident: 42,
+ isInTrash: function() { return false; },
+ tags: ['inbox', 'test']
+ };
+
+ var mailWithTrashTag = {
+ ident: 34,
+ isInTrash: function() { return true; },
+ tags: ['inbox', 'test', 'trash']
+ };
+
+ it('add Trash tag when deleting an email that does not have it', function () {
+ var mailDeleteEvent = spyOnEvent(document, Smail.events.mail.delete);
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ this.component.trigger(document, Smail.events.ui.mail.delete, {mail: mailWithoutTrashTag});
+
+ var expectedDeleteEventData = {
+ mail: mailWithoutTrashTag,
+ successMessage: i18n('Your message was moved to trash!')
+ };
+
+ expect(mailDeleteEvent).toHaveBeenTriggeredOnAndWith(document, expectedDeleteEventData);
+ });
+
+ it('removes permanently email that has Trash tag', function(){
+ var mailDeleteEvent = spyOnEvent(document, Smail.events.mail.delete);
+ var openNoMessageSelectedEvent = spyOnEvent(document, Smail.events.dispatchers.rightPane.openNoMessageSelected);
+
+ this.component.trigger(document, Smail.events.ui.mail.delete, {mail: mailWithTrashTag});
+
+ var expectedDeleteEventData = {
+ mail: mailWithTrashTag,
+ successMessage: i18n('Your message was permanently deleted!')
+ };
+
+ expect(mailDeleteEvent).toHaveBeenTriggeredOnAndWith(document, expectedDeleteEventData );
+ });
+
+});
diff --git a/web-ui/test/spec/services/mail_service.spec.js b/web-ui/test/spec/services/mail_service.spec.js
new file mode 100644
index 00000000..31e130fa
--- /dev/null
+++ b/web-ui/test/spec/services/mail_service.spec.js
@@ -0,0 +1,307 @@
+/*global jasmine */
+/*global Smail */
+'use strict';
+
+describeComponent('services/mail_service', function () {
+
+ var email1, i18n;
+
+ beforeEach( function () {
+ setupComponent();
+ email1 = Smail.testData().parsedMail.simpleTextPlain;
+ i18n = require('views/i18n');
+ } );
+
+ it('marks the desired message as read', function () {
+ var readRequest = spyOn($, 'ajax').andReturn({});
+
+ this.component.trigger(Smail.events.mail.read, {ident: 1});
+
+ expect(readRequest.mostRecentCall.args[0]).toEqual('/mail/1/read');
+ });
+
+ describe('when marks many emails as read', function () {
+ var readRequest, checkedMails, uncheckedEmailsEvent, setCheckAllEvent, doneMarkAsRead;
+
+ beforeEach(function () {
+ readRequest = spyOn($, 'ajax').andReturn({done: function(f) { doneMarkAsRead = f; return {fail: function() {}};}});
+ uncheckedEmailsEvent = spyOnEvent(document, Smail.events.ui.mail.unchecked);
+ setCheckAllEvent = spyOnEvent(document, Smail.events.ui.mails.hasMailsChecked);
+ spyOn(this.component, 'refreshResults');
+
+ checkedMails = {
+ 1: {ident: 1},
+ 2: {ident: 2}
+ };
+
+ this.component.trigger(Smail.events.mail.read, {checkedMails: checkedMails});
+ });
+
+ it('makes the correct request to the backend', function () {
+ expect(readRequest.mostRecentCall.args[0]).toEqual('/mails/read');
+ expect(readRequest.mostRecentCall.args[1].data).toEqual({idents: '[1,2]'});
+ });
+
+ it('will trigger that a message has been deleted when it is done deleting', function() {
+ doneMarkAsRead({mails: checkedMails});
+ expect(this.component.refreshResults).toHaveBeenCalled();
+ });
+
+ it('unchecks read emails', function () {
+ doneMarkAsRead({mails: checkedMails});
+ expect(uncheckedEmailsEvent).toHaveBeenTriggeredOnAndWith(document, {mails: checkedMails});
+ });
+
+ it('clears the check all checkbox', function () {
+ doneMarkAsRead({mails: checkedMails});
+ expect(setCheckAllEvent).toHaveBeenTriggeredOnAndWith(document, false);
+ });
+ });
+
+ it('fetches a single email', function () {
+ var me = {};
+ var spyAjax = spyOn($, 'ajax').andReturn({done: function(f) { f(email1); return {fail: function() {}};}});
+ var mailHereEvent = spyOnEvent(me, Smail.events.mail.here);
+
+ this.component.trigger(Smail.events.mail.want, { caller: me, mail: email1.ident });
+
+ expect(mailHereEvent).toHaveBeenTriggeredOn(me);
+ expect(spyAjax.mostRecentCall.args[0]).toEqual('/mail/' + email1.ident);
+ });
+
+ it('answers mail:notFound if mail returned from server is null', function () {
+ var me = {};
+ var spyAjax = spyOn($, 'ajax').andReturn({done: function(f) { f(null); return {fail: function() {}};}});
+ var mailNotFound = spyOnEvent(me, Smail.events.mail.notFound);
+
+ this.component.trigger(Smail.events.mail.want, { caller: me, mail: email1.ident });
+
+ expect(mailNotFound).toHaveBeenTriggeredOn(me);
+ });
+
+ it('updates the tags of the desired message', function () {
+ spyOn(this.component, 'refreshResults');
+ var spyAjax = spyOn($, 'ajax').andReturn({done: function(f) { f(); return {fail: function() {}};}});
+
+ var spyEvent = spyOnEvent(document, Smail.events.mail.tags.updated);
+ var component = jasmine.createSpyObj('component',['successUpdateTags']);
+ spyOn(this.component, 'fetchMail');
+
+ this.component.trigger(Smail.events.mail.tags.update, { ident: email1.ident, tags: email1.tags });
+
+ expect(spyEvent).toHaveBeenTriggeredOn(document);
+ expect(spyAjax.calls[0].args[0]).toEqual('/mail/1/tags');
+ expect(spyAjax.calls[0].args[1].data).toEqual(JSON.stringify({ newtags: email1.tags } ));
+ expect(this.component.refreshResults).toHaveBeenCalled();
+ });
+
+ it('triggers an error message when it can\'t update the tags', function () {
+ var spyAjax = spyOn($, 'ajax').andReturn({done: function() { return {fail: function(f) {f();}};}});
+
+ var spyEvent = spyOnEvent(document, Smail.events.ui.userAlerts.displayMessage);
+ var component = jasmine.createSpyObj('component',['failureUpdateTags']);
+
+ this.component.trigger(Smail.events.mail.tags.update, { ident: email1.ident, tags: email1.tags });
+
+ expect(spyEvent).toHaveBeenTriggeredOn(document);
+ expect(spyAjax.mostRecentCall.args[0]).toEqual('/mail/1/tags');
+ expect(spyAjax.mostRecentCall.args[1].data).toEqual(JSON.stringify({ newtags: email1.tags } ));
+ });
+
+ it('will try to delete a message when requested to', function() {
+ var spyAjax = spyOn($, 'ajax').andReturn({done: function() { return {fail: function(f) {}};}});
+ this.component.trigger(Smail.events.mail.delete, {mail: {ident: '43'}});
+ expect(spyAjax).toHaveBeenCalled();
+ expect(spyAjax.mostRecentCall.args[0]).toEqual('/mail/43');
+ expect(spyAjax.mostRecentCall.args[1].type).toEqual('DELETE');
+ });
+
+ describe('when successfuly deletes an email', function () {
+ var displayMessageEvent, uncheckedEmailsEvent, setCheckAllEvent, mailsDeletedEvent;
+
+ beforeEach(function () {
+ displayMessageEvent = spyOnEvent(document, Smail.events.ui.userAlerts.displayMessage);
+ uncheckedEmailsEvent = spyOnEvent(document, Smail.events.ui.mail.unchecked);
+ setCheckAllEvent = spyOnEvent(document, Smail.events.ui.mails.hasMailsChecked);
+ mailsDeletedEvent = spyOnEvent(document, Smail.events.mail.deleted);
+ spyOn(this.component, 'refreshResults');
+
+ this.component.triggerDeleted({
+ successMessage: 'A success message',
+ mails: {1: 'email 1', 2: 'email 2'}
+ })();
+ });
+
+ it('will trigger that a message has been deleted when it is done deleting', function() {
+ expect(this.component.refreshResults).toHaveBeenCalled();
+ });
+
+ it('displays a success message', function () {
+ expect(displayMessageEvent).toHaveBeenTriggeredOnAndWith(document, {message: 'A success message'});
+ });
+
+ it('unchecks deleted emails', function () {
+ expect(uncheckedEmailsEvent).toHaveBeenTriggeredOnAndWith(document, { mails: {1: 'email 1', 2: 'email 2'} });
+ });
+
+ it('tells about deleted emails', function () {
+ expect(mailsDeletedEvent).toHaveBeenTriggeredOnAndWith(document, { mails: {1: 'email 1', 2: 'email 2'} });
+ });
+
+ it('clears the check all checkbox', function () {
+ expect(setCheckAllEvent).toHaveBeenTriggeredOnAndWith(document, false);
+ });
+ });
+
+ it('will trigger an error message when a message cannot be deleted', function() {
+ spyOn($, 'ajax').andReturn({done: function() { return {fail: function(f) { f(); }};}});
+ var spyEvent = spyOnEvent(document, Smail.events.ui.userAlerts.displayMessage);
+
+ this.component.trigger(Smail.events.mail.delete, {mail: {ident: '43'}});
+
+ expect(spyEvent).toHaveBeenTriggeredOnAndWith(document, {message: i18n('Could not delete email')} );
+ });
+
+ it('triggers mails:available with received mails and keeps that tag as the current tag', function() {
+ var g;
+ var eventSpy = spyOnEvent(document, Smail.events.mails.available);
+
+ spyOn($, 'ajax').andReturn({done: function(f) { g = f; return {fail: function(){}};}});
+ this.component.trigger(Smail.events.ui.mails.fetchByTag, {tag: 'inbox'});
+
+ g({stats: {}, mails: [email1]});
+ expect(eventSpy.mostRecentCall.data.stats).toEqual({});
+ expect(eventSpy.mostRecentCall.data.tag).toEqual('inbox');
+ expect(this.component.attr.currentTag).toEqual('inbox');
+ });
+
+ it('wraps the tag in quotes before fetching by tag (to support tags with spaces)', function () {
+ spyOn($, 'ajax').andReturn({done: function(f) { return {fail: function(){}};}});
+
+ this.component.trigger(Smail.events.ui.mails.fetchByTag, {tag: 'new tag'});
+
+ expect($.ajax.mostRecentCall.args[0]).toContain(encodeURI('tag:"new tag"'));
+ });
+
+ it('sends the previous tag when mails:refresh is called without a tag (this happens when the refresher calls it)', function () {
+ var g;
+ var eventSpy = spyOnEvent(document, Smail.events.mails.availableForRefresh);
+ this.component.attr.currentTag = 'sent';
+
+ spyOn($, 'ajax').andReturn({done: function(f) { g = f; return {fail: function(){}};}});
+ this.component.trigger(Smail.events.ui.mails.refresh);
+
+ g({stats: {}, mails: [email1]});
+ expect(eventSpy.mostRecentCall.data.tag).toEqual('sent');
+ expect(eventSpy.mostRecentCall.data.stats).toEqual({});
+ });
+
+ describe('pagination', function() {
+ var pageChangedEvent;
+ var g;
+
+ beforeEach(function () {
+ pageChangedEvent = spyOnEvent(document, Smail.events.ui.page.changed);
+ spyOn($, 'ajax').andReturn({done: function(f) {
+ g = f;
+ return {fail: function(){}};
+ }});
+ spyOn(this.component, 'fetchMail').andCallThrough();
+ });
+
+ it('changes to the previous page and refetch email when ui:page:previous is fired', function() {
+ this.component.attr.currentPage = 1;
+
+ this.component.trigger(Smail.events.ui.page.previous);
+
+ expect(this.component.fetchMail).toHaveBeenCalled();
+ expect(this.component.attr.currentPage).toEqual(0);
+ });
+
+ it('won\'t change the page if it was already at the first page and trying to go to previous', function() {
+ this.component.attr.currentPage = 0;
+
+ this.component.trigger(Smail.events.ui.page.previous);
+
+ expect(this.component.fetchMail).not.toHaveBeenCalled();
+ expect(this.component.attr.currentPage).toEqual(0);
+ });
+
+ it('changes to the next page and refetch email when ui:page:next is fired', function() {
+ this.component.attr.numPages = 10;
+ this.component.attr.currentPage = 1;
+
+ this.component.trigger(Smail.events.ui.page.next);
+
+ expect(this.component.fetchMail).toHaveBeenCalled();
+ expect(this.component.attr.currentPage).toEqual(2);
+ });
+
+ it('won\'t change the page if it was already at the first page and trying to go to previous', function() {
+ this.component.attr.numPages = 10;
+ this.component.attr.currentPage = 9;
+
+ this.component.trigger(Smail.events.ui.page.next);
+
+ expect(this.component.fetchMail).not.toHaveBeenCalled();
+ expect(this.component.attr.currentPage).toEqual(9);
+ });
+
+
+ it('triggers pageChanged event when going to next page', function() {
+ this.component.attr.numPages = 10;
+ this.component.trigger(Smail.events.ui.page.next);
+
+ expect(pageChangedEvent).toHaveBeenTriggeredOnAndWith(document, {currentPage: 1, numPages: 10});
+ });
+
+ it('triggers pageChanged event when going to previous page', function() {
+ this.component.attr.numPages = 10;
+ this.component.attr.currentPage = 1;
+ this.component.trigger(Smail.events.ui.page.previous);
+
+ expect(pageChangedEvent).toHaveBeenTriggeredOnAndWith(document, {currentPage: 0, numPages: 10});
+ });
+
+ it('resets currentPage when fetching mails by tag', function() {
+ this.component.attr.numPages = 10;
+ this.component.attr.currentPage = 999;
+ this.component.trigger(Smail.events.ui.mails.fetchByTag, {tag: 'inbox'});
+
+ expect(this.component.attr.currentPage).toEqual(0);
+ expect(pageChangedEvent).toHaveBeenTriggeredOnAndWith(document, {currentPage: 0, numPages: 10});
+ });
+
+ describe('total page numbers', function() {
+ var mailSetData = {
+ tag: 'inbox',
+ stats: { },
+ mails: [],
+ timing: {}
+ };
+
+ it('should have 5 pages with a 100 results and w 20', function() {
+ mailSetData.stats.total = 100;
+ this.component.attr.w = 20;
+ this.component.attr.numPages = 0;
+
+ this.component.trigger(Smail.events.ui.mails.fetchByTag, {tag: 'another tag'});
+
+ g(mailSetData);
+ expect(this.component.attr.numPages).toBe(5);
+ });
+
+ it('should have 6 pages with a 101 results and w 20', function() {
+ mailSetData.stats.total = 101;
+ this.component.attr.w = 20;
+ this.component.attr.numPages = 0;
+
+ this.component.trigger(Smail.events.ui.mails.fetchByTag, {tag: 'another tag'});
+
+ g(mailSetData);
+ expect(this.component.attr.numPages).toBe(6);
+ });
+ });
+
+ });
+});
diff --git a/web-ui/test/spec/services/model/mail.spec.js b/web-ui/test/spec/services/model/mail.spec.js
new file mode 100644
index 00000000..5bdad88b
--- /dev/null
+++ b/web-ui/test/spec/services/model/mail.spec.js
@@ -0,0 +1,116 @@
+/*global Smail */
+
+require(['services/model/mail'], function (Mail) {
+ var testData;
+
+ describe('services/model/mail', function () {
+ describe('reply addresses', function () {
+ it('returns the "to" and "cc" addresses if the mail was sent', function () {
+ var mail = Mail.create({
+ header: { to: ['a@b.c', 'e@f.g'], cc: ['x@x.x'] },
+ tags: ['sent']
+ });
+
+ var addresses = mail.replyToAddress();
+
+ expect(addresses).toEqual({ to: ['a@b.c', 'e@f.g'], cc: ['x@x.x']});
+ });
+ });
+
+ describe('parsing', function () {
+ describe('a single email', function () {
+ var sentMail, draftMail, recievedMail, recievedMailWithCC;
+ beforeEach(function () {
+ sentMail = Mail.create(Smail.testData().rawMail.sent);
+ draftMail = Mail.create(Smail.testData().rawMail.draft);
+ recievedMail = Mail.create(Smail.testData().rawMail.recieved);
+ recievedMailWithCC = Mail.create(Smail.testData().rawMail.recievedWithCC);
+ });
+
+ it('correctly identifies a sent mail', function () {
+ expect(sentMail.isSentMail()).toBe(true);
+ });
+
+ it('correctly identifies a draft mail', function () {
+ expect(draftMail.isDraftMail()).toBe(true);
+ });
+
+ it('correctly identifies a recieved mail', function () {
+ expect(recievedMail.isSentMail()).toBe(false);
+ expect(recievedMail.isDraftMail()).toBe(false);
+ });
+
+ it('reply to of a sent mail should be original recipient', function () {
+ expect(sentMail.replyToAddress()).toEqual({to: ['mariane_dach@davis.info'], cc: ['duda@la.lu']});
+ });
+
+ it('reply to of a mail should be the reply_to field if existent', function () {
+ expect(recievedMail.replyToAddress()).toEqual({to: ['afton_braun@botsford.biz'], cc: [] });
+ });
+
+ it('reply to of a mail should be the from field if no reply_to present', function () {
+ expect(recievedMailWithCC.replyToAddress()).toEqual({to: ['cleve_jaskolski@schimmelhirthe.net'], cc: []});
+ });
+
+ it('reply to all should include all email addresses in the header', function () {
+ expect(recievedMailWithCC.replyToAllAddress()).toEqual({
+ to: ['cleve_jaskolski@schimmelhirthe.net', 'stanford@sipes.com'],
+ cc: ['mariane_dach@davis.info']
+ });
+ });
+ });
+
+ describe('multipart email', function () {
+ var parsedMultipartMail;
+
+ beforeEach(function () {
+ parsedMultipartMail = Mail.create(Smail.testData().rawMail.multipart);
+ });
+
+ it('parses the mail as multipart/alternative', function () {
+ expect(parsedMultipartMail.isMailMultipartAlternative()).toBe(true);
+ });
+
+ it('lists the correct available content-type of the parts', function () {
+ expect(parsedMultipartMail.availableBodyPartsContentType()).toEqual(['text/plain;', 'text/html;']);
+ });
+
+ it('gets the list of parts', function () {
+ var expectedParts = [
+ {
+ headers: { 'Content-Type': 'text/plain;' },
+ body: 'Hello everyone!\n'
+ },
+ {
+ headers: {
+ 'Content-Type': 'text/html;',
+ 'Content-Transfer-Encoding': 'quoted-printable'
+ },
+ body: '<p><b>Hello everyone!</b></p>\n'
+ }
+ ];
+
+ expect(parsedMultipartMail.getMailMultiParts()).toEqual(expectedParts);
+ });
+
+ it('gets the text/plain body by the content-type', function () {
+ expect(parsedMultipartMail.getMailPartByContentType('text/plain;')).toEqual(
+ {
+ headers: { 'Content-Type': 'text/plain;' },
+ body: 'Hello everyone!\n'
+ });
+ });
+
+ it('parses the content type of a text/html body', function () {
+ expect(parsedMultipartMail.getMailPartByContentType('text/html;')).toEqual({
+ headers: {
+ 'Content-Type': 'text/html;',
+ 'Content-Transfer-Encoding': 'quoted-printable'
+ },
+ body: '<p><b>Hello everyone!</b></p>\n'
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/web-ui/test/spec/tags/data/tags.spec.js b/web-ui/test/spec/tags/data/tags.spec.js
new file mode 100644
index 00000000..8e7d33c3
--- /dev/null
+++ b/web-ui/test/spec/tags/data/tags.spec.js
@@ -0,0 +1,39 @@
+describeComponent('tags/data/tags', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ it('asks the server for tags when receiving the tags:want event', function() {
+ spyOn($, 'ajax').andReturn({done: function() {}});
+
+ this.component.trigger(Smail.events.tags.want);
+
+ expect($.ajax.mostRecentCall.args[0]).toEqual('/tags');
+ });
+
+ it('triggers an event on the initial sender after receiving tags', function() {
+ var f;
+ spyOn($, 'ajax').andReturn({done: function(d) { f = d; }});
+ var me = {};
+ var eventSpy = spyOnEvent(me, Smail.events.tags.received);
+
+ this.component.trigger(Smail.events.tags.want, { caller: me});
+
+ f(['foo', 'bar', 'quux/bar']);
+ expect(eventSpy).toHaveBeenTriggeredOn(me);
+ });
+
+ it('triggers an event containing the returned tags', function() {
+ var f;
+ spyOn($, 'ajax').andReturn({done: function(d) { f = d; }});
+ var me = {};
+ var eventSpy = spyOnEvent(me, Smail.events.tags.received);
+ this.component.trigger(Smail.events.tags.want, { caller: me });
+ var tags = ['foo', 'bar', 'quux/bar'];
+ f(tags);
+ tags.push(this.component.all);
+ expect(eventSpy.mostRecentCall.data).toEqual({tags: tags});
+ });
+});
diff --git a/web-ui/test/spec/tags/ui/tag.spec.js b/web-ui/test/spec/tags/ui/tag.spec.js
new file mode 100644
index 00000000..12f16330
--- /dev/null
+++ b/web-ui/test/spec/tags/ui/tag.spec.js
@@ -0,0 +1,151 @@
+/*global Smail */
+/*global _ */
+
+describeComponent('tags/ui/tag', function () {
+ 'use strict';
+
+ describe('inbox tag', function() {
+ beforeEach(function () {
+ setupComponent('<li></li>', {
+ tag: {
+ name: 'inbox',
+ ident: '1',
+ counts: {
+ total: 100,
+ read: 0
+ }
+ }
+ });
+ });
+
+ it('selects the tag on click', function () {
+ var tagSelectEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+ var cleanSelectedEvent = spyOnEvent(document, Smail.events.ui.mails.cleanSelected);
+
+ this.component.$node.click();
+
+ expect(this.component.attr.selected).toBeTruthy();
+ expect(this.$node.attr('class')).toMatch('selected');
+ expect(tagSelectEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'inbox' });
+ expect(cleanSelectedEvent).toHaveBeenTriggeredOn(document);
+ });
+
+ it('should remove selected class when selecting a different tag', function () {
+ this.$node.click();
+
+ $(document).trigger(Smail.events.ui.tag.select, {tag: 'drafts'});
+
+ expect(this.$node).not.toHaveClass('selected');
+ });
+
+ it('triggers tag selected on tag select', function () {
+ var tagSelectedEvent = spyOnEvent(document, Smail.events.ui.tag.select);
+
+ $(document).trigger(Smail.events.ui.tag.select, { tag: 'drafts'});
+
+ expect(tagSelectedEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'drafts'});
+ });
+
+ it('increases the read count when there is an email read and the email has that tag', function () {
+ $(document).trigger(Smail.events.mail.read, { tags: ['inbox'] });
+
+ expect(this.component.attr.tag.counts.read).toEqual(1);
+ expect(this.$node.html()).toMatch('<span class="unread-count">99</span>');
+ });
+
+ it('doesnt increase the read count when the read email doesnt have the tag', function () {
+ $(document).trigger(Smail.events.mail.read, { tags: ['amazing']});
+
+ expect(this.component.attr.tag.counts.read).toEqual(0);
+ expect(this.$node.html()).not.toMatch('<span class="unread-count">99</span>');
+ });
+
+ it('doesnt display the unread count when there are no unreads', function () {
+ this.component.attr.tag.counts.read = 100;
+ $(document).trigger(Smail.events.mail.read, { tags: ['inbox']});
+ expect(this.$node.html()).not.toMatch('"unread-count"');
+ });
+ });
+
+ describe('drafts tag', function () {
+ var containerFordrafts;
+ beforeEach(function () {
+ setupComponent('<li></li>', {
+ tag: {
+ name: 'drafts',
+ ident: '42',
+ counts: {
+ total: 100,
+ read: 50
+ }
+ }
+ });
+ });
+
+ it('shows the total count instead of the unread count', function () {
+ $(document).trigger(Smail.events.mail.read, { tags: ['drafts']});
+ expect(this.$node.html()).toMatch('<span class="total-count">100</span>');
+ expect(this.$node.html()).not.toMatch('"unread-count"');
+ });
+ });
+
+ describe('all tag', function(){
+ beforeEach(function () {
+ setupComponent('<li></li>', {
+ tag: {
+ name: 'all',
+ ident: '45',
+ counts: {
+ total: 100,
+ read: 50
+ }
+ }
+ });
+ });
+
+ it('adds searching class when user is doing a search', function(){
+ $(document).trigger(Smail.events.search.perform, {});
+ expect(this.$node.attr('class')).toMatch('searching');
+ });
+
+ it('removes searching class when user searches for empty string', function(){
+ $(document).trigger(Smail.events.search.perform, {});
+ $(document).trigger(Smail.events.search.empty);
+ expect(this.$node.attr('class')).not.toMatch('searching');
+ });
+
+ it('removes searching class when user clicks in any tag', function(){
+ $(document).trigger(Smail.events.search.perform, {});
+ this.$node.click();
+ expect(this.$node.attr('class')).not.toMatch('searching');
+ });
+
+ });
+
+ _.each(['sent', 'trash'], function(tag_name) {
+ describe(tag_name + ' tag', function() {
+ beforeEach(function () {
+ setupComponent('<li></li>', {
+ tag: {
+ name: tag_name,
+ ident: '42',
+ counts: {
+ total: 100,
+ read: 50
+ }
+ }
+ });
+ });
+
+ it('doesn\'t display unread count for special folder', function () {
+ $(document).trigger(Smail.events.mail.read, { tags: [tag_name]});
+ expect(this.$node.html()).not.toMatch('unread-count');
+ });
+
+ it('doesn\'t display read count for special folder', function () {
+ $(document).trigger(Smail.events.mail.read, { tags: [tag_name]});
+ expect(this.$node.html()).not.toMatch('total-count');
+ });
+ });
+ });
+});
diff --git a/web-ui/test/spec/tags/ui/tag_list.spec.js b/web-ui/test/spec/tags/ui/tag_list.spec.js
new file mode 100644
index 00000000..af3ddd3a
--- /dev/null
+++ b/web-ui/test/spec/tags/ui/tag_list.spec.js
@@ -0,0 +1,75 @@
+describeComponent('tags/ui/tag_list', function () {
+ 'use strict';
+
+ var tag = function(name, ident, def) {
+ def = def || false;
+ return {name: name, counts: {read: 0, total: 0, replied: 0, starred: 0}, ident: ident, default: def};
+ };
+
+
+ describe('post initialization', function() {
+ beforeEach(function () {
+ setupComponent();
+ });
+
+ it('should render tags when tagsList:load is received', function() {
+ this.component.attr.default = false;
+ var tagList = [tag('tag1', 1), tag('tag2', 2), tag('tag3', 3)];
+
+ $(document).trigger(Smail.events.ui.tagList.load, {tags: tagList});
+
+ var items = _.map(this.$node.find('li'), function(el) {
+ return $(el).attr('id');
+ });
+
+ expect(items).toEqual(['tag-1', 'tag-2', 'tag-3']);
+ });
+
+ it('should render the default tags when tagsList:load is received and default attribute is true', function() {
+ var tagList = [tag('tag1', 1, false), tag('tag2', 2, true), tag('tag3', 3, true)];
+
+ $(document).trigger(Smail.events.ui.tagList.load, {tags: tagList});
+
+ var items = _.map(this.component.select('defaultTagList').find('li'), function(el) {
+ return $(el).attr('id');
+ });
+
+ expect(items).toEqual(['tag-2', 'tag-3']);
+ });
+
+ it('should render the custom tags when tagsList:load is received and default attribute is false', function() {
+ var tagList = [tag('tag1', 1, false), tag('tag2', 2, true), tag('tag3', 3, true)];
+
+ $(document).trigger(Smail.events.ui.tagList.load, {tags: tagList});
+
+ var items = _.map(this.component.select('customTagList').find('li'), function(el) {
+ return $(el).attr('id');
+ });
+
+ expect(items).toEqual(['tag-1']);
+ });
+
+ it('should trigger event to tell that tags were loaded sending the current tag', function () {
+ this.component.attr.currentTag = 'Drafts';
+ var tagsLoadedEvent = spyOnEvent(document, Smail.events.ui.tags.loaded);
+
+ $(document).trigger(Smail.events.ui.tagList.load, {tags: [] });
+
+ expect(tagsLoadedEvent).toHaveBeenTriggeredOnAndWith(document, { tag: 'Drafts'});
+ });
+
+ it('should send tag as undefined when tags are loaded and no tag was selected yet', function () {
+ var tagsLoadedEvent = spyOnEvent(document, Smail.events.ui.tags.loaded);
+
+ $(document).trigger(Smail.events.ui.tagList.load, {tags: [] });
+
+ expect(tagsLoadedEvent).toHaveBeenTriggeredOnAndWith(document, { tag: undefined });
+ });
+
+ it('should save the current tag when a tag is selected', function () {
+ $(document).trigger(Smail.events.ui.tag.selected, { tag: 'amazing'});
+
+ expect(this.component.attr.currentTag).toEqual('amazing');
+ });
+ });
+});
diff --git a/web-ui/test/spec/tags/ui/tag_shortcut.spec.js b/web-ui/test/spec/tags/ui/tag_shortcut.spec.js
new file mode 100644
index 00000000..7df35631
--- /dev/null
+++ b/web-ui/test/spec/tags/ui/tag_shortcut.spec.js
@@ -0,0 +1,35 @@
+describeComponent("tags/ui/tag_shortcut", function () {
+
+ var parent, shortcut, component, TagShortcut;
+
+ beforeEach(function () {
+ TagShortcut = require('tags/ui/tag_shortcut');
+
+ component = jasmine.createSpyObj('tagComponent', ['triggerSelect']);
+ parent = $("<ul>");
+ shortcut = TagShortcut.appendedTo(parent, { linkTo: { name: 'inbox', counts: { total: 15 }}, trigger: component });
+ });
+
+ it('renders the shortcut inside the parent', function () {
+ expect(parent.html()).toMatch('<a title="inbox">');
+ expect(parent.html()).toMatch('<i class="fa fa-inbox"></i>');
+ expect(parent.html()).toMatch('<div class="shortcut-label">inbox</div>');
+ });
+
+ it('selects and unselect on tag.select', function () {
+ $(document).trigger(Smail.events.ui.tag.select, { tag: 'inbox'});
+
+ expect(shortcut.$node).toHaveClass("selected");
+
+ $(document).trigger(Smail.events.ui.tag.select, { tag: 'sent'});
+
+ expect(shortcut.$node).not.toHaveClass("selected");
+ });
+
+ it('delegates the click to linked tag', function (){
+ shortcut.$node.click();
+
+ expect(component.triggerSelect).toHaveBeenCalled();
+ });
+
+});
diff --git a/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js b/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js
new file mode 100644
index 00000000..f013b744
--- /dev/null
+++ b/web-ui/test/spec/user_alerts/ui/user_alerts.spec.js
@@ -0,0 +1,23 @@
+describeComponent('user_alerts/ui/user_alerts', function () {
+ 'use strict';
+
+ beforeEach(function () {
+ setupComponent('<div id="userAlerts"></div>', { dismissTimeout: 100 });
+ });
+
+ it('should render message when ui:user_alerts:displayMessage is triggered', function () {
+ this.component.trigger(Smail.events.ui.userAlerts.displayMessage, { message: 'a message' });
+
+ expect(this.component.$node.html()).toMatch('a message');
+ });
+
+ it('should be emptied and hidden when hide is called', function() {
+ expect(this.$node).not.toBeHidden();
+ this.component.hide()
+ expect(this.$node).toBeHidden();
+ expect(this.$node.html()).toEqual('')
+ });
+
+
+
+});
diff --git a/web-ui/test/test-main.js b/web-ui/test/test-main.js
new file mode 100644
index 00000000..e07d292c
--- /dev/null
+++ b/web-ui/test/test-main.js
@@ -0,0 +1,57 @@
+'use strict';
+
+var tests = Object.keys(window.__karma__.files).filter(function (file) {
+ return (/\.spec\.js$/.test(file));
+});
+
+requirejs.config({
+
+ baseUrl: '/base',
+
+ paths: {
+ 'page': 'app/js/page',
+ 'js': 'app/js',
+ 'lib': 'app/js/lib',
+ 'hbs': 'app/js/generated/hbs',
+ 'flight': 'app/bower_components/flight',
+ 'views': 'app/js/views',
+ 'helpers': 'app/js/helpers',
+ 'tags': 'app/js/tags',
+ 'mail_list': 'app/js/mail_list',
+ 'mail_list_actions': 'app/js/mail_list_actions',
+ 'user_alerts': 'app/js/user_alerts',
+ 'mail_view': 'app/js/mail_view',
+ 'dispatchers': 'app/js/dispatchers',
+ 'mixins': 'app/js/mixins',
+ 'services': 'app/js/services',
+ 'search': 'app/js/search',
+ 'monkey_patching': 'app/js/monkey_patching',
+ 'i18next': 'app/bower_components/i18next/i18next.amd',
+ 'quoted-printable': 'app/bower_components/quoted-printable',
+ 'test': 'test'
+ },
+
+
+ deps: tests,
+
+ callback: function () {
+ require(['page/events','test/test_data', 'views/i18n', 'monkey_patching/array', 'views/recipientListFormatter'], function (events, testData, i18n, mp, recipientListFormatter) {
+ window['Smail'] = window['Smail'] || {};
+ window['Smail'].events = events;
+ window['Smail'].testData = testData;
+ window['Smail'].mockBloodhound = function() {
+ window.Bloodhound = function() {};
+ window.Bloodhound.prototype.initialize = function() {};
+ window.Bloodhound.prototype.ttAdapter = function() {};
+ window.Bloodhound.prototype.clear = function() {};
+ window.Bloodhound.prototype.clearPrefetchCache = function() {};
+ window.Bloodhound.prototype.clearRemoteCache = function() {};
+ $.fn.typeahead = function() {};
+ };
+
+ i18n.init('/base/app/');
+ // start test run, once Require.js is done
+ window.__karma__.start();
+ });
+ }
+});
diff --git a/web-ui/test/test_data.js b/web-ui/test/test_data.js
new file mode 100644
index 00000000..8c7b6f21
--- /dev/null
+++ b/web-ui/test/test_data.js
@@ -0,0 +1,170 @@
+/*global _ */
+'use strict';
+
+define(function() {
+ var rawMail = {
+ header: {
+ to:'jed_waelchi@cummerata.info',
+ from:'laurel@hamill.info',
+ subject:'Velit aut tempora animi ut nulla esse.',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident:2048,
+ tags:['gang_family','garden','nailartaddicts','inbox'],
+ status:[],
+ body: 'Porro quam minus. Doloribus odio vel. Placeat alias sed est assumenda qui esse. Tenetur tempora deserunt est consequatur ducimus laborum. Velit dolor voluptatibus.\n\nRerum repellendus tempore. Aliquam dolores laudantium amet et dolor voluptas. Quod eos magni mollitia et ex. Corrupti quis reprehenderit quasi. Quam cum nobis voluptas accusamus quisquam ut asperiores.\n\nFacilis dicta mollitia non molestiae. Eligendi perspiciatis aut qui eos qui. Laborum cumque odit velit nobis. Cumque quo impedit dignissimos quia.',
+ security_casing: {
+ locks: [],
+ imprints: []
+ }
+ };
+
+ var rawSentMail = {
+ 'header':{'to':'mariane_dach@davis.info', 'cc': 'duda@la.lu', 'from':'afton_braun@botsford.biz','subject':'Consectetur sit omnis veniam blanditiis.','date':'2014-06-17T11:56:53-03:00'},
+ 'ident':9359,
+ 'tags':['sent','photography','sky'],
+ 'status':['read'],
+ 'body':'Illum eos nihil commodi voluptas. Velit consequatur odio quibusdam. Beatae aliquam hic quos.'
+ };
+
+ var rawDraftMail = {
+ 'header':{'to':'mariane_dach@davis.info','from':'afton_braun@botsford.biz','subject':'Consectetur sit omnis veniam blanditiis.','date':'2014-06-17T11:56:53-03:00'},
+ 'ident':9360,
+ 'tags':['drafts','photography','sky'],
+ 'status':['read'],
+ 'body':'Illum eos nihil commodi voluptas. Velit consequatur odio quibusdam. Beatae aliquam hic quos.'
+ };
+
+ var rawRecievedMail = {
+ 'header':{'to':'stanford@sipes.com','from':'cleve_jaskolski@schimmelhirthe.net','reply_to':'afton_braun@botsford.biz','subject':'Cumque pariatur vel consequuntur deleniti ex.','date':'2014-06-17T05:40:29-03:00'},
+ 'ident':242,
+ 'tags':['garden','instalovers','popularpic'],
+ 'status':['read'],
+ 'body':'Sed est neque tempore. Alias officiis pariatur ullam porro corporis. Tempore eum quia placeat. Sapiente fuga cum.'
+ };
+
+ var rawRecievedWithCCMail = {
+ 'header':{'to':'stanford@sipes.com','from':'cleve_jaskolski@schimmelhirthe.net','cc':'mariane_dach@davis.info','subject':'Cumque pariatur vel consequuntur deleniti ex.','date':'2014-06-17T05:40:29-03:00'},
+ 'ident':242,
+ 'tags':['garden','instalovers','popularpic'],
+ 'status':['read'],
+ 'body':'Sed est neque tempore. Alias officiis pariatur ullam porro corporis. Tempore eum quia placeat. Sapiente fuga cum.'
+ };
+
+ var rawMultipartMail = {
+ header: {
+ to:'multipart@multipart.info',
+ from:'laurel@hamill.info',
+ subject:'multipart email with text/plain and text/html',
+ content_type: 'multipart/alternative; boundary=asdfghjkl',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident: 11,
+ tags:['multipart','inbox'],
+ status:[],
+ body: '--asdfghjkl\n' +
+ 'Content-Type: text/plain;\n' +
+ '\n' +
+ 'Hello everyone!\n' +
+ '--asdfghjkl\n' +
+ 'Content-Type: text/html;\n' +
+ 'Content-Transfer-Encoding: quoted-printable\n' +
+ '\n' +
+ '<p><b>Hello everyone!</b></p>\n' +
+ '--asdfghjkl--\n'
+ };
+
+ var simpleTextPlainMail = {
+ header: {
+ to:'jed_waelchi@cummerata.info',
+ from:'laurel@hamill.info',
+ subject:'Velit aut tempora animi ut nulla esse.',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident:1,
+ tags:['textplain','inbox'],
+ status:[],
+ body: 'Porro quam minus. Doloribus odio vel. Placeat alias sed est assumenda qui esse. Tenetur tempora deserunt est consequatur ducimus laborum. Velit dolor voluptatibus.\n\nRerum repellendus tempore. Aliquam dolores laudantium amet et dolor voluptas. Quod eos magni mollitia et ex. Corrupti quis reprehenderit quasi. Quam cum nobis voluptas accusamus quisquam ut asperiores.\n\nFacilis dicta mollitia non molestiae. Eligendi perspiciatis aut qui eos qui. Laborum cumque odit velit nobis. Cumque quo impedit dignissimos quia.',
+ isSentMail: function() { return false; },
+ isDraftMail: function() { return false; },
+ replyToAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ replyToAllAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ isMailMultipartAlternative: function() { return false; },
+ availableBodyPartsContentType: function() { return []; },
+ getMailPartByContentType: function() { return; }
+ };
+
+ var htmlNoEncodingMail = {
+ header: {
+ to:'jed_waelchi@cummerata.info',
+ from:'laurel@hamill.info',
+ subject:'Velit aut tempora animi ut nulla esse.',
+ content_type: 'multipart/alternative; boundary=asdfghjkl',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident:2,
+ tags:['html','noencoding','inbox'],
+ status:[],
+ body: '--asdfghjkl\nContent-Type: text/html; charset=utf8\n\n<DOCTYPE html>\n<body> <div> <p>Hello everyone!</p> </div> </body>\n--asdfghjkl--\n',
+ isSentMail: function() { return false; },
+ isDraftMail: function() { return false; },
+ replyToAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ replyToAllAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ isMailMultipartAlternative: function () { return true; },
+ availableBodyPartsContentType: function () { return ['text/html']; },
+ getMailPartByContentType: function () {
+ return {
+ headers: { 'Content-Type': 'text/html; charset=utf-8' },
+ body: '<!DOCTYPE html> <body> <div> <p>Hello everyone!</p> </div> </body>'
+ };
+ }
+ };
+
+ var htmlQuotedPrintableMail = {
+ header: {
+ to:'jed_waelchi@cummerata.info',
+ from:'laurel@hamill.info',
+ subject:'Velit aut tempora animi ut nulla esse.',
+ content_type: 'multipart/alternative; boundary=asdfghjkl',
+ date:'2014-06-04T14:41:13-03:00'
+ },
+ ident:3,
+ tags:['html','quotedprintable','inbox'],
+ status:[],
+ body: '--asdfghjkl\nContent-Type: text/html; charset=utf8\nContent-Transfer-Encoding: quoted-printable\n\n<DOCTYPE html>\n<body> <div style=3D"border: 5px;"> <p>Hello everyone!</p> </div> </body>\n--asdfghjkl--\n',
+ isSentMail: function() { return false; },
+ isDraftMail: function() { return false; },
+ replyToAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ replyToAllAddress: function() { return { to: ['laurel@hamill.info'], cc: [] }; },
+ isMailMultipartAlternative: function () { return true; },
+ availableBodyPartsContentType: function () { return ['text/html']; },
+ getMailPartByContentType: function () {
+ return {
+ headers: {
+ 'Content-Type': 'text/html; charset=utf-8',
+ 'Content-Transfer-Encoding': 'quoted-printable'},
+ body: '<!DOCTYPE html> <body> <div> <p style=3D"border: 5px;">Hello everyone!</p> </div> </body>'
+ };
+ }
+ };
+
+ var testData = {
+ rawMail: {
+ mail: rawMail,
+ sent: rawSentMail,
+ draft: rawDraftMail,
+ recieved: rawRecievedMail,
+ recievedWithCC: rawRecievedWithCCMail,
+ multipart: rawMultipartMail
+ },
+ parsedMail: {
+ simpleTextPlain: simpleTextPlainMail,
+ html: htmlNoEncodingMail,
+ htmlQuotedPrintable: htmlQuotedPrintableMail
+ }
+ };
+
+ return function () {
+ return _.cloneDeep(testData);
+ };
+});