diff --git a/tests/main/tests/integration/records/unload-all-test.js b/tests/main/tests/integration/records/unload-all-test.js index 833f228c63b..e1a6ecc7625 100644 --- a/tests/main/tests/integration/records/unload-all-test.js +++ b/tests/main/tests/integration/records/unload-all-test.js @@ -4,7 +4,7 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; -import Model, { attr } from '@ember-data/model'; +import Model, { attr, hasMany } from '@ember-data/model'; module('Integration | Records | unloadAll', function (hooks) { setupTest(hooks); @@ -392,4 +392,166 @@ module('Integration | Records | unloadAll', function (hooks) { await settled(); assert.strictEqual(store.peekAll('post').length, 0, '0 posts in the store at the end'); }); + + const TYPES = ['post', 'category', 'author']; + TYPES.forEach((type) => { + const RemainingTypes = TYPES.filter((t) => t !== type); + RemainingTypes.forEach((remainingType) => { + const finalType = RemainingTypes.find((t) => t !== remainingType); + const UnloadOrder = [type, remainingType, finalType]; + + test(`unloadAll() works when some of the related records of another type are also unloaded (${UnloadOrder.join( + ' => ' + )})`, function (assert) { + const { owner } = this; + + // since async relationships are retainers, we make all + // sides here async to dial up the potential cycle + // we also do a three-way cycle to add extra complexity + class Post extends Model { + @attr title; + @hasMany('author', { async: true, inverse: 'posts' }) authors; + } + class Category extends Model { + @attr name; + @hasMany('author', { async: true, inverse: 'categories' }) authors; + } + class Author extends Model { + @attr name; + @hasMany('category', { async: true, inverse: 'authors' }) categories; + @hasMany('post', { async: true, inverse: 'authors' }) posts; + } + + owner.register('model:post', Post); + owner.register('model:category', Category); + owner.register('model:author', Author); + const store = owner.lookup('service:store'); + + // push some data into the store + store.push({ + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Lorem ipsum', + }, + relationships: { + authors: { + data: [{ type: 'author', id: '1' }], + }, + }, + }, + { + type: 'category', + id: '1', + attributes: { + name: 'Lorem ipsum', + }, + relationships: { + authors: { + data: [{ type: 'author', id: '1' }], + }, + }, + }, + { + type: 'author', + id: '1', + attributes: { + name: 'Lorem ipsum', + }, + relationships: { + posts: { + data: [{ type: 'post', id: '1' }], + }, + categories: { + data: [{ type: 'category', id: '1' }], + }, + }, + }, + ], + }); + + // unload all the records of each type by type + UnloadOrder.forEach((type) => { + store.unloadAll(type); + }); + + // assert that all the records are unloaded + assert.strictEqual(store.peekAll('post').length, 0, '0 posts in the store'); + assert.strictEqual(store.peekAll('category').length, 0, '0 categories in the store'); + assert.strictEqual(store.peekAll('author').length, 0, '0 authors in the store'); + }); + + test(`unloadAll() works when some of the related records of another type were never loaded (${UnloadOrder.join( + ' => ' + )})`, function (assert) { + const { owner } = this; + + // since async relationships are retainers, we make all + // sides here async to dial up the potential cycle + // we also do a three-way cycle to add extra complexity + class Post extends Model { + @attr title; + @hasMany('author', { async: true, inverse: 'posts' }) authors; + } + class Category extends Model { + @attr name; + @hasMany('author', { async: true, inverse: 'categories' }) authors; + } + class Author extends Model { + @attr name; + @hasMany('category', { async: true, inverse: 'authors' }) categories; + @hasMany('post', { async: true, inverse: 'authors' }) posts; + } + + owner.register('model:post', Post); + owner.register('model:category', Category); + owner.register('model:author', Author); + const store = owner.lookup('service:store'); + + // push some data into the store + // and make sure all relationships are materialized + // note: we intentionally do not load author + store.push({ + data: [ + { + type: 'post', + id: '1', + attributes: { + title: 'Lorem ipsum', + }, + relationships: { + authors: { + data: [{ type: 'author', id: '1' }], + }, + }, + }, + { + type: 'category', + id: '1', + attributes: { + text: 'Lorem ipsum', + }, + relationships: { + authors: { + data: [{ type: 'author', id: '1' }], + }, + }, + }, + ], + }); + + // unload all the records of each type by type + UnloadOrder.forEach((type) => { + store.unloadAll(type); + }); + + // assert that all the records are unloaded + assert.strictEqual(store.peekAll('post').length, 0, '0 posts in the store'); + assert.strictEqual(store.peekAll('category').length, 0, '0 categories in the store'); + assert.strictEqual(store.peekAll('author').length, 0, '0 authors in the store'); + }); + }); + }); });