mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-22 00:06:06 +08:00
Spec fixes
This commit is contained in:
parent
63d36a78c3
commit
f4ca355bf4
|
@ -7,6 +7,7 @@
|
|||
DraftStore,
|
||||
AccountStore,
|
||||
DatabaseStore,
|
||||
FileUploadStore,
|
||||
SoundRegistry,
|
||||
SendDraftTask,
|
||||
ChangeMailTask,
|
||||
|
@ -667,22 +668,25 @@ describe "DraftStore", ->
|
|||
describe "sending a draft", ->
|
||||
draftClientId = "local-123"
|
||||
beforeEach ->
|
||||
@draft = new Message(clientId: draftClientId, threadId: "thread-123", replyToMessageId: "message-123")
|
||||
@uploads = ['stub']
|
||||
DraftStore._draftSessions = {}
|
||||
DraftStore._draftsSending = {}
|
||||
@forceCommit = false
|
||||
msg = new Message(clientId: draftClientId, threadId: "thread-123", replyToMessageId: "message-123")
|
||||
proxy =
|
||||
prepare: -> Promise.resolve(proxy)
|
||||
teardown: ->
|
||||
draft: -> msg
|
||||
draft: => @draft
|
||||
changes:
|
||||
commit: ({force}={}) =>
|
||||
@forceCommit = force
|
||||
Promise.resolve()
|
||||
|
||||
DraftStore._draftSessions[draftClientId] = proxy
|
||||
spyOn(DraftStore, "_doneWithSession").andCallThrough()
|
||||
spyOn(DraftStore, "trigger")
|
||||
spyOn(SoundRegistry, "playSound")
|
||||
spyOn(FileUploadStore, "uploadsForMessage").andReturn(@uploads)
|
||||
spyOn(Actions, "queueTask")
|
||||
|
||||
it "plays a sound immediately when sending draft", ->
|
||||
|
@ -749,15 +753,7 @@ describe "DraftStore", ->
|
|||
runs ->
|
||||
expect(NylasEnv.close).not.toHaveBeenCalled()
|
||||
|
||||
it "forces a commit to happen before sending", ->
|
||||
runs ->
|
||||
DraftStore._onSendDraft(draftClientId)
|
||||
waitsFor ->
|
||||
DraftStore._doneWithSession.calls.length > 0
|
||||
runs ->
|
||||
expect(@forceCommit).toBe true
|
||||
|
||||
it "includes the threadId", ->
|
||||
it "queues the correct SendDraftTask", ->
|
||||
runs ->
|
||||
DraftStore._onSendDraft(draftClientId)
|
||||
waitsFor ->
|
||||
|
@ -766,18 +762,8 @@ describe "DraftStore", ->
|
|||
expect(Actions.queueTask).toHaveBeenCalled()
|
||||
task = Actions.queueTask.calls[0].args[0]
|
||||
expect(task instanceof SendDraftTask).toBe true
|
||||
expect(task.threadId).toBe "thread-123"
|
||||
|
||||
it "includes the replyToMessageId", ->
|
||||
runs ->
|
||||
DraftStore._onSendDraft(draftClientId)
|
||||
waitsFor ->
|
||||
DraftStore._doneWithSession.calls.length > 0
|
||||
runs ->
|
||||
expect(Actions.queueTask).toHaveBeenCalled()
|
||||
task = Actions.queueTask.calls[0].args[0]
|
||||
expect(task instanceof SendDraftTask).toBe true
|
||||
expect(task.replyToMessageId).toBe "message-123"
|
||||
expect(task.draft).toBe @draft
|
||||
expect(task.uploads).toBe @uploads
|
||||
|
||||
it "queues a SendDraftTask", ->
|
||||
runs ->
|
||||
|
|
|
@ -251,5 +251,4 @@ describe "TaskQueue", ->
|
|||
waitsForPromise =>
|
||||
TaskQueue._processTask(@taskAA).then =>
|
||||
expect(TaskQueue.dequeue).toHaveBeenCalledWith(@taskAA)
|
||||
expect(spyAACallback).not.toHaveBeenCalled()
|
||||
expect(@taskAA.queueState.remoteError.message).toBe "Test Error"
|
||||
|
|
|
@ -4,6 +4,7 @@ _ = require 'underscore'
|
|||
DatabaseStore,
|
||||
DatabaseTransaction,
|
||||
Message,
|
||||
Contact,
|
||||
Task,
|
||||
TaskQueue,
|
||||
SendDraftTask,
|
||||
|
@ -28,65 +29,35 @@ describe "SendDraftTask", ->
|
|||
name: 'Dummy'
|
||||
email: 'dummy@nylas.com'
|
||||
|
||||
@draftB = new Message
|
||||
version: '1'
|
||||
clientId: 'localid-B'
|
||||
serverId: '1233OTHERDRAFT'
|
||||
accountId: 'A12ADE'
|
||||
subject: 'New Draft'
|
||||
draft: true
|
||||
to:
|
||||
name: 'Dummy'
|
||||
email: 'dummy@nylas.com'
|
||||
|
||||
@saveA = new SyncbackDraftTask('localid-A')
|
||||
@saveB = new SyncbackDraftTask('localid-B')
|
||||
@sendA = new SendDraftTask('localid-A')
|
||||
@saveA = new SyncbackDraftTask(@draftA, [])
|
||||
@sendA = new SendDraftTask(@draftA, [])
|
||||
|
||||
expect(@sendA.isDependentTask(@saveA)).toBe(false)
|
||||
|
||||
describe "performLocal", ->
|
||||
it "throws an error if we we don't pass a draftClientId", ->
|
||||
it "throws an error if we we don't pass a draft", ->
|
||||
badTask = new SendDraftTask()
|
||||
badTask.performLocal()
|
||||
.then ->
|
||||
throw new Error("Shouldn't succeed")
|
||||
.catch (err) ->
|
||||
expect(err.message).toBe "Attempt to call SendDraftTask.performLocal without @draftClientId."
|
||||
expect(err.message).toBe "SendDraftTask - must be provided a draft."
|
||||
|
||||
it "finds the message and saves a backup copy of it", ->
|
||||
draft = new Message
|
||||
clientId: "local-123"
|
||||
serverId: "server-123"
|
||||
draft: true
|
||||
|
||||
calledBody = "ERROR: The body wasn't included!"
|
||||
spyOn(DatabaseStore, "findBy").andCallFake ->
|
||||
then: -> throw new Error("You must include the body!")
|
||||
include: (body) ->
|
||||
calledBody = body
|
||||
return Promise.resolve(draft)
|
||||
|
||||
task = new SendDraftTask('local-123')
|
||||
waitsForPromise => task.performLocal().then =>
|
||||
expect(task.backupDraft).toBeDefined()
|
||||
expect(task.backupDraft.clientId).toBe "local-123"
|
||||
expect(task.backupDraft.serverId).toBe "server-123"
|
||||
expect(task.backupDraft).not.toBe draft # It's a clone
|
||||
expect(task.replyToMessageId).not.toBeDefined()
|
||||
expect(task.threadId).not.toBeDefined()
|
||||
expect(calledBody).toBe Message.attributes.body
|
||||
it "throws an error if we we don't pass uploads", ->
|
||||
badTask = new SendDraftTask(new Message(), null)
|
||||
badTask.performLocal()
|
||||
.then ->
|
||||
throw new Error("Shouldn't succeed")
|
||||
.catch (err) ->
|
||||
expect(err.message).toBe "SendDraftTask - must be provided an array of uploads."
|
||||
|
||||
describe "performRemote", ->
|
||||
beforeEach ->
|
||||
@accountId = "a123"
|
||||
@draftClientId = "local-123"
|
||||
@serverMessageId = '1233123AEDF1'
|
||||
|
||||
@response =
|
||||
version: 2
|
||||
id: @serverMessageId
|
||||
account_id: @accountId
|
||||
id: '1233123AEDF1'
|
||||
account_id: TEST_ACCOUNT_ID
|
||||
from: [new Contact(email: TEST_ACCOUNT_EMAIL)]
|
||||
subject: 'New Draft'
|
||||
body: 'hello world'
|
||||
to:
|
||||
|
@ -105,128 +76,50 @@ describe "SendDraftTask", ->
|
|||
spyOn(Actions, "sendDraftSuccess")
|
||||
spyOn(NylasEnv, "emitError")
|
||||
|
||||
runFetchLatestDraftTests = ->
|
||||
it "fetches the draft object from the DB", ->
|
||||
waitsForPromise => @task._fetchLatestDraft().then (model) =>
|
||||
expect(model).toBe @draft
|
||||
expect(@task.draftAccountId).toBe @draft.accountId
|
||||
expect(@task.draftServerId).toBe @draft.serverId
|
||||
expect(@task.draftVersion).toBe @draft.version
|
||||
|
||||
it "throws a `NotFoundError` if the model is blank", ->
|
||||
spyOn(@task, "_notifyUserOfError")
|
||||
spyOn(@task, "_permanentError").andCallThrough()
|
||||
@draftResolver = -> Promise.resolve(null)
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
expect(DBt.persistModel.callCount).toBe 1
|
||||
expect(DBt.persistModel).toHaveBeenCalledWith(@backupDraft)
|
||||
expect(@task._permanentError).toHaveBeenCalled()
|
||||
|
||||
it "throws a `NotFoundError` if findBy fails", ->
|
||||
spyOn(@task, "_notifyUserOfError")
|
||||
spyOn(@task, "_permanentError").andCallThrough()
|
||||
@draftResolver = -> Promise.reject(new Error("Test Problem"))
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
expect(DBt.persistModel.callCount).toBe 1
|
||||
expect(DBt.persistModel).toHaveBeenCalledWith(@backupDraft)
|
||||
expect(@task._permanentError).toHaveBeenCalled()
|
||||
|
||||
# All of these are run in both the context of a saved draft and a new
|
||||
# draft.
|
||||
runMakeSendRequestTests = ->
|
||||
sharedTests = =>
|
||||
it "makes a send request with the correct data", ->
|
||||
@task.draftAccountId = @accountId
|
||||
waitsForPromise => @task._makeSendRequest(@draft).then =>
|
||||
waitsForPromise => @task._sendAndCreateMessage().then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
reqArgs = NylasAPI.makeRequest.calls[0].args[0]
|
||||
expect(reqArgs.accountId).toBe @accountId
|
||||
expect(reqArgs.accountId).toBe TEST_ACCOUNT_ID
|
||||
expect(reqArgs.body).toEqual @draft.toJSON()
|
||||
|
||||
it "should pass returnsModel:false", ->
|
||||
waitsForPromise => @task._makeSendRequest(@draft).then ->
|
||||
waitsForPromise => @task._sendAndCreateMessage().then ->
|
||||
expect(NylasAPI.makeRequest.calls.length).toBe(1)
|
||||
options = NylasAPI.makeRequest.mostRecentCall.args[0]
|
||||
expect(options.returnsModel).toBe(false)
|
||||
|
||||
it "should always send the draft body in the request body (joined attribute check)", ->
|
||||
waitsForPromise =>
|
||||
@task._makeSendRequest(@draft).then =>
|
||||
@task._sendAndCreateMessage().then =>
|
||||
expect(NylasAPI.makeRequest.calls.length).toBe(1)
|
||||
options = NylasAPI.makeRequest.mostRecentCall.args[0]
|
||||
expect(options.body.body).toBe('hello world')
|
||||
|
||||
it "should start an API request to /send", -> waitsForPromise =>
|
||||
@task._makeSendRequest(@draft).then =>
|
||||
@task._sendAndCreateMessage().then =>
|
||||
expect(NylasAPI.makeRequest.calls.length).toBe(1)
|
||||
options = NylasAPI.makeRequest.mostRecentCall.args[0]
|
||||
expect(options.path).toBe("/send")
|
||||
expect(options.method).toBe('POST')
|
||||
|
||||
it "retries the task if 'Invalid message public id'", ->
|
||||
jasmine.unspy(NylasAPI, "makeRequest")
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
if options.body.reply_to_message_id
|
||||
err = new APIError(body: "Invalid message public id")
|
||||
Promise.reject(err)
|
||||
else
|
||||
options.success?(@response)
|
||||
Promise.resolve(@response)
|
||||
|
||||
@draft.replyToMessageId = "reply-123"
|
||||
@draft.threadId = "thread-123"
|
||||
waitsForPromise => @task._makeSendRequest(@draft).then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toEqual 2
|
||||
req1 = NylasAPI.makeRequest.calls[0].args[0]
|
||||
req2 = NylasAPI.makeRequest.calls[1].args[0]
|
||||
expect(req1.body.reply_to_message_id).toBe "reply-123"
|
||||
expect(req1.body.thread_id).toBe "thread-123"
|
||||
|
||||
expect(req2.body.reply_to_message_id).toBe null
|
||||
expect(req2.body.thread_id).toBe "thread-123"
|
||||
|
||||
it "retries the task if 'Invalid message public id'", ->
|
||||
jasmine.unspy(NylasAPI, "makeRequest")
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
if options.body.reply_to_message_id
|
||||
err = new APIError(body: "Invalid thread")
|
||||
Promise.reject(err)
|
||||
else
|
||||
options.success?(@response)
|
||||
Promise.resolve(@response)
|
||||
|
||||
@draft.replyToMessageId = "reply-123"
|
||||
@draft.threadId = "thread-123"
|
||||
waitsForPromise => @task._makeSendRequest(@draft).then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toEqual 2
|
||||
req1 = NylasAPI.makeRequest.calls[0].args[0]
|
||||
req2 = NylasAPI.makeRequest.calls[1].args[0]
|
||||
expect(req1.body.reply_to_message_id).toBe "reply-123"
|
||||
expect(req1.body.thread_id).toBe "thread-123"
|
||||
|
||||
expect(req2.body.reply_to_message_id).toBe null
|
||||
expect(req2.body.thread_id).toBe null
|
||||
|
||||
runSaveNewMessageTests = ->
|
||||
it "should write the saved message to the database with the same client ID", ->
|
||||
waitsForPromise =>
|
||||
@task._saveNewMessage(@response).then =>
|
||||
@task._sendAndCreateMessage().then =>
|
||||
expect(DBt.persistModel).toHaveBeenCalled()
|
||||
expect(DBt.persistModel.mostRecentCall.args[0].clientId).toEqual(@draftClientId)
|
||||
expect(DBt.persistModel.mostRecentCall.args[0].serverId).toEqual(@serverMessageId)
|
||||
expect(DBt.persistModel.mostRecentCall.args[0].clientId).toEqual(@draft.clientId)
|
||||
expect(DBt.persistModel.mostRecentCall.args[0].serverId).toEqual(@response.id)
|
||||
expect(DBt.persistModel.mostRecentCall.args[0].draft).toEqual(false)
|
||||
|
||||
runNotifySuccess = ->
|
||||
it "should notify the draft was sent", ->
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
args = Actions.sendDraftSuccess.calls[0].args[0]
|
||||
expect(args.draftClientId).toBe @draftClientId
|
||||
expect(args.draftClientId).toBe @draft.clientId
|
||||
|
||||
it "get an object back on success", ->
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
args = Actions.sendDraftSuccess.calls[0].args[0]
|
||||
expect(args.newMessage.id).toBe @serverMessageId
|
||||
|
||||
it "should play a sound", ->
|
||||
spyOn(NylasEnv.config, "get").andReturn true
|
||||
|
@ -240,10 +133,9 @@ describe "SendDraftTask", ->
|
|||
expect(NylasEnv.config.get).toHaveBeenCalledWith("core.sending.sounds")
|
||||
expect(SoundRegistry.playSound).not.toHaveBeenCalled()
|
||||
|
||||
runIntegrativeWithErrors = ->
|
||||
describe "when there are errors", ->
|
||||
beforeEach ->
|
||||
spyOn(@task, "_notifyUserOfError")
|
||||
spyOn(Actions, 'draftSendingFailed')
|
||||
jasmine.unspy(NylasAPI, "makeRequest")
|
||||
|
||||
it "notifies of a permanent error of misc error types", ->
|
||||
|
@ -257,9 +149,53 @@ describe "SendDraftTask", ->
|
|||
@task.performRemote().then (status) =>
|
||||
expect(status[0]).toBe Task.Status.Failed
|
||||
expect(status[1]).toBe thrownError
|
||||
expect(@task._notifyUserOfError).toHaveBeenCalled()
|
||||
expect(Actions.draftSendingFailed).toHaveBeenCalled()
|
||||
expect(NylasEnv.emitError).toHaveBeenCalled()
|
||||
|
||||
it "retries the task if 'Invalid message public id'", ->
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
if options.body.reply_to_message_id
|
||||
err = new APIError(body: "Invalid message public id")
|
||||
Promise.reject(err)
|
||||
else
|
||||
options.success?(@response)
|
||||
Promise.resolve(@response)
|
||||
|
||||
@draft.replyToMessageId = "reply-123"
|
||||
@draft.threadId = "thread-123"
|
||||
waitsForPromise => @task._sendAndCreateMessage(@draft).then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toEqual 2
|
||||
req1 = NylasAPI.makeRequest.calls[0].args[0]
|
||||
req2 = NylasAPI.makeRequest.calls[1].args[0]
|
||||
expect(req1.body.reply_to_message_id).toBe "reply-123"
|
||||
expect(req1.body.thread_id).toBe "thread-123"
|
||||
|
||||
expect(req2.body.reply_to_message_id).toBe null
|
||||
expect(req2.body.thread_id).toBe "thread-123"
|
||||
|
||||
it "retries the task if 'Invalid message public id'", ->
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
if options.body.reply_to_message_id
|
||||
err = new APIError(body: "Invalid thread")
|
||||
Promise.reject(err)
|
||||
else
|
||||
options.success?(@response)
|
||||
Promise.resolve(@response)
|
||||
|
||||
@draft.replyToMessageId = "reply-123"
|
||||
@draft.threadId = "thread-123"
|
||||
waitsForPromise => @task._sendAndCreateMessage(@draft).then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toEqual 2
|
||||
req1 = NylasAPI.makeRequest.calls[0].args[0]
|
||||
req2 = NylasAPI.makeRequest.calls[1].args[0]
|
||||
expect(req1.body.reply_to_message_id).toBe "reply-123"
|
||||
expect(req1.body.thread_id).toBe "thread-123"
|
||||
|
||||
expect(req2.body.reply_to_message_id).toBe null
|
||||
expect(req2.body.thread_id).toBe null
|
||||
|
||||
it "notifies of a permanent error on 500 errors", ->
|
||||
thrownError = new APIError(statusCode: 500, body: "err")
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
|
@ -267,8 +203,7 @@ describe "SendDraftTask", ->
|
|||
waitsForPromise => @task.performRemote().then (status) =>
|
||||
expect(status[0]).toBe Task.Status.Failed
|
||||
expect(status[1]).toBe thrownError
|
||||
expect(@task._notifyUserOfError).toHaveBeenCalled()
|
||||
expect(NylasEnv.emitError).not.toHaveBeenCalled()
|
||||
expect(Actions.draftSendingFailed).toHaveBeenCalled()
|
||||
|
||||
it "notifies us and users of a permanent error on 400 errors", ->
|
||||
thrownError = new APIError(statusCode: 400, body: "err")
|
||||
|
@ -277,8 +212,7 @@ describe "SendDraftTask", ->
|
|||
waitsForPromise => @task.performRemote().then (status) =>
|
||||
expect(status[0]).toBe Task.Status.Failed
|
||||
expect(status[1]).toBe thrownError
|
||||
expect(@task._notifyUserOfError).toHaveBeenCalled()
|
||||
expect(NylasEnv.emitError).toHaveBeenCalled()
|
||||
expect(Actions.draftSendingFailed).toHaveBeenCalled()
|
||||
|
||||
it "notifies of a permanent error on timeouts", ->
|
||||
thrownError = new APIError(statusCode: NylasAPI.TimeoutErrorCode, body: "err")
|
||||
|
@ -287,31 +221,19 @@ describe "SendDraftTask", ->
|
|||
waitsForPromise => @task.performRemote().then (status) =>
|
||||
expect(status[0]).toBe Task.Status.Failed
|
||||
expect(status[1]).toBe thrownError
|
||||
expect(@task._notifyUserOfError).toHaveBeenCalled()
|
||||
expect(NylasEnv.emitError).not.toHaveBeenCalled()
|
||||
|
||||
it "retries for other error types", ->
|
||||
thrownError = new APIError(statusCode: 402, body: "err")
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
Promise.reject(thrownError)
|
||||
waitsForPromise => @task.performRemote().then (status) =>
|
||||
expect(status).toBe Task.Status.Retry
|
||||
expect(@task._notifyUserOfError).not.toHaveBeenCalled()
|
||||
expect(NylasEnv.emitError).not.toHaveBeenCalled()
|
||||
expect(Actions.draftSendingFailed).toHaveBeenCalled()
|
||||
|
||||
describe "checking the promise chain halts on errors", ->
|
||||
beforeEach ->
|
||||
spyOn(@task,"_makeSendRequest").andCallThrough()
|
||||
spyOn(@task,"_saveNewMessage").andCallThrough()
|
||||
spyOn(@task,"_sendAndCreateMessage").andCallThrough()
|
||||
spyOn(@task,"_deleteRemoteDraft").andCallThrough()
|
||||
spyOn(@task,"_notifySuccess").andCallThrough()
|
||||
spyOn(@task,"_onSuccess").andCallThrough()
|
||||
spyOn(@task,"_onError").andCallThrough()
|
||||
|
||||
@expectBlockedChain = =>
|
||||
expect(@task._makeSendRequest).toHaveBeenCalled()
|
||||
expect(@task._saveNewMessage).not.toHaveBeenCalled()
|
||||
expect(@task._sendAndCreateMessage).toHaveBeenCalled()
|
||||
expect(@task._deleteRemoteDraft).not.toHaveBeenCalled()
|
||||
expect(@task._notifySuccess).not.toHaveBeenCalled()
|
||||
expect(@task._onSuccess).not.toHaveBeenCalled()
|
||||
expect(@task._onError).toHaveBeenCalled()
|
||||
|
||||
it "halts on 500s", ->
|
||||
|
@ -340,125 +262,108 @@ describe "SendDraftTask", ->
|
|||
options.success?(@response)
|
||||
Promise.resolve(@response)
|
||||
waitsForPromise => @task.performRemote().then (status) =>
|
||||
expect(@task._makeSendRequest).toHaveBeenCalled()
|
||||
expect(@task._saveNewMessage).toHaveBeenCalled()
|
||||
expect(@task._sendAndCreateMessage).toHaveBeenCalled()
|
||||
expect(@task._deleteRemoteDraft).toHaveBeenCalled()
|
||||
expect(@task._notifySuccess).toHaveBeenCalled()
|
||||
expect(@task._onSuccess).toHaveBeenCalled()
|
||||
expect(@task._onError).not.toHaveBeenCalled()
|
||||
|
||||
|
||||
describe "with a new draft", ->
|
||||
beforeEach ->
|
||||
@draft = new Message
|
||||
version: 1
|
||||
clientId: @draftClientId
|
||||
accountId: @accountId
|
||||
clientId: 'client-id'
|
||||
accountId: TEST_ACCOUNT_ID
|
||||
from: [new Contact(email: TEST_ACCOUNT_EMAIL)]
|
||||
subject: 'New Draft'
|
||||
draft: true
|
||||
body: 'hello world'
|
||||
@task = new SendDraftTask(@draftClientId)
|
||||
@backupDraft = @draft.clone()
|
||||
@task.backupDraft = @backupDraft # Since performLocal doesn't run
|
||||
@draftResolver = -> Promise.resolve(@draft)
|
||||
@uploads = []
|
||||
@task = new SendDraftTask(@draft, @uploads)
|
||||
@calledBody = "ERROR: The body wasn't included!"
|
||||
spyOn(DatabaseStore, "findBy").andCallFake =>
|
||||
include: (body) =>
|
||||
@calledBody = body
|
||||
return @draftResolver()
|
||||
Promise.resolve(@draft)
|
||||
|
||||
sharedTests()
|
||||
|
||||
it "can complete a full performRemote", -> waitsForPromise =>
|
||||
@task.performRemote().then (status) ->
|
||||
expect(status).toBe Task.Status.Success
|
||||
|
||||
runFetchLatestDraftTests.call(@)
|
||||
runMakeSendRequestTests.call(@)
|
||||
runSaveNewMessageTests.call(@)
|
||||
|
||||
it "shouldn't attempt to delete a draft", -> waitsForPromise =>
|
||||
expect(@task.draftServerId).not.toBeDefined()
|
||||
@task._deleteRemoteDraft().then =>
|
||||
expect(NylasAPI.makeRequest).not.toHaveBeenCalled()
|
||||
|
||||
runNotifySuccess.call(@)
|
||||
runIntegrativeWithErrors.call(@)
|
||||
|
||||
it "should locally convert the draft to a message on send", ->
|
||||
expect(@draft.clientId).toBe @draftClientId
|
||||
expect(@draft.serverId).toBeUndefined()
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
expect(DBt.persistModel).toHaveBeenCalled()
|
||||
model = DBt.persistModel.calls[0].args[0]
|
||||
expect(model.clientId).toBe @draftClientId
|
||||
expect(model.serverId).toBe @serverMessageId
|
||||
expect(model.clientId).toBe @draft.clientId
|
||||
expect(model.serverId).toBe @response.id
|
||||
expect(model.draft).toBe false
|
||||
|
||||
|
||||
describe "with an existing persisted draft", ->
|
||||
beforeEach ->
|
||||
@draftServerId = 'server-123'
|
||||
@draft = new Message
|
||||
version: 1
|
||||
clientId: @draftClientId
|
||||
serverId: @draftServerId
|
||||
accountId: @accountId
|
||||
clientId: 'client-id'
|
||||
serverId: 'server-123'
|
||||
accountId: TEST_ACCOUNT_ID
|
||||
from: [new Contact(email: TEST_ACCOUNT_EMAIL)]
|
||||
subject: 'New Draft'
|
||||
draft: true
|
||||
body: 'hello world'
|
||||
to:
|
||||
name: 'Dummy'
|
||||
email: 'dummy@nylas.com'
|
||||
@task = new SendDraftTask(@draftClientId)
|
||||
@backupDraft = @draft.clone()
|
||||
@task.backupDraft = @backupDraft # Since performLocal doesn't run
|
||||
@draftResolver = -> Promise.resolve(@draft)
|
||||
@uploads = []
|
||||
@task = new SendDraftTask(@draft, @uploads)
|
||||
@calledBody = "ERROR: The body wasn't included!"
|
||||
spyOn(DatabaseStore, "findBy").andCallFake =>
|
||||
then: -> throw new Error("You must include the body!")
|
||||
include: (body) =>
|
||||
@calledBody = body
|
||||
return @draftResolver()
|
||||
Promise.resolve(@draft)
|
||||
|
||||
sharedTests()
|
||||
|
||||
it "can complete a full performRemote", -> waitsForPromise =>
|
||||
@task.performLocal()
|
||||
@task.performRemote().then (status) ->
|
||||
expect(status).toBe Task.Status.Success
|
||||
|
||||
runFetchLatestDraftTests.call(@)
|
||||
runMakeSendRequestTests.call(@)
|
||||
runSaveNewMessageTests.call(@)
|
||||
|
||||
it "should make a request to delete a draft", ->
|
||||
waitsForPromise => @task._fetchLatestDraft().then(@task._deleteRemoteDraft).then =>
|
||||
expect(@task.draftServerId).toBe @draftServerId
|
||||
@task.performLocal()
|
||||
waitsForPromise => @task._deleteRemoteDraft().then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toBe 1
|
||||
req = NylasAPI.makeRequest.calls[0].args[0]
|
||||
expect(req.path).toBe "/drafts/#{@draftServerId}"
|
||||
expect(req.accountId).toBe @accountId
|
||||
expect(req.path).toBe "/drafts/#{@draft.serverId}"
|
||||
expect(req.accountId).toBe TEST_ACCOUNT_ID
|
||||
expect(req.method).toBe "DELETE"
|
||||
expect(req.returnsModel).toBe false
|
||||
|
||||
it "should continue if the request failes", ->
|
||||
it "should continue if the request fails", ->
|
||||
jasmine.unspy(NylasAPI, "makeRequest")
|
||||
spyOn(console, "error")
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (options) =>
|
||||
err = new APIError(body: "Boo", statusCode: 500)
|
||||
Promise.reject(err)
|
||||
waitsForPromise => @task._fetchLatestDraft().then(@task._deleteRemoteDraft).then =>
|
||||
Promise.reject(new APIError(body: "Boo", statusCode: 500))
|
||||
|
||||
@task.performLocal()
|
||||
waitsForPromise => @task._deleteRemoteDraft().then =>
|
||||
expect(NylasAPI.makeRequest).toHaveBeenCalled()
|
||||
expect(NylasAPI.makeRequest.callCount).toBe 1
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
.catch =>
|
||||
throw new Error("Shouldn't fail the promise")
|
||||
|
||||
runNotifySuccess.call(@)
|
||||
runIntegrativeWithErrors.call(@)
|
||||
|
||||
it "should locally convert the existing draft to a message on send", ->
|
||||
expect(@draft.clientId).toBe @draftClientId
|
||||
expect(@draft.clientId).toBe @draft.clientId
|
||||
expect(@draft.serverId).toBe "server-123"
|
||||
|
||||
@task.performLocal()
|
||||
waitsForPromise => @task.performRemote().then =>
|
||||
expect(DBt.persistModel).toHaveBeenCalled()
|
||||
model = DBt.persistModel.calls[0].args[0]
|
||||
expect(model.clientId).toBe @draftClientId
|
||||
expect(model.serverId).toBe @serverMessageId
|
||||
expect(model.clientId).toBe @draft.clientId
|
||||
expect(model.serverId).toBe @response.id
|
||||
expect(model.draft).toBe false
|
||||
|
|
|
@ -100,28 +100,6 @@ describe "SyncbackDraftTask", ->
|
|||
expect(@taskB.queueState.isProcessing).toBe false
|
||||
expect(@taskB.runRemote).not.toHaveBeenCalled()
|
||||
|
||||
it "does not get dequeued if dependent tasks fail", ->
|
||||
@taskA.queueState.localComplete = true
|
||||
@taskB.queueState.localComplete = true
|
||||
|
||||
spyOn(@taskA, "performRemote").andReturn Promise.resolve(Task.Status.Failed)
|
||||
spyOn(@taskB, "performRemote").andReturn Promise.resolve(Task.Status.Success)
|
||||
|
||||
spyOn(TaskQueue, "dequeue").andCallThrough()
|
||||
spyOn(TaskQueue, "trigger")
|
||||
|
||||
TaskQueue._queue = [@taskA, @taskB]
|
||||
TaskQueue._processQueue()
|
||||
advanceClock(100)
|
||||
TaskQueue._processQueue()
|
||||
advanceClock(100)
|
||||
expect(@taskA.performRemote).toHaveBeenCalled()
|
||||
expect(@taskB.performRemote).toHaveBeenCalled()
|
||||
expect(TaskQueue.dequeue.calls.length).toBe 2
|
||||
|
||||
expect(@taskA.queueState.debugStatus).not.toBe Task.DebugStatus.DequeuedDependency
|
||||
expect(@taskA.queueState.debugStatus).not.toBe Task.DebugStatus.DequeuedDependency
|
||||
|
||||
describe "performRemote", ->
|
||||
beforeEach ->
|
||||
spyOn(NylasAPI, 'makeRequest').andCallFake (opts) ->
|
||||
|
@ -180,56 +158,25 @@ describe "SyncbackDraftTask", ->
|
|||
body: inboxError
|
||||
requestOptions: method: method
|
||||
)
|
||||
describe 'when PUT-ing', ->
|
||||
beforeEach ->
|
||||
@task = new SyncbackDraftTask("removeDraftId")
|
||||
spyOn(@task, "getLatestLocalDraft").andCallFake -> Promise.resolve(remoteDraft())
|
||||
spyOn(@task, "detatchFromRemoteID").andCallFake -> Promise.resolve(remoteDraft())
|
||||
|
||||
[400, 404, 409].forEach (code) ->
|
||||
it "Retries on #{code} errors when we're PUT-ing", ->
|
||||
stubAPI(code, "PUT")
|
||||
waitsForPromise =>
|
||||
@task.performRemote().then (status) =>
|
||||
expect(@task.getLatestLocalDraft).toHaveBeenCalled()
|
||||
expect(@task.getLatestLocalDraft.calls.length).toBe 2
|
||||
expect(@task.detatchFromRemoteID).toHaveBeenCalled()
|
||||
expect(@task.detatchFromRemoteID.calls.length).toBe 1
|
||||
expect(status).toBe Task.Status.Retry
|
||||
beforeEach ->
|
||||
@task = new SyncbackDraftTask("removeDraftId")
|
||||
spyOn(@task, "getLatestLocalDraft").andCallFake -> Promise.resolve(remoteDraft())
|
||||
|
||||
[500, 0].forEach (code) ->
|
||||
it "Fails on #{code} errors when we're PUT-ing", ->
|
||||
stubAPI(code, "PUT")
|
||||
waitsForPromise =>
|
||||
@task.performRemote().then ([status, err]) =>
|
||||
expect(status).toBe Task.Status.Failed
|
||||
expect(@task.getLatestLocalDraft).toHaveBeenCalled()
|
||||
expect(@task.getLatestLocalDraft.calls.length).toBe 1
|
||||
expect(@task.detatchFromRemoteID).not.toHaveBeenCalled()
|
||||
expect(err.statusCode).toBe code
|
||||
|
||||
describe 'when POST-ing', ->
|
||||
beforeEach ->
|
||||
@task = new SyncbackDraftTask("removeDraftId")
|
||||
spyOn(@task, "getLatestLocalDraft").andCallFake -> Promise.resolve(localDraft())
|
||||
spyOn(@task, "detatchFromRemoteID").andCallFake -> Promise.resolve(localDraft())
|
||||
|
||||
[400, 404, 409, 500, 0].forEach (code) ->
|
||||
it "Fails on #{code} errors when we're POST-ing", ->
|
||||
stubAPI(code, "POST")
|
||||
waitsForPromise =>
|
||||
@task.performRemote().then ([status, err]) =>
|
||||
expect(status).toBe Task.Status.Failed
|
||||
expect(@task.getLatestLocalDraft).toHaveBeenCalled()
|
||||
expect(@task.getLatestLocalDraft.calls.length).toBe 1
|
||||
expect(@task.detatchFromRemoteID).not.toHaveBeenCalled()
|
||||
expect(err.statusCode).toBe code
|
||||
|
||||
it "Fails on unknown errors", ->
|
||||
spyOn(NylasAPI, "makeRequest").andCallFake -> Promise.reject(new APIError())
|
||||
[500, 400, 0].forEach (code) ->
|
||||
it "Fails on #{code} errors when we're PUT-ing", ->
|
||||
stubAPI(code, "PUT")
|
||||
waitsForPromise =>
|
||||
@task.performRemote().then ([status, err]) =>
|
||||
expect(status).toBe Task.Status.Failed
|
||||
expect(@task.getLatestLocalDraft).toHaveBeenCalled()
|
||||
expect(@task.getLatestLocalDraft.calls.length).toBe 1
|
||||
expect(@task.detatchFromRemoteID).not.toHaveBeenCalled()
|
||||
expect(err.statusCode).toBe code
|
||||
|
||||
it "Fails on unknown errors", ->
|
||||
spyOn(NylasAPI, "makeRequest").andCallFake -> Promise.reject(new APIError())
|
||||
waitsForPromise =>
|
||||
@task.performRemote().then ([status, err]) =>
|
||||
expect(status).toBe Task.Status.Failed
|
||||
expect(@task.getLatestLocalDraft).toHaveBeenCalled()
|
||||
expect(@task.getLatestLocalDraft.calls.length).toBe 1
|
||||
|
|
|
@ -52,6 +52,8 @@ class SendDraftTask extends Task
|
|||
return Promise.reject(new Error("SendDraftTask - must be provided a draft."))
|
||||
unless @uploads and @uploads instanceof Array
|
||||
return Promise.reject(new Error("SendDraftTask - must be provided an array of uploads."))
|
||||
unless @draft.from[0]
|
||||
return Promise.reject(new Error("SendDraftTask - you must populate `from` before sending."))
|
||||
|
||||
account = AccountStore.accountForEmail(@draft.from[0].email)
|
||||
unless account
|
||||
|
@ -65,8 +67,10 @@ class SendDraftTask extends Task
|
|||
|
||||
if account.id isnt @draft.accountId
|
||||
@draft.accountId = account.id
|
||||
@draft.replyToMessageId = null
|
||||
@draft.threadId = null
|
||||
delete @draft.serverId
|
||||
delete @draft.version
|
||||
delete @draft.threadId
|
||||
delete @draft.replyToMessageId
|
||||
|
||||
Promise.resolve()
|
||||
|
||||
|
@ -174,19 +178,16 @@ class SendDraftTask extends Task
|
|||
return Promise.resolve(Task.Status.Success)
|
||||
|
||||
_onError: (err) =>
|
||||
msg = "Your message could not be sent at this time. Please try again soon."
|
||||
# OUTBOX COMING SOON!
|
||||
|
||||
msg = "Your message could not be sent. Check your network connection and try again."
|
||||
if err instanceof APIError and err.statusCode is NylasAPI.TimeoutErrorCode
|
||||
msg = "We lost internet connection just as we were trying to send your message! Please wait a little bit to see if it went through. If not, check your internet connection and try sending again."
|
||||
|
||||
recoverableStatusCodes = [400, 404, 500, NylasAPI.TimeoutErrorCode]
|
||||
Actions.draftSendingFailed
|
||||
threadId: @draft.threadId
|
||||
draftClientId: @draft.clientId,
|
||||
errorMessage: msg
|
||||
NylasEnv.emitError(err)
|
||||
|
||||
if err instanceof APIError and err.statusCode in recoverableStatusCodes
|
||||
return Promise.resolve(Task.Status.Retry)
|
||||
|
||||
else
|
||||
Actions.draftSendingFailed
|
||||
threadId: @draft.threadId
|
||||
draftClientId: @draft.clientId,
|
||||
errorMessage: msg
|
||||
NylasEnv.emitError(err)
|
||||
return Promise.resolve([Task.Status.Failed, err])
|
||||
return Promise.resolve([Task.Status.Failed, err])
|
||||
|
|
|
@ -466,6 +466,7 @@ class Task
|
|||
# Returns `true` (should dequeue) or `false` (should not dequeue)
|
||||
shouldDequeueOtherTask: (other) -> false
|
||||
|
||||
onDependentTaskError: (other, error) ->
|
||||
|
||||
##### UNDO / REDO METHODS #####
|
||||
|
||||
|
|
Loading…
Reference in a new issue