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

Refactor setupRenderingContext so that element is stable after setup. #282

Merged
merged 2 commits into from
Dec 20, 2017

Conversation

rwjblue
Copy link
Member

@rwjblue rwjblue commented Dec 20, 2017

Previously (with moduleForComponent) eager rendering was avoided because it was not clear that rendering was actually desired (and therefore the extra work would be wasted in cases that were not testing rendering). Unlike moduleForComponent we can be certain that setupRenderingContext is only used in actual rendering contexts (its in the name :P ), so we do not need to be concerned with the performance.

This change is a compatible change (unless someone was relying on the fact that this.element was undefined, which seems super weird) that ensures this.element is set immediately upon setupRenderingContext being called (instead of lazily when the first render is done). At that point this.element is essentially an empty element (roughly akin to having only {{outlet}} in an application template without an index template).

This unlocks the ability to test pending promises during rendering (via things like waitUntil).

Fixes #281

Previously (with `moduleForComponent`) eager rendering was avoided
because it was not clear that rendering was _actually_ desired (and
therefore the extra work would be wasted in cases that were not testing
rendering). Unlike `moduleForComponent` we can be certain that
`setupRenderingContext` is only used in actual rendering contexts (its
in the name :P ), so we do not need to be concerned with the
performance.

This change is a compatible change (unless someone was _relying_ on
the fact that `this.element` was undefined, which seems super weird)
that ensures `this.element` is set immediately upon
`setupRenderingContext` being called (instead of lazily when the first
`render` is done). At that point `this.element` is essentially an empty
element (roughly akin to having only `{{outlet}}` in an `application`
template without an `index` template).

This unlocks the ability to test pending promises during rendering (via
things like `waitUntil`).
@rwjblue
Copy link
Member Author

rwjblue commented Dec 20, 2017

@ro0gr - Can you review the test I added (in the second commit) to make sure it roughly emulates your scenario?

/cc @cibernox (I believe you mentioned this case the other day also)


if (global.jQuery) {
context.$ = function $(selector) {
// emulates Ember internal behavor of `this.$` in a component
// https://github.com/emberjs/ember.js/blob/v2.5.1/packages/ember-views/lib/views/states/has_element.js#L18
return selector ? global.jQuery(selector, element) : global.jQuery(element);
return selector ? global.jQuery(selector, context.element) : global.jQuery(context.element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, but I just learned that context.element is a jQuery element if you have jQuery. Is that intended?
I'd have expeted user to do the wrapping themselves if they want to, like

import $ from 'jquery';
// ...
  assert.equal($(this.element).hasClass('foo'));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cibernox this.$ = $(this.element), this.element is always a native DOM element

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cibernox - That is very surprising indeed! As you can see (just above in the diff) this is how we set context.element now (was the same before but done via Object.defineProperty):

    context.element = document.querySelector('#ember-testing > .ember-view');

How could that ever be a jQuery element? Are you certain that this wasn't in a moduleForComponent test?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind. I read this ternary completely wrong. I thought the line was setting context.element to global.jQuery(context.element).

Copy link
Member

@Turbo87 Turbo87 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it even seems to simplify the rendering logic quite a bit :)

@rwjblue
Copy link
Member Author

rwjblue commented Dec 20, 2017

it even seems to simplify the rendering logic quite a bit :)

Totally agreed. A number of conditionals removed...

// Does not use `await` intentionally
let renderPromise = render(hbs`{{promise-wrapper promise=promise }}`);

await waitFor('.loading');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly what I was looking for two days ago 🎉

@rwjblue rwjblue merged commit fb4c8d4 into emberjs:master Dec 20, 2017
@rwjblue rwjblue deleted the make-element-available-earlier branch December 20, 2017 16:57
@ro0gr
Copy link
Contributor

ro0gr commented Dec 20, 2017

@rwjblue yes, it does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants