mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 12:40:08 +08:00
afe77b27fb
Summary: Replaces `new Notification`-based HTML5 notifications with system native notifications on Mac OS X. This allows us to implement the "Reply" button in the notifications. This will also serve as the hook for native Windows notifications, which are unsupported in Chromium. Test Plan: Run tests Reviewers: evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2199
275 lines
9.9 KiB
CoffeeScript
275 lines
9.9 KiB
CoffeeScript
_ = require 'underscore'
|
|
Contact = require '../../../src/flux/models/contact'
|
|
Message = require '../../../src/flux/models/message'
|
|
Thread = require '../../../src/flux/models/thread'
|
|
Label = require '../../../src/flux/models/label'
|
|
CategoryStore = require '../../../src/flux/stores/category-store'
|
|
DatabaseStore = require '../../../src/flux/stores/database-store'
|
|
AccountStore = require '../../../src/flux/stores/account-store'
|
|
SoundRegistry = require '../../../src/sound-registry'
|
|
NativeNotifications = require '../../../src/native-notifications'
|
|
Main = require '../lib/main'
|
|
|
|
describe "UnreadNotifications", ->
|
|
beforeEach ->
|
|
Main.activate()
|
|
|
|
inbox = new Label(id: "l1", name: "inbox", displayName: "Inbox")
|
|
archive = new Label(id: "l2", name: "archive", displayName: "Archive")
|
|
|
|
spyOn(CategoryStore, "getStandardCategory").andReturn inbox
|
|
|
|
@threadA = new Thread
|
|
labels: [inbox]
|
|
@threadB = new Thread
|
|
labels: [archive]
|
|
|
|
@msg1 = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "A"
|
|
@msgNoSender = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: []
|
|
subject: "Hello World"
|
|
threadId: "A"
|
|
@msg2 = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Mark', email: 'mark@example.com')]
|
|
subject: "Hello World 2"
|
|
threadId: "A"
|
|
@msg3 = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "A"
|
|
@msg4 = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "A"
|
|
@msg5 = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "A"
|
|
@msgUnreadButArchived = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Mark', email: 'mark@example.com')]
|
|
subject: "Hello World 2"
|
|
threadId: "B"
|
|
@msgRead = new Message
|
|
unread: false
|
|
date: new Date()
|
|
from: [new Contact(name: 'Mark', email: 'mark@example.com')]
|
|
subject: "Hello World Read Already"
|
|
threadId: "A"
|
|
@msgOld = new Message
|
|
unread: true
|
|
date: new Date(2000,1,1)
|
|
from: [new Contact(name: 'Mark', email: 'mark@example.com')]
|
|
subject: "Hello World Old"
|
|
threadId: "A"
|
|
@msgFromMe = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [AccountStore.current().me()]
|
|
subject: "A Sent Mail!"
|
|
threadId: "A"
|
|
|
|
spyOn(DatabaseStore, 'find').andCallFake (klass, id) =>
|
|
return Promise.resolve(@threadA) if id is 'A'
|
|
return Promise.resolve(@threadB) if id is 'B'
|
|
return Promise.resolve(null)
|
|
|
|
spyOn(NativeNotifications, 'displayNotification').andCallFake ->
|
|
spyOn(Promise, 'props').andCallFake (dict) ->
|
|
dictOut = {}
|
|
for key, val of dict
|
|
if val.value?
|
|
dictOut[key] = val.value()
|
|
else
|
|
dictOut[key] = val
|
|
Promise.resolve(dictOut)
|
|
|
|
afterEach ->
|
|
Main.deactivate()
|
|
|
|
it "should create a Notification if there is one unread message", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgRead, @msg1]})
|
|
.then ->
|
|
advanceClock(2000)
|
|
expect(NativeNotifications.displayNotification).toHaveBeenCalled()
|
|
options = NativeNotifications.displayNotification.mostRecentCall.args[0]
|
|
delete options['onActivate']
|
|
expect(options).toEqual({
|
|
title: 'Ben',
|
|
subtitle: 'Hello World',
|
|
body: undefined,
|
|
canReply: true,
|
|
tag: 'unread-update'
|
|
})
|
|
|
|
it "should create multiple Notifications if there is more than one but less than five unread messages", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msg1, @msg2, @msg3]})
|
|
.then ->
|
|
#Need to call advance clock twice because we call setTimeout twice
|
|
advanceClock(2000)
|
|
advanceClock(2000)
|
|
expect(NativeNotifications.displayNotification.callCount).toEqual(3)
|
|
|
|
it "should create a Notification if there are five or more unread messages", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({
|
|
message: [@msg1, @msg2, @msg3, @msg4, @msg5]})
|
|
.then ->
|
|
advanceClock(2000)
|
|
expect(NativeNotifications.displayNotification).toHaveBeenCalled()
|
|
expect(NativeNotifications.displayNotification.mostRecentCall.args).toEqual([{
|
|
title: '5 Unread Messages',
|
|
tag: 'unread-update'
|
|
}])
|
|
|
|
it "should create a Notification correctly, even if new mail has no sender", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgNoSender]})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).toHaveBeenCalled()
|
|
|
|
options = NativeNotifications.displayNotification.mostRecentCall.args[0]
|
|
delete options['onActivate']
|
|
expect(options).toEqual({
|
|
title: 'Unknown',
|
|
subtitle: 'Hello World',
|
|
body: undefined,
|
|
canReply : true,
|
|
tag: 'unread-update'
|
|
})
|
|
|
|
it "should not create a Notification if there are no new messages", ->
|
|
waitsForPromise ->
|
|
Main._onNewMailReceived({message: []})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
waitsForPromise ->
|
|
Main._onNewMailReceived({})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
it "should not notify about unread messages that are outside the inbox", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgUnreadButArchived, @msg1]})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).toHaveBeenCalled()
|
|
options = NativeNotifications.displayNotification.mostRecentCall.args[0]
|
|
delete options['onActivate']
|
|
expect(options).toEqual({
|
|
title: 'Ben',
|
|
subtitle: 'Hello World',
|
|
body: undefined,
|
|
canReply : true,
|
|
tag: 'unread-update'
|
|
})
|
|
|
|
it "should not create a Notification if the new messages are not unread", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgRead]})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
it "should not create a Notification if the new messages are actually old ones", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgOld]})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
it "should not create a Notification if the new message is one I sent", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgFromMe]})
|
|
.then ->
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
it "should play a sound when it gets new mail", ->
|
|
spyOn(atom.config, "get").andCallFake (config) ->
|
|
if config is "core.notifications.enabled" then return true
|
|
if config is "core.notifications.sounds" then return true
|
|
|
|
spyOn(SoundRegistry, "playSound")
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msg1]})
|
|
.then ->
|
|
expect(atom.config.get.calls[1].args[0]).toBe "core.notifications.sounds"
|
|
expect(SoundRegistry.playSound).toHaveBeenCalledWith("new-mail")
|
|
|
|
it "should not play a sound if the config is off", ->
|
|
spyOn(atom.config, "get").andCallFake (config) ->
|
|
if config is "core.notifications.enabled" then return true
|
|
if config is "core.notifications.sounds" then return false
|
|
spyOn(SoundRegistry, "playSound")
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msg1]})
|
|
.then ->
|
|
expect(atom.config.get.calls[1].args[0]).toBe "core.notifications.sounds"
|
|
expect(SoundRegistry.playSound).not.toHaveBeenCalled()
|
|
|
|
describe "when the message has no matching thread", ->
|
|
beforeEach ->
|
|
@msgNoThread = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "missing"
|
|
|
|
it "should not create a Notification, since it cannot be determined whether the message is in the Inbox", ->
|
|
waitsForPromise =>
|
|
Main._onNewMailReceived({message: [@msgNoThread]})
|
|
.then ->
|
|
advanceClock(2000)
|
|
expect(NativeNotifications.displayNotification).not.toHaveBeenCalled()
|
|
|
|
it "should call _onNewMessagesMissingThreads to try displaying a notification again in 10 seconds", ->
|
|
waitsForPromise =>
|
|
spyOn(Main, '_onNewMessagesMissingThreads')
|
|
Main._onNewMailReceived({message: [@msgNoThread]})
|
|
.then =>
|
|
advanceClock(2000)
|
|
expect(Main._onNewMessagesMissingThreads).toHaveBeenCalledWith([@msgNoThread])
|
|
|
|
describe "_onNewMessagesMissingThreads", ->
|
|
beforeEach ->
|
|
@msgNoThread = new Message
|
|
unread: true
|
|
date: new Date()
|
|
from: [new Contact(name: 'Ben', email: 'ben@example.com')]
|
|
subject: "Hello World"
|
|
threadId: "missing"
|
|
spyOn(Main, '_onNewMailReceived')
|
|
Main._onNewMessagesMissingThreads([@msgNoThread])
|
|
advanceClock(2000)
|
|
|
|
it "should wait 10 seconds and then re-query for threads", ->
|
|
expect(DatabaseStore.find).not.toHaveBeenCalled()
|
|
@msgNoThread.threadId = "A"
|
|
advanceClock(10000)
|
|
expect(DatabaseStore.find).toHaveBeenCalled()
|
|
advanceClock()
|
|
expect(Main._onNewMailReceived).toHaveBeenCalledWith({message: [@msgNoThread], thread: [@threadA]})
|
|
|
|
it "should do nothing if the threads still can't be found", ->
|
|
expect(DatabaseStore.find).not.toHaveBeenCalled()
|
|
advanceClock(10000)
|
|
expect(DatabaseStore.find).toHaveBeenCalled()
|
|
advanceClock()
|
|
expect(Main._onNewMailReceived).not.toHaveBeenCalled()
|