From 3bb4450580516ec51721b7cc0c48bb84f15f9783 Mon Sep 17 00:00:00 2001 From: Eric Kelly Date: Thu, 15 Aug 2019 23:54:40 -0700 Subject: [PATCH] [CHORE] Refactor away from `createStore` test helper From https://github.com/emberjs/data/issues/6166 This refactors some tests so that they don't rely on the `createStore` test helper. `createStore` was helpful in the past but is less so now that we have [nice APIs for dependency injection](https://guides.emberjs.com/release/applications/dependency-injection/). --- One test was removed from `unit/store/adapter-interop - Store working with a Adapter` because I don't think it was correct. Here was the test: https://github.com/emberjs/data/blob/39182f324d5777e4a75c4a582f0791631e37d8de/packages/-ember-data/tests/unit/store/adapter-interop-test.js#L28-L32 This test was, at one time, testing that it was possible to pass a factory as the `adapter` property to `Store`. This feature was removed in https://github.com/emberjs/data/pull/3191 but the test continued passing because of the way the `createStore` works. https://github.com/emberjs/data/blob/39182f324d5777e4a75c4a582f0791631e37d8de/packages/-ember-data/tests/helpers/store.js#L57-L60 --- packages/-ember-data/tests/helpers/store.js | 4 - .../adapter-populated-record-array-test.js | 67 +- .../record-arrays/peeked-records-test.js | 15 +- .../group-records-for-find-many-test.js | 23 +- packages/-ember-data/tests/unit/debug-test.js | 195 +-- .../unit/model/lifecycle-callbacks-test.js | 135 +- .../tests/unit/model/merge-test.js | 98 +- .../tests/unit/store/adapter-interop-test.js | 635 ++++---- .../tests/unit/store/create-record-test.js | 69 +- .../tests/unit/store/has-model-for-test.js | 21 +- .../tests/unit/store/unload-test.js | 72 +- .../polymorphic-relationship-payloads-test.js | 1445 +++++++++-------- 12 files changed, 1394 insertions(+), 1385 deletions(-) diff --git a/packages/-ember-data/tests/helpers/store.js b/packages/-ember-data/tests/helpers/store.js index 211b7e64823..c3c9992ef76 100644 --- a/packages/-ember-data/tests/helpers/store.js +++ b/packages/-ember-data/tests/helpers/store.js @@ -107,7 +107,3 @@ export default function setupStore(options) { } export { setupStore }; - -export function createStore(options) { - return setupStore(options).store; -} diff --git a/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js b/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js index e712215893b..aeea4d8dec2 100644 --- a/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js +++ b/packages/-ember-data/tests/integration/record-arrays/adapter-populated-record-array-test.js @@ -1,35 +1,35 @@ import { run } from '@ember/runloop'; import { Promise } from 'rsvp'; -import { setupStore, createStore } from 'dummy/tests/helpers/store'; - +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; - -let store; +import Adapter from '@ember-data/adapter'; +import Model, { attr } from '@ember-data/model'; -const Person = DS.Model.extend({ - name: DS.attr('string'), +const Person = Model.extend({ + name: attr('string'), toString() { return ``; }, }); -const adapter = DS.Adapter.extend({ - deleteRecord() { - return Promise.resolve(); - }, -}); +module('integration/record-arrays/adapter_populated_record_array - AdapterPopulatedRecordArray', function(hooks) { + setupTest(hooks); -module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPopulatedRecordArray', function(hooks) { hooks.beforeEach(function() { - store = createStore({ - adapter: adapter, - person: Person, - }); + this.owner.register('model:person', Person); }); test('when a record is deleted in an adapter populated record array, it should be removed', function(assert) { + let ApplicationAdapter = Adapter.extend({ + deleteRecord() { + return Promise.resolve(); + }, + }); + + this.owner.register('adapter:application', ApplicationAdapter); + + let store = this.owner.lookup('service:store'); let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { @@ -70,6 +70,7 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('stores the metadata off the payload', function(assert) { + let store = this.owner.lookup('service:store'); let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { @@ -109,6 +110,7 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('stores the links off the payload', function(assert) { + let store = this.owner.lookup('service:store'); let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); let payload = { @@ -152,6 +154,7 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('recordArray.replace() throws error', function(assert) { + let store = this.owner.lookup('service:store'); let recordArray = store.recordArrayManager.createAdapterPopulatedRecordArray('person', null); assert.throws( @@ -164,8 +167,8 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('pass record array to adapter.query regardless of arity', function(assert) { - let env = setupStore({ person: Person }); - let store = env.store; + let store = this.owner.lookup('service:store'); + let adapter = store.adapterFor('application'); let payload = { data: [ @@ -174,14 +177,14 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop ], }; - env.adapter.query = function(store, type, query) { + adapter.query = function(store, type, query) { // Due to #6232, we now expect 5 arguments regardless of arity assert.equal(arguments.length, 5); return payload; }; return store.query('person', {}).then(recordArray => { - env.adapter.query = function(store, type, query, _recordArray) { + adapter.query = function(store, type, query, _recordArray) { assert.equal(arguments.length, 5); return payload; }; @@ -190,8 +193,8 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('pass record array to adapter.query regardless of arity', function(assert) { - let env = setupStore({ person: Person }); - let store = env.store; + let store = this.owner.lookup('service:store'); + let adapter = store.adapterFor('application'); let payload = { data: [ @@ -214,14 +217,14 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop return superCreateAdapterPopulatedRecordArray.apply(this, arguments); }; - env.adapter.query = function(store, type, query) { + adapter.query = function(store, type, query) { // Due to #6232, we now expect 5 arguments regardless of arity assert.equal(arguments.length, 5); return payload; }; return store.query('person', actualQuery).then(recordArray => { - env.adapter.query = function(store, type, query, _recordArray) { + adapter.query = function(store, type, query, _recordArray) { assert.equal(arguments.length, 5); return payload; }; @@ -239,8 +242,8 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop }); test('loadRecord re-syncs internalModels recordArrays', function(assert) { - let env = setupStore({ person: Person }); - let store = env.store; + let store = this.owner.lookup('service:store'); + let adapter = store.adapterFor('application'); let payload = { data: [ @@ -249,7 +252,7 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop ], }; - env.adapter.query = function(store, type, query, recordArray) { + adapter.query = function(store, type, query, recordArray) { return payload; }; @@ -282,18 +285,18 @@ module('integration/record-arrays/adapter_populated_record_array - DS.AdapterPop assert.expect(8); let queryPromise, queryArr, findPromise, findArray; - let env = setupStore({ person: Person }); - let store = env.store; + let store = this.owner.lookup('service:store'); + let adapter = store.adapterFor('application'); let array = [{ id: '1', type: 'person', attributes: { name: 'Scumbag Dale' } }]; // resemble server side filtering - env.adapter.query = function(store, type, query, recordArray) { + adapter.query = function(store, type, query, recordArray) { return { data: array.slice(query.slice) }; }; // implement findAll to further test that query updates won't muddle // with the non-query record arrays - env.adapter.findAll = function(store, type, sinceToken) { + adapter.findAll = function(store, type, sinceToken) { return { data: array.slice(0) }; }; diff --git a/packages/-ember-data/tests/integration/record-arrays/peeked-records-test.js b/packages/-ember-data/tests/integration/record-arrays/peeked-records-test.js index a17ecc78a85..44fdc585e26 100644 --- a/packages/-ember-data/tests/integration/record-arrays/peeked-records-test.js +++ b/packages/-ember-data/tests/integration/record-arrays/peeked-records-test.js @@ -1,24 +1,25 @@ +import Model, { attr } from '@ember-data/model'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; import { get } from '@ember/object'; import { watchProperties } from '../../helpers/watch-property'; let store; -const Person = DS.Model.extend({ - name: DS.attr('string'), +const Person = Model.extend({ + name: attr('string'), toString() { return ``; }, }); module('integration/peeked-records', function(hooks) { + setupTest(hooks); + hooks.beforeEach(function() { - store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); + store = this.owner.lookup('service:store'); }); test('repeated calls to peekAll in separate run-loops works as expected', function(assert) { diff --git a/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js b/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js index e08aa9e62ee..ba0cb293685 100644 --- a/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js +++ b/packages/-ember-data/tests/unit/adapters/rest-adapter/group-records-for-find-many-test.js @@ -1,32 +1,33 @@ import { run } from '@ember/runloop'; import { Promise as EmberPromise } from 'rsvp'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; +import Model from '@ember-data/model'; +import RESTAdapter from '@ember-data/adapter/rest'; -let GroupsAdapter, store, requests; +let store, requests; let maxLength; let lengths; module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAdapter#groupRecordsForFindMany', function( hooks ) { + setupTest(hooks); + hooks.beforeEach(function() { maxLength = -1; requests = []; lengths = []; - GroupsAdapter = DS.RESTAdapter.extend({ + let ApplicationAdapter = RESTAdapter.extend({ coalesceFindRequests: true, findRecord(store, type, id, snapshot) { return { id }; }, - }); - GroupsAdapter.reopen({ ajax(url, type, options) { requests.push({ url, @@ -48,14 +49,10 @@ module('unit/adapters/rest_adapter/group_records_for_find_many_test - DS.RESTAda }, }); - store = createStore({ - adapter: GroupsAdapter, - testRecord: DS.Model.extend(), - }); - }); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('model:test-record', Model.extend()); - hooks.afterEach(function() { - run(store, 'destroy'); + store = this.owner.lookup('service:store'); }); test('groupRecordsForFindMany - findMany', function(assert) { diff --git a/packages/-ember-data/tests/unit/debug-test.js b/packages/-ember-data/tests/unit/debug-test.js index a6312cdfcfc..36fb5332a3b 100644 --- a/packages/-ember-data/tests/unit/debug-test.js +++ b/packages/-ember-data/tests/unit/debug-test.js @@ -1,105 +1,106 @@ +import Model, { attr, belongsTo } from '@ember-data/model'; import { computed } from '@ember/object'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; - -const TestAdapter = DS.Adapter.extend(); - -module('Debug'); - -test('_debugInfo groups the attributes and relationships correctly', function(assert) { - const MaritalStatus = DS.Model.extend({ - name: DS.attr('string'), - }); - - const Post = DS.Model.extend({ - title: DS.attr('string'), - }); - - const User = DS.Model.extend({ - name: DS.attr('string'), - isDrugAddict: DS.attr('boolean'), - maritalStatus: DS.belongsTo('marital-status', { async: false }), - posts: DS.hasMany('post', { async: false }), - }); - - let store = createStore({ - adapter: TestAdapter.extend(), - maritalStatus: MaritalStatus, - post: Post, - user: User, - }); - - let record = store.createRecord('user'); - - let propertyInfo = record._debugInfo().propertyInfo; - - assert.equal(propertyInfo.groups.length, 4); - assert.deepEqual(propertyInfo.groups[0].properties, ['id', 'name', 'isDrugAddict']); - assert.deepEqual(propertyInfo.groups[1].properties, ['maritalStatus']); - assert.deepEqual(propertyInfo.groups[2].properties, ['posts']); -}); - -test('_debugInfo supports arbitray relationship types', function(assert) { - const MaritalStatus = DS.Model.extend({ - name: DS.attr('string'), - }); - - const Post = DS.Model.extend({ - title: DS.attr('string'), - }); - - const User = DS.Model.extend({ - name: DS.attr('string'), - isDrugAddict: DS.attr('boolean'), - maritalStatus: DS.belongsTo('marital-status', { async: false }), - posts: computed(() => [1, 2, 3]) - .readOnly() - .meta({ - options: { inverse: null }, - isRelationship: true, - kind: 'customRelationship', - name: 'posts', - type: 'post', - }), - }); - - let store = createStore({ - adapter: TestAdapter.extend(), - maritalStatus: MaritalStatus, - post: Post, - user: User, +module('Debug', function(hooks) { + setupTest(hooks); + + test('_debugInfo groups the attributes and relationships correctly', function(assert) { + const MaritalStatus = Model.extend({ + name: attr('string'), + }); + + const Post = Model.extend({ + title: attr('string'), + }); + + const User = Model.extend({ + name: attr('string'), + isDrugAddict: attr('boolean'), + maritalStatus: belongsTo('marital-status', { async: false }), + posts: computed(() => [1, 2, 3]) + .readOnly() + .meta({ + options: { inverse: null }, + isRelationship: true, + kind: 'customRelationship', + name: 'posts', + type: 'post', + }), + }); + + this.owner.register('model:marital-status', MaritalStatus); + this.owner.register('model:post', Post); + this.owner.register('model:user', User); + + let record = this.owner.lookup('service:store').createRecord('user'); + + let propertyInfo = record._debugInfo().propertyInfo; + + assert.equal(propertyInfo.groups.length, 4); + assert.deepEqual(propertyInfo.groups[0].properties, ['id', 'name', 'isDrugAddict']); + assert.deepEqual(propertyInfo.groups[1].properties, ['maritalStatus']); + assert.deepEqual(propertyInfo.groups[2].properties, ['posts']); }); - let record = store.createRecord('user'); - - let propertyInfo = record._debugInfo().propertyInfo; - - assert.deepEqual(propertyInfo, { - includeOtherProperties: true, - groups: [ - { - name: 'Attributes', - properties: ['id', 'name', 'isDrugAddict'], - expand: true, - }, - { - name: 'maritalStatus', - properties: ['maritalStatus'], - expand: true, - }, - { - name: 'posts', - properties: ['posts'], - expand: true, - }, - { - name: 'Flags', - properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'], - }, - ], - expensiveProperties: ['maritalStatus', 'posts'], + test('_debugInfo supports arbitray relationship types', function(assert) { + const MaritalStatus = Model.extend({ + name: attr('string'), + }); + + const Post = Model.extend({ + title: attr('string'), + }); + + const User = Model.extend({ + name: attr('string'), + isDrugAddict: attr('boolean'), + maritalStatus: belongsTo('marital-status', { async: false }), + posts: computed(() => [1, 2, 3]) + .readOnly() + .meta({ + options: { inverse: null }, + isRelationship: true, + kind: 'customRelationship', + name: 'posts', + type: 'post', + }), + }); + + this.owner.register('model:marital-status', MaritalStatus); + this.owner.register('model:post', Post); + this.owner.register('model:user', User); + + let record = this.owner.lookup('service:store').createRecord('user'); + + let propertyInfo = record._debugInfo().propertyInfo; + + assert.deepEqual(propertyInfo, { + includeOtherProperties: true, + groups: [ + { + name: 'Attributes', + properties: ['id', 'name', 'isDrugAddict'], + expand: true, + }, + { + name: 'maritalStatus', + properties: ['maritalStatus'], + expand: true, + }, + { + name: 'posts', + properties: ['posts'], + expand: true, + }, + { + name: 'Flags', + properties: ['isLoaded', 'hasDirtyAttributes', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid'], + }, + ], + expensiveProperties: ['maritalStatus', 'posts'], + }); }); }); diff --git a/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js b/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js index 95f82138971..aac36ef6a56 100644 --- a/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js +++ b/packages/-ember-data/tests/unit/model/lifecycle-callbacks-test.js @@ -1,61 +1,71 @@ import { resolve, reject } from 'rsvp'; import { get } from '@ember/object'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; +import Adapter from '@ember-data/adapter'; +import JSONAPISerializer from '@ember-data/serializer/json-api'; +import Model, { attr } from '@ember-data/model'; +import { InvalidError } from '@ember-data/adapter/error'; + +module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function(hooks) { + setupTest(hooks); -module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { test('a record receives a didLoad callback when it has finished loading', function(assert) { assert.expect(3); - const Person = DS.Model.extend({ - name: DS.attr(), + const Person = Model.extend({ + name: attr(), didLoad() { assert.ok('The didLoad callback was called'); }, }); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); return run(() => { - return store.findRecord('person', 1).then(person => { - assert.equal(person.get('id'), '1', `The person's ID is available`); - assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`); - }); + return this.owner + .lookup('service:store') + .findRecord('person', 1) + .then(person => { + assert.equal(person.get('id'), '1', `The person's ID is available`); + assert.equal(person.get('name'), 'Foo', `The person's properties are availablez`); + }); }); }); test(`TEMPORARY: a record receives a didLoad callback once it materializes if it wasn't materialized when loaded`, function(assert) { assert.expect(2); + let didLoadCalled = 0; - const Person = DS.Model.extend({ - name: DS.attr(), + const Person = Model.extend({ + name: attr(), didLoad() { didLoadCalled++; }, }); - let store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); + + let store = this.owner.lookup('service:store'); run(() => { store._pushInternalModel({ id: 1, type: 'person' }); assert.equal(didLoadCalled, 0, 'didLoad was not called'); }); + run(() => store.peekRecord('person', 1)); + assert.equal(didLoadCalled, 1, 'didLoad was called'); }); @@ -64,9 +74,9 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { let callCount = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + const Person = Model.extend({ + bar: attr('string'), + name: attr('string'), didUpdate() { callCount++; @@ -75,24 +85,22 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, updateRecord(store, type, snapshot) { assert.equal(callCount, 0, 'didUpdate callback was not called until didSaveRecord is called'); - return resolve(); }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - let asyncPerson = run(() => store.findRecord('person', 1)); + let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1)); assert.equal(callCount, 0, 'precond - didUpdate callback was not called yet'); @@ -115,7 +123,7 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { let callCount = 0; - const Person = DS.Model.extend({ + const Person = Model.extend({ didCreate() { callCount++; assert.equal(get(this, 'isSaving'), false, 'record should not be saving'); @@ -123,21 +131,22 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ createRecord(store, type, snapshot) { assert.equal(callCount, 0, 'didCreate callback was not called until didSaveRecord is called'); - return resolve(); }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); assert.equal(callCount, 0, 'precond - didCreate callback was not called yet'); - let person = store.createRecord('person', { id: 69, name: 'Newt Gingrich' }); + + let person = this.owner.lookup('service:store').createRecord('person', { + id: 69, + name: 'Newt Gingrich', + }); return run(() => { return person.save().then(() => { @@ -151,9 +160,9 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { let callCount = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + const Person = Model.extend({ + bar: attr('string'), + name: attr('string'), didDelete() { callCount++; @@ -163,7 +172,7 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, @@ -175,11 +184,11 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); - let asyncPerson = run(() => store.findRecord('person', 1)); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1)); assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); @@ -202,9 +211,9 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { let callCount = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + const Person = Model.extend({ + bar: attr('string'), + name: attr('string'), didDelete() { callCount++; @@ -213,12 +222,11 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - let store = createStore({ - adapter: DS.Adapter.extend(), - person: Person, - }); + this.owner.register('model:person', Person); - let person = store.createRecord('person', { name: 'Tomster' }); + let person = this.owner.lookup('service:store').createRecord('person', { + name: 'Tomster', + }); assert.equal(callCount, 0, 'precond - didDelete callback was not called yet'); @@ -232,9 +240,9 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { let callCount = 0; - const Person = DS.Model.extend({ - bar: DS.attr('string'), - name: DS.attr('string'), + const Person = Model.extend({ + bar: attr('string'), + name: attr('string'), becameInvalid() { callCount++; @@ -244,7 +252,7 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Foo' } } }; }, @@ -253,7 +261,7 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { assert.equal(callCount, 0, 'becameInvalid callback was not called until recordWasInvalid is called'); return reject( - new DS.InvalidError([ + new InvalidError([ { title: 'Invalid Attribute', detail: 'error', @@ -266,12 +274,11 @@ module('unit/model/lifecycle_callbacks - Lifecycle Callbacks', function() { }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - let asyncPerson = run(() => store.findRecord('person', 1)); + let asyncPerson = run(() => this.owner.lookup('service:store').findRecord('person', 1)); assert.equal(callCount, 0, 'precond - becameInvalid callback was not called yet'); // Make sure that the error handler has a chance to attach before diff --git a/packages/-ember-data/tests/unit/model/merge-test.js b/packages/-ember-data/tests/unit/model/merge-test.js index 1b2eff77ada..6510d689c13 100644 --- a/packages/-ember-data/tests/unit/model/merge-test.js +++ b/packages/-ember-data/tests/unit/model/merge-test.js @@ -1,36 +1,40 @@ import { resolve, reject, Promise as EmberPromise } from 'rsvp'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { InvalidError } from '@ember-data/adapter/error'; import { module, test } from 'qunit'; -import DS from 'ember-data'; - -let Person; +import Adapter from '@ember-data/adapter'; +import JSONAPISerializer from '@ember-data/serializer/json-api'; +import Model, { attr } from '@ember-data/model'; module('unit/model/merge - Merging', function(hooks) { + setupTest(hooks); + hooks.beforeEach(function() { - Person = DS.Model.extend({ - name: DS.attr(), - city: DS.attr(), + const Person = Model.extend({ + name: attr(), + city: attr(), }); + + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + this.store = this.owner.lookup('service:store'); }); test('When a record is in flight, changes can be made', function(assert) { assert.expect(3); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ createRecord(store, type, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Tom Dale' } } }; }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('adapter:application', ApplicationAdapter); - let person = store.createRecord('person', { name: 'Tom Dale' }); + let person = this.store.createRecord('person', { name: 'Tom Dale' }); // Make sure saving isn't resolved synchronously return run(() => { @@ -50,7 +54,7 @@ module('unit/model/merge - Merging', function(hooks) { test('Make sure snapshot is created at save time not at flush time', function(assert) { assert.expect(5); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ updateRecord(store, type, snapshot) { assert.equal(snapshot.attr('name'), 'Thomas Dale'); @@ -58,11 +62,11 @@ module('unit/model/merge - Merging', function(hooks) { }, }); - let store = createStore({ adapter: Adapter, person: Person }); + this.owner.register('adapter:application', ApplicationAdapter); let person; run(() => { - person = store.push({ + person = this.store.push({ data: { type: 'person', id: '1', @@ -93,7 +97,7 @@ module('unit/model/merge - Merging', function(hooks) { test('When a record is in flight, pushes are applied underneath the in flight changes', function(assert) { assert.expect(6); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ updateRecord(store, type, snapshot) { // Make sure saving isn't resolved synchronously return new EmberPromise(resolve => { @@ -108,14 +112,12 @@ module('unit/model/merge - Merging', function(hooks) { }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('adapter:application', ApplicationAdapter); + let person; run(() => { - person = store.push({ + person = this.store.push({ data: { type: 'person', id: '1', @@ -134,7 +136,7 @@ module('unit/model/merge - Merging', function(hooks) { person.set('name', 'Tomasz Dale'); - store.push({ + this.store.push({ data: { type: 'person', id: '1', @@ -157,14 +159,10 @@ module('unit/model/merge - Merging', function(hooks) { }); test('When a record is dirty, pushes are overridden by local changes', function(assert) { - let store = createStore({ - adapter: DS.Adapter, - person: Person, - }); let person; run(() => { - person = store.push({ + person = this.store.push({ data: { type: 'person', id: '1', @@ -182,7 +180,7 @@ module('unit/model/merge - Merging', function(hooks) { assert.equal(person.get('city'), 'San Francisco', 'the original data applies'); run(() => { - store.push({ + this.store.push({ data: { type: 'person', id: '1', @@ -200,19 +198,18 @@ module('unit/model/merge - Merging', function(hooks) { }); test('When a record is invalid, pushes are overridden by local changes', async function(assert) { - let store = createStore({ - adapter: DS.Adapter, - person: Person, + const ApplicationAdapter = Adapter.extend({ + updateRecord() { + return reject(new InvalidError()); + }, }); - let person; - let adapter = store.adapterFor('application'); - adapter.updateRecord = () => { - return reject(new InvalidError()); - }; + this.owner.register('adapter:application', ApplicationAdapter); + + let person; run(() => { - person = store.push({ + person = this.store.push({ data: { type: 'person', id: '1', @@ -238,7 +235,7 @@ module('unit/model/merge - Merging', function(hooks) { assert.equal(person.get('city'), 'Boston', 'the original data applies'); run(() => { - store.push({ + this.store.push({ data: { type: 'person', id: '1', @@ -259,22 +256,20 @@ module('unit/model/merge - Merging', function(hooks) { test('A record with no changes can still be saved', function(assert) { assert.expect(1); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ updateRecord(store, type, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale' } } }; }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('adapter:application', ApplicationAdapter); + let person = run(() => { - return store.push({ + return this.store.push({ data: { type: 'person', id: '1', - attributeS: { + attributes: { name: 'Tom Dale', }, }, @@ -282,7 +277,7 @@ module('unit/model/merge - Merging', function(hooks) { }); return run(() => { - return person.save().then(() => { + return person.save().then(foo => { assert.equal(person.get('name'), 'Thomas Dale', 'the updates occurred'); }); }); @@ -291,7 +286,7 @@ module('unit/model/merge - Merging', function(hooks) { test('A dirty record can be reloaded', function(assert) { assert.expect(3); - const Adapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id: 1, type: 'person', attributes: { name: 'Thomas Dale', city: 'Portland' } }, @@ -299,15 +294,12 @@ module('unit/model/merge - Merging', function(hooks) { }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('adapter:application', ApplicationAdapter); let person; run(() => { - person = store.push({ + person = this.store.push({ data: { type: 'person', id: '1', diff --git a/packages/-ember-data/tests/unit/store/adapter-interop-test.js b/packages/-ember-data/tests/unit/store/adapter-interop-test.js index 6b12ff0a606..40fa0ed8f98 100644 --- a/packages/-ember-data/tests/unit/store/adapter-interop-test.js +++ b/packages/-ember-data/tests/unit/store/adapter-interop-test.js @@ -2,58 +2,47 @@ import { A } from '@ember/array'; import { resolve, all, Promise as EmberPromise } from 'rsvp'; import { set, get } from '@ember/object'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; -import setupStore from 'dummy/tests/helpers/store'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import DS from 'ember-data'; +import { setupTest } from 'ember-qunit'; -let TestAdapter, store; +import Adapter from '@ember-data/adapter'; +import JSONAPISerializer from '@ember-data/serializer/json-api'; +import JSONSerializer from '@ember-data/serializer/json'; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; +import RESTAdapter from '@ember-data/adapter/rest'; +import Store from '@ember-data/store'; -module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', function(hooks) { - hooks.beforeEach(function() { - TestAdapter = DS.Adapter.extend(); - }); - - hooks.afterEach(function() { - run(() => { - if (store) { - store.destroy(); - } - }); - }); - - test('Adapter can be set as a factory', function(assert) { - store = createStore({ adapter: TestAdapter }); - - assert.ok(store.get('defaultAdapter') instanceof TestAdapter); - }); +module('unit/store/adapter-interop - Store working with a Adapter', function(hooks) { + setupTest(hooks); test('Adapter can be set as a name', function(assert) { - store = createStore({ adapter: '-rest' }); + this.owner.register('service:store', Store.extend({ adapter: '-rest' })); - assert.ok(store.get('defaultAdapter') instanceof DS.RESTAdapter); + let store = this.owner.lookup('service:store'); + + assert.ok(store.get('defaultAdapter') instanceof RESTAdapter); }); testInDebug('Adapter can not be set as an instance', function(assert) { assert.expect(1); - store = DS.Store.create({ - adapter: DS.Adapter.create(), + let store = Store.create({ + adapter: Adapter.create(), }); + assert.expectAssertion(() => store.get('defaultAdapter')); }); test('Calling Store#find invokes its adapter#find', function(assert) { assert.expect(5); - let currentStore; - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.ok(true, 'Adapter#find was called'); - assert.equal(store, currentStore, 'Adapter#find was called with the right store'); + assert.equal(store, store, 'Adapter#find was called with the right store'); assert.equal(type, store.modelFor('test'), 'Adapter#find was called with the type passed into Store#find'); assert.equal(id, 1, 'Adapter#find was called with the id passed into Store#find'); assert.equal(snapshot.id, '1', 'Adapter#find was called with the record created from Store#find'); @@ -67,20 +56,19 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - const Type = DS.Model.extend(); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('model:test', Model.extend()); - currentStore = createStore({ - adapter: Adapter, - test: Type, - }); + let store = this.owner.lookup('service:store'); - return run(() => currentStore.findRecord('test', 1)); + return run(() => store.findRecord('test', 1)); }); test('Calling Store#findRecord multiple times coalesces the calls into a adapter#findMany call', function(assert) { assert.expect(2); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.ok(false, 'Adapter#findRecord was not called'); }, @@ -92,11 +80,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi coalesceFindRequests: true, }); - const Type = DS.Model.extend(); - let store = createStore({ - adapter: Adapter, - test: Type, - }); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('model:test', Model.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { return all([store.findRecord('test', 1), store.findRecord('test', 2)]); @@ -106,20 +94,17 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('Returning a promise from `findRecord` asynchronously loads data', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return resolve({ data: { id: 1, type: 'test', attributes: { name: 'Scumbag Dale' } } }); }, }); - const Type = DS.Model.extend({ - name: DS.attr('string'), - }); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('model:test', Model.extend({ name: attr() })); - let store = createStore({ - adapter: Adapter, - test: Type, - }); + let store = this.owner.lookup('service:store'); return run(() => { return store.findRecord('test', 1).then(object => { @@ -131,21 +116,18 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('IDs provided as numbers are coerced to strings', function(assert) { assert.expect(5); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(typeof id, 'string', 'id has been normalized to a string'); return resolve({ data: { id, type: 'test', attributes: { name: 'Scumbag Sylvain' } } }); }, }); - const Type = DS.Model.extend({ - name: DS.attr('string'), - }); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('model:test', Model.extend({ name: attr() })); - let store = createStore({ - adapter: Adapter, - test: Type, - }); + let store = this.owner.lookup('service:store'); return run(() => { return store @@ -180,19 +162,22 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('can load data for the same record if it is not dirty', function(assert) { assert.expect(3); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - let store = createStore({ - person: Person, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord() { - return false; - }, - }), + const ApplicationAdapter = Adapter.extend({ + shouldBackgroundReloadRecord() { + return false; + }, }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); + return run(() => { store.push({ data: { @@ -227,11 +212,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi let passedQuery = { page: 1 }; - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ query(store, type, query) { assert.equal(type, store.modelFor('person'), 'The type was Person'); assert.equal(query, passedQuery, 'The query was passed in'); @@ -239,57 +224,54 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); run(() => store.query('person', passedQuery)); }); test('Find with query calls the correct normalizeResponse', function(assert) { let passedQuery = { page: 1 }; + let callCount = 0; - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ query(store, type, query) { return resolve([]); }, }); - let callCount = 0; - - const ApplicationSerializer = DS.JSONSerializer.extend({ + const ApplicationSerializer = JSONSerializer.extend({ normalizeQueryResponse() { callCount++; return this._super(...arguments); }, }); - let env = setupStore({ - adapter: Adapter, - person: Person, - }); - - let { store } = env; + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', ApplicationSerializer); - env.owner.register('serializer:application', ApplicationSerializer); + run(() => this.owner.lookup('service:store').query('person', passedQuery)); - run(() => store.query('person', passedQuery)); assert.equal(callCount, 1, 'normalizeQueryResponse was called'); }); test('peekAll(type) returns a record array of all records of a specific type', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - let store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); run(() => { store.push({ @@ -327,14 +309,13 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }); test('a new record of a particular type is created via store.createRecord(type)', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - let store = createStore({ - person: Person, + const Person = Model.extend({ + name: attr('string'), }); - let person = store.createRecord('person'); + this.owner.register('model:person', Person); + + let person = this.owner.lookup('service:store').createRecord('person'); assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); assert.equal(get(person, 'isNew'), true, 'A newly created record is new'); @@ -348,8 +329,8 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi testInDebug("a new record with a specific id can't be created if this id is already used in the store", function( assert ) { - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); Person.reopenClass({ @@ -358,9 +339,9 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); + + let store = this.owner.lookup('service:store'); store.createRecord('person', { id: 5 }); @@ -370,14 +351,13 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }); test('an initial data hash can be provided via store.createRecord(type, hash)', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - let store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); let person = store.createRecord('person', { name: 'Brohuda Katz' }); assert.equal(get(person, 'isLoaded'), true, 'A newly created record is loaded'); @@ -390,17 +370,19 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('if an id is supplied in the initial data hash, it can be looked up using `store.find`', function(assert) { assert.expect(1); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); - let store = createStore({ - person: Person, - adapter: DS.Adapter.extend({ - shouldBackgroundReloadRecord: () => false, - }), + const ApplicationAdapter = Adapter.extend({ + shouldBackgroundReloadRecord: () => false, }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + + let store = this.owner.lookup('service:store'); + return run(() => { let person = store.createRecord('person', { id: 1, name: 'Brohuda Katz' }); @@ -413,21 +395,22 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of attributes can be passed in as the third argument to find', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const TestModel = Model.extend({ + name: attr('string'), + }); + + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.attr('name'), 'Test', 'Preloaded attribtue set'); return { data: { id: '1', type: 'test', attributes: { name: 'Test' } } }; }, }); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); + this.owner.register('model:test', TestModel); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + let store = this.owner.lookup('service:store'); return run(() => store.findRecord('test', 1, { preload: { name: 'Test' } })); }); @@ -435,25 +418,23 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of belongsTo can be passed in as the third argument to find as records', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.belongsTo('friend').attr('name'), 'Tom', 'Preloaded belongsTo set'); return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, + const Person = Model.extend({ + name: attr('string'), + friend: belongsTo('person', { inverse: null, async: true }), }); - let { store } = env; + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - const Person = DS.Model.extend({ - name: DS.attr('string'), - friend: DS.belongsTo('person', { inverse: null, async: true }), - }); - - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -474,23 +455,22 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of belongsTo can be passed in as the third argument to find as ids', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const Person = Model.extend({ + name: attr('string'), + friend: belongsTo('person', { async: true, inverse: null }), + }); + + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, - }); - let { store } = env; - - const Person = DS.Model.extend({ - name: DS.attr('string'), - friend: DS.belongsTo('person', { async: true, inverse: null }), - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => { return store.findRecord('person', 1, { preload: { friend: 2 } }).then(() => { @@ -507,25 +487,23 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of hasMany can be passed in as the third argument to find as records', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].attr('name'), 'Tom', 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, + const Person = Model.extend({ + name: attr('string'), + friends: hasMany('person', { inverse: null, async: true }), }); - let { store } = env; - - const Person = DS.Model.extend({ - name: DS.attr('string'), - friends: DS.hasMany('person', { inverse: null, async: true }), - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -546,24 +524,23 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of hasMany can be passed in as the third argument to find as ids', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends')[0].id, '2', 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, + const Person = Model.extend({ + name: attr('string'), + friends: hasMany('person', { async: true, inverse: null }), }); - let { store } = env; - const Person = DS.Model.extend({ - name: DS.attr('string'), - friends: DS.hasMany('person', { async: true, inverse: null }), - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => store.findRecord('person', 1, { preload: { friends: [2] } })); }); @@ -571,25 +548,23 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial empty values of hasMany can be passed in as the third argument to find as records', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const Person = Model.extend({ + name: attr('string'), + friends: hasMany('person', { inverse: null, async: true }), + }); + + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, - }); - - let { store } = env; - - const Person = DS.Model.extend({ - name: DS.attr('string'), - friends: DS.hasMany('person', { inverse: null, async: true }), - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => { return store.findRecord('person', 1, { preload: { friends: [] } }); @@ -599,24 +574,23 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('initial values of hasMany can be passed in as the third argument to find as ids', function(assert) { assert.expect(1); - const Adapter = TestAdapter.extend({ + const Person = Model.extend({ + name: attr('string'), + friends: hasMany('person', { async: true, inverse: null }), + }); + + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { assert.equal(snapshot.hasMany('friends').length, 0, 'Preloaded hasMany set'); return { data: { id, type: 'person' } }; }, }); - let env = setupStore({ - adapter: Adapter, - }); - let { store } = env; + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); - const Person = DS.Model.extend({ - name: DS.attr('string'), - friends: DS.hasMany('person', { async: true, inverse: null }), - }); - - env.owner.register('model:person', Person); + let store = this.owner.lookup('service:store'); return run(() => store.findRecord('person', 1, { preload: { friends: [] } })); }); @@ -624,12 +598,12 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('records should have their ids updated when the adapter returns the id data', function(assert) { assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr('string'), }); let idCounter = 1; - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ createRecord(store, type, snapshot) { return { data: { @@ -643,10 +617,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let people = store.peekAll('person'); let tom = store.createRecord('person', { name: 'Tom Dale' }); @@ -664,11 +639,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store.fetchMany should always return a promise', function(assert) { assert.expect(3); - const Person = DS.Model.extend(); - let store = createStore({ - adapter: TestAdapter.extend(), - person: Person, - }); + const Person = Model.extend(); + + this.owner.register('model:person', Person); + + let store = this.owner.lookup('service:store'); store.createRecord('person'); @@ -686,10 +661,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store._scheduleFetchMany should not resolve until all the records are resolved', function(assert) { assert.expect(1); - const Person = DS.Model.extend(); - const Phone = DS.Model.extend(); - - const adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findRecord(store, type, id, snapshot) { let record = { id, type: type.modelName }; @@ -709,11 +681,12 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: adapter, - test: Person, - phone: Phone, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('model:phone', Model.extend()); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + + let store = this.owner.lookup('service:store'); store.createRecord('test'); @@ -735,9 +708,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('the store calls adapter.findMany according to groupings returned by adapter.groupRecordsForFindMany', function(assert) { assert.expect(3); - const Person = DS.Model.extend(); - - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ groupRecordsForFindMany(store, snapshots) { return [[snapshots[0]], [snapshots[1], snapshots[2]]]; }, @@ -756,10 +727,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let internalModels = [ store._internalModelForId('test', 10), @@ -780,8 +752,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi let davidResolved = false; - const Person = DS.Model.extend(); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ groupRecordsForFindMany(store, snapshots) { return [[snapshots[0]], [snapshots[1]]]; }, @@ -802,10 +773,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + + let store = this.owner.lookup('service:store'); return run(() => { let david = store.findRecord('test', 'david'); @@ -833,8 +805,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi let davidResolved = false; - const Person = DS.Model.extend(); - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ groupRecordsForFindMany(store, snapshots) { return [[snapshots[0]], [snapshots[1]]]; }, @@ -855,10 +826,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + + let store = this.owner.lookup('service:store'); return run(() => { let david = store.findRecord('test', 'david'); @@ -886,19 +858,18 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi function(assert) { assert.expect(3); - const Person = DS.Model.extend(); - - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findMany(store, type, ids, snapshots) { let records = ids.map(id => ({ id, type: 'test' })); return { data: [records[0]] }; }, }); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let wait = []; assert.expectWarning(() => { @@ -916,9 +887,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi ); testInDebug('store._fetchRecord warns when records are missing', function(assert) { - const Person = DS.Model.extend(); - - const Adapter = TestAdapter.extend({ + const ApplicationAdapter = Adapter.extend({ findMany(store, type, ids, snapshots) { let records = ids.map(id => ({ id, type: 'test' })).filter(({ id }) => id === 'david'); @@ -926,10 +895,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: Adapter, - test: Person, - }); + this.owner.register('model:test', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let wait = []; let igorDidReject = true; @@ -960,11 +930,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not call shouldReloadRecord when the record is not in the store', function(assert) { assert.expect(1); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(false, 'shouldReloadRecord should not be called when the record is not loaded'); return false; @@ -975,10 +941,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - let store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => store.findRecord('person', 1)); }); @@ -986,11 +953,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not reload record when shouldReloadRecord returns false', function(assert) { assert.expect(1); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return false; @@ -1003,10 +966,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -1023,11 +987,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should reload record when shouldReloadRecord returns true', function(assert) { assert.expect(3); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldReloadRecord should be called when the record is in the store'); return true; @@ -1038,10 +998,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend({ name: attr() })); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -1060,11 +1021,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not call shouldBackgroundReloadRecord when the store is already loading the record', function(assert) { assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr(), }); - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadRecord(store, type, id, snapshot) { return true; }, @@ -1077,10 +1038,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -1099,11 +1061,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not reload a record when `shouldBackgroundReloadRecord` is false', function(assert) { assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return false; @@ -1114,10 +1072,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { store.push({ @@ -1136,11 +1095,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should reload the record in the background when `shouldBackgroundReloadRecord` is true', function(assert) { assert.expect(4); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldBackgroundReloadRecord(store, type, id, snapshot) { assert.ok(true, 'shouldBackgroundReloadRecord is called when record is loaded form the cache'); return true; @@ -1151,10 +1106,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend({ name: attr() })); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let done = run(() => { store.push({ @@ -1177,11 +1133,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not reload record array when shouldReloadAll returns false', function(assert) { assert.expect(1); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadAll(store, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return false; @@ -1194,10 +1146,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => store.findAll('person')); }); @@ -1205,11 +1158,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should reload all records when shouldReloadAll returns true', function(assert) { assert.expect(3); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr(), }); - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll should be called when the record is in the store'); return true; @@ -1220,10 +1173,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { return store.findAll('person').then(records => { @@ -1235,11 +1189,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not call shouldBackgroundReloadAll when the store is already loading all records', function(assert) { assert.expect(2); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr(), }); - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { return true; }, @@ -1252,10 +1206,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { return store.findAll('person').then(records => { @@ -1267,11 +1222,7 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should not reload all records when `shouldBackgroundReloadAll` is false', function(assert) { assert.expect(3); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadAll(store, type, id, snapshot) { assert.ok(true, 'shouldReloadAll is called when record is loaded form the cache'); return false; @@ -1286,10 +1237,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Model.extend()); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); return run(() => { return store.findAll('person').then(records => { @@ -1301,11 +1253,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi test('store should reload all records in the background when `shouldBackgroundReloadAll` is true', function(assert) { assert.expect(5); - const Person = DS.Model.extend({ - name: DS.attr('string'), + const Person = Model.extend({ + name: attr(), }); - const TestAdapter = DS.Adapter.extend({ + const ApplicationAdapter = Adapter.extend({ shouldReloadAll() { assert.ok(true, 'shouldReloadAll is called'); return false; @@ -1320,10 +1272,11 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi }, }); - store = createStore({ - adapter: TestAdapter, - person: Person, - }); + this.owner.register('model:person', Person); + this.owner.register('adapter:application', ApplicationAdapter); + this.owner.register('serializer:application', JSONAPISerializer.extend()); + + let store = this.owner.lookup('service:store'); let done = run(() => { return store.findAll('person').then(records => { @@ -1339,30 +1292,20 @@ module('unit/store/adapter-interop - DS.Store working with a DS.Adapter', functi testInDebug('store should assert of the user tries to call store.filter', function(assert) { assert.expect(1); - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); - - store = createStore({ - person: Person, - }); + this.owner.register('model:person', Model.extend()); assert.expectAssertion(() => { - run(() => store.filter('person', {})); + run(() => this.owner.lookup('service:store').filter('person', {})); }, /The filter API has been moved to a plugin/); }); testInDebug('Calling adapterFor with a model class should assert', function(assert) { - const Person = DS.Model.extend({ - name: DS.attr('string'), - }); + let Person = Model.extend(); - store = createStore({ - person: Person, - }); + this.owner.register('model:person', Person); assert.expectAssertion(() => { - store.adapterFor(Person); + this.owner.lookup('service:store').adapterFor(Person); }, /Passing classes to store.adapterFor has been removed/); }); }); diff --git a/packages/-ember-data/tests/unit/store/create-record-test.js b/packages/-ember-data/tests/unit/store/create-record-test.js index a04b9147ea5..814b308c8ea 100644 --- a/packages/-ember-data/tests/unit/store/create-record-test.js +++ b/packages/-ember-data/tests/unit/store/create-record-test.js @@ -1,31 +1,12 @@ import { A } from '@ember/array'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; -import setupStore from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; -const { Model, attr, belongsTo, hasMany } = DS; - -let store, Record, Storage; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; module('unit/store/createRecord - Store creating records', function(hooks) { - hooks.beforeEach(function() { - Record = DS.Model.extend({ - title: DS.attr('string'), - }); - - Storage = DS.Model.extend({ - name: DS.attr('name'), - records: DS.hasMany('record', { async: false }), - }); - - store = createStore({ - adapter: DS.Adapter.extend(), - record: Record, - storage: Storage, - }); - }); + setupTest(hooks); test(`doesn't modify passed in properties hash`, function(assert) { const Post = Model.extend({ @@ -33,20 +14,23 @@ module('unit/store/createRecord - Store creating records', function(hooks) { author: belongsTo('author', { async: false, inverse: 'post' }), comments: hasMany('comment', { async: false, inverse: 'post' }), }); + const Comment = Model.extend({ text: attr(), post: belongsTo('post', { async: false, inverse: 'comments' }), }); + const Author = Model.extend({ name: attr(), post: belongsTo('post', { async: false, inverse: 'author' }), }); - let env = setupStore({ - post: Post, - comment: Comment, - author: Author, - }); - let store = env.store; + + this.owner.register('model:post', Post); + this.owner.register('model:comment', Comment); + this.owner.register('model:author', Author); + + let store = this.owner.lookup('service:store'); + let comment, author; run(() => { @@ -89,6 +73,19 @@ module('unit/store/createRecord - Store creating records', function(hooks) { }); test('allow passing relationships as well as attributes', function(assert) { + const Record = Model.extend({ + title: attr('string'), + }); + + const Storage = Model.extend({ + name: attr('name'), + records: hasMany('record', { async: false }), + }); + + this.owner.register('model:record', Record); + this.owner.register('model:storage', Storage); + + let store = this.owner.lookup('service:store'); let records, storage; run(() => { @@ -130,16 +127,16 @@ module('unit/store/createRecord - Store creating records', function(hooks) { }); module('unit/store/createRecord - Store with models by dash', function(hooks) { - hooks.beforeEach(function() { - let env = setupStore({ - someThing: DS.Model.extend({ - foo: DS.attr('string'), - }), - }); - store = env.store; - }); + setupTest(hooks); test('creating a record by dasherize string finds the model', function(assert) { + const SomeThing = Model.extend({ + foo: attr('string'), + }); + + this.owner.register('model:some-thing', SomeThing); + + let store = this.owner.lookup('service:store'); let attributes = { foo: 'bar' }; let record = store.createRecord('some-thing', attributes); diff --git a/packages/-ember-data/tests/unit/store/has-model-for-test.js b/packages/-ember-data/tests/unit/store/has-model-for-test.js index 7ca96c91149..899153fddd5 100644 --- a/packages/-ember-data/tests/unit/store/has-model-for-test.js +++ b/packages/-ember-data/tests/unit/store/has-model-for-test.js @@ -1,20 +1,17 @@ -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import { module, test } from 'qunit'; -import DS from 'ember-data'; - -let store; +import Model from '@ember-data/model'; module('unit/store/has-model-For', function(hooks) { - hooks.beforeEach(function() { - store = createStore({ - adapter: DS.Adapter.extend(), - 'one-foo': DS.Model.extend({}), - 'two-foo': DS.Model.extend({}), - }); - }); + setupTest(hooks); test(`hasModelFor correctly normalizes`, function(assert) { + this.owner.register('model:one-foo', Model.extend({})); + this.owner.register('model:two-foo', Model.extend({})); + + let store = this.owner.lookup('service:store'); + assert.equal(store._hasModelFor('oneFoo'), true); - assert.equal(store._hasModelFor('twoFoo').true); + assert.equal(store._hasModelFor('twoFoo'), true); }); }); diff --git a/packages/-ember-data/tests/unit/store/unload-test.js b/packages/-ember-data/tests/unit/store/unload-test.js index 0ff981dfc03..f2a2ba45183 100644 --- a/packages/-ember-data/tests/unit/store/unload-test.js +++ b/packages/-ember-data/tests/unit/store/unload-test.js @@ -1,20 +1,24 @@ import { resolve } from 'rsvp'; import { get } from '@ember/object'; import { run } from '@ember/runloop'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import testInDebug from 'dummy/tests/helpers/test-in-debug'; import { module, test } from 'qunit'; -import DS from 'ember-data'; +import Adapter from '@ember-data/adapter'; +import Model, { attr, belongsTo } from '@ember-data/model'; +import JSONAPISerializer from '@ember-data/serializer/json-api'; -let store, tryToFind, Record; +let store, tryToFind; module('unit/store/unload - Store unloading records', function(hooks) { + setupTest(hooks); + hooks.beforeEach(function() { - Record = DS.Model.extend({ - title: DS.attr('string'), - wasFetched: DS.attr('boolean'), + let Record = Model.extend({ + title: attr('string'), + wasFetched: attr('boolean'), }); Record.reopenClass({ @@ -23,22 +27,22 @@ module('unit/store/unload - Store unloading records', function(hooks) { }, }); - store = createStore({ - adapter: DS.Adapter.extend({ + this.owner.register('model:record', Record); + this.owner.register('serializer:application', JSONAPISerializer); + + this.owner.register( + 'adapter:application', + Adapter.extend({ findRecord(store, type, id, snapshot) { tryToFind = true; return resolve({ data: { id, type: snapshot.modelName, attributes: { 'was-fetched': true } }, }); }, - }), - - record: Record, - }); - }); + }) + ); - hooks.afterEach(function() { - run(store, 'destroy'); + store = this.owner.lookup('service:store'); }); testInDebug('unload a dirty record asserts', function(assert) { @@ -118,12 +122,14 @@ module('unit/store/unload - Store unloading records', function(hooks) { }); }); -module('DS.Store - unload record with relationships', function() { +module('Store - unload record with relationships', function(hooks) { + setupTest(hooks); + test('can commit store after unload record with relationships', function(assert) { assert.expect(1); - const Brand = DS.Model.extend({ - name: DS.attr('string'), + const Brand = Model.extend({ + name: attr('string'), }); Brand.reopenClass({ @@ -132,9 +138,9 @@ module('DS.Store - unload record with relationships', function() { }, }); - const Product = DS.Model.extend({ - description: DS.attr('string'), - brand: DS.belongsTo('brand', { + const Product = Model.extend({ + description: attr('string'), + brand: belongsTo('brand', { async: false, }), }); @@ -145,8 +151,8 @@ module('DS.Store - unload record with relationships', function() { }, }); - const Like = DS.Model.extend({ - product: DS.belongsTo('product', { + const Like = Model.extend({ + product: belongsTo('product', { async: false, }), }); @@ -157,8 +163,15 @@ module('DS.Store - unload record with relationships', function() { }, }); - let store = createStore({ - adapter: DS.Adapter.extend({ + this.owner.register('model:brand', Brand); + this.owner.register('model:product', Product); + this.owner.register('model:like', Like); + + this.owner.register('serializer:application', JSONAPISerializer); + + this.owner.register( + 'adapter:application', + Adapter.extend({ findRecord(store, type, id, snapshot) { return resolve({ data: { @@ -175,11 +188,10 @@ module('DS.Store - unload record with relationships', function() { createRecord(store, type, snapshot) { return resolve(); }, - }), - brand: Brand, - product: Product, - like: Like, - }); + }) + ); + + let store = this.owner.lookup('service:store'); return run(() => { store.push({ diff --git a/packages/-ember-data/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js b/packages/-ember-data/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js index 43c2db2e5d4..de75b2090de 100644 --- a/packages/-ember-data/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js +++ b/packages/-ember-data/tests/unit/system/relationships/polymorphic-relationship-payloads-test.js @@ -1,805 +1,868 @@ import { run } from '@ember/runloop'; -import DS from 'ember-data'; -import { createStore } from 'dummy/tests/helpers/store'; +import { setupTest } from 'ember-qunit'; import deepCopy from 'dummy/tests/helpers/deep-copy'; import { module, test } from 'qunit'; import testInDebug from '../../../helpers/test-in-debug'; -const { Model, hasMany, belongsTo, attr } = DS; +import Model, { attr, belongsTo, hasMany } from '@ember-data/model'; -module('unit/system/relationships/relationship-payloads-manager (polymorphic)', { - beforeEach() { - const User = DS.Model.extend({ +module('unit/system/relationships/relationship-payloads-manager (polymorphic)', function(hooks) { + setupTest(hooks); + + hooks.beforeEach(function() { + this.store = this.owner.lookup('service:store'); + }); + + test('push one side is polymorphic, baseType then subTypes', function(assert) { + let User = Model.extend({ hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), - sharedHats: hasMany('hat', { async: false, polymorphic: true, inverse: 'sharingUsers' }), }); - User.toString = () => 'User'; - const Alien = User.extend({}); - Alien.toString = () => 'Alien'; - - const Hat = Model.extend({ + let Hat = Model.extend({ type: attr('string'), user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), - sharingUsers: belongsTo('users', { async: false, inverse: 'sharedHats', polymorphic: true }), - hat: belongsTo('hat', { async: false, inverse: 'hats', polymorphic: true }), - hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }), }); - const BigHat = Hat.extend({}); - const SmallHat = Hat.extend({}); - - this.store = createStore({ - user: User, - alien: Alien, - hat: Hat, - 'big-hat': BigHat, - 'small-hat': SmallHat, - }); - }, -}); -test('push one side is polymorphic, baseType then subTypes', function(assert) { - let id = 1; - - function makeHat(type, props) { - const resource = deepCopy(props); - resource.id = `${id++}`; - resource.type = type; - resource.attributes.type = type; - return resource; - } - - const hatData = { - attributes: {}, - relationships: { - user: { - data: { id: '1', type: 'user' }, - }, - }, - }; + this.owner.register('model:user', User); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); - const hatData1 = makeHat('hat', hatData), - bigHatData1 = makeHat('big-hat', hatData), - smallHatData1 = makeHat('small-hat', hatData); + let id = 1; + + function makeHat(type, props) { + const resource = deepCopy(props); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } - const userData = { - data: { - id: '1', - type: 'user', + const hatData = { attributes: {}, - }, - included: [hatData1, bigHatData1, smallHatData1], - }; + relationships: { + user: { + data: { id: '1', type: 'user' }, + }, + }, + }; - const user = run(() => this.store.push(userData)); + const hatData1 = makeHat('hat', hatData), + bigHatData1 = makeHat('big-hat', hatData), + smallHatData1 = makeHat('small-hat', hatData); - const finalResult = user.get('hats').mapBy('type'); + const userData = { + data: { + id: '1', + type: 'user', + attributes: {}, + }, + included: [hatData1, bigHatData1, smallHatData1], + }; - assert.deepEqual(finalResult, ['hat', 'big-hat', 'small-hat'], 'We got all our hats!'); -}); + const user = run(() => this.store.push(userData)); -test('push one side is polymorphic, subType then baseType', function(assert) { - let id = 1; - - function makeHat(type, props) { - const resource = deepCopy(props); - resource.id = `${id++}`; - resource.type = type; - resource.attributes.type = type; - return resource; - } - - const hatData = { - attributes: {}, - relationships: { - user: { - data: { id: '1', type: 'user' }, - }, - }, - }; - - const bigHatData1 = makeHat('hat', hatData), - smallHatData1 = makeHat('small-hat', hatData), - hatData1 = makeHat('big-hat', hatData), - included = [bigHatData1, smallHatData1, hatData1]; - - const userData = { - data: { - id: '1', - type: 'user', - attributes: {}, - }, - included, - }; + const finalResult = user.get('hats').mapBy('type'); - const user = run(() => this.store.push(userData)), - finalResult = user.get('hats').mapBy('type'), - expectedResults = included.map(m => m.type); + assert.deepEqual(finalResult, ['hat', 'big-hat', 'small-hat'], 'We got all our hats!'); + }); - assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); -}); + test('push one side is polymorphic, subType then baseType', function(assert) { + let User = Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + }); -test('push one side is polymorphic, different subtypes', function(assert) { - let id = 1; - - function makeHat(type, props) { - const resource = deepCopy(props); - resource.id = `${id++}`; - resource.type = type; - resource.attributes.type = type; - return resource; - } - - const hatData = { - attributes: {}, - relationships: { - user: { - data: { id: '1', type: 'user' }, - }, - }, - }; - - const bigHatData1 = makeHat('big-hat', hatData), - smallHatData1 = makeHat('small-hat', hatData), - bigHatData2 = makeHat('big-hat', hatData), - smallHatData2 = makeHat('small-hat', hatData), - included = [bigHatData1, smallHatData1, bigHatData2, smallHatData2]; - - const userData = { - data: { - id: '1', - type: 'user', - attributes: {}, - }, - included, - }; + let Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + }); - const user = run(() => this.store.push(userData)), - finalResult = user.get('hats').mapBy('type'), - expectedResults = included.map(m => m.type); + this.owner.register('model:user', User); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); - assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); -}); + let id = 1; + + function makeHat(type, props) { + const resource = deepCopy(props); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } -test('push both sides are polymorphic', function(assert) { - let id = 1; - - function makeHat(type, props) { - const resource = deepCopy(props); - resource.id = `${id++}`; - resource.type = type; - resource.attributes.type = type; - return resource; - } - - const alienHatData = { - attributes: {}, - relationships: { - user: { - data: { id: '1', type: 'alien' }, + const hatData = { + attributes: {}, + relationships: { + user: { + data: { id: '1', type: 'user' }, + }, }, - }, - }; + }; - const bigHatData1 = makeHat('hat', alienHatData), - hatData1 = makeHat('big-hat', alienHatData), - alienIncluded = [bigHatData1, hatData1]; + const bigHatData1 = makeHat('hat', hatData), + smallHatData1 = makeHat('small-hat', hatData), + hatData1 = makeHat('big-hat', hatData), + included = [bigHatData1, smallHatData1, hatData1]; - const alienData = { - data: { - id: '1', - type: 'alien', - attributes: {}, - }, - included: alienIncluded, - }; + const userData = { + data: { + id: '1', + type: 'user', + attributes: {}, + }, + included, + }; - const expectedAlienResults = alienIncluded.map(m => m.type), - alien = run(() => this.store.push(alienData)), - alienFinalHats = alien.get('hats').mapBy('type'); + const user = run(() => this.store.push(userData)), + finalResult = user.get('hats').mapBy('type'), + expectedResults = included.map(m => m.type); - assert.deepEqual(alienFinalHats, expectedAlienResults, 'We got all alien hats!'); -}); + assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); + }); -test('handles relationships where both sides are polymorphic', function(assert) { - let id = 1; - function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { - return { - id: `${id++}`, - type, + test('push one side is polymorphic, different subtypes', function(assert) { + let User = Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + }); + + let Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + }); + + this.owner.register('model:user', User); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); + + let id = 1; + + function makeHat(type, props) { + const resource = deepCopy(props); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; + } + + const hatData = { + attributes: {}, relationships: { - person: { - data: { - id: isForBigPerson ? '1' : '2', - type: isForBigPerson ? 'big-person' : 'small-person', - }, + user: { + data: { id: '1', type: 'user' }, }, }, }; - } - - const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); - const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); - const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); - const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); - const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); - const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); - - const bigPersonData = { - data: { - id: '1', - type: 'big-person', - attributes: {}, - }, - included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], - }; - - const smallPersonData = { - data: { - id: '2', - type: 'small-person', - attributes: {}, - }, - included: [bigHatData3, smallHatData3], - }; - - const PersonModel = Model.extend({ - hats: hasMany('hat', { - async: false, - polymorphic: true, - inverse: 'person', - }), - }); - const HatModel = Model.extend({ - type: attr('string'), - person: belongsTo('person', { - async: false, - inverse: 'hats', - polymorphic: true, - }), - }); - const BigHatModel = HatModel.extend({}); - const SmallHatModel = HatModel.extend({}); - - const BigPersonModel = PersonModel.extend({}); - const SmallPersonModel = PersonModel.extend({}); - - const store = (this.store = createStore({ - person: PersonModel, - bigPerson: BigPersonModel, - smallPerson: SmallPersonModel, - hat: HatModel, - bigHat: BigHatModel, - smallHat: SmallHatModel, - })); - - const bigPerson = run(() => { - return store.push(bigPersonData); - }); - const smallPerson = run(() => { - return store.push(smallPersonData); - }); + const bigHatData1 = makeHat('big-hat', hatData), + smallHatData1 = makeHat('small-hat', hatData), + bigHatData2 = makeHat('big-hat', hatData), + smallHatData2 = makeHat('small-hat', hatData), + included = [bigHatData1, smallHatData1, bigHatData2, smallHatData2]; - const finalBigResult = bigPerson.get('hats').toArray(); - const finalSmallResult = smallPerson.get('hats').toArray(); + const userData = { + data: { + id: '1', + type: 'user', + attributes: {}, + }, + included, + }; - assert.equal(finalBigResult.length, 4, 'We got all our hats!'); - assert.equal(finalSmallResult.length, 2, 'We got all our hats!'); -}); + const user = run(() => this.store.push(userData)), + finalResult = user.get('hats').mapBy('type'), + expectedResults = included.map(m => m.type); -test('handles relationships where both sides are polymorphic reflexive', function(assert) { - function link(a, b, relationshipName, recurse = true) { - a.relationships = a.relationships || {}; - const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); + assert.deepEqual(finalResult, expectedResults, 'We got all our hats!'); + }); - if (Array.isArray(b)) { - rel.data = b.map(i => { - let { type, id } = i; + test('push both sides are polymorphic', function(assert) { + let User = Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + }); - if (recurse === true) { - link(i, [a], relationshipName, false); - } + let Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + }); - return { type, id }; - }); - } else { - rel.data = { - type: b.type, - id: b.id, - }; + this.owner.register('model:user', User); + this.owner.register('model:alien', User.extend({})); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); - if (recurse === true) { - link(b, a, relationshipName, false); - } + let id = 1; + + function makeHat(type, props) { + const resource = deepCopy(props); + resource.id = `${id++}`; + resource.type = type; + resource.attributes.type = type; + return resource; } - } - let id = 1; - const Person = Model.extend({ - name: attr(), - family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), - twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), - }); - const Girl = Person.extend({}); - const Boy = Person.extend({}); - const Grownup = Person.extend({}); - - const brotherPayload = { - type: 'boy', - id: `${id++}`, - attributes: { - name: 'Gavin', - }, - }; - const sisterPayload = { - type: 'girl', - id: `${id++}`, - attributes: { - name: 'Rose', - }, - }; - const fatherPayload = { - type: 'grownup', - id: `${id++}`, - attributes: { - name: 'Garak', - }, - }; - const motherPayload = { - type: 'grownup', - id: `${id++}`, - attributes: { - name: 'Kira', - }, - }; - - link(brotherPayload, sisterPayload, 'twin'); - link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); - - const payload = { - data: brotherPayload, - included: [sisterPayload, fatherPayload, motherPayload], - }; - const expectedFamilyReferences = [ - { type: 'girl', id: sisterPayload.id }, - { type: 'grownup', id: fatherPayload.id }, - { type: 'grownup', id: motherPayload.id }, - ]; - const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; - - const store = (this.store = createStore({ - person: Person, - grownup: Grownup, - boy: Boy, - girl: Girl, - })); - - const boyInstance = run(() => { - return store.push(payload); + const alienHatData = { + attributes: {}, + relationships: { + user: { + data: { id: '1', type: 'alien' }, + }, + }, + }; + + const bigHatData1 = makeHat('hat', alienHatData), + hatData1 = makeHat('big-hat', alienHatData), + alienIncluded = [bigHatData1, hatData1]; + + const alienData = { + data: { + id: '1', + type: 'alien', + attributes: {}, + }, + included: alienIncluded, + }; + + const expectedAlienResults = alienIncluded.map(m => m.type), + alien = run(() => this.store.push(alienData)), + alienFinalHats = alien.get('hats').mapBy('type'); + + assert.deepEqual(alienFinalHats, expectedAlienResults, 'We got all alien hats!'); }); - const familyResultReferences = boyInstance - .get('family') - .toArray() - .map(i => { - return { type: i.constructor.modelName, id: i.id }; + test('handles relationships where both sides are polymorphic', function(assert) { + let Person = Model.extend({ + hats: hasMany('hat', { + async: false, + polymorphic: true, + inverse: 'person', + }), }); - const twinResult = boyInstance.get('twin'); - const twinResultReference = { type: twinResult.constructor.modelName, id: twinResult.id }; - assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); - assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); -}); + let Hat = Model.extend({ + type: attr('string'), + person: belongsTo('person', { + async: false, + inverse: 'hats', + polymorphic: true, + }), + }); + + this.owner.register('model:person', Person); + this.owner.register('model:big-person', Person.extend({})); + this.owner.register('model:small-person', Person.extend({})); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); + + let id = 1; + function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { + return { + id: `${id++}`, + type, + relationships: { + person: { + data: { + id: isForBigPerson ? '1' : '2', + type: isForBigPerson ? 'big-person' : 'small-person', + }, + }, + }, + }; + } + + const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); + const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); + + const bigPersonData = { + data: { + id: '1', + type: 'big-person', + attributes: {}, + }, + included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], + }; + + const smallPersonData = { + data: { + id: '2', + type: 'small-person', + attributes: {}, + }, + included: [bigHatData3, smallHatData3], + }; + + const bigPerson = run(() => { + return this.store.push(bigPersonData); + }); + + const smallPerson = run(() => { + return this.store.push(smallPersonData); + }); + + const finalBigResult = bigPerson.get('hats').toArray(); + const finalSmallResult = smallPerson.get('hats').toArray(); + + assert.equal(finalBigResult.length, 4, 'We got all our hats!'); + assert.equal(finalSmallResult.length, 2, 'We got all our hats!'); + }); + + test('handles relationships where both sides are polymorphic reflexive', function(assert) { + function link(a, b, relationshipName, recurse = true) { + a.relationships = a.relationships || {}; + const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); + + if (Array.isArray(b)) { + rel.data = b.map(i => { + let { type, id } = i; -test('handles relationships where both sides are polymorphic reflexive but the primary payload does not include linkage', function(assert) { - function link(a, b, relationshipName, recurse = true) { - a.relationships = a.relationships || {}; - const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); + if (recurse === true) { + link(i, [a], relationshipName, false); + } - if (Array.isArray(b)) { - rel.data = b.map(i => { - let { type, id } = i; + return { type, id }; + }); + } else { + rel.data = { + type: b.type, + id: b.id, + }; if (recurse === true) { - link(i, [a], relationshipName, false); + link(b, a, relationshipName, false); } + } + } + + let Person = Model.extend({ + name: attr(), + family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), + }); + + this.owner.register('model:person', Person); + this.owner.register('model:girl', Person.extend({})); + this.owner.register('model:boy', Person.extend({})); + this.owner.register('model:grownup', Person.extend({})); + + let id = 1; + + const brotherPayload = { + type: 'boy', + id: `${id++}`, + attributes: { + name: 'Gavin', + }, + }; + const sisterPayload = { + type: 'girl', + id: `${id++}`, + attributes: { + name: 'Rose', + }, + }; + const fatherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Garak', + }, + }; + const motherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Kira', + }, + }; + + link(brotherPayload, sisterPayload, 'twin'); + link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); + + const payload = { + data: brotherPayload, + included: [sisterPayload, fatherPayload, motherPayload], + }; + const expectedFamilyReferences = [ + { type: 'girl', id: sisterPayload.id }, + { type: 'grownup', id: fatherPayload.id }, + { type: 'grownup', id: motherPayload.id }, + ]; + const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; + + const boyInstance = run(() => { + return this.store.push(payload); + }); - return { type, id }; + const familyResultReferences = boyInstance + .get('family') + .toArray() + .map(i => { + return { type: i.constructor.modelName, id: i.id }; }); - } else { - rel.data = { - type: b.type, - id: b.id, - }; + const twinResult = boyInstance.get('twin'); + const twinResultReference = { type: twinResult.constructor.modelName, id: twinResult.id }; + + assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); + assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); + }); + + test('handles relationships where both sides are polymorphic reflexive but the primary payload does not include linkage', function(assert) { + function link(a, b, relationshipName, recurse = true) { + a.relationships = a.relationships || {}; + const rel = (a.relationships[relationshipName] = a.relationships[relationshipName] || {}); + + if (Array.isArray(b)) { + rel.data = b.map(i => { + let { type, id } = i; + + if (recurse === true) { + link(i, [a], relationshipName, false); + } - if (recurse === true) { - link(b, a, relationshipName, false); + return { type, id }; + }); + } else { + rel.data = { + type: b.type, + id: b.id, + }; + + if (recurse === true) { + link(b, a, relationshipName, false); + } } } - } - - let id = 1; - const Person = Model.extend({ - name: attr(), - family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), - twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), - }); - const Girl = Person.extend({}); - const Boy = Person.extend({}); - const Grownup = Person.extend({}); - - const brotherPayload = { - type: 'boy', - id: `${id++}`, - attributes: { - name: 'Gavin', - }, - }; - const sisterPayload = { - type: 'girl', - id: `${id++}`, - attributes: { - name: 'Rose', - }, - }; - const fatherPayload = { - type: 'grownup', - id: `${id++}`, - attributes: { - name: 'Garak', - }, - }; - const motherPayload = { - type: 'grownup', - id: `${id++}`, - attributes: { - name: 'Kira', - }, - }; - - link(brotherPayload, sisterPayload, 'twin'); - link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); - - // unlink all relationships from the primary payload - delete brotherPayload.relationships; - - const payload = { - data: brotherPayload, - included: [sisterPayload, fatherPayload, motherPayload], - }; - const expectedFamilyReferences = [ - { type: 'girl', id: sisterPayload.id }, - { type: 'grownup', id: fatherPayload.id }, - { type: 'grownup', id: motherPayload.id }, - ]; - const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; - - const store = (this.store = createStore({ - person: Person, - grownup: Grownup, - boy: Boy, - girl: Girl, - })); - - const boyInstance = run(() => { - return store.push(payload); - }); - const familyResultReferences = boyInstance - .get('family') - .toArray() - .map(i => { - return { type: i.constructor.modelName, id: i.id }; + let Person = Model.extend({ + name: attr(), + family: hasMany('person', { async: false, polymorphic: true, inverse: 'family' }), + twin: belongsTo('person', { async: false, polymorphic: true, inverse: 'twin' }), }); - const twinResult = boyInstance.get('twin'); - const twinResultReference = twinResult && { - type: twinResult.constructor.modelName, - id: twinResult.id, - }; - - assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); - assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); -}); -test('push polymorphic self-referential non-reflexive relationship', function(assert) { - const store = this.store; - const hat1Data = { - data: { - id: '1', - type: 'big-hat', - attributes: {}, - }, - }; - const hat2Data = { - data: { - id: '2', - type: 'big-hat', - attributes: {}, - relationships: { - hats: { - data: [{ id: '1', type: 'big-hat' }], - }, + this.owner.register('model:person', Person); + this.owner.register('model:girl', Person.extend({})); + this.owner.register('model:boy', Person.extend({})); + this.owner.register('model:grownup', Person.extend({})); + + let id = 1; + + const brotherPayload = { + type: 'boy', + id: `${id++}`, + attributes: { + name: 'Gavin', }, - }, - }; + }; + const sisterPayload = { + type: 'girl', + id: `${id++}`, + attributes: { + name: 'Rose', + }, + }; + const fatherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Garak', + }, + }; + const motherPayload = { + type: 'grownup', + id: `${id++}`, + attributes: { + name: 'Kira', + }, + }; - const hat1 = run(() => store.push(hat1Data)); - const hat2 = run(() => store.push(hat2Data)); + link(brotherPayload, sisterPayload, 'twin'); + link(brotherPayload, [sisterPayload, fatherPayload, motherPayload], 'family'); - const expectedHatReference = { id: '2', type: 'big-hat' }; - const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; + // unlink all relationships from the primary payload + delete brotherPayload.relationships; - const finalHatsReferences = hat2 - .get('hats') - .toArray() - .map(i => { - return { type: i.constructor.modelName, id: i.id }; + const payload = { + data: brotherPayload, + included: [sisterPayload, fatherPayload, motherPayload], + }; + const expectedFamilyReferences = [ + { type: 'girl', id: sisterPayload.id }, + { type: 'grownup', id: fatherPayload.id }, + { type: 'grownup', id: motherPayload.id }, + ]; + const expectedTwinReference = { type: 'girl', id: sisterPayload.id }; + + const boyInstance = run(() => { + return this.store.push(payload); }); - const hatResult = hat1.get('hat'); - const finalHatReference = hatResult && { - type: hatResult.constructor.modelName, - id: hatResult.id, - }; - - assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); - assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); -}); - -test('push polymorphic self-referential circular non-reflexive relationship', function(assert) { - const store = this.store; - const hatData = { - data: { - id: '1', - type: 'big-hat', - attributes: {}, - relationships: { - hat: { - data: { id: '1', type: 'big-hat' }, - }, - hats: { - data: [{ id: '1', type: 'big-hat' }], - }, - }, - }, - }; - const hat = run(() => store.push(hatData)); + const familyResultReferences = boyInstance + .get('family') + .toArray() + .map(i => { + return { type: i.constructor.modelName, id: i.id }; + }); + const twinResult = boyInstance.get('twin'); + const twinResultReference = twinResult && { + type: twinResult.constructor.modelName, + id: twinResult.id, + }; - const expectedHatReference = { id: '1', type: 'big-hat' }; - const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; + assert.deepEqual(familyResultReferences, expectedFamilyReferences, 'We linked family correctly'); + assert.deepEqual(twinResultReference, expectedTwinReference, 'We linked twin correctly'); + }); - const finalHatsReferences = hat - .get('hats') - .toArray() - .map(i => { - return { type: i.constructor.modelName, id: i.id }; + test('push polymorphic self-referential non-reflexive relationship', function(assert) { + let Hat = Model.extend({ + type: attr('string'), + hat: belongsTo('hat', { async: false, inverse: 'hats', polymorphic: true }), + hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }), }); - const hatResult = hat.get('hat'); - const finalHatReference = hatResult && { - type: hatResult.constructor.modelName, - id: hatResult.id, - }; - - assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); - assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); -}); -test('polymorphic hasMany to types with separate id-spaces', function(assert) { - const user = run(() => - this.store.push({ + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + + const hat1Data = { data: { id: '1', - type: 'user', + type: 'big-hat', + attributes: {}, + }, + }; + const hat2Data = { + data: { + id: '2', + type: 'big-hat', + attributes: {}, relationships: { hats: { - data: [{ id: '1', type: 'big-hat' }, { id: '1', type: 'small-hat' }], + data: [{ id: '1', type: 'big-hat' }], }, }, }, - included: [ - { - id: '1', - type: 'big-hat', - }, - { - id: '1', - type: 'small-hat', - }, - ], - }) - ); + }; - const hats = user.get('hats'); + const hat1 = run(() => this.store.push(hat1Data)); + const hat2 = run(() => this.store.push(hat2Data)); - assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); - assert.deepEqual(hats.map(h => h.id), ['1', '1']); -}); + const expectedHatReference = { id: '2', type: 'big-hat' }; + const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; + + const finalHatsReferences = hat2 + .get('hats') + .toArray() + .map(i => { + return { type: i.constructor.modelName, id: i.id }; + }); + const hatResult = hat1.get('hat'); + const finalHatReference = hatResult && { + type: hatResult.constructor.modelName, + id: hatResult.id, + }; + + assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); + assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); + }); -test('polymorphic hasMany to types with separate id-spaces, from inverse payload', function(assert) { - const user = run(() => - this.store.push({ + test('push polymorphic self-referential circular non-reflexive relationship', function(assert) { + let Hat = Model.extend({ + type: attr('string'), + hat: belongsTo('hat', { async: false, inverse: 'hats', polymorphic: true }), + hats: hasMany('hat', { async: false, inverse: 'hat', polymorphic: true }), + }); + + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + + const hatData = { data: { id: '1', - type: 'user', - }, - included: [ - { - id: '1', - type: 'big-hat', - relationships: { - user: { - data: { id: '1', type: 'user' }, - }, + type: 'big-hat', + attributes: {}, + relationships: { + hat: { + data: { id: '1', type: 'big-hat' }, }, - }, - { - id: '1', - type: 'small-hat', - relationships: { - user: { - data: { id: '1', type: 'user' }, - }, + hats: { + data: [{ id: '1', type: 'big-hat' }], }, }, - ], - }) - ); + }, + }; - const hats = user.get('hats'); + const hat = run(() => this.store.push(hatData)); - assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); - assert.deepEqual(hats.map(h => h.id), ['1', '1']); -}); + const expectedHatReference = { id: '1', type: 'big-hat' }; + const expectedHatsReferences = [{ id: '1', type: 'big-hat' }]; -test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', function(assert) { - let bigHatId = 1; - let smallHatId = 1; - function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { - const isSmallHat = type === 'small-hat'; - return { - id: `${isSmallHat ? smallHatId++ : bigHatId++}`, - type, - relationships: { - person: { - data: { - id: '1', - type: isForBigPerson ? 'big-person' : 'small-person', - }, - }, - }, + const finalHatsReferences = hat + .get('hats') + .toArray() + .map(i => { + return { type: i.constructor.modelName, id: i.id }; + }); + const hatResult = hat.get('hat'); + const finalHatReference = hatResult && { + type: hatResult.constructor.modelName, + id: hatResult.id, }; - } - - const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); - const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); - const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); - const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); - const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); - const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); - - const bigPersonData = { - data: { - id: '1', - type: 'big-person', - attributes: {}, - }, - included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], - }; - - const smallPersonData = { - data: { - id: '1', - type: 'small-person', - attributes: {}, - }, - included: [bigHatData3, smallHatData3], - }; - - const PersonModel = Model.extend({ - hats: hasMany('hat', { - async: false, - polymorphic: true, - inverse: 'person', - }), - }); - const HatModel = Model.extend({ - type: attr('string'), - person: belongsTo('person', { - async: false, - inverse: 'hats', - polymorphic: true, - }), - }); - const BigHatModel = HatModel.extend({}); - const SmallHatModel = HatModel.extend({}); - - const BigPersonModel = PersonModel.extend({}); - const SmallPersonModel = PersonModel.extend({}); - - const store = (this.store = createStore({ - person: PersonModel, - bigPerson: BigPersonModel, - smallPerson: SmallPersonModel, - hat: HatModel, - bigHat: BigHatModel, - smallHat: SmallHatModel, - })); - - const bigPerson = run(() => { - return store.push(bigPersonData); - }); - const smallPerson = run(() => { - return store.push(smallPersonData); + assert.deepEqual(finalHatReference, expectedHatReference, 'we set hat on hat:1'); + assert.deepEqual(finalHatsReferences, expectedHatsReferences, 'We have hats on hat:2'); }); - const finalBigResult = bigPerson.get('hats').toArray(); - const finalSmallResult = smallPerson.get('hats').toArray(); - - assert.deepEqual( - finalBigResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), - [ - { type: 'big-hat', id: '1' }, - { type: 'small-hat', id: '1' }, - { type: 'big-hat', id: '2' }, - { type: 'small-hat', id: '2' }, - ], - 'big-person hats is all good' - ); - - assert.deepEqual( - finalSmallResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), - [{ type: 'big-hat', id: '3' }, { type: 'small-hat', id: '3' }], - 'small-person hats is all good' - ); -}); + test('polymorphic hasMany to types with separate id-spaces', function(assert) { + let User = Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + }); -testInDebug('Invalid inverses throw errors', function(assert) { - let PostModel = Model.extend({ - comments: hasMany('comment', { async: false, inverse: 'post' }), - }); - let CommentModel = Model.extend({ - post: belongsTo('post', { async: false, inverse: null }), - }); - let store = createStore({ - post: PostModel, - comment: CommentModel, - }); + let Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + }); + + let BigHat = Hat.extend({}); + let SmallHat = Hat.extend({}); + + this.owner.register('model:user', User); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', BigHat); + this.owner.register('model:small-hat', SmallHat); - function runInvalidPush() { - return run(() => { - return store.push({ + const user = run(() => + this.store.push({ data: { - type: 'post', id: '1', + type: 'user', relationships: { - comments: { - data: [{ type: 'comment', id: '1' }], + hats: { + data: [{ id: '1', type: 'big-hat' }, { id: '1', type: 'small-hat' }], }, }, }, included: [ { - type: 'comment', id: '1', + type: 'big-hat', + }, + { + id: '1', + type: 'small-hat', + }, + ], + }) + ); + + const hats = user.get('hats'); + + assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); + assert.deepEqual(hats.map(h => h.id), ['1', '1']); + }); + + test('polymorphic hasMany to types with separate id-spaces, from inverse payload', function(assert) { + let User = Model.extend({ + hats: hasMany('hat', { async: false, polymorphic: true, inverse: 'user' }), + }); + + let Hat = Model.extend({ + type: attr('string'), + user: belongsTo('user', { async: false, inverse: 'hats', polymorphic: true }), + }); + + this.owner.register('model:user', User); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); + + const user = run(() => + this.store.push({ + data: { + id: '1', + type: 'user', + }, + included: [ + { + id: '1', + type: 'big-hat', relationships: { - post: { - data: { - type: 'post', - id: '1', - }, + user: { + data: { id: '1', type: 'user' }, + }, + }, + }, + { + id: '1', + type: 'small-hat', + relationships: { + user: { + data: { id: '1', type: 'user' }, }, }, }, ], - }); + }) + ); + + const hats = user.get('hats'); + + assert.deepEqual(hats.map(h => h.constructor.modelName), ['big-hat', 'small-hat']); + assert.deepEqual(hats.map(h => h.id), ['1', '1']); + }); + + test('polymorphic hasMany to polymorphic hasMany types with separate id-spaces', function(assert) { + let Person = Model.extend({ + hats: hasMany('hat', { + async: false, + polymorphic: true, + inverse: 'person', + }), }); - } - assert.expectAssertion( - runInvalidPush, - /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, - 'We detected the invalid inverse' - ); + let Hat = Model.extend({ + type: attr('string'), + person: belongsTo('person', { + async: false, + inverse: 'hats', + polymorphic: true, + }), + }); + + this.owner.register('model:person', Person); + this.owner.register('model:big-person', Person.extend({})); + this.owner.register('model:small-person', Person.extend({})); + this.owner.register('model:hat', Hat); + this.owner.register('model:big-hat', Hat.extend({})); + this.owner.register('model:small-hat', Hat.extend({})); + + let bigHatId = 1; + let smallHatId = 1; + function makePolymorphicHatForPolymorphicPerson(type, isForBigPerson = true) { + const isSmallHat = type === 'small-hat'; + return { + id: `${isSmallHat ? smallHatId++ : bigHatId++}`, + type, + relationships: { + person: { + data: { + id: '1', + type: isForBigPerson ? 'big-person' : 'small-person', + }, + }, + }, + }; + } + + const bigHatData1 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData2 = makePolymorphicHatForPolymorphicPerson('big-hat'); + const bigHatData3 = makePolymorphicHatForPolymorphicPerson('big-hat', false); + const smallHatData1 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData2 = makePolymorphicHatForPolymorphicPerson('small-hat'); + const smallHatData3 = makePolymorphicHatForPolymorphicPerson('small-hat', false); + + const bigPersonData = { + data: { + id: '1', + type: 'big-person', + attributes: {}, + }, + included: [bigHatData1, smallHatData1, bigHatData2, smallHatData2], + }; + + const smallPersonData = { + data: { + id: '1', + type: 'small-person', + attributes: {}, + }, + included: [bigHatData3, smallHatData3], + }; + + const bigPerson = run(() => { + return this.store.push(bigPersonData); + }); + + const smallPerson = run(() => { + return this.store.push(smallPersonData); + }); + + const finalBigResult = bigPerson.get('hats').toArray(); + const finalSmallResult = smallPerson.get('hats').toArray(); + + assert.deepEqual( + finalBigResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), + [ + { type: 'big-hat', id: '1' }, + { type: 'small-hat', id: '1' }, + { type: 'big-hat', id: '2' }, + { type: 'small-hat', id: '2' }, + ], + 'big-person hats is all good' + ); + + assert.deepEqual( + finalSmallResult.map(h => ({ type: h.constructor.modelName, id: h.get('id') })), + [{ type: 'big-hat', id: '3' }, { type: 'small-hat', id: '3' }], + 'small-person hats is all good' + ); + }); + + testInDebug('Invalid inverses throw errors', function(assert) { + this.owner.register( + 'model:post', + Model.extend({ + comments: hasMany('comment', { async: false, inverse: 'post' }), + }) + ); + + this.owner.register( + 'model:comment', + Model.extend({ + post: belongsTo('post', { async: false, inverse: null }), + }) + ); + + let runInvalidPush = () => { + return run(() => { + return this.store.push({ + data: { + type: 'post', + id: '1', + relationships: { + comments: { + data: [{ type: 'comment', id: '1' }], + }, + }, + }, + included: [ + { + type: 'comment', + id: '1', + relationships: { + post: { + data: { + type: 'post', + id: '1', + }, + }, + }, + }, + ], + }); + }); + }; + + assert.expectAssertion( + runInvalidPush, + /The comment:post relationship declares 'inverse: null', but it was resolved as the inverse for post:comments/, + 'We detected the invalid inverse' + ); + }); });