-
-
Notifications
You must be signed in to change notification settings - Fork 66
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
Use a disposable object to serve as context for Ember test helpers #461
Conversation
b883290
to
474c727
Compare
Because Ember 3.13 introduces an inaccessible WeakMap for framework-provided setters (to support tracked properties) keyed off of the owning object, the contexts used in Ember tests _need_ to be disposable objects, lest a stale setter be used for a property sharing the same name with one from a previous test. To balance the ergonomics of Mochajs, this change introduces such a disposable object, which gets passed to the various `@ember/test-helper`-provided setup methods, and then forwarding attributes are set up and torn down on `this` that provide transparent access to the disposable context. One drawback to this approach is that attributes added to the Ember test context without invoking `setUnknownProperty()` will be unavailable on the Mocha context unless an empty value is added to the Ember context before setup; there is already an example of this in the application test function `visit()`, which sets `element` on the context without it having been added to the context as part of `setupApplicationContext()`. This solution would necessitate such attributes be added to the disposable context object before forwarding is set up (as is done already with `element`). This is somewhat mitigated by adding `unknownProperty()` and `setUnknownProperty()` to the EmberTestContext class, as it allows templates to access attributes which may have been set on the Mocha context without using `this.set`, but it's still not ideal in that the calling getter/setter must respect the `unknownProperty()/setUnknownProperty()` methods, which a native getter/setter will not.
474c727
to
78a6842
Compare
@@ -0,0 +1,43 @@ | |||
export default class EmberTestContext { | |||
constructor(mochaContext) { | |||
this.element = null; |
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.
should this only apply to rendering 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.
That had been my initial thought, but the visit()
method, used in acceptance tests, assigns context.element
without it having been set up on the context beforehand. I suppose we could assign element
to the context in setupApplicationTest()
(it already gets assigned as part of the call to setupRenderingContext()
in setupRenderingTest()
) instead of declaring it here, so that it's more explicit why it's needed. 🤔
I like how explicit this approach is! I have been stumbling my way throughout each piece here. |
And thank you @kobsy for taking this on! FWIW I just ran this on our application's codebase and am seeing a number of errors relating to the rendering test context not set up properly. |
I think you have a valid point about this approach both being very explicit ... but also about it adding a lot of surface area that would need to be maintained. 😞 I'd be curious what sorts of errors you're encountering; I was able to incorporate this with our application's tests and was able to run without any errors, but I may not have taken the same approaches as you have in your tests to setting up the context. (I fear besides maintenance, this kind of mechanism is pretty brittle in-and-of itself, with plenty of edge cases and "gotchas" waiting to be encountered.) With that said, I did some more digging and found an example how I might access Ember's internal method to clean up the offending WeakMap entries. I carried over the tests and then implemented the solution in #462. While I don't love using private API in this way, the solution is so much less complex than what's presented in this PR, I think I'd prefer the other solution over this one. 😅 |
Our integration test suite easily has 2,000 or more tests. Quick survey:
After these two there are a cascade of errors I've seen before.
Thanks to your explanations in your PR and all the pieces of the conversation I've been following, I started trying to do the same locally in #460 :)
Totally agree. |
I think in light of the comments around this solution, I'm going to go ahead and close this PR. It was a good spike on what it would take to supply a disposable context object, but because of the complexity involved, it just doesn't seem like a good direction for solving this problem. |
Summary
Because Ember 3.13 introduces an inaccessible WeakMap for framework-provided setters (to support tracked properties) keyed off of the owning object, the contexts used in Ember tests need to be disposable objects, lest a stale setter be used for a property sharing the same name with one from a previous test. To balance the ergonomics of Mocha, this change introduces such a disposable object, which gets passed to the various
@ember/test-helper
-provided setup methods, and then forwarding attributes are set up and torn down onthis
that provide transparent access to the disposable context.One drawback to this approach is that attributes added to the Ember test context without invoking
setUnknownProperty()
will be unavailable on the Mocha context unless an empty value is added to the Ember context before setup; there is already an example of this in the application test functionvisit()
, which setselement
on the context without it having been added to the context as part ofsetupApplicationContext()
. This solution would necessitate such attributes be added to the disposable context object before forwarding is set up (as is done already withelement
). This is somewhat mitigated by addingunknownProperty()
andsetUnknownProperty()
to the EmberTestContext class, as it allows templates to access attributes which may have been set on the Mocha context without usingthis.set
, but it's still not ideal in that the calling getter/setter must respect theunknownProperty()/setUnknownProperty()
methods, which a native getter/setter will not.This PR would be an alternate solution from #460 to address #430 (and indeed two of the added tests were pulled almost directly from #460 and #450; the other two represent what is perhaps not best practices, but they validate that it continues to work how it did previously, at any rate). I'd done some digging on my own, but I was glad to have my suspicions confirmed by @simonihmig in the discussion on #450. Thanks! 🙂