diff --git a/packages/-ember-data/tests/integration/relationships/promise-many-array-test.js b/packages/-ember-data/tests/integration/relationships/promise-many-array-test.js index 7b58ab43340..98967d05e81 100644 --- a/packages/-ember-data/tests/integration/relationships/promise-many-array-test.js +++ b/packages/-ember-data/tests/integration/relationships/promise-many-array-test.js @@ -1,5 +1,7 @@ import { A } from '@ember/array'; -import { w } from '@ember/string'; +import EmberObject, { computed } from '@ember/object'; +import { filterBy } from '@ember/object/computed'; +import { settled } from '@ember/test-helpers'; import { module, test } from 'qunit'; @@ -7,7 +9,7 @@ import { setupRenderingTest } from 'ember-qunit'; import Model, { attr, hasMany } from '@ember-data/model'; -module('PromiseManyArray side-affected by EmberArray', (hooks) => { +module('PromiseManyArray', (hooks) => { setupRenderingTest(hooks); test('PromiseManyArray is not side-affected by EmberArray', async function (assert) { @@ -16,12 +18,12 @@ module('PromiseManyArray side-affected by EmberArray', (hooks) => { @attr('string') name; } class Group extends Model { - @hasMany('person', { inverse: null }) members; + @hasMany('person', { async: true, inverse: null }) members; } owner.register('model:person', Person); owner.register('model:group', Group); const store = owner.lookup('service:store'); - const members = w('Bob John Michael Larry Lucy').map((name) => store.createRecord('person', { name })); + const members = ['Bob', 'John', 'Michael', 'Larry', 'Lucy'].map((name) => store.createRecord('person', { name })); const group = store.createRecord('group', { members }); const replaceFn = group.members.replace; @@ -36,4 +38,85 @@ module('PromiseManyArray side-affected by EmberArray', (hooks) => { group.members.replace(0, 1); assert.strictEqual(group.members.length, 3, 'updated length is correct'); }); + + test('PromiseManyArray can be subscribed to by computed chains', async function (assert) { + const { owner } = this; + class Person extends Model { + @attr('string') name; + } + class Group extends Model { + @hasMany('person', { async: true, inverse: null }) members; + + @computed('members.@each.id') + get memberIds() { + return this.members.map((m) => m.id); + } + + @filterBy('members', 'name', 'John') + johns; + } + owner.register('model:person', Person); + owner.register('model:group', Group); + owner.register( + 'serializer:application', + class extends EmberObject { + normalizeResponse(_, __, data) { + return data; + } + } + ); + + let _id = 0; + const names = ['Bob', 'John', 'Michael', 'John', 'Larry', 'Lucy']; + owner.register( + 'adapter:application', + class extends EmberObject { + findRecord() { + const name = names[_id++]; + const data = { + type: 'person', + id: `${_id}`, + attributes: { + name, + }, + }; + return { data }; + } + } + ); + const store = owner.lookup('service:store'); + + const group = store.push({ + data: { + type: 'group', + id: '1', + relationships: { + members: { + data: [ + { type: 'person', id: '1' }, + { type: 'person', id: '2' }, + { type: 'person', id: '3' }, + { type: 'person', id: '4' }, + { type: 'person', id: '5' }, + { type: 'person', id: '6' }, + ], + }, + }, + }, + }); + + // access the group data + let memberIds = group.memberIds; + let johnRecords = group.johns; + assert.strictEqual(memberIds.length, 0, 'member ids is 0 initially'); + assert.strictEqual(johnRecords.length, 0, 'john ids is 0 initially'); + + await settled(); + + memberIds = group.memberIds; + johnRecords = group.johns; + assert.strictEqual(memberIds.length, 6, 'memberIds length is correct'); + assert.strictEqual(johnRecords.length, 2, 'johnRecords length is correct'); + assert.strictEqual(group.members.length, 6, 'members length is correct'); + }); }); diff --git a/packages/model/addon/-private/system/promise-many-array.ts b/packages/model/addon/-private/system/promise-many-array.ts index ac8a7063bda..c2831738cf6 100644 --- a/packages/model/addon/-private/system/promise-many-array.ts +++ b/packages/model/addon/-private/system/promise-many-array.ts @@ -61,6 +61,9 @@ export default class PromiseManyArray { */ @dependentKeyCompat get length(): number { + // shouldn't be needed, but ends up being needed + // for computed chains even in 4.x + this['[]']; return this.content ? this.content.length : 0; }