test(api): add specs for nylas api

Summary: Specs for nylas api

Test Plan: edgehill --test

Reviewers: dillon, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D1973
This commit is contained in:
Evan Morikawa 2015-09-02 12:22:20 -07:00
parent 0ea3dfca62
commit 442bcd99d1
4 changed files with 177 additions and 44 deletions

View file

@ -116,25 +116,5 @@ describe "NylasSyncWorkerPool", ->
expect(DatabaseStore.find).toHaveBeenCalledWith(Thread, 'idhere')
expect(DatabaseStore.unpersistModel).toHaveBeenCalledWith(@thread)
# These specs are on hold because this function is changing very soon
xdescribe "handleModelResponse", ->
it "should reject if no JSON is provided", ->
it "should resolve if an empty JSON array is provided", ->
describe "if JSON contains the same object more than once", ->
it "should warn", ->
it "should omit duplicates", ->
describe "if JSON contains objects which are of unknown types", ->
it "should warn and resolve", ->
describe "when the object type is `thread`", ->
it "should check that models are acceptable", ->
describe "when the object type is `draft`", ->
it "should check that models are acceptable", ->
it "should call persistModels to save all of the received objects", ->
it "should resolve with the objects", ->
describe "handleModelResponse", ->
# SEE spec-nylas/nylas-api-spec.coffee

View file

