Skip to content
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

{{link-to}} + click action on component has different behavior in test vs. real usage #14071

Closed
blimmer opened this issue Aug 15, 2016 · 8 comments

Comments

@blimmer
Copy link

blimmer commented Aug 15, 2016

I noticed this difference between the actually using the app vs. in test. In this case, I have a button inside a component that goes to a different route than the component itself. We could argue about the UX, but that's another story. If you interact with the real component, clicking the button goes to a different route, but this behavior is different in test.

Twiddle with test showing the problem

I wasn't sure if this should be filed here or in the ember-test-helpers project, so please let me know if this isn't the right place and I'll happily file elsewhere.

@pixelhandler
Copy link
Contributor

pixelhandler commented Aug 16, 2016

@blimmer the click event bubbles up so to prevent that you could return false, e.g. in the case that a clild element like a link-to should have handled the click. See the guard condition I added in this twiddle - https://ember-twiddle.com/81a79d72da79c32704217b4b2eb9c26a?openFiles=components.card-thingy.js%2C&route=%2Fmy-other-route

I don't think this is a bug, the example app is just handling clicks where it should ignore certain click events.

@blimmer
Copy link
Author

blimmer commented Aug 19, 2016

That definitely seems to fix the problem. Still a bit concerning that it behaves differently in test vs. in real interaction though. I would expect the test and real interaction to exhibit the same behavior.

@pixelhandler
Copy link
Contributor

pixelhandler commented Aug 19, 2016

@blimmer yeah when I disable testing on the twiddle I made your original use case is broken. The bubbling behavior works different in test and development environments. You can see the difference by using the app below the test output, the outer click no longer works.

@krisselden
Copy link
Contributor

@rwjblue is this fixed by the use real events testing flag?

@pixelhandler
Copy link
Contributor

@blimmer @krisselden @rwjblue is this still an issue, perhaps we should close or create a new reproduction of this, what do you think?

Perhaps using the testing helpers for v3+ this is a non issue, https://guides.emberjs.com/release/testing/testing-helpers/

@blimmer
Copy link
Author

blimmer commented Sep 20, 2018

@rwjblue
Copy link
Member

rwjblue commented Dec 11, 2018

Hmph, I don't actually understand what is going on here. Why doesn't it work? Has anyone dug into it?

@rwjblue
Copy link
Member

rwjblue commented Dec 19, 2018

OK, I did a bunch of digging on this to figure out what was going on.

When running in "normal" mode (e.g. non-tests) when the button is clicked there is no preexisting run loop, however when running in test mode the click promise has resolved but the run loop has not fully finished flushing (e.g. we haven't fired BB's end hooks).

Now, you ask why the heck do I care if there is a run loop or not?!, and I agree with you that you shouldn't care. So here goes a semi random series of points:

  • The event dispatcher uses run.join to handle events
  • When run.join is ran within an existing run loop, it runs the callback immediately and queues any side effects to run when the run loop it joined has completed (some future time)
  • When run.join is ran without an existing run loop, it runs the callback and immediately flushing any async side effects)
  • When in tests, our click helper uses an RSVP.Promise to resolve when settled
  • When an RSVP.Promise resolves, it creates a run loop

So, given that information, when ran in tests the {{link-to handles the click event and queues up a router.transitionTo('my-other-route') but since we are joining an existing run loop the transition is deferred (to the end of that run loop). Since the {{link-to is not setting bubbles=false the click event continues bubbling through the DOM. The event dispatcher finds another component that could handle the event and runs the click handler in card-thingy component. That click event queues up a transition to my-route. The second transition queued overrules the first, and we end up on my-route.

Now, outside of tests a slightly different thing is happening. When the {{link-to handles the click event we have no existing run loop which ultimately means that any side effects are synchronously flushed. So the {{link-to click handler queues up the transition which is then performed immediately (at this point we are already on my-other-route). Just like in the testing scenario, preventPropagation() wasn't called by {{link-to (because bubbles=false wasn't used) so the event dispatcher attempts to bubble up the DOM looking for other components to handle the event. However, since the transition has already flushed synchronously, the card-thingy component is actually no longer present to dispatch the event to.

tldr; this isn't really a bug (though there are a few things to be done to make it better), and you should use bubbles=false with your {{link-to to avoid the discrepancy.

@rwjblue rwjblue closed this as completed Dec 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants