-
-
Notifications
You must be signed in to change notification settings - Fork 407
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 Ember.run.callback() #115
Conversation
The method takes a single function as an argument, and returns a wrapper function that can be used in place of the originally supplied one. This wrapper does two things: | ||
|
||
1. Ensures the callback is wrapped in an `Ember.run()` call, mostly for convenience. | ||
2. More importantly, it wraps the user-supplied function with a `registerWaiter` method (and the associated state management / cleanup) which resolves once the |
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.
Run is part of metal, and register waiter is part of test, i am unclear if this should be part of run namespace.
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's fair. My thought was that the behavior here matches similar behavior with the other Ember.run.* methods (i.e. want an Ember aware setTimeout? run.later
. Want an Ember aware callback? run.callback
). It mixes concerns under the hood, but from my perspective when trying to solve this problem, Ember.run
was my gut reaction first place to check.
Certainly open to suggestions of a better spot for it to live.
can side-by side examples be provided comparing this to registerWaiter? |
@stefanpenner added example code for both current approaches in the Alternatives section (manual waiters and direct state manipulation). I took a stab at the example code, but if either one seems uncharitable to the current alternatives, feedback is welcome. |
|
||
By having the application register the waiters itself, we can avoid compromising the "purity" of the acceptance tests which would otherwise need to reach into the application's running state. | ||
|
||
The return value of of `Ember.run.callback()` would be the wrapped function, but the waiter would be registered immediately. If the callback is no longer needed, the user could cancel the waiter by passing the callback to `Ember.run.cancel()` (matching the other async `Ember.run.*` methods). |
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.
The return value of of Ember.run.callback()
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.
Good catch 👍
The manual registration example is somewhat strange. Wouldn't the waiter be in the app code, so that all tests interacting with that entity would work the same? Ember.run.callback itself has a fairly vague name, I could users using it in place of run.bind and being confused by the outcome.any ideas? Another thing, which types of callbacks should this be passed to, all/any/some. How can we make users fall into a pit of success. |
Fair point. I'll add an example demonstrating that.
Totally agree, I don't really like the name either, I just couldn't think of a better one 😉 It does bear some similarity to
It should be used for any async callbacks that aren't already tracked by Ember. I can see a few places where users might run awry:
@stefanpenner do these points belong in the RFC somewhere (Unresolved Questions)? Or should we let the discussion play out first? |
This isn't an async method, and we don't really have control checking this from the callee side. Literally any-place that we would want to use this, is more or less by definition out of our control.
Maybe, but this would be valuable as well (maybe a different RFC) aka, named waiters that track their callstack that invoked them during testing for easy inspection. Introducing a high-level API does usually mean we need to investigate improved debug-ability.
This isn't the hazard I'm concerned with, let me demonstrate, given:
If someone was like, oh a callback, I should use won't be: didInsertElement() {
this.$().click(Ember.run.callback(this, this.method));
// testing would just hang when the component was rendered, regardless of intent.
} will be: didInsertElement() {
this.$().click(_ => {
$(this).one('didLoad', Ember.run.callback(this, this.method)); // likely works as expected
});
} I do think we need to improve this, (i literally spent 2 days last week tracking down related issues in test suites). But maybe first several common scenarios that don't pause tests but should should be enumerated. That way we can look at each case, and decide what the appropriate solution is (I would venture to guess, we could do more automatically then we do today). Another thing to consider, is testWaiters can be aborted but callback in this RFC cannot. Their is no way (currently) to say, oops NVM no longer block tests. Here is a quick example (inspired by one of the fixes I made last week); let complete = false;
Ember.Test.registerWaiter( _ => complete);
this.one('didLoad', _=> complete = true); // assume cleanup of the error listener
this.one('error', _=> complete = true); // assume cleanup of the error listener |
My point was the opposite - that we might want to warn if someplace inside our control receives a
Ah, okay. Your examples make sense. Yea, that could be tricky, and I don't see a good way of preventing that apart from choosing a better name and good docs, since there isn't a great way to tell those use cases apart in an automated fashion (AFAICT).
Sure. Should I add these additional examples to the RFC doc? Suggestions of scenarios are welcome.
The callback can be canceled. From the RFC:
This is implemented in the addon spike. Are you looking for some other kind of "abort" behavior? |
Ah. I must have missed the cancellation aspect. Yes I think enumerating the use-cases explicitly would be good. It will help this discussion, and maybe spark complementary solutions. |
You have two Current solutions in the RFC which illustrate quite vividly the pain this RFC is aiming to resolve. 👍 But can you please add a code sample to the RFC demonstrating what those Current solutions could be replaced with? |
Oops, didn't notice this RFC is old! Is it still relevant? |
I'm going to assume this is no longer relevant. If I'm incorrect, let me know and I'll see what I can do to get it moving forwards again. |
Rendered