@ -51,25 +51,175 @@ describe "NylasAPI", ->
expect(Actions.postNotification).toHaveBeenCalled()
expect(Actions.postNotification.mostRecentCall.args[0].message).toEqual("Nylas can no longer authenticate with your mail provider. You will not be able to send or receive mail. Please log out and sign in again.")
# These specs are on hold because this function is changing very soon
describe "handleModelResponse", ->
beforeEach ->
spyOn(DatabaseStore, "persistModels").andCallFake (models) ->
Promise.resolve(models)
stubDB = ({models, testClass, testMatcher}) ->
spyOn(DatabaseStore, "findAll").andCallFake (klass) ->
testClass?(klass)
where: (matcher) ->
testMatcher?(matcher)
Promise.resolve(models)
xdescribe "handleModelResponse", ->
it "should reject if no JSON is provided", ->
it "should resolve if an empty JSON array is provided", ->
waitsForPromise ->
NylasAPI._handleModelResponse()
.then -> throw new Error("Should reject!")
.catch (err) ->
expect(err.message).toEqual "handleModelResponse with no JSON provided"
describe "if JSON contains the same object more than once", ->
it "should warn", ->
it "should omit duplicates", ->
it "should resolve if an empty JSON array is provided", ->
waitsForPromise ->
NylasAPI._handleModelResponse([])
.then (resp) ->
expect(resp).toEqual []
describe "if JSON contains objects which are of unknown types", ->
it "should warn and resolve", ->
spyOn(console, "warn")
waitsForPromise ->
NylasAPI._handleModelResponse([{id: 'a', object: 'unknown'}])
.then (resp) ->
expect(resp).toEqual []
expect(console.warn).toHaveBeenCalled()
expect(console.warn.calls.length).toBe 1
describe "when the object type is `thread`", ->
it "should check that models are acceptable", ->
describe "if JSON contains the same object more than once", ->
beforeEach ->
stubDB(models: [])
spyOn(console, "warn")
@dupes = [
{id: 'a', object: 'thread'}
{id: 'a', object: 'thread'}
{id: 'b', object: 'thread'}
]
describe "when the object type is `draft`", ->
it "should check that models are acceptable", ->
it "should warn", ->
waitsForPromise =>
NylasAPI._handleModelResponse(@dupes)
.then ->
expect(console.warn).toHaveBeenCalled()
expect(console.warn.calls.length).toBe 1
it "should call persistModels to save all of the received objects", ->
it "should omit duplicates", ->
waitsForPromise =>
NylasAPI._handleModelResponse(@dupes)
.then ->
models = DatabaseStore.persistModels.calls[0].args[0]
expect(models.length).toBe 2
expect(models[0].id).toBe 'a'
expect(models[1].id).toBe 'b'
it "should resolve with the objects", ->
describe "when locked by the optimistic change tracker", ->
it "should remove locked models from the set", ->
json = [
{id: 'a', object: 'thread'}
{id: 'b', object: 'thread'}
]
spyOn(NylasAPI._optimisticChangeTracker, "acceptRemoteChangesTo").andCallFake (klass, id) ->
if id is "a" then return false
stubDB models: [new Thread(json[1])], testMatcher: (whereMatcher) ->
expect(whereMatcher.val).toEqual ['b']
waitsForPromise =>
NylasAPI._handleModelResponse(json)
.then (models) ->
expect(models.length).toBe 1
models = DatabaseStore.persistModels.calls[0].args[0]
expect(models.length).toBe 1
expect(models[0].id).toBe 'b'
describe "when updating models", ->
Message = require '../src/flux/models/message'
beforeEach ->
@json = [
{id: 'a', object: 'draft', unread: true}
{id: 'b', object: 'draft', starred: true}
]
@existing = new Message(id: 'b', unread: true)
stubDB models: [@existing]
verifyUpdateHappened = (responseModels) ->
changedModels = DatabaseStore.persistModels.calls[0].args[0]
expect(changedModels.length).toBe 2
expect(changedModels[1].id).toBe 'b'
expect(changedModels[1].starred).toBe true
# Doesn't override existing values
expect(changedModels[1].unread).toBe true
expect(responseModels.length).toBe 2
expect(responseModels[0].id).toBe 'a'
expect(responseModels[0].unread).toBe true
it "updates found models with new data", ->
waitsForPromise =>
NylasAPI._handleModelResponse(@json).then verifyUpdateHappened
it "updates if the json version is newer", ->
@existing.version = 9
@json[1].version = 10
waitsForPromise =>
NylasAPI._handleModelResponse(@json).then verifyUpdateHappened
verifyUpdateStopped = (responseModels) ->
changedModels = DatabaseStore.persistModels.calls[0].args[0]
expect(changedModels.length).toBe 1
expect(changedModels[0].id).toBe 'a'
expect(changedModels[0].unread).toBe true
expect(responseModels.length).toBe 2
expect(responseModels[1].id).toBe 'b'
expect(responseModels[1].starred).toBeUndefined()
it "doesn't update if the json version is older", ->
@existing.version = 10
@json[1].version = 9
waitsForPromise =>
NylasAPI._handleModelResponse(@json).then verifyUpdateStopped
it "doesn't update if it's already sent", ->
@existing.draft = false
@json[1].draft = true
waitsForPromise =>
NylasAPI._handleModelResponse(@json).then verifyUpdateStopped
describe "handling all types of objects", ->
apiObjectToClassMap =
"file": require('../src/flux/models/file')
"event": require('../src/flux/models/event')
"label": require('../src/flux/models/label')
"folder": require('../src/flux/models/folder')
"thread": require('../src/flux/models/thread')
"draft": require('../src/flux/models/message')
"account": require('../src/flux/models/account')
"message": require('../src/flux/models/message')
"contact": require('../src/flux/models/contact')
"calendar": require('../src/flux/models/calendar')
"metadata": require('../src/flux/models/metadata')
verifyUpdateHappened = (klass, responseModels) ->
changedModels = DatabaseStore.persistModels.calls[0].args[0]
expect(changedModels.length).toBe 2
expect(changedModels[0].id).toBe 'a'
expect(changedModels[1].id).toBe 'b'
expect(changedModels[0] instanceof klass).toBe true
expect(changedModels[1] instanceof klass).toBe true
expect(responseModels.length).toBe 2
expect(responseModels[0].id).toBe 'a'
expect(responseModels[1].id).toBe 'b'
expect(responseModels[0] instanceof klass).toBe true
expect(responseModels[1] instanceof klass).toBe true
_.forEach apiObjectToClassMap, (klass, type) ->
it "properly handle the '#{type}' type", ->
json = [
{id: 'a', object: type}
{id: 'b', object: type}
]
stubDB models: [new klass(id: 'b')]
verifyUpdate = _.partial(verifyUpdateHappened, klass)
waitsForPromise =>
NylasAPI._handleModelResponse(json).then verifyUpdate

View file

@ -38,6 +38,8 @@ class Event extends Model
fromJSON: (json) ->
super(json)
return @ unless @when
# For indexing and querying purposes, we flatten the start and end of the different
# "when" formats into two timestamps we can use for range querying. Note that for
# all-day events, we use first second of start date and last second of end date.

View file

@ -1,12 +1,9 @@
_ = require 'underscore'
Model = require './model'
Attributes = require '../attributes'
{generateTempId} = require './utils'
Function::getter = (prop, get) ->
Object.defineProperty @prototype, prop, {get, configurable: yes}
class Metadata extends Model
@attributes:
@attributes: _.extend {}, Model.attributes,
'type': Attributes.String
queryable: true
modelKey: 'type'
@ -26,10 +23,14 @@ class Metadata extends Model
modelKey: 'value'
jsonKey: 'value'
@getter 'id', ->
if @type and @publicId and @key
@id = "#{@type}/#{@publicId}/#{@key}"
else
@id = generateTempId()
Object.defineProperty @prototype, "id",
enumerable: false
get: ->
if @type and @publicid and @key
return "#{@type}/#{@publicid}/#{@key}"
else
return @serverId ? @clientId
set: ->
throw new Error("You may not directly set the ID of an object. Set either the `clientId` or the `serverId` instead.")
module.exports = Metadata