-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add guard & more helpful error massage when calling _setupRelationships when store is destroyed #5282
Conversation
Not sure why the test is failing in Phantom... It's passing just fine for me locally |
addon/-private/system/store.js
Outdated
@@ -2415,6 +2415,11 @@ Store = Service.extend({ | |||
return; | |||
} | |||
|
|||
if (this.isDestroyed) { | |||
assert('Attempting to set up relationships after store has been destroyed'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add the isDestroyed
check directly in the assert
invocation. That will allow all of the code to be stripped in production builds...
I believe it would be something like:
assert('Attempting to set up relationships after store has been destroyed', !this.isDestroying && !this.isDestroyed);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
In prod, Ember.assert is stripped, so this test would fail
Alright, so I noticed that the failing test was in the production environment, so I added a conditional in the test file. Let me know if there's a better way to do that. |
tests/integration/store-test.js
Outdated
assert.equal(personWillDestroy.called.length, 1, 'expected person to have recieved willDestroy once'); | ||
assert.equal(carWillDestroy.called.length, 1, 'expected car to recieve willDestroy once'); | ||
assert.equal(carsWillDestroy.called.length, 1, 'expected person.cars to recieve willDestroy once'); | ||
assert.equal(adapterPopulatedPeopleWillDestroy.called.length, 1, 'expected adapterPopulatedPeople to recieve willDestroy once'); | ||
assert.equal(filterdPeopleWillDestroy.called.length, 1, 'expected filterdPeople.willDestroy to have been called once'); | ||
if (config.environment !== 'production') { | ||
assert.throws(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we generally use assert.expectAssertion(() => {}, /some matcher/)
for this. That custom assertion is provided by https://github.com/workmanw/ember-qunit-assert-helpers/ and is aware of development vs production...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rwjblue - If I do that, then the production test still fails, because it moves on and hits the original TypeError: Cannot read property 'push' of null
.
This is why I had originally built the assertion into a conditional. It would allow an early return - in production, the assertion would be skipped, but you wouldn't hit that error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or another idea: Maybe we want to just throw
instead of assert
? i.e. maybe we want this better error message in production too? This case is currently throwing an error in prod either way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rwjblue ⬆️ Any thoughts on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pinging again... @rwjblue ⬆️ Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danwenzel I don't think we want to throw in prod
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I'm happy to pick this up from where @rwjblue and help you get it over the line. I've been working to fix a lot of these async cleanup issues in Ember-data and Ember so that folks get better info about what went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @runspired ! Any thoughts on the other issues above? If we want to leave production alone, we'll have to think of some way to only call that method in the non-prod tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @runspired , that worked perfectly! All passing now
@runspired @rwjblue - Ok to ship this? |
assert.throws(() => { | ||
store._setupRelationshipsForModel(null, { relationships: {} }); | ||
}, /Attempting to set up relationships after store has been destroyed/); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should design a test scenario similar to a real-world scenario that would have caused this to happen. I'm especially interested in such a test because:
- It may be that we need to adjust our waiters [FEAT] Prevent async test leakage (feat. adds test waiters) #5422
- _setupRelationshipsForModel should still occur in the same run-loop as whatever scheduled it. This indicates to me that this either might be the wrong location to assert, or that we could improve the message to tell people exactly what they need to do to resolve the error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also note, for createRecord
causing this, we've improved things: #5415
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @runspired. I agree that we should eventually dig more into the root issue, but this PR at least makes the situation 1 step better - Someone encountering this in dev or test will know more about what's going on and fix it faster.
I unfortunately won't have time to dig deeper for a while, so maybe we could ship this as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@danwenzel if you can jot down some notes for me about roughly the setup you encountered in the wild, and give me commit access to your fork, I will continue to improve this :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @runspired , sorry for the delay.
I can't remember the details of my setup, but this gives a pretty good example of the issue: miragejs/ember-cli-mirage#1220.
I've given you access to my fork. Let me know if you need anything else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Will revisit this soon, I have a pretty good idea of how to design a good test for it, and likely we can simply do the "right" thing and no-op here vs. error. Basically, the waiters in #5545 and an assert about using |
After revisiting I confirmed that there are only two ways for _setupRelationships to be called: via |
This PR adds a guard against trying to set up relationships after the store has been destroyed, providing a more helpful error message.
Background:
We ran into a test failure which showed the following error:
similar to this issue: miragejs/ember-cli-mirage#1220
After some digging, it turned out that the store had been destroyed too early in the test, and this line was causing the error: https://github.com/emberjs/data/blob/master/addon/-private/system/store.js#L2418
The error happened because the store sets
_pushedInternalModels
tonull
when destroyed: https://github.com/emberjs/data/blob/master/addon/-private/system/store.js#L2706, so trying to later callpush
on it causes an error.This PR adds an assertion that makes it clearer what's going on, making for faster debugging.