You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It took some time to find a reproducible qunit test but here it is:
import{run}from'@ember/runloop';importModel,{attr,belongsTo,hasMany}from'@ember-data/model';import{setupTest}from'ember-qunit';import{module,test}from'qunit';letstore;module('integration/relationship/clear hasMany relation twice',function(hooks){setupTest(hooks);hooks.beforeEach(function(){classDocPageextendsModel{
@hasMany('entry',{inverse: 'docPageId',async: false})entries;}classEntryextendsModel{
@attrstate;
@belongsTo('doc-page',{async: true,inverse: 'entries'})docPageId;
@belongsTo('page-assembly',{async: false,inverse: 'entries'})pageAssembly;}classPageAssemblyextendsModel{
@hasMany('entry',{async: false,inverse: 'pageAssembly'})entries;}store=this.owner.lookup('service:store');this.owner.register('model:doc-page',DocPage);this.owner.register('model:entry',Entry);this.owner.register('model:page-assembly',PageAssembly);});consthashDocPage={data: [{id: '0',type: 'doc-page',},],};consthashEntries={data: [{id: '0',type: 'page-assembly',relationships: {entries: {data: [{id: '0',type: 'entry'}]}},},],included: [{id: '0',type: 'entry',attributes: {state: 'CREATED'},relationships: {docPageId: {data: {id: '0',type: 'doc-page'}},},},],};consthashClearDocPageEntries={data: [{id: '0',type: 'page-assembly',relationships: {entries: {data: [{id: '0',type: 'entry'}]}},},],included: [{id: '0',type: 'entry',attributes: {state: 'CLEARED'},relationships: {docPageId: {data: null},},},],};asyncfunctionpushDocPage(){letdocPages;awaitrun(()=>{docPages=store.push(hashDocPage);});returndocPages;}asyncfunctionpushEntries(){letpageAssemblies;awaitrun(()=>{pageAssemblies=store.push(JSON.parse(JSON.stringify(hashEntries)));});returnpageAssemblies;}asyncfunctionpushClearDocPageEntries(){letpageAssemblies;awaitrun(()=>{pageAssemblies=store.push(JSON.parse(JSON.stringify(hashClearDocPageEntries)));});returnpageAssemblies;}test('pushEntries',asyncfunction(assert){letdocPages=awaitpushDocPage();// 1st iteration to create relationship entry->docPage with 'pushEntries()' and to clear it with 'pushClearDocPageEntries()'letpageAssemblies=awaitpushEntries();assert.equal(store.peekAll('page-assembly').length,1);assert.equal(store.peekAll('entry').length,1);assert.equal(store.peekAll('doc-page').length,1);assert.equal(pageAssemblies[0].entries.length,1);letdocPage=awaitpageAssemblies[0].entries[0].docPageId;assert.equal(docPage.entries.length,1,'docPage linked with entry');pageAssemblies=awaitpushClearDocPageEntries();assert.equal(docPage.entries.length,0,'docPage cleared');// 2nd iteration to create relationship entry->docPage with 'pushEntries()' and to clear it with 'pushClearDocPageEntries()'pageAssemblies=awaitpushEntries();assert.equal(pageAssemblies[0].entries.length,1);docPage=awaitpageAssemblies[0].entries[0].docPageId;// NOTE: UNCOMMENT THE LINE BELOW: i.e. simply accessing the "docPage.entries" relationship once more and THE TEST SUCCEEDS!// assert.equal(docPage.entries.length, 1, 'docPage linked with entry');pageAssemblies=awaitpushClearDocPageEntries();assert.equal(docPage.entries.length,0,'docPage cleared 2nd time');});});
Description
Populate a "belongsTo" relationship with an inverse "hasMany", and clear it afterwards. This works fine the first time. (see 1st iteration in comment)
The second time however, running the same scenario by submitting the same payload(s), an assertion error occurs: "Cannot remove a resource that is not present". (see 2nd iteration in comment)
Expected: the same result the 2nd time the payloads are submitted.
Unexpected is also that when the "docPage.entries" relationship is simply accessed by reading the property, the test succeeds while this should have no effect. (to reproduce, uncomment the line after "NOTE: UNCOMMENT THE LINE BELOW..." in the test above)
Debugging the issue learned the following:
In the 2nd iteration of the scenario above, the docPage.entries relationship.localState = []. This causes the assert in the 2nd scenario when clearing the belongsTo relationship of the entry.docPage by updating the reverse relationship of docPage.entries in '_removeRemote', called from 'removeFromInverse' because localState is not null, but an empty array:
function_removeRemote(relationship,value){
....// if we have existing localState// and we have an index// apply the change, as this is more efficient// than recomputing localState and// it allows us to preserve local ordering// to a small extend. Local ordering should not// be relied upon as any remote change will blow it awayif(relationship.localState){index=relationship.localState.indexOf(value);assert(`Cannot remove a resource that is not present`,index!==-1);relationship.localState.splice(index,1);}
....}
By reading the "docPage.entries" relationship, before the belongsTo relationship of the entry.docPage is cleared (UNCOMMENT THE LINE - in the test above), the docPage.entries relationship.localState is not empty and does contain the identifier, which can then be successfully removed when clearing the entry.docPage belongsTo relationship, passing the test.
Versions
Works fine in v5.2.0.
Fails from v5.3.0
The text was updated successfully, but these errors were encountered:
separate from whether there is a bug here, the payload setup here isn't describing the doc-page entries relationship in a valid way. The invalid setup likely contributes to the observed issue by putting the relationship into an invalid state, from which point the later behaviors become less well defined.
Hi @runspired,
Finally found the time to look into this again (our major release is out..). I couldn't figure our immediately what was wrong in the setup, so instead I tried to extend one of the exiting tests from the ember-data testsuite since the setup was almost similar.
I've made a PR (#9326) that will make it clear I guess. Repeating the scenario twice (i.e. setting the belongsTo relation to null) generates the same error.
Hope this helps to figure this one out.
Reproduction
It took some time to find a reproducible qunit test but here it is:
Description
Populate a "belongsTo" relationship with an inverse "hasMany", and clear it afterwards. This works fine the first time. (see 1st iteration in comment)
The second time however, running the same scenario by submitting the same payload(s), an assertion error occurs: "Cannot remove a resource that is not present". (see 2nd iteration in comment)
Expected: the same result the 2nd time the payloads are submitted.
Unexpected is also that when the "docPage.entries" relationship is simply accessed by reading the property, the test succeeds while this should have no effect. (to reproduce, uncomment the line after "NOTE: UNCOMMENT THE LINE BELOW..." in the test above)
Debugging the issue learned the following:
In the 2nd iteration of the scenario above, the docPage.entries relationship.localState = []. This causes the assert in the 2nd scenario when clearing the belongsTo relationship of the entry.docPage by updating the reverse relationship of docPage.entries in '_removeRemote', called from 'removeFromInverse' because localState is not null, but an empty array:
By reading the "docPage.entries" relationship, before the belongsTo relationship of the entry.docPage is cleared (UNCOMMENT THE LINE - in the test above), the docPage.entries relationship.localState is not empty and does contain the identifier, which can then be successfully removed when clearing the entry.docPage belongsTo relationship, passing the test.
Versions
The text was updated successfully, but these errors were encountered: