Spec fixes

This commit is contained in:
Ben Gotow 2016-01-26 19:12:46 -08:00
parent 63d36a78c3
commit f4ca355bf4
6 changed files with 154 additions and 315 deletions

View file

@ -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 ->

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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])

View file

@ -466,6 +466,7 @@ class Task
# Returns `true` (should dequeue) or `false` (should not dequeue)
shouldDequeueOtherTask: (other) -> false
onDependentTaskError: (other, error) ->
##### UNDO / REDO METHODS #####