From 7779287ea3e16b1970caa4f63df5929f46130b2c Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Wed, 31 Mar 2021 22:04:44 -0500 Subject: [PATCH 1/7] Bugfix: coalesceFindRequests should work with non native Adapter classes --- packages/adapter/addon/index.ts | 14 +++++++++++++- packages/adapter/addon/json-api.ts | 3 ++- packages/adapter/addon/rest.ts | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/adapter/addon/index.ts b/packages/adapter/addon/index.ts index b24c34a3804..38d80210c87 100644 --- a/packages/adapter/addon/index.ts +++ b/packages/adapter/addon/index.ts @@ -470,6 +470,8 @@ export default class Adapter extends EmberObject implements MinimumAdapterInterf return RSVPPromise.resolve(); } + _coalesceFindRequests = true; + /** By default the store will try to coalesce all `fetchRecord` calls within the same runloop into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. @@ -479,7 +481,17 @@ export default class Adapter extends EmberObject implements MinimumAdapterInterf @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests = true; + get coalesceFindRequests() { + let coalesceFindRequests = this._coalesceFindRequests; + if (typeof coalesceFindRequests === 'boolean') { + return coalesceFindRequests; + } + return (this._coalesceFindRequests = false); + } + + set coalesceFindRequests(value: boolean) { + this._coalesceFindRequests = value; + } /** The store will call `findMany` instead of multiple `findRecord` diff --git a/packages/adapter/addon/json-api.ts b/packages/adapter/addon/json-api.ts index 87a6e7b1a1e..b1f89abf488 100644 --- a/packages/adapter/addon/json-api.ts +++ b/packages/adapter/addon/json-api.ts @@ -231,7 +231,8 @@ class JSONAPIAdapter extends RESTAdapter { @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests: boolean = false; + + _coalesceFindRequests: boolean = false; findMany(store: Store, type: ShimModelClass, ids: string[], snapshots: Snapshot[]): Promise { let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); diff --git a/packages/adapter/addon/rest.ts b/packages/adapter/addon/rest.ts index ea560f7091a..9623fe726de 100644 --- a/packages/adapter/addon/rest.ts +++ b/packages/adapter/addon/rest.ts @@ -471,7 +471,8 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { @property coalesceFindRequests @type {boolean} */ - coalesceFindRequests: boolean = false; + + _coalesceFindRequests: boolean = false; /** Endpoint paths can be prefixed with a `namespace` by setting the namespace From db3202c317b27aa459cc318212b076001e420075 Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Sat, 3 Apr 2021 15:03:20 -0500 Subject: [PATCH 2/7] add a test --- .../integration/adapter/rest-adapter-test.js | 4270 +++++++++-------- packages/adapter/addon/index.ts | 6 +- packages/adapter/addon/json-api.ts | 11 +- packages/adapter/addon/rest.ts | 14 +- 4 files changed, 2208 insertions(+), 2093 deletions(-) diff --git a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js index 5cd03eb360c..a7c82ddd622 100644 --- a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js @@ -47,7 +47,6 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { server = new Pretender(); store = this.owner.lookup('service:store'); - adapter = store.adapterFor('application'); passedUrl = passedVerb = passedHash = null; }); @@ -130,199 +129,220 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }); }; } + + module('with setup adapter', function(hooks) { + hooks.beforeEach(() => { + adapter = store.adapterFor('application'); + }); - test('findRecord - basic payload', function(assert) { - ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findRecord - basic payload', function(assert) { + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - test('findRecord - passes buildURL a requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/post/' + id; - }; + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); + }); - ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); + test('findRecord - passes buildURL a requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/post/' + id; + }; - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/findRecord/post/1'); - }) - ); - }); + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - test('findRecord - basic payload (with legacy singular name)', function(assert) { - ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/findRecord/post/1'); + }) + ); + }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findRecord - basic payload (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - test('findRecord - payload with sideloaded records of the same type', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findRecord - payload with sideloaded records of the same type', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - let post2 = store.peekRecord('post', 2); - assert.equal(post2.get('id'), '2'); - assert.equal(post2.get('name'), 'The Parley Letter'); - }) - ); - }); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); - test('findRecord - payload with sideloaded records of a different type', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is omakase' }], - comments: [{ id: 1, name: 'FIRST' }], + let post2 = store.peekRecord('post', 2); + assert.equal(post2.get('id'), '2'); + assert.equal(post2.get('name'), 'The Parley Letter'); + }) + ); }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); - - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); + test('findRecord - payload with sideloaded records of a different type', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is omakase' }], + comments: [{ id: 1, name: 'FIRST' }], + }); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('id'), '1'); - assert.equal(comment.get('name'), 'FIRST'); - }) - ); - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - test('findRecord - payload with an serializer-specified primary key', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - }) - ); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); - ajaxResponse({ posts: [{ _ID_: 1, name: 'Rails is omakase' }] }); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('id'), '1'); + assert.equal(comment.get('name'), 'FIRST'); + }) + ); + }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findRecord - payload with an serializer-specified primary key', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + }) + ); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); + ajaxResponse({ posts: [{ _ID_: 1, name: 'Rails is omakase' }] }); - test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: '_NAME_', - createdAt: { key: '_CREATED_AT_', someOtherOption: 'option' }, - }, - }) - ); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - Post.reopen({ - createdAt: DS.attr('number'), + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); }); - ajaxResponse({ posts: [{ id: 1, _NAME_: 'Rails is omakase', _CREATED_AT_: 2013 }] }); + test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_NAME_', + createdAt: { key: '_CREATED_AT_', someOtherOption: 'option' }, + }, + }) + ); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + Post.reopen({ + createdAt: DS.attr('number'), + }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - assert.equal(post.get('createdAt'), 2013); - }) - ); - }); + ajaxResponse({ posts: [{ id: 1, _NAME_: 'Rails is omakase', _CREATED_AT_: 2013 }] }); + + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - test('findRecord - passes `include` as a query parameter to ajax', function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is very expensive sushi' }, + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + assert.equal(post.get('createdAt'), 2013); + }) + ); }); - return run(() => - store.findRecord('post', 1, { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - }) - ); - }); + test('findRecord - passes `include` as a query parameter to ajax', function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is very expensive sushi' }, + }); - test('createRecord - an empty payload is a basic success if an id was specified', function(assert) { - ajaxResponse(); + return run(() => + store.findRecord('post', 1, { include: 'comments' }).then(() => { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); + }) + ); + }); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { id: 'some-uuid', name: 'The Parley Letter' } }); + test('createRecord - an empty payload is a basic success if an id was specified', function(assert) { + ajaxResponse(); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { id: 'some-uuid', name: 'The Parley Letter' } }); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); + }); }); }); - }); - test('createRecord - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/post/' + requestType; - }; + test('createRecord - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/post/' + requestType; + }; - ajaxResponse(); + ajaxResponse(); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/post/createRecord'); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/post/createRecord'); + }); }); }); - }); - test('createRecord - a payload with a new ID and data applies the updates', function(assert) { - ajaxResponse({ posts: [{ id: '1', name: 'Dat Parley Letter' }] }); + test('createRecord - a payload with a new ID and data applies the updates', function(assert) { + ajaxResponse({ posts: [{ id: '1', name: 'Dat Parley Letter' }] }); + + return run(() => { + let post = store.createRecord('post', { name: 'The Parley Letter' }); + + return post.save().then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - return run(() => { + assert.equal(post.get('id'), '1', 'the post has the updated ID'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); + }); + }); + + test('createRecord - a payload with a new ID and data applies the updates (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: '1', name: 'Dat Parley Letter' } }); let post = store.createRecord('post', { name: 'The Parley Letter' }); - return post.save().then(post => { + return run(post, 'save').then(post => { assert.equal(passedUrl, '/posts'); assert.equal(passedVerb, 'POST'); assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); @@ -332,1550 +352,1639 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); }); - }); - - test('createRecord - a payload with a new ID and data applies the updates (with legacy singular name)', function(assert) { - ajaxResponse({ post: { id: '1', name: 'Dat Parley Letter' } }); - let post = store.createRecord('post', { name: 'The Parley Letter' }); - - return run(post, 'save').then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - - assert.equal(post.get('id'), '1', 'the post has the updated ID'); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - }); - }); - test("createRecord - findMany doesn't overwrite owner", function(assert) { - ajaxResponse({ comment: { id: '1', name: 'Dat Parley Letter', post: 1 } }); + test("createRecord - findMany doesn't overwrite owner", function(assert) { + ajaxResponse({ comment: { id: '1', name: 'Dat Parley Letter', post: 1 } }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [], + }, }, }, - }, + }); }); - }); - let post = store.peekRecord('post', 1); + let post = store.peekRecord('post', 1); - let comment = store.createRecord('comment', { name: 'The Parley Letter' }); + let comment = store.createRecord('comment', { name: 'The Parley Letter' }); - run(() => { - post.get('comments').pushObject(comment); + run(() => { + post.get('comments').pushObject(comment); - assert.equal(comment.get('post'), post, 'the post has been set correctly'); - }); + assert.equal(comment.get('post'), post, 'the post has been set correctly'); + }); - return run(() => { - return comment.save().then(comment => { - assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(comment.get('name'), 'Dat Parley Letter', 'the post was updated'); - assert.equal(comment.get('post'), post, 'the post is still set'); + return run(() => { + return comment.save().then(comment => { + assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(comment.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(comment.get('post'), post, 'the post is still set'); + }); }); }); - }); - test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_id_', + test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - attrs: { - name: '_name_', - }, - }) - ); + attrs: { + name: '_name_', + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return run(() => - post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { _id_: 'some-uuid', _name_: 'The Parley Letter' }, - }); - }) - ); - }); + return run(() => + post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { _id_: 'some-uuid', _name_: 'The Parley Letter' }, + }); + }) + ); + }); - test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { - let post; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: '_name_', - }, - }) - ); + test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { + let post; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_name_', + }, + }) + ); - ajaxResponse({ - post: { _name_: 'The Parley Letter', id: '1' }, - }); + ajaxResponse({ + post: { _name_: 'The Parley Letter', id: '1' }, + }); - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + return post.save().then(post => { + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + }); }); }); - }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: 'given_name', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: 'given_name', + }, - keyForAttribute(attr) { - return attr.toUpperCase(); - }, - }) - ); + keyForAttribute(attr) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { given_name: 'The Parley Letter', id: 'some-uuid' }, + return post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { given_name: 'The Parley Letter', id: 'some-uuid' }, + }); }); }); }); - }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - attrs: { - post: 'article', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + attrs: { + post: 'article', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - }, - }) - ); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - return run(() => { - let post = store.createRecord('post', { id: 'a-post-id', name: 'The Parley Letter' }); - let comment = store.createRecord('comment', { - id: 'some-uuid', - name: 'Letters are fun', - post: post, - }); + return run(() => { + let post = store.createRecord('post', { id: 'a-post-id', name: 'The Parley Letter' }); + let comment = store.createRecord('comment', { + id: 'some-uuid', + name: 'Letters are fun', + post: post, + }); - return comment.save().then(post => { - assert.deepEqual(passedHash.data, { - comment: { article: 'a-post-id', id: 'some-uuid', name: 'Letters are fun' }, + return comment.save().then(post => { + assert.deepEqual(passedHash.data, { + comment: { article: 'a-post-id', id: 'some-uuid', name: 'Letters are fun' }, + }); }); }); }); - }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - comments: 'opinions', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + comments: 'opinions', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - }, - }) - ); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - return run(() => { - let comment = store.createRecord('comment', { id: 'a-comment-id', name: 'First!' }); - let post = store.createRecord('post', { - id: 'some-uuid', - name: 'The Parley Letter', - comments: [comment], - }); + return run(() => { + let comment = store.createRecord('comment', { id: 'a-comment-id', name: 'First!' }); + let post = store.createRecord('post', { + id: 'some-uuid', + name: 'The Parley Letter', + comments: [comment], + }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { opinions: ['a-comment-id'], id: 'some-uuid', name: 'The Parley Letter' }, + return post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { opinions: ['a-comment-id'], id: 'some-uuid', name: 'The Parley Letter' }, + }); }); }); }); - }); - test('createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded', function(assert) { - assert.expect(3); + test('createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded', function(assert) { + assert.expect(3); - ajaxResponse({ - posts: [ - { - id: '1', - name: 'Rails is omakase', - comments: [1, 2], - }, - ], - comments: [ - { - id: '2', - name: 'Another Comment', - post: 1, - }, - { - id: '1', - name: 'Dat Parley Letter', - post: 1, - }, - ], - // My API is returning a comment:{} as well as a comments:[{...},...] - //, comment: { - // id: "2", - // name: "Another Comment", - // post: 1 - // } - }); - - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { + ajaxResponse({ + posts: [ + { + id: '1', name: 'Rails is omakase', + comments: [1, 2], }, - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }], - }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, }, - }, + { + id: '1', + name: 'Dat Parley Letter', + post: 1, + }, + ], + // My API is returning a comment:{} as well as a comments:[{...},...] + //, comment: { + // id: "2", + // name: "Another Comment", + // post: 1 + // } }); - store.push({ - data: { - type: 'comment', - id: '1', - attributes: { - name: 'Dat Parlay Letter', + + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, + }, }, - relationships: { - post: { - data: { type: 'post', id: '1' }, + }); + store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + name: 'Dat Parlay Letter', + }, + relationships: { + post: { + data: { type: 'post', id: '1' }, + }, }, }, - }, + }); }); - }); - let post = store.peekRecord('post', 1); - let commentCount = run(() => post.get('comments.length')); + let post = store.peekRecord('post', 1); + let commentCount = run(() => post.get('comments.length')); - assert.equal(commentCount, 1, 'the post starts life with a comment'); + assert.equal(commentCount, 1, 'the post starts life with a comment'); - return run(() => { - let comment = store.createRecord('comment', { name: 'Another Comment', post: post }); + return run(() => { + let comment = store.createRecord('comment', { name: 'Another Comment', post: post }); - return comment.save().then(comment => { - assert.equal(comment.get('post'), post, 'the comment is related to the post'); - return post.reload().then(post => { - assert.equal(post.get('comments.length'), 2, 'Post comment count has been updated'); + return comment.save().then(comment => { + assert.equal(comment.get('post'), post, 'the comment is related to the post'); + return post.reload().then(post => { + assert.equal(post.get('comments.length'), 2, 'Post comment count has been updated'); + }); }); }); }); - }); - test('createRecord - sideloaded belongsTo relationships are both marked as loaded', function(assert) { - assert.expect(4); + test('createRecord - sideloaded belongsTo relationships are both marked as loaded', function(assert) { + assert.expect(4); - Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: 'man' }); + let post = store.createRecord('post', { name: 'man' }); - ajaxResponse({ - posts: [{ id: 1, comment: 1, name: 'marked' }], - comments: [{ id: 1, post: 1, name: 'Comcast is a bargain' }], - }); + ajaxResponse({ + posts: [{ id: 1, comment: 1, name: 'marked' }], + comments: [{ id: 1, post: 1, name: 'Comcast is a bargain' }], + }); - return run(() => { - return post.save().then(record => { - assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); - assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); - assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); - assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); + return run(() => { + return post.save().then(record => { + assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); + assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); + assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); + }); }); }); - }); - test("createRecord - response can contain relationships the client doesn't yet know about", function(assert) { - assert.expect(3); // while records.length is 2, we are getting 4 assertions + test("createRecord - response can contain relationships the client doesn't yet know about", function(assert) { + assert.expect(3); // while records.length is 2, we are getting 4 assertions - ajaxResponse({ - posts: [ - { - id: '1', - name: 'Rails is omakase', - comments: [2], - }, - ], - comments: [ - { - id: '2', - name: 'Another Comment', - post: 1, - }, - ], - }); - - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + ajaxResponse({ + posts: [ + { + id: '1', + name: 'Rails is omakase', + comments: [2], + }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, + }, + ], + }); - let post = store.createRecord('post', { name: 'Rails is omakase' }); + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - return run(() => { - return post.save().then(post => { - assert.equal(post.get('comments.firstObject.post'), post, 'the comments are related to the correct post model'); - assert.equal( - store._internalModelsFor('post').models.length, - 1, - 'There should only be one post record in the store' - ); + let post = store.createRecord('post', { name: 'Rails is omakase' }); - let postRecords = store._internalModelsFor('post').models; - for (var i = 0; i < postRecords.length; i++) { - assert.equal(post, postRecords[i].getRecord(), 'The object in the identity map is the same'); - } + return run(() => { + return post.save().then(post => { + assert.equal(post.get('comments.firstObject.post'), post, 'the comments are related to the correct post model'); + assert.equal( + store._internalModelsFor('post').models.length, + 1, + 'There should only be one post record in the store' + ); + + let postRecords = store._internalModelsFor('post').models; + for (var i = 0; i < postRecords.length; i++) { + assert.equal(post, postRecords[i].getRecord(), 'The object in the identity map is the same'); + } + }); }); }); - }); - test('createRecord - relationships are not duplicated', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + test('createRecord - relationships are not duplicated', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: 'Tomtomhuda' }); - let comment = store.createRecord('comment', { id: 2, name: 'Comment title' }); + let post = store.createRecord('post', { name: 'Tomtomhuda' }); + let comment = store.createRecord('comment', { id: 2, name: 'Comment title' }); - ajaxResponse({ post: [{ id: 1, name: 'Rails is omakase', comments: [] }] }); + ajaxResponse({ post: [{ id: 1, name: 'Rails is omakase', comments: [] }] }); - return run(() => - post - .save() - .then(post => { - assert.equal(post.get('comments.length'), 0, 'post has 0 comments'); - post.get('comments').pushObject(comment); - assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); + return run(() => + post + .save() + .then(post => { + assert.equal(post.get('comments.length'), 0, 'post has 0 comments'); + post.get('comments').pushObject(comment); + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); - ajaxResponse({ - post: [{ id: 1, name: 'Rails is omakase', comments: [2] }], - comments: [{ id: 2, name: 'Comment title' }], - }); + ajaxResponse({ + post: [{ id: 1, name: 'Rails is omakase', comments: [2] }], + comments: [{ id: 2, name: 'Comment title' }], + }); - return post.save(); - }) - .then(post => { - assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); - }) - ); - }); + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); + }) + ); + }); - test('updateRecord - an empty payload is a basic success', function(assert) { - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + test('updateRecord - an empty payload is a basic success', function(assert) { + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); }); - }); - return run(() => { - let post = store.peekRecord('post', 1); - ajaxResponse(); + return run(() => { + let post = store.peekRecord('post', 1); + ajaxResponse(); - post.set('name', 'The Parley Letter'); - return post.save().then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + post.set('name', 'The Parley Letter'); + return post.save().then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); + }); }); }); - }); - test('updateRecord - passes the requestType to buildURL', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/posts/' + id + '/' + requestType; - }; - adapter.shouldBackgroundReloadRecord = () => false; + test('updateRecord - passes the requestType to buildURL', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/posts/' + id + '/' + requestType; + }; + adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); + }); + + return run(() => { + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); + + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1/updateRecord'); + }); }); }); - return run(() => { + test('updateRecord - a payload with updates applies the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + }); + }); + return store .findRecord('post', 1) .then(post => { - ajaxResponse(); + ajaxResponse({ posts: [{ id: 1, name: 'Dat Parley Letter' }] }); post.set('name', 'The Parley Letter'); return post.save(); }) .then(post => { - assert.equal(passedUrl, '/posts/1/updateRecord'); + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); }); - }); - test('updateRecord - a payload with updates applies the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + test('updateRecord - a payload with updates applies the updates (with legacy singular name)', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ posts: [{ id: 1, name: 'Dat Parley Letter' }] }); - - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ post: { id: 1, name: 'Dat Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - }); - }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - test('updateRecord - a payload with updates applies the updates (with legacy singular name)', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ post: { id: 1, name: 'Dat Parley Letter' } }); - - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { + let post; + ajaxResponse({ + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], }); - }); - - test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { - let post; - ajaxResponse({ - posts: [{ id: 1, name: 'Dat Parley Letter' }], - comments: [{ id: 1, name: 'FIRST' }], - }); - - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('id'), '1', 'the post has the updated ID'); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + + assert.equal(post.get('id'), '1', 'the post has the updated ID'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); }); }); - }); - test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - posts: [{ id: 1, name: 'Dat Parley Letter' }], - comments: [{ id: 1, name: 'FIRST' }], - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], + }); - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); - }); - }); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); + }); - test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_id_', + test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - attrs: { - name: '_name_', - }, - }) - ); + attrs: { + name: '_name_', + }, + }) + ); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - name: 'Rails is omakase', - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + name: 'Rails is omakase', + }, + }); }); - }); - ajaxResponse(); + ajaxResponse(); - return store - .findRecord('post', 1) - .then(post => { - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); - }); - }); + return store + .findRecord('post', 1) + .then(post => { + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + }); + }); - test('updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - adapter.shouldBackgroundReloadRecord = () => false; + test('updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Not everyone uses Rails', - }, - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }], - }, - }, - }, - included: [ - { - type: 'comment', + run(() => { + store.push({ + data: { + type: 'post', id: '1', attributes: { - name: 'Rails is omakase', + name: 'Not everyone uses Rails', }, - }, - { - type: 'comment', - id: '2', - attributes: { - name: 'Yes. Yes it is.', + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, }, }, - ], + included: [ + { + type: 'comment', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + { + type: 'comment', + id: '2', + attributes: { + name: 'Yes. Yes it is.', + }, + }, + ], + }); }); - }); - ajaxResponse({ - posts: { id: 1, name: 'Not everyone uses Rails', comments: [2] }, - }); - - return store - .findRecord('comment', 2) - .then(() => { - return store.findRecord('post', 1); - }) - .then(post => { - let newComment = store.peekRecord('comment', 2); - let comments = post.get('comments'); + ajaxResponse({ + posts: { id: 1, name: 'Not everyone uses Rails', comments: [2] }, + }); - // Replace the comment with a new one - comments.popObject(); - comments.pushObject(newComment); + return store + .findRecord('comment', 2) + .then(() => { + return store.findRecord('post', 1); + }) + .then(post => { + let newComment = store.peekRecord('comment', 2); + let comments = post.get('comments'); - return post.save(); - }) - .then(post => { - assert.equal(post.get('comments.length'), 1, 'the post has the correct number of comments'); - assert.equal(post.get('comments.firstObject.name'), 'Yes. Yes it is.', 'the post has the correct comment'); - }); - }); + // Replace the comment with a new one + comments.popObject(); + comments.pushObject(newComment); - test('deleteRecord - an empty payload is a basic success', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - }); + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'the post has the correct number of comments'); + assert.equal(post.get('comments.firstObject.name'), 'Yes. Yes it is.', 'the post has the correct comment'); + }); }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse(); - - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); - - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + test('deleteRecord - an empty payload is a basic success', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + }); }); - }); - test('deleteRecord - passes the requestType to buildURL', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/posts/' + id + '/' + requestType; - }; + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - }); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + }); }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse(); + test('deleteRecord - passes the requestType to buildURL', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/posts/' + id + '/' + requestType; + }; - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1/deleteRecord'); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + }); }); - }); - test('deleteRecord - a payload with sideloaded updates pushes the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); + + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1/deleteRecord'); + }); + }); + + test('deleteRecord - a payload with sideloaded updates pushes the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1, name: 'FIRST' }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1, name: 'FIRST' }] }); - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); - }); - }); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); + }); - test('deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', + test('deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ posts: [{ id: 2, name: 'The Parley Letter' }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ posts: [{ id: 2, name: 'The Parley Letter' }] }); - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the original post is now deleted'); + assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the original post is now deleted'); - let newPost = store.peekRecord('post', 2); - assert.equal(newPost.get('name'), 'The Parley Letter', 'The new post was added to the store'); - }); - }); + let newPost = store.peekRecord('post', 2); + assert.equal(newPost.get('name'), 'The Parley Letter', 'The new post was added to the store'); + }); + }); - test('deleteRecord - deleting a newly created record should not throw an error', function(assert) { - let post = store.createRecord('post'); + test('deleteRecord - deleting a newly created record should not throw an error', function(assert) { + let post = store.createRecord('post'); - return run(() => { - post.deleteRecord(); - return post.save().then(post => { - assert.equal(passedUrl, null, 'There is no ajax call to delete a record that has never been saved.'); - assert.equal(passedVerb, null, 'There is no ajax call to delete a record that has never been saved.'); - assert.equal(passedHash, null, 'There is no ajax call to delete a record that has never been saved.'); + return run(() => { + post.deleteRecord(); + return post.save().then(post => { + assert.equal(passedUrl, null, 'There is no ajax call to delete a record that has never been saved.'); + assert.equal(passedVerb, null, 'There is no ajax call to delete a record that has never been saved.'); + assert.equal(passedHash, null, 'There is no ajax call to delete a record that has never been saved.'); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - assert.equal(post.get('isError'), false, 'the post is not an error'); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + assert.equal(post.get('isError'), false, 'the post is not an error'); + }); }); }); - }); - test('findAll - returning an array populates the array', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + test('findAll - returning an array populates the array', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - return store.findAll('post').then(posts => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + return store.findAll('post').then(posts => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + }); }); - }); - test('findAll - passes buildURL the requestType and snapshot', function(assert) { - assert.expect(2); - let adapterOptionsStub = { stub: true }; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.equal(snapshot.adapterOptions, adapterOptionsStub); - return '/' + requestType + '/posts'; - }; + test('findAll - passes buildURL the requestType and snapshot', function(assert) { + assert.expect(2); + let adapterOptionsStub = { stub: true }; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.equal(snapshot.adapterOptions, adapterOptionsStub); + return '/' + requestType + '/posts'; + }; - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { - assert.equal(passedUrl, '/findAll/posts'); + return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { + assert.equal(passedUrl, '/findAll/posts'); + }); }); - }); - test('findAll - passed `include` as a query parameter to ajax', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('findAll - passed `include` as a query parameter to ajax', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); + return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); + }); }); - }); - test('findAll - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - comments: [{ id: 1, name: 'FIRST' }], - }); + test('findAll - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.findAll('post').then(posts => { - let comment = store.peekRecord('comment', 1); + return store.findAll('post').then(posts => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + }); }); - }); - test('findAll - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + test('findAll - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - ajaxResponse({ - posts: [ - { _ID_: 1, _NAME_: 'Rails is omakase' }, - { _ID_: 2, _NAME_: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { _ID_: 1, _NAME_: 'Rails is omakase' }, + { _ID_: 2, _NAME_: 'The Parley Letter' }, + ], + }); - return store.findAll('post').then(posts => { - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + return store.findAll('post').then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + }); }); - }); - test('query - if `sortQueryParams` option is not provided, query params are sorted alphabetically', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('query - if `sortQueryParams` option is not provided, query params are sorted alphabetically', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['in', 'order', 'params', 'wrong'], - 'query params are received in alphabetical order' - ); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['in', 'order', 'params', 'wrong'], + 'query params are received in alphabetical order' + ); + }); }); - }); - test('query - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/posts'; - }; - - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('query - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/posts'; + }; - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.equal(passedUrl, '/query/posts'); - }); - }); + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - test('query - if `sortQueryParams` is falsey, query params are not sorted at all', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.equal(passedUrl, '/query/posts'); + }); }); - adapter.sortQueryParams = null; + test('query - if `sortQueryParams` is falsey, query params are not sorted at all', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['params', 'in', 'wrong', 'order'], - 'query params are received in their original order' - ); - }); - }); + adapter.sortQueryParams = null; - test('query - if `sortQueryParams` is a custom function, query params passed through that function', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['params', 'in', 'wrong', 'order'], + 'query params are received in their original order' + ); + }); }); - adapter.sortQueryParams = function(obj) { - let sortedKeys = Object.keys(obj) - .sort() - .reverse(); - let len = sortedKeys.length; - let newQueryParams = {}; + test('query - if `sortQueryParams` is a custom function, query params passed through that function', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - for (var i = 0; i < len; i++) { - newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; - } - return newQueryParams; - }; + adapter.sortQueryParams = function(obj) { + let sortedKeys = Object.keys(obj) + .sort() + .reverse(); + let len = sortedKeys.length; + let newQueryParams = {}; - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['wrong', 'params', 'order', 'in'], - 'query params are received in reverse alphabetical order' - ); - }); - }); + for (var i = 0; i < len; i++) { + newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; + } + return newQueryParams; + }; - test("query - payload 'meta' is accessible on the record array", function(assert) { - ajaxResponse({ - meta: { offset: 5 }, - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['wrong', 'params', 'order', 'in'], + 'query params are received in reverse alphabetical order' + ); + }); }); - return store.query('post', { page: 2 }).then(posts => { - assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); - }); - }); + test("query - payload 'meta' is accessible on the record array", function(assert) { + ajaxResponse({ + meta: { offset: 5 }, + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - test("query - each record array can have it's own meta object", function(assert) { - ajaxResponse({ - meta: { offset: 5 }, - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + return store.query('post', { page: 2 }).then(posts => { + assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); + }); }); - return store.query('post', { page: 2 }).then(posts => { - assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); + test("query - each record array can have it's own meta object", function(assert) { ajaxResponse({ - meta: { offset: 1 }, + meta: { offset: 5 }, posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); - return store.query('post', { page: 1 }).then(newPosts => { - assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); - assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); + return store.query('post', { page: 2 }).then(posts => { + assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); + ajaxResponse({ + meta: { offset: 1 }, + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); + + return store.query('post', { page: 1 }).then(newPosts => { + assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); + assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); + }); }); }); - }); - test('query - returning an array populates the array', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + test('query - returning an array populates the array', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - return store.query('post', { page: 1 }).then(posts => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, { page: 1 }); + return store.query('post', { page: 1 }).then(posts => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, { page: 1 }); - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + }); }); - }); - test('query - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - comments: [{ id: 1, name: 'FIRST' }], - }); + test('query - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.query('post', { page: 1 }).then(posts => { - let comment = store.peekRecord('comment', 1); + return store.query('post', { page: 1 }).then(posts => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + }); }); - }); - test('query - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + test('query - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - ajaxResponse({ - posts: [ - { _ID_: 1, _NAME_: 'Rails is omakase' }, - { _ID_: 2, _NAME_: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { _ID_: 1, _NAME_: 'Rails is omakase' }, + { _ID_: 2, _NAME_: 'The Parley Letter' }, + ], + }); - return store.query('post', { page: 1 }).then(posts => { - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + return store.query('post', { page: 1 }).then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); + }); }); - }); - test('queryRecord - empty response', function(assert) { - ajaxResponse({}); + test('queryRecord - empty response', function(assert) { + ajaxResponse({}); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.strictEqual(post, null); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.strictEqual(post, null); + }); }); - }); - test('queryRecord - primary data being null', function(assert) { - ajaxResponse({ - post: null, - }); + test('queryRecord - primary data being null', function(assert) { + ajaxResponse({ + post: null, + }); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.strictEqual(post, null); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.strictEqual(post, null); + }); }); - }); - test('queryRecord - primary data being a single object', function(assert) { - ajaxResponse({ - post: { - id: '1', - name: 'Ember.js rocks', - }, - }); + test('queryRecord - primary data being a single object', function(assert) { + ajaxResponse({ + post: { + id: '1', + name: 'Ember.js rocks', + }, + }); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.deepEqual(post.get('name'), 'Ember.js rocks'); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.deepEqual(post.get('name'), 'Ember.js rocks'); + }); }); - }); - test('queryRecord - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is omakase' }, - comments: [{ id: 1, name: 'FIRST' }], - }); + test('queryRecord - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is omakase' }, + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let comment = store.peekRecord('comment', 1); + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + }); }); - }); - testInDebug('queryRecord - returning an array picks the first one but saves all records to the store', function( - assert - ) { - ajaxResponse({ - post: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'Ember is js' }, - ], - }); + testInDebug('queryRecord - returning an array picks the first one but saves all records to the store', function( + assert + ) { + ajaxResponse({ + post: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'Ember is js' }, + ], + }); - assert.expectDeprecation( - () => - run(() => { - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let post2 = store.peekRecord('post', 2); + assert.expectDeprecation( + () => + run(() => { + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post.getProperties('id', 'name'), { - id: '1', - name: 'Rails is omakase', + assert.deepEqual(post.getProperties('id', 'name'), { + id: '1', + name: 'Rails is omakase', + }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'Ember is js' }); }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'Ember is js' }); - }); - }), - - /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./ - ); - }); + }), - testInDebug('queryRecord - returning an array is deprecated', function(assert) { - ajaxResponse({ - post: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'Ember is js' }, - ], + /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./ + ); }); - assert.expectDeprecation( - () => run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), - 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.' - ); - }); + testInDebug('queryRecord - returning an array is deprecated', function(assert) { + ajaxResponse({ + post: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'Ember is js' }, + ], + }); - testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is omakase' }, + assert.expectDeprecation( + () => run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), + 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.' + ); }); - assert.expectNoDeprecation(); - - return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); - }); + testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is omakase' }, + }); - test('queryRecord - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + assert.expectNoDeprecation(); - ajaxResponse({ - post: { _ID_: 1, _NAME_: 'Rails is omakase' }, + return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); }); - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - assert.deepEqual( - post.getProperties('id', 'name'), - { id: '1', name: 'Rails is omakase' }, - 'Post 1 is loaded with correct data' + test('queryRecord - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) ); + + ajaxResponse({ + post: { _ID_: 1, _NAME_: 'Rails is omakase' }, + }); + + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + assert.deepEqual( + post.getProperties('id', 'name'), + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded with correct data' + ); + }); }); - }); - test('findMany - findMany uses a correct URL to access the records', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + test('findMany - findMany uses a correct URL to access the records', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, + }); }); - }); - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return run(() => - post.get('comments').then(comments => { - assert.equal(passedUrl, '/comments'); - assert.deepEqual(passedHash, { data: { ids: ['1', '2', '3'] } }); - }) - ); - }); + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments'); + assert.deepEqual(passedHash, { data: { ids: ['1', '2', '3'] } }); + }) + ); + }); - test('findMany - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/' + type; - }; + test('findMany - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/' + type; + }; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, + }); }); - }); - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return run(post, 'get', 'comments').then(comments => { - assert.equal(passedUrl, '/findMany/comment'); + return run(post, 'get', 'comments').then(comments => { + assert.equal(passedUrl, '/findMany/comment'); + }); }); - }); - test('findMany - findMany does not coalesce by default', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('findMany - findMany does not coalesce by default', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, + }); }); - }); - let post = store.peekRecord('post', 1); - //It's still ok to return this even without coalescing because RESTSerializer supports sideloading - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + let post = store.peekRecord('post', 1); + //It's still ok to return this even without coalescing because RESTSerializer supports sideloading + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return run(() => - post.get('comments').then(comments => { - assert.equal(passedUrl, '/comments/3'); - assert.deepEqual(passedHash.data, {}); - }) - ); - }); + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments/3'); + assert.deepEqual(passedHash.data, {}); + }) + ); + }); - test('findMany - returning an array populates the array', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + test('findMany - returning an array populates the array', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', - }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', + }); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }); - }); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + }); + }); - test('findMany - returning sideloaded data loads the data', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + test('findMany - returning sideloaded data loads the data', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, + }); }); - }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - { id: 4, name: 'Unrelated comment' }, - ], - posts: [{ id: 2, name: 'The Parley Letter' }], + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + { id: 4, name: 'Unrelated comment' }, + ], + posts: [{ id: 2, name: 'The Parley Letter' }], + }); + + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let comment4 = store.peekRecord('comment', 4); + let post2 = store.peekRecord('post', 2); + + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + + assert.deepEqual(comment4.getProperties('id', 'name'), { + id: '4', + name: 'Unrelated comment', + }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); }); + }); - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let comment4 = store.peekRecord('comment', 4); - let post2 = store.peekRecord('post', 2); + test('findMany - a custom serializer is used if present', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); + + adapter.coalesceFindRequests = true; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - assert.deepEqual(comment4.getProperties('id', 'name'), { - id: '4', - name: 'Unrelated comment', + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); }); - }); - test('findMany - a custom serializer is used if present', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - adapter.coalesceFindRequests = true; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', + }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + }); + }); + + test('findHasMany - returning an array populates the array', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', + }, + }, }, }, - }, + }); }); + + return run(() => + store + .findRecord('post', '1') + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); + + return post.get('comments'); + }) + .then(comments => { + assert.equal(passedUrl, '/posts/1/comments'); + assert.equal(passedVerb, 'GET'); + assert.strictEqual(passedHash, undefined); + + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { + id: '2', + name: 'Rails is unagi', + }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', + }); + + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + }) + ); }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { _ID_: 1, _NAME_: 'FIRST' }, - { _ID_: 2, _NAME_: 'Rails is unagi' }, - { _ID_: 3, _NAME_: 'What is omakase?' }, - ], - }); + test('findHasMany - passes buildURL the requestType', function(assert) { + assert.expect(2); + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); + assert.equal(requestType, 'findHasMany'); + }; - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', + }, + }, + }, + }, }); - - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); }); - }); - test('findHasMany - returning an array populates the array', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + return run(() => + store.findRecord('post', '1').then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', + return post.get('comments'); + }) + ); + }); + + test('findMany - returning sideloaded data loads the data (with JSONApi Links)', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', + }, }, }, }, - }, + }); }); - }); - return run(() => - store - .findRecord('post', '1') + return store + .findRecord('post', 1) .then(post => { ajaxResponse({ comments: [ @@ -1883,246 +1992,242 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { { id: 2, name: 'Rails is unagi' }, { id: 3, name: 'What is omakase?' }, ], + posts: [{ id: 2, name: 'The Parley Letter' }], }); return post.get('comments'); }) .then(comments => { - assert.equal(passedUrl, '/posts/1/comments'); - assert.equal(passedVerb, 'GET'); - assert.strictEqual(passedHash, undefined); + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let post2 = store.peekRecord('post', 2); + + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + }); + }); + + test('findMany - a custom serializer is used if present', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); + + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); + + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', + }, + }, + }, + }, + }); + }); + + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); + return post.get('comments'); + }) + .then(comments => { let comment1 = store.peekRecord('comment', 1); let comment2 = store.peekRecord('comment', 2); let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { - id: '2', - name: 'Rails is unagi', - }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); assert.deepEqual(comment3.getProperties('id', 'name'), { id: '3', name: 'What is omakase?', }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }) - ); - }); + }); + }); - test('findHasMany - passes buildURL the requestType', function(assert) { - assert.expect(2); - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.ok(snapshot instanceof DS.Snapshot); - assert.equal(requestType, 'findHasMany'); - }; + test('findBelongsTo - passes buildURL the requestType', function(assert) { + assert.expect(2); + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); + assert.equal(requestType, 'findBelongsTo'); + }; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', + run(() => { + store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + name: 'FIRST', + }, + relationships: { + post: { + links: { + related: '/posts/1', + }, }, }, }, - }, - }); - }); - - return run(() => - store.findRecord('post', '1').then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], }); + }); - return post.get('comments'); - }) - ); - }); + return run(() => + store.findRecord('comment', '1').then(comment => { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); + return comment.get('post'); + }) + ); + }); - test('findMany - returning sideloaded data loads the data (with JSONApi Links)', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + testInDebug( + 'coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', + function(assert) { + assert.expect(2); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', - }, - }, - }, - }, - }); - }); + adapter.coalesceFindRequests = true; - return store - .findRecord('post', 1) - .then(post => { ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - posts: [{ id: 2, name: 'The Parley Letter' }], + comments: [{ id: '1', type: 'comment' }], }); - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let post2 = store.peekRecord('post', 2); - - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); - }); - }); - - test('findMany - a custom serializer is used if present', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); - - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); - - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', + let post = run(() => + store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, }, - }, - }, - }); - }); + }) + ); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { _ID_: 1, _NAME_: 'FIRST' }, - { _ID_: 2, _NAME_: 'Rails is unagi' }, - { _ID_: 3, _NAME_: 'What is omakase?' }, - ], - }); - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); + assert.expectWarning(() => { + return run(() => { + return post.get('comments').catch(e => { + assert.equal( + e.message, + `Expected: '' to be present in the adapter provided payload, but it was not found.` + ); + }); + }); + }, /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/); + } + ); - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', - }); + test('groupRecordsForFindMany groups records based on their url', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }); - }); + adapter.buildURL = function(type, id, snapshot) { + if (id === '1') { + return '/comments/1'; + } else { + return '/other_comments/' + id; + } + }; - test('findBelongsTo - passes buildURL the requestType', function(assert) { - assert.expect(2); - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.ok(snapshot instanceof DS.Snapshot); - assert.equal(requestType, 'findBelongsTo'); - }; + adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(id, '1'); + return resolve({ comments: { id: 1 } }); + }; - Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, ['2', '3']); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); + }; - run(() => { - store.push({ - data: { - type: 'comment', - id: '1', - attributes: { - name: 'FIRST', - }, - relationships: { - post: { - links: { - related: '/posts/1', + let post; + run(() => { + store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, }, - }, + }); + post = store.peekRecord('post', 2); }); - }); - return run(() => - store.findRecord('comment', '1').then(comment => { - ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - return comment.get('post'); - }) - ); - }); + run(() => post.get('comments')); + }); - testInDebug( - 'coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', - function(assert) { - assert.expect(2); + test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; - ajaxResponse({ - comments: [{ id: '1', type: 'comment' }], - }); + adapter.buildURL = function(type, id, snapshot) { + if (id === '1') { + return '/comments?id=1'; + } else { + return '/other_comments?id=' + id; + } + }; + + adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(id, '1'); + return resolve({ comments: { id: 1 } }); + }; + + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, ['2', '3']); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); + }; + let post; - let post = run(() => + run(() => { store.push({ data: { type: 'post', @@ -2137,306 +2242,252 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }, }, }, - }) - ); - - assert.expectWarning(() => { - return run(() => { - return post.get('comments').catch(e => { - assert.equal( - e.message, - `Expected: '' to be present in the adapter provided payload, but it was not found.` - ); - }); }); - }, /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/); - } - ); - - test('groupRecordsForFindMany groups records based on their url', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; - - adapter.buildURL = function(type, id, snapshot) { - if (id === '1') { - return '/comments/1'; - } else { - return '/other_comments/' + id; - } - }; + post = store.peekRecord('post', 2); + }); - adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(id, '1'); - return resolve({ comments: { id: 1 } }); - }; + run(() => post.get('comments')); + }); - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, ['2', '3']); - return resolve({ comments: [{ id: 2 }, { id: 3 }] }); - }; + test('normalizeKey - to set up _ids and _id', function(assert) { + this.owner.register( + 'serializer:application', + DS.RESTSerializer.extend({ + keyForAttribute(attr) { + return underscore(attr); + }, - let post; - run(() => { - store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + keyForBelongsTo(belongsTo) {}, + + keyForRelationship(rel, kind) { + if (kind === 'belongsTo') { + let underscored = underscore(rel); + return underscored + '_id'; + } else { + let singular = singularize(rel); + return underscore(singular) + '_ids'; + } }, - }, - }); - post = store.peekRecord('post', 2); - }); + }) + ); - run(() => post.get('comments')); - }); + this.owner.register( + 'model:post', + DS.Model.extend({ + name: DS.attr(), + authorName: DS.attr(), + author: DS.belongsTo('user', { async: false }), + comments: DS.hasMany('comment', { async: false }), + }) + ); - test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + this.owner.register( + 'model:user', + DS.Model.extend({ + createdAt: DS.attr(), + name: DS.attr(), + }) + ); - adapter.buildURL = function(type, id, snapshot) { - if (id === '1') { - return '/comments?id=1'; - } else { - return '/other_comments?id=' + id; - } - }; + this.owner.register( + 'model:comment', + DS.Model.extend({ + body: DS.attr(), + }) + ); - adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(id, '1'); - return resolve({ comments: { id: 1 } }); - }; + ajaxResponse({ + posts: [ + { + id: '1', + name: 'Rails is omakase', + author_name: '@d2h', + author_id: '1', + comment_ids: ['1', '2'], + }, + ], - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, ['2', '3']); - return resolve({ comments: [{ id: 2 }, { id: 3 }] }); - }; - let post; - - run(() => { - store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + users: [ + { + id: '1', + name: 'D2H', }, - }, + ], + + comments: [ + { + id: '1', + body: 'Rails is unagi', + }, + { + id: '2', + body: 'What is omakase?', + }, + ], }); - post = store.peekRecord('post', 2); - }); - run(() => post.get('comments')); - }); + return run(() => { + return store.findRecord('post', 1).then(post => { + assert.equal(post.get('authorName'), '@d2h'); + assert.equal(post.get('author.name'), 'D2H'); + assert.deepEqual(post.get('comments').mapBy('body'), ['Rails is unagi', 'What is omakase?']); + }); + }); + }); - test('normalizeKey - to set up _ids and _id', function(assert) { - this.owner.register( - 'serializer:application', - DS.RESTSerializer.extend({ - keyForAttribute(attr) { - return underscore(attr); - }, + test('groupRecordsForFindMany splits up calls for large ids', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - keyForBelongsTo(belongsTo) {}, + assert.expect(2); - keyForRelationship(rel, kind) { - if (kind === 'belongsTo') { - let underscored = underscore(rel); - return underscored + '_id'; - } else { - let singular = singularize(rel); - return underscore(singular) + '_ids'; - } - }, - }) - ); + function repeatChar(character, n) { + return new Array(n + 1).join(character); + } - this.owner.register( - 'model:post', - DS.Model.extend({ - name: DS.attr(), - authorName: DS.attr(), - author: DS.belongsTo('user', { async: false }), - comments: DS.hasMany('comment', { async: false }), - }) - ); + let a2000 = repeatChar('a', 2000); + let b2000 = repeatChar('b', 2000); + let post; - this.owner.register( - 'model:user', - DS.Model.extend({ - createdAt: DS.attr(), - name: DS.attr(), - }) - ); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: a2000 }, + { type: 'comment', id: b2000 }, + ], + }, + }, + }, + }); + post = store.peekRecord('post', 1); + }); - this.owner.register( - 'model:comment', - DS.Model.extend({ - body: DS.attr(), - }) - ); + adapter.coalesceFindRequests = true; - ajaxResponse({ - posts: [ - { - id: '1', - name: 'Rails is omakase', - author_name: '@d2h', - author_id: '1', - comment_ids: ['1', '2'], - }, - ], + adapter.findRecord = function(store, type, id, snapshot) { + if (id === a2000 || id === b2000) { + assert.ok(true, 'Found ' + id); + } - users: [ - { - id: '1', - name: 'D2H', - }, - ], + return resolve({ comments: { id: id } }); + }; - comments: [ - { - id: '1', - body: 'Rails is unagi', - }, - { - id: '2', - body: 'What is omakase?', - }, - ], - }); + adapter.findMany = function(store, type, ids, snapshots) { + assert.ok(false, 'findMany should not be called - we expect 2 calls to find for a2000 and b2000'); + return reject(); + }; - return run(() => { - return store.findRecord('post', 1).then(post => { - assert.equal(post.get('authorName'), '@d2h'); - assert.equal(post.get('author.name'), 'D2H'); - assert.deepEqual(post.get('comments').mapBy('body'), ['Rails is unagi', 'What is omakase?']); - }); + run(() => post.get('comments')); }); - }); - test('groupRecordsForFindMany splits up calls for large ids', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('groupRecordsForFindMany groups calls for small ids', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - assert.expect(2); + assert.expect(1); - function repeatChar(character, n) { - return new Array(n + 1).join(character); - } + function repeatChar(character, n) { + return new Array(n + 1).join(character); + } - let a2000 = repeatChar('a', 2000); - let b2000 = repeatChar('b', 2000); - let post; + let a100 = repeatChar('a', 100); + let b100 = repeatChar('b', 100); + let post; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: a2000 }, - { type: 'comment', id: b2000 }, - ], + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: a100 }, + { type: 'comment', id: b100 }, + ], + }, }, }, - }, + }); + post = store.peekRecord('post', 1); }); - post = store.peekRecord('post', 1); - }); - - adapter.coalesceFindRequests = true; - - adapter.findRecord = function(store, type, id, snapshot) { - if (id === a2000 || id === b2000) { - assert.ok(true, 'Found ' + id); - } - - return resolve({ comments: { id: id } }); - }; - - adapter.findMany = function(store, type, ids, snapshots) { - assert.ok(false, 'findMany should not be called - we expect 2 calls to find for a2000 and b2000'); - return reject(); - }; - run(() => post.get('comments')); - }); + adapter.coalesceFindRequests = true; - test('groupRecordsForFindMany groups calls for small ids', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(false, 'findRecord should not be called - we expect 1 call to findMany for a100 and b100'); + return reject(); + }; - assert.expect(1); + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, [a100, b100]); + return resolve({ comments: [{ id: a100 }, { id: b100 }] }); + }; - function repeatChar(character, n) { - return new Array(n + 1).join(character); - } + run(() => post.get('comments')); + }); - let a100 = repeatChar('a', 100); - let b100 = repeatChar('b', 100); - let post; + if (hasJQuery) { + test('calls adapter.handleResponse with the jqXHR and json', function(assert) { + assert.expect(2); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: a100 }, - { type: 'comment', id: b100 }, - ], - }, + let data = { + post: { + id: '1', + name: 'Docker is amazing', }, - }, + }; + + server.get('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; + }); + + adapter.handleResponse = function(status, headers, json) { + assert.deepEqual(status, 200); + assert.deepEqual(json, data); + return json; + }; + + return run(() => store.findRecord('post', '1')); }); - post = store.peekRecord('post', 1); - }); - adapter.coalesceFindRequests = true; + test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { + assert.expect(4); - adapter.findRecord = function(store, type, id, snapshot) { - assert.ok(false, 'findRecord should not be called - we expect 1 call to findMany for a100 and b100'); - return reject(); - }; + let responseText = 'Nope lol'; - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, [a100, b100]); - return resolve({ comments: [{ id: a100 }, { id: b100 }] }); - }; + let expectedRequestData = { + method: 'GET', + url: '/posts/1', + }; - run(() => post.get('comments')); - }); + server.get('/posts/1', function() { + return [400, {}, responseText]; + }); - if (hasJQuery) { - test('calls adapter.handleResponse with the jqXHR and json', function(assert) { - assert.expect(2); + adapter.handleResponse = function(status, headers, json, requestData) { + assert.deepEqual(status, 400); + assert.deepEqual(json, responseText); + assert.deepEqual(requestData, expectedRequestData); + return new DS.AdapterError('nope!'); + }; + + return run(() => { + return store.findRecord('post', '1').catch(err => assert.ok(err, 'promise rejected')); + }); + }); + } + + test('rejects promise if DS.AdapterError is returned from adapter.handleResponse', function(assert) { + assert.expect(3); let data = { - post: { - id: '1', - name: 'Docker is amazing', - }, + something: 'is invalid', }; server.get('/posts/1', function() { @@ -2444,390 +2495,435 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }); adapter.handleResponse = function(status, headers, json) { - assert.deepEqual(status, 200); - assert.deepEqual(json, data); - return json; + assert.ok(true, 'handleResponse should be called'); + return new DS.AdapterError(json); }; - return run(() => store.findRecord('post', '1')); + return run(() => { + return store.findRecord('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); + }); + }); }); - test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { - assert.expect(4); + test('gracefully handles exceptions in handleResponse', function(assert) { + assert.expect(1); - let responseText = 'Nope lol'; + server.post('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, 'ok']; + }); - let expectedRequestData = { - method: 'GET', - url: '/posts/1', + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); }; + return run(() => { + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); + }); + }); + }); + + test('gracefully handles exceptions in handleResponse where the ajax request errors', function(assert) { + assert.expect(1); + server.get('/posts/1', function() { - return [400, {}, responseText]; + return [500, { 'Content-Type': 'application/json' }, 'Internal Server Error']; }); - adapter.handleResponse = function(status, headers, json, requestData) { - assert.deepEqual(status, 400); - assert.deepEqual(json, responseText); - assert.deepEqual(requestData, expectedRequestData); - return new DS.AdapterError('nope!'); + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); }; return run(() => { - return store.findRecord('post', '1').catch(err => assert.ok(err, 'promise rejected')); + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); + }); }); }); - } - test('rejects promise if DS.AdapterError is returned from adapter.handleResponse', function(assert) { - assert.expect(3); + test('treats status code 0 as an abort', function(assert) { + assert.expect(3); - let data = { - something: 'is invalid', - }; + ajaxZero(); + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; - server.get('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; + return run(() => { + return store.findRecord('post', '1').catch(err => { + assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); + assert.equal(err.errors.length, 1, 'AbortError includes errors with request/response details'); + let expectedError = { + title: 'Adapter Error', + detail: 'Request failed: GET /posts/1', + status: 0, + }; + assert.deepEqual(err.errors[0], expectedError, 'method, url and, status are captured as details'); + }); + }); }); - adapter.handleResponse = function(status, headers, json) { - assert.ok(true, 'handleResponse should be called'); - return new DS.AdapterError(json); - }; + if (hasJQuery) { + test('on error appends errorThrown for sanity', async function(assert) { + assert.expect(2); - return run(() => { - return store.findRecord('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); - }); - }); - }); + let jqXHR = { + responseText: 'Nope lol', + getAllResponseHeaders() { + return ''; + }, + }; - test('gracefully handles exceptions in handleResponse', function(assert) { - assert.expect(1); + let errorThrown = new Error('nope!'); - server.post('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, 'ok']; - }); + adapter._ajaxRequest = function(hash) { + hash.error(jqXHR, jqXHR.responseText, errorThrown); + }; - adapter.handleResponse = function(status, headers, json) { - throw new Error('Unexpected error'); - }; + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; - return run(() => { - return store.findRecord('post', '1').catch(error => { - assert.ok(true, 'Unexpected error is captured by the promise chain'); + try { + await store.findRecord('post', '1'); + } catch (err) { + assert.equal(err, errorThrown); + assert.ok(err, 'promise rejected'); + } }); - }); - }); - test('gracefully handles exceptions in handleResponse where the ajax request errors', function(assert) { - assert.expect(1); + test('on error wraps the error string in an DS.AdapterError object', function(assert) { + assert.expect(2); - server.get('/posts/1', function() { - return [500, { 'Content-Type': 'application/json' }, 'Internal Server Error']; - }); + let jqXHR = { + responseText: '', + getAllResponseHeaders() { + return ''; + }, + }; - adapter.handleResponse = function(status, headers, json) { - throw new Error('Unexpected error'); - }; + let errorThrown = 'nope!'; + + adapter._ajaxRequest = function(hash) { + hash.error(jqXHR, 'error', errorThrown); + }; - return run(() => { - return store.findRecord('post', '1').catch(error => { - assert.ok(true, 'Unexpected error is captured by the promise chain'); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal(err.errors[0].detail, errorThrown); + assert.ok(err, 'promise rejected'); + }); + }); }); - }); - }); + } - test('treats status code 0 as an abort', function(assert) { - assert.expect(3); + test('rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes', function(assert) { + assert.expect(10); - ajaxZero(); - adapter.handleResponse = function(status, headers, payload) { - assert.ok(false); - }; + ajaxError('error', 401); - return run(() => { - return store.findRecord('post', '1').catch(err => { - assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); - assert.equal(err.errors.length, 1, 'AbortError includes errors with request/response details'); - let expectedError = { - title: 'Adapter Error', - detail: 'Request failed: GET /posts/1', - status: 0, - }; - assert.deepEqual(err.errors[0], expectedError, 'method, url and, status are captured as details'); + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); + }); }); - }); - }); - if (hasJQuery) { - test('on error appends errorThrown for sanity', async function(assert) { - assert.expect(2); + ajaxError('error', 403); - let jqXHR = { - responseText: 'Nope lol', - getAllResponseHeaders() { - return ''; - }, - }; + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); + }); + }); - let errorThrown = new Error('nope!'); + ajaxError('error', 404); - adapter._ajaxRequest = function(hash) { - hash.error(jqXHR, jqXHR.responseText, errorThrown); - }; + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); + }); + }); - adapter.handleResponse = function(status, headers, payload) { - assert.ok(false); - }; + ajaxError('error', 409); - try { - await store.findRecord('post', '1'); - } catch (err) { - assert.equal(err, errorThrown); - assert.ok(err, 'promise rejected'); - } - }); + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); + }); + }); - test('on error wraps the error string in an DS.AdapterError object', function(assert) { - assert.expect(2); + ajaxError('error', 500); - let jqXHR = { - responseText: '', - getAllResponseHeaders() { - return ''; - }, - }; + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); + }); + }); + }); - let errorThrown = 'nope!'; + test('error handling includes a detailed message from the server', assert => { + assert.expect(2); - adapter._ajaxRequest = function(hash) { - hash.error(jqXHR, 'error', errorThrown); - }; + ajaxError('An error message, perhaps generated from a backend server!', 500, { + 'Content-Type': 'text/plain', + }); run(() => { store.findRecord('post', '1').catch(err => { - assert.equal(err.errors[0].detail, errorThrown); + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!' + ); assert.ok(err, 'promise rejected'); }); }); }); - } - test('rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes', function(assert) { - assert.expect(10); + test('error handling with a very long HTML-formatted payload truncates the friendly message', assert => { + assert.expect(2); - ajaxError('error', 401); + ajaxError(new Array(100).join(''), 500, { 'Content-Type': 'text/html' }); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]' + ); + assert.ok(err, 'promise rejected'); + }); }); }); - ajaxError('error', 403); + test('findAll resolves with a collection of DS.Models, not DS.InternalModels', assert => { + assert.expect(4); + + ajaxResponse({ + posts: [ + { + id: 1, + name: 'dhh lol', + }, + { + id: 2, + name: 'james mickens is rad', + }, + { + id: 3, + name: 'in the name of love', + }, + ], + }); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); + return run(() => { + return store.findAll('post').then(posts => { + assert.equal(get(posts, 'length'), 3); + posts.forEach(post => assert.ok(post instanceof DS.Model)); + }); }); }); - ajaxError('error', 404); + test('createRecord - sideloaded records are pushed to the store', function(assert) { + Post.reopen({ + comments: DS.hasMany('comment'), + }); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); + ajaxResponse({ + post: { + id: 1, + name: 'The Parley Letter', + comments: [2, 3], + }, + comments: [ + { + id: 2, + name: 'First comment', + }, + { + id: 3, + name: 'Second comment', + }, + ], }); - }); + let post; + + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); - ajaxError('error', 409); + return post.save().then(post => { + let comments = store.peekAll('comment'); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); + assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); + assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); + assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); + }); }); }); - ajaxError('error', 500); + testInDebug('warns when an empty 201 response is returned, though a valid stringified JSON is expected', function( + assert + ) { + assert.expect(1); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); + server.post('/posts', function() { + return [201, { 'Content-Type': 'application/json' }, '']; }); + + let post = store.createRecord('post'); + return post.save().then( + () => { + assert.equal(true, false, 'should not have fulfilled'); + }, + reason => { + if (!hasJQuery) { + assert.ok(/saved to the server/.test(reason.message)); + // Workaround for #7371 to get the record a correct state before teardown + let identifier = recordIdentifierFor(post); + let im = store._internalModelForResource(identifier); + store.didSaveRecord(im, { data: { id: '1', type: 'post' } }, 'createRecord'); + } else { + assert.ok(/JSON/.test(reason.message)); + } + } + ); }); - }); - test('error handling includes a detailed message from the server', assert => { - assert.expect(2); + if (!hasJQuery) { + testInDebug( + 'warns when an empty 200 response is returned, though a valid stringified JSON is expected', + async function(assert) { + assert.expect(2); - ajaxError('An error message, perhaps generated from a backend server!', 500, { - 'Content-Type': 'text/plain', - }); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, '']; + }); - run(() => { - store.findRecord('post', '1').catch(err => { - assert.equal( - err.message, - 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!' - ); - assert.ok(err, 'promise rejected'); - }); - }); - }); + let post = store.push({ data: { id: '1', type: 'post' } }); + await assert.expectWarning(async () => { + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + }, /JSON/); + } + ); - test('error handling with a very long HTML-formatted payload truncates the friendly message', assert => { - assert.expect(2); + test('can return an empty 200 response, though a valid stringified JSON is expected', async function(assert) { + assert.expect(1); - ajaxError(new Array(100).join(''), 500, { 'Content-Type': 'text/html' }); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, '']; + }); - run(() => { - store.findRecord('post', '1').catch(err => { - assert.equal( - err.message, - 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]' - ); - assert.ok(err, 'promise rejected'); + let post = store.push({ data: { id: '1', type: 'post' } }); + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); }); - }); - }); - test('findAll resolves with a collection of DS.Models, not DS.InternalModels', assert => { - assert.expect(4); + test('can return a null 200 response, though a valid stringified JSON is expected', async function(assert) { + assert.expect(1); - ajaxResponse({ - posts: [ - { - id: 1, - name: 'dhh lol', - }, - { - id: 2, - name: 'james mickens is rad', - }, - { - id: 3, - name: 'in the name of love', - }, - ], - }); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, null]; + }); - return run(() => { - return store.findAll('post').then(posts => { - assert.equal(get(posts, 'length'), 3); - posts.forEach(post => assert.ok(post instanceof DS.Model)); + let post = store.push({ data: { id: '1', type: 'post' } }); + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); }); - }); + } }); - test('createRecord - sideloaded records are pushed to the store', function(assert) { - Post.reopen({ - comments: DS.hasMany('comment'), - }); - - ajaxResponse({ - post: { - id: 1, - name: 'The Parley Letter', - comments: [2, 3], - }, - comments: [ - { - id: 2, - name: 'First comment', - }, - { - id: 3, - name: 'Second comment', - }, - ], - }); - let post; + module('init adapter coalesceFindRequests', function() { + test('findMany - passes buildURL the requestType', function(assert) { + this.owner.register('adapter:application', RESTAdapter.extend({ coalesceFindRequests: true })); + adapter = store.adapterFor('application'); - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/' + type; + }; - return post.save().then(post => { - let comments = store.peekAll('comment'); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); - assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); - assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + ], + }, + }, + }, + }); }); - }); - }); - testInDebug('warns when an empty 201 response is returned, though a valid stringified JSON is expected', function( - assert - ) { - assert.expect(1); - - server.post('/posts', function() { - return [201, { 'Content-Type': 'application/json' }, '']; - }); - - let post = store.createRecord('post'); - return post.save().then( - () => { - assert.equal(true, false, 'should not have fulfilled'); - }, - reason => { - if (!hasJQuery) { - assert.ok(/saved to the server/.test(reason.message)); - // Workaround for #7371 to get the record a correct state before teardown - let identifier = recordIdentifierFor(post); - let im = store._internalModelForResource(identifier); - store.didSaveRecord(im, { data: { id: '1', type: 'post' } }, 'createRecord'); - } else { - assert.ok(/JSON/.test(reason.message)); - } - } - ); - }); + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + ], + }); - if (!hasJQuery) { - testInDebug( - 'warns when an empty 200 response is returned, though a valid stringified JSON is expected', - async function(assert) { - assert.expect(2); + return run(post, 'get', 'comments').then(comments => { + assert.equal(passedUrl, '/findMany/comment'); + }); + }); - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, '']; - }); + test('class findMany - passes buildURL the requestType', function(assert) { + this.owner.unregister('adapter:application'); + this.owner.register('adapter:application', class MyClass extends RESTAdapter { coalesceFindRequests = true; }); + adapter = store.adapterFor('application'); - let post = store.push({ data: { id: '1', type: 'post' } }); - await assert.expectWarning(async () => { - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); - }, /JSON/); - } - ); + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/' + type; + }; - test('can return an empty 200 response, though a valid stringified JSON is expected', async function(assert) { - assert.expect(1); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, '']; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, + }, + }, + }); }); - let post = store.push({ data: { id: '1', type: 'post' } }); - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); - }); - - test('can return a null 200 response, though a valid stringified JSON is expected', async function(assert) { - assert.expect(1); - - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, null]; + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - let post = store.push({ data: { id: '1', type: 'post' } }); - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + return run(post, 'get', 'comments').then(comments => { + assert.equal(passedUrl, '/findMany/comment'); + }); }); - } + }); }); diff --git a/packages/adapter/addon/index.ts b/packages/adapter/addon/index.ts index 38d80210c87..c6e4134347a 100644 --- a/packages/adapter/addon/index.ts +++ b/packages/adapter/addon/index.ts @@ -66,6 +66,8 @@ type SnapshotRecordArray = import('@ember-data/store/-private/system/snapshot-re @extends EmberObject */ export default class Adapter extends EmberObject implements MinimumAdapterInterface { + declare _coalesceFindRequests: boolean; + /** If you would like your adapter to use a custom serializer you can set the `defaultSerializer` property to be the name of the custom @@ -470,8 +472,6 @@ export default class Adapter extends EmberObject implements MinimumAdapterInterf return RSVPPromise.resolve(); } - _coalesceFindRequests = true; - /** By default the store will try to coalesce all `fetchRecord` calls within the same runloop into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call. @@ -486,7 +486,7 @@ export default class Adapter extends EmberObject implements MinimumAdapterInterf if (typeof coalesceFindRequests === 'boolean') { return coalesceFindRequests; } - return (this._coalesceFindRequests = false); + return (this._coalesceFindRequests = true); } set coalesceFindRequests(value: boolean) { diff --git a/packages/adapter/addon/json-api.ts b/packages/adapter/addon/json-api.ts index b1f89abf488..b16281a0ab7 100644 --- a/packages/adapter/addon/json-api.ts +++ b/packages/adapter/addon/json-api.ts @@ -231,8 +231,17 @@ class JSONAPIAdapter extends RESTAdapter { @property coalesceFindRequests @type {boolean} */ + get coalesceFindRequests() { + let coalesceFindRequests = this._coalesceFindRequests; + if (typeof coalesceFindRequests === 'boolean') { + return coalesceFindRequests; + } + return (this._coalesceFindRequests = false); + } - _coalesceFindRequests: boolean = false; + set coalesceFindRequests(value: boolean) { + this._coalesceFindRequests = value; + } findMany(store: Store, type: ShimModelClass, ids: string[], snapshots: Snapshot[]): Promise { let url = this.buildURL(type.modelName, ids, snapshots, 'findMany'); diff --git a/packages/adapter/addon/rest.ts b/packages/adapter/addon/rest.ts index 9623fe726de..34c215d4144 100644 --- a/packages/adapter/addon/rest.ts +++ b/packages/adapter/addon/rest.ts @@ -367,6 +367,18 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { this._fastboot = value; } + get coalesceFindRequests() { + let coalesceFindRequests = this._coalesceFindRequests; + if (typeof coalesceFindRequests === 'boolean') { + return coalesceFindRequests; + } + return (this._coalesceFindRequests = false); + } + + set coalesceFindRequests(value: boolean) { + this._coalesceFindRequests = value; + } + /** By default, the RESTAdapter will send the query params sorted alphabetically to the server. @@ -472,8 +484,6 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { @type {boolean} */ - _coalesceFindRequests: boolean = false; - /** Endpoint paths can be prefixed with a `namespace` by setting the namespace property on the adapter: From fa678357aa2430d9701966534cfbe49ba780560a Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Sat, 3 Apr 2021 20:55:05 -0500 Subject: [PATCH 3/7] Add unit tests for rest and json-api --- .../json-api-adapter/json-api-test.js | 34 +++++++++++++++++++ .../unit/adapters/rest-adapter/rest-test.js | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js create mode 100644 packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js diff --git a/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js b/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js new file mode 100644 index 00000000000..41128624839 --- /dev/null +++ b/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js @@ -0,0 +1,34 @@ +import { module, test } from 'qunit'; +import JSONAPIAdapter from '@ember-data/adapter/json-api'; + +module('unit/adapters/json-api-test', function() { + test('coalesceFindRequests default', function(assert) { + const adapter = JSONAPIAdapter.extend(); + assert.deepEqual(adapter.create().coalesceFindRequests, false, 'default result is false'); + }); + + test('coalesceFindRequests true', function(assert) { + const adapter = JSONAPIAdapter.extend({ coalesceFindRequests: true }); + assert.deepEqual(adapter.create().coalesceFindRequests, true, 'result is true'); + }); + + test('coalesceFindRequests false', function(assert) { + const adapter = JSONAPIAdapter.extend({ coalesceFindRequests: false }); + assert.deepEqual(adapter.create().coalesceFindRequests, false, 'result is false'); + }); + + test('coalesceFindRequests class default', function(assert) { + class MyClass extends JSONAPIAdapter {} + assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'default result is false'); + }); + + test('coalesceFindRequests class true', function(assert) { + class MyClass extends JSONAPIAdapter { coalesceFindRequests = true } + assert.deepEqual(MyClass.create().coalesceFindRequests, true, 'result is true'); + }); + + test('coalesceFindRequests class false', function(assert) { + class MyClass extends JSONAPIAdapter { coalesceFindRequests = false } + assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'result is false'); + }); +}); diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js new file mode 100644 index 00000000000..43ddc472b03 --- /dev/null +++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js @@ -0,0 +1,34 @@ +import { module, test } from 'qunit'; +import RESTAdapter from '@ember-data/adapter/rest'; + +module('unit/adapters/rest-test', function() { + test('coalesceFindRequests default', function(assert) { + const adapter = RESTAdapter.extend(); + assert.deepEqual(adapter.create().coalesceFindRequests, false, 'default result is false'); + }); + + test('coalesceFindRequests true', function(assert) { + const adapter = RESTAdapter.extend({ coalesceFindRequests: true }); + assert.deepEqual(adapter.create().coalesceFindRequests, true, 'result is true'); + }); + + test('coalesceFindRequests false', function(assert) { + const adapter = RESTAdapter.extend({ coalesceFindRequests: false }); + assert.deepEqual(adapter.create().coalesceFindRequests, false, 'result is false'); + }); + + test('coalesceFindRequests class default', function(assert) { + class MyClass extends RESTAdapter {} + assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'default result is false'); + }); + + test('coalesceFindRequests class true', function(assert) { + class MyClass extends RESTAdapter { coalesceFindRequests = true } + assert.deepEqual(MyClass.create().coalesceFindRequests, true, 'result is true'); + }); + + test('coalesceFindRequests class false', function(assert) { + class MyClass extends RESTAdapter { coalesceFindRequests = false } + assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'result is false'); + }); +}); From f4f5382e2240147c7223649df983d7fb666a2c71 Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Sat, 3 Apr 2021 20:55:42 -0500 Subject: [PATCH 4/7] revert integration test --- .../integration/adapter/rest-adapter-test.js | 4266 ++++++++--------- 1 file changed, 2085 insertions(+), 2181 deletions(-) diff --git a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js index a7c82ddd622..5cd03eb360c 100644 --- a/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js +++ b/packages/-ember-data/tests/integration/adapter/rest-adapter-test.js @@ -47,6 +47,7 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { server = new Pretender(); store = this.owner.lookup('service:store'); + adapter = store.adapterFor('application'); passedUrl = passedVerb = passedHash = null; }); @@ -129,220 +130,199 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }); }; } - - module('with setup adapter', function(hooks) { - hooks.beforeEach(() => { - adapter = store.adapterFor('application'); - }); - - test('findRecord - basic payload', function(assert) { - ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); - - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); - test('findRecord - passes buildURL a requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/post/' + id; - }; + test('findRecord - basic payload', function(assert) { + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/findRecord/post/1'); - }) - ); - }); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); + }); - test('findRecord - basic payload (with legacy singular name)', function(assert) { - ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); + test('findRecord - passes buildURL a requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/post/' + id; + }; - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + ajaxResponse({ posts: [{ id: 1, name: 'Rails is omakase' }] }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/findRecord/post/1'); + }) + ); + }); - test('findRecord - payload with sideloaded records of the same type', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + test('findRecord - basic payload (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); + }); - let post2 = store.peekRecord('post', 2); - assert.equal(post2.get('id'), '2'); - assert.equal(post2.get('name'), 'The Parley Letter'); - }) - ); + test('findRecord - payload with sideloaded records of the same type', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], }); - test('findRecord - payload with sideloaded records of a different type', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is omakase' }], - comments: [{ id: 1, name: 'FIRST' }], - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); + let post2 = store.peekRecord('post', 2); + assert.equal(post2.get('id'), '2'); + assert.equal(post2.get('name'), 'The Parley Letter'); + }) + ); + }); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('id'), '1'); - assert.equal(comment.get('name'), 'FIRST'); - }) - ); + test('findRecord - payload with sideloaded records of a different type', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is omakase' }], + comments: [{ id: 1, name: 'FIRST' }], }); - test('findRecord - payload with an serializer-specified primary key', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - }) - ); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - ajaxResponse({ posts: [{ _ID_: 1, name: 'Rails is omakase' }] }); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('id'), '1'); + assert.equal(comment.get('name'), 'FIRST'); + }) + ); + }); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - }) - ); - }); + test('findRecord - payload with an serializer-specified primary key', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + }) + ); - test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: '_NAME_', - createdAt: { key: '_CREATED_AT_', someOtherOption: 'option' }, - }, - }) - ); + ajaxResponse({ posts: [{ _ID_: 1, name: 'Rails is omakase' }] }); - Post.reopen({ - createdAt: DS.attr('number'), - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - ajaxResponse({ posts: [{ id: 1, _NAME_: 'Rails is omakase', _CREATED_AT_: 2013 }] }); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + }) + ); + }); - return run(() => - store.findRecord('post', 1).then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findRecord - payload with a serializer-specified attribute mapping', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_NAME_', + createdAt: { key: '_CREATED_AT_', someOtherOption: 'option' }, + }, + }) + ); - assert.equal(post.get('id'), '1'); - assert.equal(post.get('name'), 'Rails is omakase'); - assert.equal(post.get('createdAt'), 2013); - }) - ); + Post.reopen({ + createdAt: DS.attr('number'), }); - test('findRecord - passes `include` as a query parameter to ajax', function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is very expensive sushi' }, - }); + ajaxResponse({ posts: [{ id: 1, _NAME_: 'Rails is omakase', _CREATED_AT_: 2013 }] }); - return run(() => - store.findRecord('post', 1, { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); - }) - ); - }); + return run(() => + store.findRecord('post', 1).then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - test('createRecord - an empty payload is a basic success if an id was specified', function(assert) { - ajaxResponse(); + assert.equal(post.get('id'), '1'); + assert.equal(post.get('name'), 'Rails is omakase'); + assert.equal(post.get('createdAt'), 2013); + }) + ); + }); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { id: 'some-uuid', name: 'The Parley Letter' } }); - - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); - }); - }); + test('findRecord - passes `include` as a query parameter to ajax', function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is very expensive sushi' }, }); - test('createRecord - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/post/' + requestType; - }; + return run(() => + store.findRecord('post', 1, { include: 'comments' }).then(() => { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` parameter sent to adapter.ajax'); + }) + ); + }); - ajaxResponse(); + test('createRecord - an empty payload is a basic success if an id was specified', function(assert) { + ajaxResponse(); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/post/createRecord'); - }); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { id: 'some-uuid', name: 'The Parley Letter' } }); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); }); }); + }); - test('createRecord - a payload with a new ID and data applies the updates', function(assert) { - ajaxResponse({ posts: [{ id: '1', name: 'Dat Parley Letter' }] }); - - return run(() => { - let post = store.createRecord('post', { name: 'The Parley Letter' }); + test('createRecord - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/post/' + requestType; + }; - return post.save().then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + ajaxResponse(); - assert.equal(post.get('id'), '1', 'the post has the updated ID'); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - }); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/post/createRecord'); }); }); + }); + + test('createRecord - a payload with a new ID and data applies the updates', function(assert) { + ajaxResponse({ posts: [{ id: '1', name: 'Dat Parley Letter' }] }); - test('createRecord - a payload with a new ID and data applies the updates (with legacy singular name)', function(assert) { - ajaxResponse({ post: { id: '1', name: 'Dat Parley Letter' } }); + return run(() => { let post = store.createRecord('post', { name: 'The Parley Letter' }); - return run(post, 'save').then(post => { + return post.save().then(post => { assert.equal(passedUrl, '/posts'); assert.equal(passedVerb, 'POST'); assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); @@ -352,1882 +332,1797 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); }); + }); - test("createRecord - findMany doesn't overwrite owner", function(assert) { - ajaxResponse({ comment: { id: '1', name: 'Dat Parley Letter', post: 1 } }); + test('createRecord - a payload with a new ID and data applies the updates (with legacy singular name)', function(assert) { + ajaxResponse({ post: { id: '1', name: 'Dat Parley Letter' } }); + let post = store.createRecord('post', { name: 'The Parley Letter' }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + return run(post, 'save').then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [], - }, + assert.equal(post.get('id'), '1', 'the post has the updated ID'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); + }); + + test("createRecord - findMany doesn't overwrite owner", function(assert) { + ajaxResponse({ comment: { id: '1', name: 'Dat Parley Letter', post: 1 } }); + + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [], }, }, - }); + }, }); - let post = store.peekRecord('post', 1); + }); + let post = store.peekRecord('post', 1); - let comment = store.createRecord('comment', { name: 'The Parley Letter' }); + let comment = store.createRecord('comment', { name: 'The Parley Letter' }); - run(() => { - post.get('comments').pushObject(comment); + run(() => { + post.get('comments').pushObject(comment); - assert.equal(comment.get('post'), post, 'the post has been set correctly'); - }); + assert.equal(comment.get('post'), post, 'the post has been set correctly'); + }); - return run(() => { - return comment.save().then(comment => { - assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(comment.get('name'), 'Dat Parley Letter', 'the post was updated'); - assert.equal(comment.get('post'), post, 'the post is still set'); - }); + return run(() => { + return comment.save().then(comment => { + assert.equal(comment.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(comment.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(comment.get('post'), post, 'the post is still set'); }); }); + }); - test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_id_', + test("createRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - attrs: { - name: '_name_', - }, - }) - ); + attrs: { + name: '_name_', + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return run(() => - post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { _id_: 'some-uuid', _name_: 'The Parley Letter' }, - }); - }) - ); - }); + return run(() => + post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { _id_: 'some-uuid', _name_: 'The Parley Letter' }, + }); + }) + ); + }); - test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { - let post; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: '_name_', - }, - }) - ); + test("createRecord - a serializer's attributes are consulted when building the payload if no id is pre-defined", function(assert) { + let post; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: '_name_', + }, + }) + ); - ajaxResponse({ - post: { _name_: 'The Parley Letter', id: '1' }, - }); + ajaxResponse({ + post: { _name_: 'The Parley Letter', id: '1' }, + }); - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); - }); + return post.save().then(post => { + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); }); }); + }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - name: 'given_name', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForAttribute when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + name: 'given_name', + }, - keyForAttribute(attr) { - return attr.toUpperCase(); - }, - }) - ); + keyForAttribute(attr) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - return run(() => { - let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); + return run(() => { + let post = store.createRecord('post', { id: 'some-uuid', name: 'The Parley Letter' }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { given_name: 'The Parley Letter', id: 'some-uuid' }, - }); + return post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { given_name: 'The Parley Letter', id: 'some-uuid' }, }); }); }); + }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - attrs: { - post: 'article', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (belongsTo) when building the payload", function(assert) { + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + attrs: { + post: 'article', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - }, - }) - ); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - return run(() => { - let post = store.createRecord('post', { id: 'a-post-id', name: 'The Parley Letter' }); - let comment = store.createRecord('comment', { - id: 'some-uuid', - name: 'Letters are fun', - post: post, - }); + return run(() => { + let post = store.createRecord('post', { id: 'a-post-id', name: 'The Parley Letter' }); + let comment = store.createRecord('comment', { + id: 'some-uuid', + name: 'Letters are fun', + post: post, + }); - return comment.save().then(post => { - assert.deepEqual(passedHash.data, { - comment: { article: 'a-post-id', id: 'some-uuid', name: 'Letters are fun' }, - }); + return comment.save().then(post => { + assert.deepEqual(passedHash.data, { + comment: { article: 'a-post-id', id: 'some-uuid', name: 'Letters are fun' }, }); }); }); + }); - test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - attrs: { - comments: 'opinions', - }, + test("createRecord - a serializer's attribute mapping takes precedence over keyForRelationship (hasMany) when building the payload", function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + attrs: { + comments: 'opinions', + }, - keyForRelationship(attr, kind) { - return attr.toUpperCase(); - }, - }) - ); + keyForRelationship(attr, kind) { + return attr.toUpperCase(); + }, + }) + ); - ajaxResponse(); + ajaxResponse(); - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - return run(() => { - let comment = store.createRecord('comment', { id: 'a-comment-id', name: 'First!' }); - let post = store.createRecord('post', { - id: 'some-uuid', - name: 'The Parley Letter', - comments: [comment], - }); + return run(() => { + let comment = store.createRecord('comment', { id: 'a-comment-id', name: 'First!' }); + let post = store.createRecord('post', { + id: 'some-uuid', + name: 'The Parley Letter', + comments: [comment], + }); - return post.save().then(post => { - assert.deepEqual(passedHash.data, { - post: { opinions: ['a-comment-id'], id: 'some-uuid', name: 'The Parley Letter' }, - }); + return post.save().then(post => { + assert.deepEqual(passedHash.data, { + post: { opinions: ['a-comment-id'], id: 'some-uuid', name: 'The Parley Letter' }, }); }); }); + }); - test('createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded', function(assert) { - assert.expect(3); + test('createRecord - a record on the many side of a hasMany relationship should update relationships when data is sideloaded', function(assert) { + assert.expect(3); - ajaxResponse({ - posts: [ - { - id: '1', + ajaxResponse({ + posts: [ + { + id: '1', + name: 'Rails is omakase', + comments: [1, 2], + }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, + }, + { + id: '1', + name: 'Dat Parley Letter', + post: 1, + }, + ], + // My API is returning a comment:{} as well as a comments:[{...},...] + //, comment: { + // id: "2", + // name: "Another Comment", + // post: 1 + // } + }); + + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { name: 'Rails is omakase', - comments: [1, 2], - }, - ], - comments: [ - { - id: '2', - name: 'Another Comment', - post: 1, }, - { - id: '1', - name: 'Dat Parley Letter', - post: 1, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, }, - ], - // My API is returning a comment:{} as well as a comments:[{...},...] - //, comment: { - // id: "2", - // name: "Another Comment", - // post: 1 - // } + }, }); - - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }], - }, - }, + store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + name: 'Dat Parlay Letter', }, - }); - store.push({ - data: { - type: 'comment', - id: '1', - attributes: { - name: 'Dat Parlay Letter', - }, - relationships: { - post: { - data: { type: 'post', id: '1' }, - }, + relationships: { + post: { + data: { type: 'post', id: '1' }, }, }, - }); + }, }); + }); - let post = store.peekRecord('post', 1); - let commentCount = run(() => post.get('comments.length')); + let post = store.peekRecord('post', 1); + let commentCount = run(() => post.get('comments.length')); - assert.equal(commentCount, 1, 'the post starts life with a comment'); + assert.equal(commentCount, 1, 'the post starts life with a comment'); - return run(() => { - let comment = store.createRecord('comment', { name: 'Another Comment', post: post }); + return run(() => { + let comment = store.createRecord('comment', { name: 'Another Comment', post: post }); - return comment.save().then(comment => { - assert.equal(comment.get('post'), post, 'the comment is related to the post'); - return post.reload().then(post => { - assert.equal(post.get('comments.length'), 2, 'Post comment count has been updated'); - }); + return comment.save().then(comment => { + assert.equal(comment.get('post'), post, 'the comment is related to the post'); + return post.reload().then(post => { + assert.equal(post.get('comments.length'), 2, 'Post comment count has been updated'); }); }); }); + }); - test('createRecord - sideloaded belongsTo relationships are both marked as loaded', function(assert) { - assert.expect(4); + test('createRecord - sideloaded belongsTo relationships are both marked as loaded', function(assert) { + assert.expect(4); - Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comment: DS.belongsTo('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: 'man' }); + let post = store.createRecord('post', { name: 'man' }); - ajaxResponse({ - posts: [{ id: 1, comment: 1, name: 'marked' }], - comments: [{ id: 1, post: 1, name: 'Comcast is a bargain' }], - }); + ajaxResponse({ + posts: [{ id: 1, comment: 1, name: 'marked' }], + comments: [{ id: 1, post: 1, name: 'Comcast is a bargain' }], + }); - return run(() => { - return post.save().then(record => { - assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); - assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); - assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); - assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); - }); + return run(() => { + return post.save().then(record => { + assert.equal(store.peekRecord('post', 1).get('comment.isLoaded'), true, "post's comment isLoaded (via store)"); + assert.equal(store.peekRecord('comment', 1).get('post.isLoaded'), true, "comment's post isLoaded (via store)"); + assert.equal(record.get('comment.isLoaded'), true, "post's comment isLoaded (via record)"); + assert.equal(record.get('comment.post.isLoaded'), true, "post's comment's post isLoaded (via record)"); }); }); + }); - test("createRecord - response can contain relationships the client doesn't yet know about", function(assert) { - assert.expect(3); // while records.length is 2, we are getting 4 assertions + test("createRecord - response can contain relationships the client doesn't yet know about", function(assert) { + assert.expect(3); // while records.length is 2, we are getting 4 assertions - ajaxResponse({ - posts: [ - { - id: '1', - name: 'Rails is omakase', - comments: [2], - }, - ], - comments: [ - { - id: '2', - name: 'Another Comment', - post: 1, - }, - ], - }); + ajaxResponse({ + posts: [ + { + id: '1', + name: 'Rails is omakase', + comments: [2], + }, + ], + comments: [ + { + id: '2', + name: 'Another Comment', + post: 1, + }, + ], + }); - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: 'Rails is omakase' }); + let post = store.createRecord('post', { name: 'Rails is omakase' }); - return run(() => { - return post.save().then(post => { - assert.equal(post.get('comments.firstObject.post'), post, 'the comments are related to the correct post model'); - assert.equal( - store._internalModelsFor('post').models.length, - 1, - 'There should only be one post record in the store' - ); - - let postRecords = store._internalModelsFor('post').models; - for (var i = 0; i < postRecords.length; i++) { - assert.equal(post, postRecords[i].getRecord(), 'The object in the identity map is the same'); - } - }); + return run(() => { + return post.save().then(post => { + assert.equal(post.get('comments.firstObject.post'), post, 'the comments are related to the correct post model'); + assert.equal( + store._internalModelsFor('post').models.length, + 1, + 'There should only be one post record in the store' + ); + + let postRecords = store._internalModelsFor('post').models; + for (var i = 0; i < postRecords.length; i++) { + assert.equal(post, postRecords[i].getRecord(), 'The object in the identity map is the same'); + } }); }); + }); - test('createRecord - relationships are not duplicated', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + test('createRecord - relationships are not duplicated', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - let post = store.createRecord('post', { name: 'Tomtomhuda' }); - let comment = store.createRecord('comment', { id: 2, name: 'Comment title' }); + let post = store.createRecord('post', { name: 'Tomtomhuda' }); + let comment = store.createRecord('comment', { id: 2, name: 'Comment title' }); - ajaxResponse({ post: [{ id: 1, name: 'Rails is omakase', comments: [] }] }); + ajaxResponse({ post: [{ id: 1, name: 'Rails is omakase', comments: [] }] }); - return run(() => - post - .save() - .then(post => { - assert.equal(post.get('comments.length'), 0, 'post has 0 comments'); - post.get('comments').pushObject(comment); - assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); + return run(() => + post + .save() + .then(post => { + assert.equal(post.get('comments.length'), 0, 'post has 0 comments'); + post.get('comments').pushObject(comment); + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); - ajaxResponse({ - post: [{ id: 1, name: 'Rails is omakase', comments: [2] }], - comments: [{ id: 2, name: 'Comment title' }], - }); + ajaxResponse({ + post: [{ id: 1, name: 'Rails is omakase', comments: [2] }], + comments: [{ id: 2, name: 'Comment title' }], + }); - return post.save(); - }) - .then(post => { - assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); - }) - ); - }); + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'post has 1 comment'); + }) + ); + }); - test('updateRecord - an empty payload is a basic success', function(assert) { - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + test('updateRecord - an empty payload is a basic success', function(assert) { + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); + }, }); + }); - return run(() => { - let post = store.peekRecord('post', 1); - ajaxResponse(); + return run(() => { + let post = store.peekRecord('post', 1); + ajaxResponse(); - post.set('name', 'The Parley Letter'); - return post.save().then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + post.set('name', 'The Parley Letter'); + return post.save().then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'The Parley Letter', 'the post was updated'); }); }); + }); - test('updateRecord - passes the requestType to buildURL', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/posts/' + id + '/' + requestType; - }; - adapter.shouldBackgroundReloadRecord = () => false; + test('updateRecord - passes the requestType to buildURL', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/posts/' + id + '/' + requestType; + }; + adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); - }); - - return run(() => { - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse(); - - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1/updateRecord'); - }); + }, }); }); - test('updateRecord - a payload with updates applies the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - }); - }); - + return run(() => { return store .findRecord('post', 1) .then(post => { - ajaxResponse({ posts: [{ id: 1, name: 'Dat Parley Letter' }] }); + ajaxResponse(); post.set('name', 'The Parley Letter'); return post.save(); }) .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(passedUrl, '/posts/1/updateRecord'); }); }); + }); - test('updateRecord - a payload with updates applies the updates (with legacy singular name)', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + test('updateRecord - a payload with updates applies the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); + }, }); - - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ post: { id: 1, name: 'Dat Parley Letter' } }); - - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - }); }); - test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { - let post; - ajaxResponse({ - posts: [{ id: 1, name: 'Dat Parley Letter' }], - comments: [{ id: 1, name: 'FIRST' }], - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ posts: [{ id: 1, name: 'Dat Parley Letter' }] }); - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); - return post.save().then(post => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'POST'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - - assert.equal(post.get('id'), '1', 'the post has the updated ID'); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); - }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); }); - }); + }); - test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + test('updateRecord - a payload with updates applies the updates (with legacy singular name)', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); + }, }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - posts: [{ id: 1, name: 'Dat Parley Letter' }], - comments: [{ id: 1, name: 'FIRST' }], - }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ post: { id: 1, name: 'Dat Parley Letter' } }); - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'PUT'); - assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); + }); + }); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); - }); + test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { + let post; + ajaxResponse({ + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], }); - test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_id_', + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); + return post.save().then(post => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'POST'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - attrs: { - name: '_name_', - }, - }) - ); + assert.equal(post.get('id'), '1', 'the post has the updated ID'); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); + }); + }); + + test('updateRecord - a payload with sideloaded updates pushes the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { name: 'Rails is omakase', }, - }); + }, }); + }); - ajaxResponse(); - - return store - .findRecord('post', 1) - .then(post => { - post.set('name', 'The Parley Letter'); - return post.save(); - }) - .then(post => { - assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + posts: [{ id: 1, name: 'Dat Parley Letter' }], + comments: [{ id: 1, name: 'FIRST' }], }); - }); - test('updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - adapter.shouldBackgroundReloadRecord = () => false; + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'PUT'); + assert.deepEqual(passedHash.data, { post: { name: 'The Parley Letter' } }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Not everyone uses Rails', - }, - relationships: { - comments: { - data: [{ type: 'comment', id: '1' }], - }, - }, - }, - included: [ - { - type: 'comment', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - { - type: 'comment', - id: '2', - attributes: { - name: 'Yes. Yes it is.', - }, - }, - ], - }); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('name'), 'Dat Parley Letter', 'the post was updated'); - ajaxResponse({ - posts: { id: 1, name: 'Not everyone uses Rails', comments: [2] }, + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); }); + }); - return store - .findRecord('comment', 2) - .then(() => { - return store.findRecord('post', 1); - }) - .then(post => { - let newComment = store.peekRecord('comment', 2); - let comments = post.get('comments'); + test("updateRecord - a serializer's primary key and attributes are consulted when building the payload", function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_id_', - // Replace the comment with a new one - comments.popObject(); - comments.pushObject(newComment); + attrs: { + name: '_name_', + }, + }) + ); - return post.save(); - }) - .then(post => { - assert.equal(post.get('comments.length'), 1, 'the post has the correct number of comments'); - assert.equal(post.get('comments.firstObject.name'), 'Yes. Yes it is.', 'the post has the correct comment'); - }); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + name: 'Rails is omakase', + }, + }); }); - test('deleteRecord - an empty payload is a basic success', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', + ajaxResponse(); + + return store + .findRecord('post', 1) + .then(post => { + post.set('name', 'The Parley Letter'); + return post.save(); + }) + .then(post => { + assert.deepEqual(passedHash.data, { post: { _name_: 'The Parley Letter' } }); + }); + }); + + test('updateRecord - hasMany relationships faithfully reflect simultaneous adds and removes', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: false }) }); + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + adapter.shouldBackgroundReloadRecord = () => false; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Not everyone uses Rails', + }, + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, + }, + }, + included: [ + { + type: 'comment', id: '1', attributes: { name: 'Rails is omakase', }, }, - }); + { + type: 'comment', + id: '2', + attributes: { + name: 'Yes. Yes it is.', + }, + }, + ], }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse(); + ajaxResponse({ + posts: { id: 1, name: 'Not everyone uses Rails', comments: [2] }, + }); - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); + return store + .findRecord('comment', 2) + .then(() => { + return store.findRecord('post', 1); + }) + .then(post => { + let newComment = store.peekRecord('comment', 2); + let comments = post.get('comments'); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - }); - }); + // Replace the comment with a new one + comments.popObject(); + comments.pushObject(newComment); - test('deleteRecord - passes the requestType to buildURL', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/posts/' + id + '/' + requestType; - }; + return post.save(); + }) + .then(post => { + assert.equal(post.get('comments.length'), 1, 'the post has the correct number of comments'); + assert.equal(post.get('comments.firstObject.name'), 'Yes. Yes it is.', 'the post has the correct comment'); + }); + }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + test('deleteRecord - an empty payload is a basic success', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); + }, }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse(); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1/deleteRecord'); - }); - }); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - test('deleteRecord - a payload with sideloaded updates pushes the updates', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - }, - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ comments: [{ id: 1, name: 'FIRST' }] }); + test('deleteRecord - passes the requestType to buildURL', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/posts/' + id + '/' + requestType; + }; - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + }); + }); - assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse(); - let comment = store.peekRecord('comment', 1); - assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); - }); - }); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1/deleteRecord'); + }); + }); - test('deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, + test('deleteRecord - a payload with sideloaded updates pushes the updates', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', }, - }); + }, }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ posts: [{ id: 2, name: 'The Parley Letter' }] }); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ comments: [{ id: 1, name: 'FIRST' }] }); - post.deleteRecord(); - return post.save(); - }) - .then(post => { - assert.equal(passedUrl, '/posts/1'); - assert.equal(passedVerb, 'DELETE'); - assert.strictEqual(passedHash, undefined); + post.deleteRecord(); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); + + assert.equal(post.get('hasDirtyAttributes'), false, "the post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); - assert.equal(post.get('isDeleted'), true, 'the original post is now deleted'); + let comment = store.peekRecord('comment', 1); + assert.equal(comment.get('name'), 'FIRST', 'The comment was sideloaded'); + }); + }); - let newPost = store.peekRecord('post', 2); - assert.equal(newPost.get('name'), 'The Parley Letter', 'The new post was added to the store'); - }); + test('deleteRecord - a payload with sidloaded updates pushes the updates when the original record is omitted', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + }, + }); }); - test('deleteRecord - deleting a newly created record should not throw an error', function(assert) { - let post = store.createRecord('post'); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ posts: [{ id: 2, name: 'The Parley Letter' }] }); - return run(() => { post.deleteRecord(); - return post.save().then(post => { - assert.equal(passedUrl, null, 'There is no ajax call to delete a record that has never been saved.'); - assert.equal(passedVerb, null, 'There is no ajax call to delete a record that has never been saved.'); - assert.equal(passedHash, null, 'There is no ajax call to delete a record that has never been saved.'); + return post.save(); + }) + .then(post => { + assert.equal(passedUrl, '/posts/1'); + assert.equal(passedVerb, 'DELETE'); + assert.strictEqual(passedHash, undefined); - assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); - assert.equal(post.get('isError'), false, 'the post is not an error'); - }); + assert.equal(post.get('hasDirtyAttributes'), false, "the original post isn't dirty anymore"); + assert.equal(post.get('isDeleted'), true, 'the original post is now deleted'); + + let newPost = store.peekRecord('post', 2); + assert.equal(newPost.get('name'), 'The Parley Letter', 'The new post was added to the store'); }); - }); + }); - test('findAll - returning an array populates the array', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], + test('deleteRecord - deleting a newly created record should not throw an error', function(assert) { + let post = store.createRecord('post'); + + return run(() => { + post.deleteRecord(); + return post.save().then(post => { + assert.equal(passedUrl, null, 'There is no ajax call to delete a record that has never been saved.'); + assert.equal(passedVerb, null, 'There is no ajax call to delete a record that has never been saved.'); + assert.equal(passedHash, null, 'There is no ajax call to delete a record that has never been saved.'); + + assert.equal(post.get('isDeleted'), true, 'the post is now deleted'); + assert.equal(post.get('isError'), false, 'the post is not an error'); }); + }); + }); - return store.findAll('post').then(posts => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, {}); + test('findAll - returning an array populates the array', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + return store.findAll('post').then(posts => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, {}); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); - }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); + }); - test('findAll - passes buildURL the requestType and snapshot', function(assert) { - assert.expect(2); - let adapterOptionsStub = { stub: true }; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.equal(snapshot.adapterOptions, adapterOptionsStub); - return '/' + requestType + '/posts'; - }; + test('findAll - passes buildURL the requestType and snapshot', function(assert) { + assert.expect(2); + let adapterOptionsStub = { stub: true }; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.equal(snapshot.adapterOptions, adapterOptionsStub); + return '/' + requestType + '/posts'; + }; - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { - assert.equal(passedUrl, '/findAll/posts'); - }); + return store.findAll('post', { adapterOptions: adapterOptionsStub }).then(posts => { + assert.equal(passedUrl, '/findAll/posts'); }); + }); - test('findAll - passed `include` as a query parameter to ajax', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('findAll - passed `include` as a query parameter to ajax', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { - assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); - }); + return run(store, 'findAll', 'post', { include: 'comments' }).then(() => { + assert.deepEqual(passedHash.data, { include: 'comments' }, '`include` params sent to adapter.ajax'); }); + }); - test('findAll - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - comments: [{ id: 1, name: 'FIRST' }], - }); + test('findAll - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.findAll('post').then(posts => { - let comment = store.peekRecord('comment', 1); + return store.findAll('post').then(posts => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); + }); - test('findAll - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + test('findAll - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - ajaxResponse({ - posts: [ - { _ID_: 1, _NAME_: 'Rails is omakase' }, - { _ID_: 2, _NAME_: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { _ID_: 1, _NAME_: 'Rails is omakase' }, + { _ID_: 2, _NAME_: 'The Parley Letter' }, + ], + }); - return store.findAll('post').then(posts => { - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + return store.findAll('post').then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); - }); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); + }); - test('query - if `sortQueryParams` option is not provided, query params are sorted alphabetically', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('query - if `sortQueryParams` option is not provided, query params are sorted alphabetically', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['in', 'order', 'params', 'wrong'], - 'query params are received in alphabetical order' - ); - }); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['in', 'order', 'params', 'wrong'], + 'query params are received in alphabetical order' + ); }); + }); - test('query - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/posts'; - }; + test('query - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/posts'; + }; - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.equal(passedUrl, '/query/posts'); - }); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.equal(passedUrl, '/query/posts'); }); + }); - test('query - if `sortQueryParams` is falsey, query params are not sorted at all', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('query - if `sortQueryParams` is falsey, query params are not sorted at all', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - adapter.sortQueryParams = null; + adapter.sortQueryParams = null; - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['params', 'in', 'wrong', 'order'], - 'query params are received in their original order' - ); - }); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['params', 'in', 'wrong', 'order'], + 'query params are received in their original order' + ); }); + }); - test('query - if `sortQueryParams` is a custom function, query params passed through that function', function(assert) { - ajaxResponse({ - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test('query - if `sortQueryParams` is a custom function, query params passed through that function', function(assert) { + ajaxResponse({ + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - adapter.sortQueryParams = function(obj) { - let sortedKeys = Object.keys(obj) - .sort() - .reverse(); - let len = sortedKeys.length; - let newQueryParams = {}; + adapter.sortQueryParams = function(obj) { + let sortedKeys = Object.keys(obj) + .sort() + .reverse(); + let len = sortedKeys.length; + let newQueryParams = {}; - for (var i = 0; i < len; i++) { - newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; - } - return newQueryParams; - }; + for (var i = 0; i < len; i++) { + newQueryParams[sortedKeys[i]] = obj[sortedKeys[i]]; + } + return newQueryParams; + }; - return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { - assert.deepEqual( - Object.keys(passedHash.data), - ['wrong', 'params', 'order', 'in'], - 'query params are received in reverse alphabetical order' - ); - }); + return store.query('post', { params: 1, in: 2, wrong: 3, order: 4 }).then(() => { + assert.deepEqual( + Object.keys(passedHash.data), + ['wrong', 'params', 'order', 'in'], + 'query params are received in reverse alphabetical order' + ); }); + }); - test("query - payload 'meta' is accessible on the record array", function(assert) { - ajaxResponse({ - meta: { offset: 5 }, - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); + test("query - payload 'meta' is accessible on the record array", function(assert) { + ajaxResponse({ + meta: { offset: 5 }, + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], + }); - return store.query('post', { page: 2 }).then(posts => { - assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); - }); + return store.query('post', { page: 2 }).then(posts => { + assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); + }); + }); + + test("query - each record array can have it's own meta object", function(assert) { + ajaxResponse({ + meta: { offset: 5 }, + posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); - test("query - each record array can have it's own meta object", function(assert) { + return store.query('post', { page: 2 }).then(posts => { + assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); ajaxResponse({ - meta: { offset: 5 }, + meta: { offset: 1 }, posts: [{ id: 1, name: 'Rails is very expensive sushi' }], }); - return store.query('post', { page: 2 }).then(posts => { - assert.equal(posts.get('meta.offset'), 5, 'Reponse metadata can be accessed with recordArray.meta'); - ajaxResponse({ - meta: { offset: 1 }, - posts: [{ id: 1, name: 'Rails is very expensive sushi' }], - }); - - return store.query('post', { page: 1 }).then(newPosts => { - assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); - assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); - }); + return store.query('post', { page: 1 }).then(newPosts => { + assert.equal(newPosts.get('meta.offset'), 1, 'new array has correct metadata'); + assert.equal(posts.get('meta.offset'), 5, 'metadata on the old array hasnt been clobbered'); }); }); + }); - test('query - returning an array populates the array', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - }); + test('query - returning an array populates the array', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + }); - return store.query('post', { page: 1 }).then(posts => { - assert.equal(passedUrl, '/posts'); - assert.equal(passedVerb, 'GET'); - assert.deepEqual(passedHash.data, { page: 1 }); + return store.query('post', { page: 1 }).then(posts => { + assert.equal(passedUrl, '/posts'); + assert.equal(passedVerb, 'GET'); + assert.deepEqual(passedHash.data, { page: 1 }); - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); - }); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); + }); - test('query - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - posts: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'The Parley Letter' }, - ], - comments: [{ id: 1, name: 'FIRST' }], - }); + test('query - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + posts: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'The Parley Letter' }, + ], + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.query('post', { page: 1 }).then(posts => { - let comment = store.peekRecord('comment', 1); + return store.query('post', { page: 1 }).then(posts => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); + }); - test('query - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + test('query - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - ajaxResponse({ - posts: [ - { _ID_: 1, _NAME_: 'Rails is omakase' }, - { _ID_: 2, _NAME_: 'The Parley Letter' }, - ], - }); + ajaxResponse({ + posts: [ + { _ID_: 1, _NAME_: 'Rails is omakase' }, + { _ID_: 2, _NAME_: 'The Parley Letter' }, + ], + }); - return store.query('post', { page: 1 }).then(posts => { - let post1 = store.peekRecord('post', 1); - let post2 = store.peekRecord('post', 2); + return store.query('post', { page: 1 }).then(posts => { + let post1 = store.peekRecord('post', 1); + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); + assert.deepEqual(post1.getProperties('id', 'name'), { id: '1', name: 'Rails is omakase' }, 'Post 1 is loaded'); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }, 'Post 2 is loaded'); - assert.equal(posts.get('length'), 2, 'The posts are in the array'); - assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); - assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); - }); + assert.equal(posts.get('length'), 2, 'The posts are in the array'); + assert.equal(posts.get('isLoaded'), true, 'The RecordArray is loaded'); + assert.deepEqual(posts.toArray(), [post1, post2], 'The correct records are in the array'); }); + }); - test('queryRecord - empty response', function(assert) { - ajaxResponse({}); + test('queryRecord - empty response', function(assert) { + ajaxResponse({}); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.strictEqual(post, null); - }); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.strictEqual(post, null); }); + }); - test('queryRecord - primary data being null', function(assert) { - ajaxResponse({ - post: null, - }); + test('queryRecord - primary data being null', function(assert) { + ajaxResponse({ + post: null, + }); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.strictEqual(post, null); - }); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.strictEqual(post, null); }); + }); - test('queryRecord - primary data being a single object', function(assert) { - ajaxResponse({ - post: { - id: '1', - name: 'Ember.js rocks', - }, - }); + test('queryRecord - primary data being a single object', function(assert) { + ajaxResponse({ + post: { + id: '1', + name: 'Ember.js rocks', + }, + }); - return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { - assert.deepEqual(post.get('name'), 'Ember.js rocks'); - }); + return store.queryRecord('post', { slug: 'ember-js-rocks' }).then(post => { + assert.deepEqual(post.get('name'), 'Ember.js rocks'); }); + }); - test('queryRecord - returning sideloaded data loads the data', function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is omakase' }, - comments: [{ id: 1, name: 'FIRST' }], - }); + test('queryRecord - returning sideloaded data loads the data', function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is omakase' }, + comments: [{ id: 1, name: 'FIRST' }], + }); - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let comment = store.peekRecord('comment', 1); + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let comment = store.peekRecord('comment', 1); - assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - }); + assert.deepEqual(comment.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); }); + }); - testInDebug('queryRecord - returning an array picks the first one but saves all records to the store', function( - assert - ) { - ajaxResponse({ - post: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'Ember is js' }, - ], - }); + testInDebug('queryRecord - returning an array picks the first one but saves all records to the store', function( + assert + ) { + ajaxResponse({ + post: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'Ember is js' }, + ], + }); - assert.expectDeprecation( - () => - run(() => { - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - let post2 = store.peekRecord('post', 2); + assert.expectDeprecation( + () => + run(() => { + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + let post2 = store.peekRecord('post', 2); - assert.deepEqual(post.getProperties('id', 'name'), { - id: '1', - name: 'Rails is omakase', - }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'Ember is js' }); + assert.deepEqual(post.getProperties('id', 'name'), { + id: '1', + name: 'Rails is omakase', }); - }), + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'Ember is js' }); + }); + }), - /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./ - ); + /The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record./ + ); + }); + + testInDebug('queryRecord - returning an array is deprecated', function(assert) { + ajaxResponse({ + post: [ + { id: 1, name: 'Rails is omakase' }, + { id: 2, name: 'Ember is js' }, + ], }); - testInDebug('queryRecord - returning an array is deprecated', function(assert) { - ajaxResponse({ - post: [ - { id: 1, name: 'Rails is omakase' }, - { id: 2, name: 'Ember is js' }, - ], - }); + assert.expectDeprecation( + () => run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), + 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.' + ); + }); - assert.expectDeprecation( - () => run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })), - 'The adapter returned an array for the primary data of a `queryRecord` response. This is deprecated as `queryRecord` should return a single record.' - ); + testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { + ajaxResponse({ + post: { id: 1, name: 'Rails is omakase' }, }); - testInDebug("queryRecord - returning an single object doesn't throw a deprecation", function(assert) { - ajaxResponse({ - post: { id: 1, name: 'Rails is omakase' }, - }); + assert.expectNoDeprecation(); + + return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); + }); - assert.expectNoDeprecation(); + test('queryRecord - data is normalized through custom serializers', function(assert) { + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - return run(() => store.queryRecord('post', { slug: 'rails-is-omakaze' })); + ajaxResponse({ + post: { _ID_: 1, _NAME_: 'Rails is omakase' }, }); - test('queryRecord - data is normalized through custom serializers', function(assert) { - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) + return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { + assert.deepEqual( + post.getProperties('id', 'name'), + { id: '1', name: 'Rails is omakase' }, + 'Post 1 is loaded with correct data' ); - - ajaxResponse({ - post: { _ID_: 1, _NAME_: 'Rails is omakase' }, - }); - - return store.queryRecord('post', { slug: 'rails-is-omakaze' }).then(post => { - assert.deepEqual( - post.getProperties('id', 'name'), - { id: '1', name: 'Rails is omakase' }, - 'Post 1 is loaded with correct data' - ); - }); }); + }); - test('findMany - findMany uses a correct URL to access the records', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + test('findMany - findMany uses a correct URL to access the records', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); - }); - - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], + }, }); + }); - return run(() => - post.get('comments').then(comments => { - assert.equal(passedUrl, '/comments'); - assert.deepEqual(passedHash, { data: { ids: ['1', '2', '3'] } }); - }) - ); + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - test('findMany - passes buildURL the requestType', function(assert) { - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/' + type; - }; + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments'); + assert.deepEqual(passedHash, { data: { ids: ['1', '2', '3'] } }); + }) + ); + }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + test('findMany - passes buildURL the requestType', function(assert) { + adapter.buildURL = function(type, id, snapshot, requestType) { + return '/' + requestType + '/' + type; + }; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); + }, }); + }); - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + let post = store.peekRecord('post', 1); + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + }); - return run(post, 'get', 'comments').then(comments => { - assert.equal(passedUrl, '/findMany/comment'); - }); + return run(post, 'get', 'comments').then(comments => { + assert.equal(passedUrl, '/findMany/comment'); }); + }); - test('findMany - findMany does not coalesce by default', function(assert) { - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('findMany - findMany does not coalesce by default', function(assert) { + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); - }); - - let post = store.peekRecord('post', 1); - //It's still ok to return this even without coalescing because RESTSerializer supports sideloading - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], + }, }); + }); - return run(() => - post.get('comments').then(comments => { - assert.equal(passedUrl, '/comments/3'); - assert.deepEqual(passedHash.data, {}); - }) - ); + let post = store.peekRecord('post', 1); + //It's still ok to return this even without coalescing because RESTSerializer supports sideloading + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - test('findMany - returning an array populates the array', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + return run(() => + post.get('comments').then(comments => { + assert.equal(passedUrl, '/comments/3'); + assert.deepEqual(passedHash.data, {}); + }) + ); + }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + test('findMany - returning an array populates the array', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); + }, }); - - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); - - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', - }); - - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }); }); - test('findMany - returning sideloaded data loads the data', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; - - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, - }, - }, + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - }); - - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - { id: 4, name: 'Unrelated comment' }, - ], - posts: [{ id: 2, name: 'The Parley Letter' }], - }); - - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let comment4 = store.peekRecord('comment', 4); - let post2 = store.peekRecord('post', 2); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(comment4.getProperties('id', 'name'), { - id: '4', - name: 'Unrelated comment', - }); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', }); - }); - test('findMany - a custom serializer is used if present', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); - - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + }); + }); - adapter.coalesceFindRequests = true; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('findMany - returning sideloaded data loads the data', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); + }, }); - - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { _ID_: 1, _NAME_: 'FIRST' }, - { _ID_: 2, _NAME_: 'Rails is unagi' }, - { _ID_: 3, _NAME_: 'What is omakase?' }, - ], - }); - - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', - }); - - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }); }); - test('findHasMany - returning an array populates the array', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', - }, - }, - }, - }, + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + { id: 4, name: 'Unrelated comment' }, + ], + posts: [{ id: 2, name: 'The Parley Letter' }], }); - }); - - return run(() => - store - .findRecord('post', '1') - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); - - return post.get('comments'); - }) - .then(comments => { - assert.equal(passedUrl, '/posts/1/comments'); - assert.equal(passedVerb, 'GET'); - assert.strictEqual(passedHash, undefined); - - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - - assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { - id: '2', - name: 'Rails is unagi', - }); - assert.deepEqual(comment3.getProperties('id', 'name'), { - id: '3', - name: 'What is omakase?', - }); - - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }) - ); - }); - test('findHasMany - passes buildURL the requestType', function(assert) { - assert.expect(2); - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.ok(snapshot instanceof DS.Snapshot); - assert.equal(requestType, 'findHasMany'); - }; + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let comment4 = store.peekRecord('comment', 4); + let post2 = store.peekRecord('post', 2); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', - }, - }, - }, - }, + assert.deepEqual(comment4.getProperties('id', 'name'), { + id: '4', + name: 'Unrelated comment', }); + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); }); + }); - return run(() => - store.findRecord('post', '1').then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + test('findMany - a custom serializer is used if present', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - return post.get('comments'); - }) - ); - }); + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - test('findMany - returning sideloaded data loads the data (with JSONApi Links)', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', - }, - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); + }, }); + }); - return store - .findRecord('post', 1) - .then(post => { - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - posts: [{ id: 2, name: 'The Parley Letter' }], - }); - - return post.get('comments'); - }) - .then(comments => { - let comment1 = store.peekRecord('comment', 1); - let comment2 = store.peekRecord('comment', 2); - let comment3 = store.peekRecord('comment', 3); - let post2 = store.peekRecord('post', 2); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); - assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); - assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', }); - }); - - test('findMany - a custom serializer is used if present', function(assert) { - adapter.shouldBackgroundReloadRecord = () => false; - this.owner.register( - 'serializer:post', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); - this.owner.register( - 'serializer:comment', - DS.RESTSerializer.extend({ - primaryKey: '_ID_', - attrs: { name: '_NAME_' }, - }) - ); + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); + }); + }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('findHasMany - returning an array populates the array', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - links: { - related: '/posts/1/comments', - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', }, }, }, - }); + }, }); + }); - return store - .findRecord('post', 1) + return run(() => + store + .findRecord('post', '1') .then(post => { ajaxResponse({ comments: [ - { _ID_: 1, _NAME_: 'FIRST' }, - { _ID_: 2, _NAME_: 'Rails is unagi' }, - { _ID_: 3, _NAME_: 'What is omakase?' }, + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, ], }); + return post.get('comments'); }) .then(comments => { + assert.equal(passedUrl, '/posts/1/comments'); + assert.equal(passedVerb, 'GET'); + assert.strictEqual(passedHash, undefined); + let comment1 = store.peekRecord('comment', 1); let comment2 = store.peekRecord('comment', 2); let comment3 = store.peekRecord('comment', 3); assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); - assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { + id: '2', + name: 'Rails is unagi', + }); assert.deepEqual(comment3.getProperties('id', 'name'), { id: '3', name: 'What is omakase?', }); assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - }); - }); + }) + ); + }); - test('findBelongsTo - passes buildURL the requestType', function(assert) { - assert.expect(2); - adapter.shouldBackgroundReloadRecord = () => false; - adapter.buildURL = function(type, id, snapshot, requestType) { - assert.ok(snapshot instanceof DS.Snapshot); - assert.equal(requestType, 'findBelongsTo'); - }; + test('findHasMany - passes buildURL the requestType', function(assert) { + assert.expect(2); + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); + assert.equal(requestType, 'findHasMany'); + }; - Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - run(() => { - store.push({ - data: { - type: 'comment', - id: '1', - attributes: { - name: 'FIRST', - }, - relationships: { - post: { - links: { - related: '/posts/1', - }, + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', }, }, }, - }); + }, }); - - return run(() => - store.findRecord('comment', '1').then(comment => { - ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); - return comment.get('post'); - }) - ); }); - testInDebug( - 'coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', - function(assert) { - assert.expect(2); - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - - adapter.coalesceFindRequests = true; - + return run(() => + store.findRecord('post', '1').then(post => { ajaxResponse({ - comments: [{ id: '1', type: 'comment' }], + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], }); - let post = run(() => - store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, + return post.get('comments'); + }) + ); + }); + + test('findMany - returning sideloaded data loads the data (with JSONApi Links)', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', }, }, - }) - ); + }, + }, + }); + }); - assert.expectWarning(() => { - return run(() => { - return post.get('comments').catch(e => { - assert.equal( - e.message, - `Expected: '' to be present in the adapter provided payload, but it was not found.` - ); - }); - }); - }, /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/); - } - ); + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { id: 1, name: 'FIRST' }, + { id: 2, name: 'Rails is unagi' }, + { id: 3, name: 'What is omakase?' }, + ], + posts: [{ id: 2, name: 'The Parley Letter' }], + }); - test('groupRecordsForFindMany groups records based on their url', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + let post2 = store.peekRecord('post', 2); - adapter.buildURL = function(type, id, snapshot) { - if (id === '1') { - return '/comments/1'; - } else { - return '/other_comments/' + id; - } - }; + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); - adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(id, '1'); - return resolve({ comments: { id: 1 } }); - }; + assert.deepEqual(post2.getProperties('id', 'name'), { id: '2', name: 'The Parley Letter' }); + }); + }); - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, ['2', '3']); - return resolve({ comments: [{ id: 2 }, { id: 3 }] }); - }; + test('findMany - a custom serializer is used if present', function(assert) { + adapter.shouldBackgroundReloadRecord = () => false; + this.owner.register( + 'serializer:post', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); - let post; - run(() => { - store.push({ - data: { - type: 'post', - id: '2', - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], + this.owner.register( + 'serializer:comment', + DS.RESTSerializer.extend({ + primaryKey: '_ID_', + attrs: { name: '_NAME_' }, + }) + ); + + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + attributes: { + name: 'Rails is omakase', + }, + relationships: { + comments: { + links: { + related: '/posts/1/comments', }, }, }, + }, + }); + }); + + return store + .findRecord('post', 1) + .then(post => { + ajaxResponse({ + comments: [ + { _ID_: 1, _NAME_: 'FIRST' }, + { _ID_: 2, _NAME_: 'Rails is unagi' }, + { _ID_: 3, _NAME_: 'What is omakase?' }, + ], + }); + return post.get('comments'); + }) + .then(comments => { + let comment1 = store.peekRecord('comment', 1); + let comment2 = store.peekRecord('comment', 2); + let comment3 = store.peekRecord('comment', 3); + + assert.deepEqual(comment1.getProperties('id', 'name'), { id: '1', name: 'FIRST' }); + assert.deepEqual(comment2.getProperties('id', 'name'), { id: '2', name: 'Rails is unagi' }); + assert.deepEqual(comment3.getProperties('id', 'name'), { + id: '3', + name: 'What is omakase?', }); - post = store.peekRecord('post', 2); + + assert.deepEqual(comments.toArray(), [comment1, comment2, comment3], 'The correct records are in the array'); }); + }); + + test('findBelongsTo - passes buildURL the requestType', function(assert) { + assert.expect(2); + adapter.shouldBackgroundReloadRecord = () => false; + adapter.buildURL = function(type, id, snapshot, requestType) { + assert.ok(snapshot instanceof DS.Snapshot); + assert.equal(requestType, 'findBelongsTo'); + }; + + Comment.reopen({ post: DS.belongsTo('post', { async: true }) }); - run(() => post.get('comments')); + run(() => { + store.push({ + data: { + type: 'comment', + id: '1', + attributes: { + name: 'FIRST', + }, + relationships: { + post: { + links: { + related: '/posts/1', + }, + }, + }, + }, + }); }); - test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { + return run(() => + store.findRecord('comment', '1').then(comment => { + ajaxResponse({ post: { id: 1, name: 'Rails is omakase' } }); + return comment.get('post'); + }) + ); + }); + + testInDebug( + 'coalesceFindRequests assert.warns if the expected records are not returned in the coalesced request', + function(assert) { + assert.expect(2); Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - adapter.coalesceFindRequests = true; - - adapter.buildURL = function(type, id, snapshot) { - if (id === '1') { - return '/comments?id=1'; - } else { - return '/other_comments?id=' + id; - } - }; - adapter.findRecord = function(store, type, id, snapshot) { - assert.equal(id, '1'); - return resolve({ comments: { id: 1 } }); - }; + adapter.coalesceFindRequests = true; - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, ['2', '3']); - return resolve({ comments: [{ id: 2 }, { id: 3 }] }); - }; - let post; + ajaxResponse({ + comments: [{ id: '1', type: 'comment' }], + }); - run(() => { + let post = run(() => store.push({ data: { type: 'post', @@ -2242,252 +2137,306 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }, }, }, - }); - post = store.peekRecord('post', 2); - }); - - run(() => post.get('comments')); - }); - - test('normalizeKey - to set up _ids and _id', function(assert) { - this.owner.register( - 'serializer:application', - DS.RESTSerializer.extend({ - keyForAttribute(attr) { - return underscore(attr); - }, - - keyForBelongsTo(belongsTo) {}, - - keyForRelationship(rel, kind) { - if (kind === 'belongsTo') { - let underscored = underscore(rel); - return underscored + '_id'; - } else { - let singular = singularize(rel); - return underscore(singular) + '_ids'; - } - }, - }) - ); - - this.owner.register( - 'model:post', - DS.Model.extend({ - name: DS.attr(), - authorName: DS.attr(), - author: DS.belongsTo('user', { async: false }), - comments: DS.hasMany('comment', { async: false }), }) ); - this.owner.register( - 'model:user', - DS.Model.extend({ - createdAt: DS.attr(), - name: DS.attr(), - }) - ); - - this.owner.register( - 'model:comment', - DS.Model.extend({ - body: DS.attr(), - }) - ); + assert.expectWarning(() => { + return run(() => { + return post.get('comments').catch(e => { + assert.equal( + e.message, + `Expected: '' to be present in the adapter provided payload, but it was not found.` + ); + }); + }); + }, /expected to find records with the following ids in the adapter response but they were missing: \[ "2", "3" \]/); + } + ); + + test('groupRecordsForFindMany groups records based on their url', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; + + adapter.buildURL = function(type, id, snapshot) { + if (id === '1') { + return '/comments/1'; + } else { + return '/other_comments/' + id; + } + }; - ajaxResponse({ - posts: [ - { - id: '1', - name: 'Rails is omakase', - author_name: '@d2h', - author_id: '1', - comment_ids: ['1', '2'], - }, - ], + adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(id, '1'); + return resolve({ comments: { id: 1 } }); + }; - users: [ - { - id: '1', - name: 'D2H', - }, - ], + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, ['2', '3']); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); + }; - comments: [ - { - id: '1', - body: 'Rails is unagi', - }, - { - id: '2', - body: 'What is omakase?', + let post; + run(() => { + store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], + }, }, - ], - }); - - return run(() => { - return store.findRecord('post', 1).then(post => { - assert.equal(post.get('authorName'), '@d2h'); - assert.equal(post.get('author.name'), 'D2H'); - assert.deepEqual(post.get('comments').mapBy('body'), ['Rails is unagi', 'What is omakase?']); - }); + }, }); + post = store.peekRecord('post', 2); }); - test('groupRecordsForFindMany splits up calls for large ids', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + run(() => post.get('comments')); + }); - assert.expect(2); + test('groupRecordsForFindMany groups records correctly when singular URLs are encoded as query params', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + adapter.coalesceFindRequests = true; - function repeatChar(character, n) { - return new Array(n + 1).join(character); + adapter.buildURL = function(type, id, snapshot) { + if (id === '1') { + return '/comments?id=1'; + } else { + return '/other_comments?id=' + id; } + }; - let a2000 = repeatChar('a', 2000); - let b2000 = repeatChar('b', 2000); - let post; + adapter.findRecord = function(store, type, id, snapshot) { + assert.equal(id, '1'); + return resolve({ comments: { id: 1 } }); + }; - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: a2000 }, - { type: 'comment', id: b2000 }, - ], - }, + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, ['2', '3']); + return resolve({ comments: [{ id: 2 }, { id: 3 }] }); + }; + let post; + + run(() => { + store.push({ + data: { + type: 'post', + id: '2', + relationships: { + comments: { + data: [ + { type: 'comment', id: '1' }, + { type: 'comment', id: '2' }, + { type: 'comment', id: '3' }, + ], }, }, - }); - post = store.peekRecord('post', 1); + }, }); + post = store.peekRecord('post', 2); + }); - adapter.coalesceFindRequests = true; + run(() => post.get('comments')); + }); - adapter.findRecord = function(store, type, id, snapshot) { - if (id === a2000 || id === b2000) { - assert.ok(true, 'Found ' + id); - } + test('normalizeKey - to set up _ids and _id', function(assert) { + this.owner.register( + 'serializer:application', + DS.RESTSerializer.extend({ + keyForAttribute(attr) { + return underscore(attr); + }, - return resolve({ comments: { id: id } }); - }; + keyForBelongsTo(belongsTo) {}, - adapter.findMany = function(store, type, ids, snapshots) { - assert.ok(false, 'findMany should not be called - we expect 2 calls to find for a2000 and b2000'); - return reject(); - }; + keyForRelationship(rel, kind) { + if (kind === 'belongsTo') { + let underscored = underscore(rel); + return underscored + '_id'; + } else { + let singular = singularize(rel); + return underscore(singular) + '_ids'; + } + }, + }) + ); + + this.owner.register( + 'model:post', + DS.Model.extend({ + name: DS.attr(), + authorName: DS.attr(), + author: DS.belongsTo('user', { async: false }), + comments: DS.hasMany('comment', { async: false }), + }) + ); + + this.owner.register( + 'model:user', + DS.Model.extend({ + createdAt: DS.attr(), + name: DS.attr(), + }) + ); + + this.owner.register( + 'model:comment', + DS.Model.extend({ + body: DS.attr(), + }) + ); + + ajaxResponse({ + posts: [ + { + id: '1', + name: 'Rails is omakase', + author_name: '@d2h', + author_id: '1', + comment_ids: ['1', '2'], + }, + ], - run(() => post.get('comments')); + users: [ + { + id: '1', + name: 'D2H', + }, + ], + + comments: [ + { + id: '1', + body: 'Rails is unagi', + }, + { + id: '2', + body: 'What is omakase?', + }, + ], }); - test('groupRecordsForFindMany groups calls for small ids', function(assert) { - Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + return run(() => { + return store.findRecord('post', 1).then(post => { + assert.equal(post.get('authorName'), '@d2h'); + assert.equal(post.get('author.name'), 'D2H'); + assert.deepEqual(post.get('comments').mapBy('body'), ['Rails is unagi', 'What is omakase?']); + }); + }); + }); - assert.expect(1); + test('groupRecordsForFindMany splits up calls for large ids', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - function repeatChar(character, n) { - return new Array(n + 1).join(character); - } + assert.expect(2); - let a100 = repeatChar('a', 100); - let b100 = repeatChar('b', 100); - let post; + function repeatChar(character, n) { + return new Array(n + 1).join(character); + } - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - relationships: { - comments: { - data: [ - { type: 'comment', id: a100 }, - { type: 'comment', id: b100 }, - ], - }, + let a2000 = repeatChar('a', 2000); + let b2000 = repeatChar('b', 2000); + let post; + + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: a2000 }, + { type: 'comment', id: b2000 }, + ], }, }, - }); - post = store.peekRecord('post', 1); + }, }); + post = store.peekRecord('post', 1); + }); - adapter.coalesceFindRequests = true; + adapter.coalesceFindRequests = true; - adapter.findRecord = function(store, type, id, snapshot) { - assert.ok(false, 'findRecord should not be called - we expect 1 call to findMany for a100 and b100'); - return reject(); - }; + adapter.findRecord = function(store, type, id, snapshot) { + if (id === a2000 || id === b2000) { + assert.ok(true, 'Found ' + id); + } - adapter.findMany = function(store, type, ids, snapshots) { - assert.deepEqual(ids, [a100, b100]); - return resolve({ comments: [{ id: a100 }, { id: b100 }] }); - }; + return resolve({ comments: { id: id } }); + }; - run(() => post.get('comments')); - }); + adapter.findMany = function(store, type, ids, snapshots) { + assert.ok(false, 'findMany should not be called - we expect 2 calls to find for a2000 and b2000'); + return reject(); + }; - if (hasJQuery) { - test('calls adapter.handleResponse with the jqXHR and json', function(assert) { - assert.expect(2); + run(() => post.get('comments')); + }); - let data = { - post: { - id: '1', - name: 'Docker is amazing', - }, - }; + test('groupRecordsForFindMany groups calls for small ids', function(assert) { + Comment.reopen({ post: DS.belongsTo('post', { async: false }) }); + Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); - server.get('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; - }); + assert.expect(1); - adapter.handleResponse = function(status, headers, json) { - assert.deepEqual(status, 200); - assert.deepEqual(json, data); - return json; - }; + function repeatChar(character, n) { + return new Array(n + 1).join(character); + } + + let a100 = repeatChar('a', 100); + let b100 = repeatChar('b', 100); + let post; - return run(() => store.findRecord('post', '1')); + run(() => { + store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [ + { type: 'comment', id: a100 }, + { type: 'comment', id: b100 }, + ], + }, + }, + }, }); + post = store.peekRecord('post', 1); + }); - test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { - assert.expect(4); - - let responseText = 'Nope lol'; - - let expectedRequestData = { - method: 'GET', - url: '/posts/1', - }; + adapter.coalesceFindRequests = true; - server.get('/posts/1', function() { - return [400, {}, responseText]; - }); + adapter.findRecord = function(store, type, id, snapshot) { + assert.ok(false, 'findRecord should not be called - we expect 1 call to findMany for a100 and b100'); + return reject(); + }; - adapter.handleResponse = function(status, headers, json, requestData) { - assert.deepEqual(status, 400); - assert.deepEqual(json, responseText); - assert.deepEqual(requestData, expectedRequestData); - return new DS.AdapterError('nope!'); - }; + adapter.findMany = function(store, type, ids, snapshots) { + assert.deepEqual(ids, [a100, b100]); + return resolve({ comments: [{ id: a100 }, { id: b100 }] }); + }; - return run(() => { - return store.findRecord('post', '1').catch(err => assert.ok(err, 'promise rejected')); - }); - }); - } + run(() => post.get('comments')); + }); - test('rejects promise if DS.AdapterError is returned from adapter.handleResponse', function(assert) { - assert.expect(3); + if (hasJQuery) { + test('calls adapter.handleResponse with the jqXHR and json', function(assert) { + assert.expect(2); let data = { - something: 'is invalid', + post: { + id: '1', + name: 'Docker is amazing', + }, }; server.get('/posts/1', function() { @@ -2495,435 +2444,390 @@ module('integration/adapter/rest_adapter - REST Adapter', function(hooks) { }); adapter.handleResponse = function(status, headers, json) { - assert.ok(true, 'handleResponse should be called'); - return new DS.AdapterError(json); + assert.deepEqual(status, 200); + assert.deepEqual(json, data); + return json; }; - return run(() => { - return store.findRecord('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); - }); - }); + return run(() => store.findRecord('post', '1')); }); - test('gracefully handles exceptions in handleResponse', function(assert) { - assert.expect(1); + test('calls handleResponse with jqXHR, jqXHR.responseText, and requestData', function(assert) { + assert.expect(4); - server.post('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, 'ok']; - }); + let responseText = 'Nope lol'; - adapter.handleResponse = function(status, headers, json) { - throw new Error('Unexpected error'); + let expectedRequestData = { + method: 'GET', + url: '/posts/1', }; - return run(() => { - return store.findRecord('post', '1').catch(error => { - assert.ok(true, 'Unexpected error is captured by the promise chain'); - }); - }); - }); - - test('gracefully handles exceptions in handleResponse where the ajax request errors', function(assert) { - assert.expect(1); - server.get('/posts/1', function() { - return [500, { 'Content-Type': 'application/json' }, 'Internal Server Error']; + return [400, {}, responseText]; }); - adapter.handleResponse = function(status, headers, json) { - throw new Error('Unexpected error'); + adapter.handleResponse = function(status, headers, json, requestData) { + assert.deepEqual(status, 400); + assert.deepEqual(json, responseText); + assert.deepEqual(requestData, expectedRequestData); + return new DS.AdapterError('nope!'); }; return run(() => { - return store.findRecord('post', '1').catch(error => { - assert.ok(true, 'Unexpected error is captured by the promise chain'); - }); + return store.findRecord('post', '1').catch(err => assert.ok(err, 'promise rejected')); }); }); + } - test('treats status code 0 as an abort', function(assert) { - assert.expect(3); + test('rejects promise if DS.AdapterError is returned from adapter.handleResponse', function(assert) { + assert.expect(3); - ajaxZero(); - adapter.handleResponse = function(status, headers, payload) { - assert.ok(false); - }; + let data = { + something: 'is invalid', + }; - return run(() => { - return store.findRecord('post', '1').catch(err => { - assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); - assert.equal(err.errors.length, 1, 'AbortError includes errors with request/response details'); - let expectedError = { - title: 'Adapter Error', - detail: 'Request failed: GET /posts/1', - status: 0, - }; - assert.deepEqual(err.errors[0], expectedError, 'method, url and, status are captured as details'); - }); - }); + server.get('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, JSON.stringify(data)]; }); - if (hasJQuery) { - test('on error appends errorThrown for sanity', async function(assert) { - assert.expect(2); + adapter.handleResponse = function(status, headers, json) { + assert.ok(true, 'handleResponse should be called'); + return new DS.AdapterError(json); + }; - let jqXHR = { - responseText: 'Nope lol', - getAllResponseHeaders() { - return ''; - }, - }; + return run(() => { + return store.findRecord('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.AdapterError, 'reason should be an instance of DS.AdapterError'); + }); + }); + }); - let errorThrown = new Error('nope!'); + test('gracefully handles exceptions in handleResponse', function(assert) { + assert.expect(1); - adapter._ajaxRequest = function(hash) { - hash.error(jqXHR, jqXHR.responseText, errorThrown); - }; + server.post('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, 'ok']; + }); - adapter.handleResponse = function(status, headers, payload) { - assert.ok(false); - }; + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); + }; - try { - await store.findRecord('post', '1'); - } catch (err) { - assert.equal(err, errorThrown); - assert.ok(err, 'promise rejected'); - } + return run(() => { + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); }); + }); + }); - test('on error wraps the error string in an DS.AdapterError object', function(assert) { - assert.expect(2); - - let jqXHR = { - responseText: '', - getAllResponseHeaders() { - return ''; - }, - }; + test('gracefully handles exceptions in handleResponse where the ajax request errors', function(assert) { + assert.expect(1); - let errorThrown = 'nope!'; + server.get('/posts/1', function() { + return [500, { 'Content-Type': 'application/json' }, 'Internal Server Error']; + }); - adapter._ajaxRequest = function(hash) { - hash.error(jqXHR, 'error', errorThrown); - }; + adapter.handleResponse = function(status, headers, json) { + throw new Error('Unexpected error'); + }; - run(() => { - store.findRecord('post', '1').catch(err => { - assert.equal(err.errors[0].detail, errorThrown); - assert.ok(err, 'promise rejected'); - }); - }); + return run(() => { + return store.findRecord('post', '1').catch(error => { + assert.ok(true, 'Unexpected error is captured by the promise chain'); }); - } - - test('rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes', function(assert) { - assert.expect(10); - - ajaxError('error', 401); + }); + }); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); - }); - }); + test('treats status code 0 as an abort', function(assert) { + assert.expect(3); - ajaxError('error', 403); + ajaxZero(); + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); - }); + return run(() => { + return store.findRecord('post', '1').catch(err => { + assert.ok(err instanceof DS.AbortError, 'reason should be an instance of DS.AbortError'); + assert.equal(err.errors.length, 1, 'AbortError includes errors with request/response details'); + let expectedError = { + title: 'Adapter Error', + detail: 'Request failed: GET /posts/1', + status: 0, + }; + assert.deepEqual(err.errors[0], expectedError, 'method, url and, status are captured as details'); }); + }); + }); - ajaxError('error', 404); + if (hasJQuery) { + test('on error appends errorThrown for sanity', async function(assert) { + assert.expect(2); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); - }); - }); + let jqXHR = { + responseText: 'Nope lol', + getAllResponseHeaders() { + return ''; + }, + }; - ajaxError('error', 409); + let errorThrown = new Error('nope!'); - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); - }); - }); + adapter._ajaxRequest = function(hash) { + hash.error(jqXHR, jqXHR.responseText, errorThrown); + }; - ajaxError('error', 500); + adapter.handleResponse = function(status, headers, payload) { + assert.ok(false); + }; - run(() => { - store.find('post', '1').catch(reason => { - assert.ok(true, 'promise should be rejected'); - assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); - }); - }); + try { + await store.findRecord('post', '1'); + } catch (err) { + assert.equal(err, errorThrown); + assert.ok(err, 'promise rejected'); + } }); - test('error handling includes a detailed message from the server', assert => { + test('on error wraps the error string in an DS.AdapterError object', function(assert) { assert.expect(2); - ajaxError('An error message, perhaps generated from a backend server!', 500, { - 'Content-Type': 'text/plain', - }); + let jqXHR = { + responseText: '', + getAllResponseHeaders() { + return ''; + }, + }; + + let errorThrown = 'nope!'; + + adapter._ajaxRequest = function(hash) { + hash.error(jqXHR, 'error', errorThrown); + }; run(() => { store.findRecord('post', '1').catch(err => { - assert.equal( - err.message, - 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!' - ); + assert.equal(err.errors[0].detail, errorThrown); assert.ok(err, 'promise rejected'); }); }); }); + } - test('error handling with a very long HTML-formatted payload truncates the friendly message', assert => { - assert.expect(2); + test('rejects promise with a specialized subclass of DS.AdapterError if ajax responds with http error codes', function(assert) { + assert.expect(10); - ajaxError(new Array(100).join(''), 500, { 'Content-Type': 'text/html' }); + ajaxError('error', 401); - run(() => { - store.findRecord('post', '1').catch(err => { - assert.equal( - err.message, - 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]' - ); - assert.ok(err, 'promise rejected'); - }); + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.UnauthorizedError, 'reason should be an instance of DS.UnauthorizedError'); }); }); - test('findAll resolves with a collection of DS.Models, not DS.InternalModels', assert => { - assert.expect(4); - - ajaxResponse({ - posts: [ - { - id: 1, - name: 'dhh lol', - }, - { - id: 2, - name: 'james mickens is rad', - }, - { - id: 3, - name: 'in the name of love', - }, - ], - }); + ajaxError('error', 403); - return run(() => { - return store.findAll('post').then(posts => { - assert.equal(get(posts, 'length'), 3); - posts.forEach(post => assert.ok(post instanceof DS.Model)); - }); + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ForbiddenError, 'reason should be an instance of DS.ForbiddenError'); }); }); - test('createRecord - sideloaded records are pushed to the store', function(assert) { - Post.reopen({ - comments: DS.hasMany('comment'), - }); + ajaxError('error', 404); - ajaxResponse({ - post: { - id: 1, - name: 'The Parley Letter', - comments: [2, 3], - }, - comments: [ - { - id: 2, - name: 'First comment', - }, - { - id: 3, - name: 'Second comment', - }, - ], + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.NotFoundError, 'reason should be an instance of DS.NotFoundError'); }); - let post; - - return run(() => { - post = store.createRecord('post', { name: 'The Parley Letter' }); + }); - return post.save().then(post => { - let comments = store.peekAll('comment'); + ajaxError('error', 409); - assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); - assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); - assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); - }); + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ConflictError, 'reason should be an instance of DS.ConflictError'); }); }); - testInDebug('warns when an empty 201 response is returned, though a valid stringified JSON is expected', function( - assert - ) { - assert.expect(1); + ajaxError('error', 500); - server.post('/posts', function() { - return [201, { 'Content-Type': 'application/json' }, '']; + run(() => { + store.find('post', '1').catch(reason => { + assert.ok(true, 'promise should be rejected'); + assert.ok(reason instanceof DS.ServerError, 'reason should be an instance of DS.ServerError'); }); - - let post = store.createRecord('post'); - return post.save().then( - () => { - assert.equal(true, false, 'should not have fulfilled'); - }, - reason => { - if (!hasJQuery) { - assert.ok(/saved to the server/.test(reason.message)); - // Workaround for #7371 to get the record a correct state before teardown - let identifier = recordIdentifierFor(post); - let im = store._internalModelForResource(identifier); - store.didSaveRecord(im, { data: { id: '1', type: 'post' } }, 'createRecord'); - } else { - assert.ok(/JSON/.test(reason.message)); - } - } - ); }); + }); - if (!hasJQuery) { - testInDebug( - 'warns when an empty 200 response is returned, though a valid stringified JSON is expected', - async function(assert) { - assert.expect(2); + test('error handling includes a detailed message from the server', assert => { + assert.expect(2); - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, '']; - }); + ajaxError('An error message, perhaps generated from a backend server!', 500, { + 'Content-Type': 'text/plain', + }); - let post = store.push({ data: { id: '1', type: 'post' } }); - await assert.expectWarning(async () => { - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); - }, /JSON/); - } - ); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/plain)\nAn error message, perhaps generated from a backend server!' + ); + assert.ok(err, 'promise rejected'); + }); + }); + }); - test('can return an empty 200 response, though a valid stringified JSON is expected', async function(assert) { - assert.expect(1); + test('error handling with a very long HTML-formatted payload truncates the friendly message', assert => { + assert.expect(2); - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, '']; - }); + ajaxError(new Array(100).join(''), 500, { 'Content-Type': 'text/html' }); - let post = store.push({ data: { id: '1', type: 'post' } }); - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + run(() => { + store.findRecord('post', '1').catch(err => { + assert.equal( + err.message, + 'Ember Data Request GET /posts/1 returned a 500\nPayload (text/html)\n[Omitted Lengthy HTML]' + ); + assert.ok(err, 'promise rejected'); }); + }); + }); - test('can return a null 200 response, though a valid stringified JSON is expected', async function(assert) { - assert.expect(1); + test('findAll resolves with a collection of DS.Models, not DS.InternalModels', assert => { + assert.expect(4); - server.put('/posts/1', function() { - return [200, { 'Content-Type': 'application/json' }, null]; - }); + ajaxResponse({ + posts: [ + { + id: 1, + name: 'dhh lol', + }, + { + id: 2, + name: 'james mickens is rad', + }, + { + id: 3, + name: 'in the name of love', + }, + ], + }); - let post = store.push({ data: { id: '1', type: 'post' } }); - return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + return run(() => { + return store.findAll('post').then(posts => { + assert.equal(get(posts, 'length'), 3); + posts.forEach(post => assert.ok(post instanceof DS.Model)); }); - } + }); }); - module('init adapter coalesceFindRequests', function() { - test('findMany - passes buildURL the requestType', function(assert) { - this.owner.register('adapter:application', RESTAdapter.extend({ coalesceFindRequests: true })); - adapter = store.adapterFor('application'); + test('createRecord - sideloaded records are pushed to the store', function(assert) { + Post.reopen({ + comments: DS.hasMany('comment'), + }); + + ajaxResponse({ + post: { + id: 1, + name: 'The Parley Letter', + comments: [2, 3], + }, + comments: [ + { + id: 2, + name: 'First comment', + }, + { + id: 3, + name: 'Second comment', + }, + ], + }); + let post; - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/' + type; - }; + return run(() => { + post = store.createRecord('post', { name: 'The Parley Letter' }); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + return post.save().then(post => { + let comments = store.peekAll('comment'); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - ], - }, - }, - }, - }); + assert.equal(get(comments, 'length'), 2, 'comments.length is correct'); + assert.equal(get(comments, 'firstObject.name'), 'First comment', 'comments.firstObject.name is correct'); + assert.equal(get(comments, 'lastObject.name'), 'Second comment', 'comments.lastObject.name is correct'); }); + }); + }); - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - ], - }); + testInDebug('warns when an empty 201 response is returned, though a valid stringified JSON is expected', function( + assert + ) { + assert.expect(1); + + server.post('/posts', function() { + return [201, { 'Content-Type': 'application/json' }, '']; + }); + + let post = store.createRecord('post'); + return post.save().then( + () => { + assert.equal(true, false, 'should not have fulfilled'); + }, + reason => { + if (!hasJQuery) { + assert.ok(/saved to the server/.test(reason.message)); + // Workaround for #7371 to get the record a correct state before teardown + let identifier = recordIdentifierFor(post); + let im = store._internalModelForResource(identifier); + store.didSaveRecord(im, { data: { id: '1', type: 'post' } }, 'createRecord'); + } else { + assert.ok(/JSON/.test(reason.message)); + } + } + ); + }); - return run(post, 'get', 'comments').then(comments => { - assert.equal(passedUrl, '/findMany/comment'); - }); - }); + if (!hasJQuery) { + testInDebug( + 'warns when an empty 200 response is returned, though a valid stringified JSON is expected', + async function(assert) { + assert.expect(2); - test('class findMany - passes buildURL the requestType', function(assert) { - this.owner.unregister('adapter:application'); - this.owner.register('adapter:application', class MyClass extends RESTAdapter { coalesceFindRequests = true; }); - adapter = store.adapterFor('application'); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, '']; + }); - adapter.buildURL = function(type, id, snapshot, requestType) { - return '/' + requestType + '/' + type; - }; + let post = store.push({ data: { id: '1', type: 'post' } }); + await assert.expectWarning(async () => { + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + }, /JSON/); + } + ); - Post.reopen({ comments: DS.hasMany('comment', { async: true }) }); + test('can return an empty 200 response, though a valid stringified JSON is expected', async function(assert) { + assert.expect(1); - run(() => { - store.push({ - data: { - type: 'post', - id: '1', - attributes: { - name: 'Rails is omakase', - }, - relationships: { - comments: { - data: [ - { type: 'comment', id: '1' }, - { type: 'comment', id: '2' }, - { type: 'comment', id: '3' }, - ], - }, - }, - }, - }); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, '']; }); - let post = store.peekRecord('post', 1); - ajaxResponse({ - comments: [ - { id: 1, name: 'FIRST' }, - { id: 2, name: 'Rails is unagi' }, - { id: 3, name: 'What is omakase?' }, - ], - }); + let post = store.push({ data: { id: '1', type: 'post' } }); + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); + }); + + test('can return a null 200 response, though a valid stringified JSON is expected', async function(assert) { + assert.expect(1); - return run(post, 'get', 'comments').then(comments => { - assert.equal(passedUrl, '/findMany/comment'); + server.put('/posts/1', function() { + return [200, { 'Content-Type': 'application/json' }, null]; }); + + let post = store.push({ data: { id: '1', type: 'post' } }); + return post.save().then(() => assert.ok(true, 'save fullfills correctly')); }); - }); + } }); From 7a942c5e9bcb1e0a85304674a2c5d79830d019d8 Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Sat, 3 Apr 2021 20:57:23 -0500 Subject: [PATCH 5/7] put next to docs --- packages/adapter/addon/rest.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/packages/adapter/addon/rest.ts b/packages/adapter/addon/rest.ts index 34c215d4144..9974931a27b 100644 --- a/packages/adapter/addon/rest.ts +++ b/packages/adapter/addon/rest.ts @@ -367,18 +367,6 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { this._fastboot = value; } - get coalesceFindRequests() { - let coalesceFindRequests = this._coalesceFindRequests; - if (typeof coalesceFindRequests === 'boolean') { - return coalesceFindRequests; - } - return (this._coalesceFindRequests = false); - } - - set coalesceFindRequests(value: boolean) { - this._coalesceFindRequests = value; - } - /** By default, the RESTAdapter will send the query params sorted alphabetically to the server. @@ -483,6 +471,17 @@ class RESTAdapter extends Adapter.extend(BuildURLMixin) { @property coalesceFindRequests @type {boolean} */ + get coalesceFindRequests() { + let coalesceFindRequests = this._coalesceFindRequests; + if (typeof coalesceFindRequests === 'boolean') { + return coalesceFindRequests; + } + return (this._coalesceFindRequests = false); + } + + set coalesceFindRequests(value: boolean) { + this._coalesceFindRequests = value; + } /** Endpoint paths can be prefixed with a `namespace` by setting the namespace From d0b5565b537c331dffaa226f7bcb7b1bcc8237f9 Mon Sep 17 00:00:00 2001 From: scott-newcomer Date: Sat, 3 Apr 2021 21:06:07 -0500 Subject: [PATCH 6/7] lint fix --- .../unit/adapters/json-api-adapter/json-api-test.js | 9 +++++++-- .../tests/unit/adapters/rest-adapter/rest-test.js | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js b/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js index 41128624839..e92a61f8c47 100644 --- a/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js +++ b/packages/-ember-data/tests/unit/adapters/json-api-adapter/json-api-test.js @@ -1,4 +1,5 @@ import { module, test } from 'qunit'; + import JSONAPIAdapter from '@ember-data/adapter/json-api'; module('unit/adapters/json-api-test', function() { @@ -23,12 +24,16 @@ module('unit/adapters/json-api-test', function() { }); test('coalesceFindRequests class true', function(assert) { - class MyClass extends JSONAPIAdapter { coalesceFindRequests = true } + class MyClass extends JSONAPIAdapter { + coalesceFindRequests = true; + } assert.deepEqual(MyClass.create().coalesceFindRequests, true, 'result is true'); }); test('coalesceFindRequests class false', function(assert) { - class MyClass extends JSONAPIAdapter { coalesceFindRequests = false } + class MyClass extends JSONAPIAdapter { + coalesceFindRequests = false; + } assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'result is false'); }); }); diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js index 43ddc472b03..10e48d5c929 100644 --- a/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js +++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/rest-test.js @@ -1,4 +1,5 @@ import { module, test } from 'qunit'; + import RESTAdapter from '@ember-data/adapter/rest'; module('unit/adapters/rest-test', function() { @@ -23,12 +24,16 @@ module('unit/adapters/rest-test', function() { }); test('coalesceFindRequests class true', function(assert) { - class MyClass extends RESTAdapter { coalesceFindRequests = true } + class MyClass extends RESTAdapter { + coalesceFindRequests = true; + } assert.deepEqual(MyClass.create().coalesceFindRequests, true, 'result is true'); }); test('coalesceFindRequests class false', function(assert) { - class MyClass extends RESTAdapter { coalesceFindRequests = false } + class MyClass extends RESTAdapter { + coalesceFindRequests = false; + } assert.deepEqual(MyClass.create().coalesceFindRequests, false, 'result is false'); }); }); From 90b02d852d7ed1b2fb57f76a829ad19293890665 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Fri, 9 Apr 2021 10:29:26 -0700 Subject: [PATCH 7/7] default to launching with no container --- packages/-ember-data/testem.js | 2 +- packages/unpublished-adapter-encapsulation-test-app/testem.js | 2 +- packages/unpublished-debug-encapsulation-test-app/testem.js | 2 +- packages/unpublished-fastboot-test-app/testem.js | 2 +- packages/unpublished-model-encapsulation-test-app/testem.js | 2 +- .../unpublished-record-data-encapsulation-test-app/testem.js | 2 +- .../unpublished-relationship-performance-test-app/testem.js | 2 +- .../unpublished-serializer-encapsulation-test-app/testem.js | 2 +- packages/unpublished-test-infra/testem.js | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/-ember-data/testem.js b/packages/-ember-data/testem.js index c1135fc03b0..a9df5e60abb 100644 --- a/packages/-ember-data/testem.js +++ b/packages/-ember-data/testem.js @@ -4,7 +4,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-adapter-encapsulation-test-app/testem.js b/packages/unpublished-adapter-encapsulation-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-adapter-encapsulation-test-app/testem.js +++ b/packages/unpublished-adapter-encapsulation-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-debug-encapsulation-test-app/testem.js b/packages/unpublished-debug-encapsulation-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-debug-encapsulation-test-app/testem.js +++ b/packages/unpublished-debug-encapsulation-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-fastboot-test-app/testem.js b/packages/unpublished-fastboot-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-fastboot-test-app/testem.js +++ b/packages/unpublished-fastboot-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-model-encapsulation-test-app/testem.js b/packages/unpublished-model-encapsulation-test-app/testem.js index 04cb091de43..e11b225fce9 100644 --- a/packages/unpublished-model-encapsulation-test-app/testem.js +++ b/packages/unpublished-model-encapsulation-test-app/testem.js @@ -9,7 +9,7 @@ if (TestIE) { } module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: TestIE ? ['IE'] : ['Chrome'], diff --git a/packages/unpublished-record-data-encapsulation-test-app/testem.js b/packages/unpublished-record-data-encapsulation-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-record-data-encapsulation-test-app/testem.js +++ b/packages/unpublished-record-data-encapsulation-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-relationship-performance-test-app/testem.js b/packages/unpublished-relationship-performance-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-relationship-performance-test-app/testem.js +++ b/packages/unpublished-relationship-performance-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-serializer-encapsulation-test-app/testem.js b/packages/unpublished-serializer-encapsulation-test-app/testem.js index b96b2b141d9..e10b064501a 100644 --- a/packages/unpublished-serializer-encapsulation-test-app/testem.js +++ b/packages/unpublished-serializer-encapsulation-test-app/testem.js @@ -5,7 +5,7 @@ const customDotReporter = require('@ember-data/unpublished-test-infra/src/testem console.log(`\n\nLaunching with ${process.env.TESTEM_CI_LAUNCHER || 'Chrome'}\n\n`); module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, reporter: customDotReporter, launch_in_ci: [process.env.TESTEM_CI_LAUNCHER || 'Chrome'], diff --git a/packages/unpublished-test-infra/testem.js b/packages/unpublished-test-infra/testem.js index 6edd28bdf63..165c63b837d 100644 --- a/packages/unpublished-test-infra/testem.js +++ b/packages/unpublished-test-infra/testem.js @@ -1,5 +1,5 @@ module.exports = { - test_page: 'tests/index.html?hidepassed', + test_page: 'tests/index.html?hidepassed&nocontainer', disable_watching: true, launch_in_ci: ['Chrome'], launch_in_dev: ['Chrome'],