diff options
author | Ola Bini <ola.bini@gmail.com> | 2014-07-31 19:29:33 -0300 |
---|---|---|
committer | Ola Bini <ola.bini@gmail.com> | 2014-07-31 19:29:33 -0300 |
commit | 04cf441c5ae18400c6b4865b0b37a71718dc9d46 (patch) | |
tree | dd0b0d049ec00389e2d4561b226c46eb1682b997 /web-ui/test/spec | |
parent | 639a663a4c37020003586438fdcd7ac529a00f10 (diff) |
Add web-ui based on previous code
Diffstat (limited to 'web-ui/test/spec')
37 files changed, 3290 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('') + }); + + + +}); |