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

remove jquery from ember-testing #16075

Merged
merged 1 commit into from
Jan 14, 2018
Merged

Conversation

snewcomer
Copy link
Contributor

@snewcomer snewcomer commented Jan 6, 2018

Edited: The path forward now is to warn the end user that if jQuery is disabled, they should use instead @ember/test-helpers.

References #16058

@ro0gr
Copy link
Contributor

ro0gr commented Jan 6, 2018

If we force the user to refactor

I believe we can't do this. At least I don't know any RFC with this discussed.
I think we have to preserve jquery support in the ember-testing package till the end of its days.

@rwjblue isn't @ember/test-helpers supposed to replace ember-testing package eventually?

@snewcomer
Copy link
Contributor Author

Another potential hairy spot - Listening for ajaxSend/ajaxComplete and triggering that event are easy with JS, but I believe one difficulty is getting all the event listeners here (across multiple browsers) with JS. jQuery makes this nice and easy. JS equivalent is getEventListeners, but I think that only works w/ Chrome Firefox. && Safari.

Could create our own data structure to hold these events instead.... 🤔

Copy link
Contributor Author

@snewcomer snewcomer left a comment

Choose a reason for hiding this comment

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

Two items left include:

  1. find - replace jquery with JS
  2. Bring back those tests with some data structure that holds / resets ajaxSend && ajaxComplete

} else {
$el.trigger('focusin');
}
let browserIsNotFocused = document.hasFocus && !document.hasFocus();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like there is a better, but similar sol'n here

selector argument to find only within the context's children
@return {Object} jQuery object representing the results of the query
@throws {Error} throws error if jQuery object returned has a length of 0
@return {Object} DOM element representing the results of the query
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has yet to be implemented. find is still using jquery. If we merge w/o the find change, I can revert these files.

// Firefox does not trigger the `focusin` event if the window
// does not have focus. If the document doesn't have focus just
// use trigger('focusin') instead.
if (browserIsNotFocused) {
fireEvent(el, 'focusin');
Copy link
Member

Choose a reason for hiding this comment

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

FWIW, I totally realize that this isn't a mistake in your migrate to native from jQuery, and that it was preexisting. During my testing of this functionality while migrating it to ember-test-helpers I don't think this is quite right, it should be something akin to this:

  // makes `document.activeElement` be `element`. If the browser is focused, it also fires a focus event
  element.focus();

  // Firefox does not trigger the `focusin` event if the window
  // does not have focus. If the document does not have focus then
  // fire `focusin` event as well.
  if (browserIsNotFocused) {
    // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it
    fireEvent(element, 'focus', {
      bubbles: false,
    });

    fireEvent(element, 'focusin');
  }

Otherwise the event ordering is incorrect...

See related implementation from @ember/test-helpers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Getting these ie11 errors after refactoring to this.

https://travis-ci.org/emberjs/ember.js/jobs/326476166

Looks like it is triggering the events multiple times and causing pain click triggering events in order.

@@ -88,7 +96,8 @@ function buildKeyboardEvent(type, options = {}) {
let event;
try {
event = document.createEvent('KeyEvents');
let eventOpts = jQuery.extend({}, DEFAULT_EVENT_OPTIONS, options);
let eventOpts = assign({}, DEFAULT_EVENT_OPTIONS);
assign(eventOpts, options);
Copy link
Member

Choose a reason for hiding this comment

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

Ember.assign is a rough polyfill for Object.assign and does properly accept multiple arguments. Can you update to:

let eventOpts = assign({}, DEFAULT_EVENT_OPTIONS, options);

@@ -32,7 +32,7 @@ export default function fillIn(app, selector, contextOrText, text) {
el = $el[0];
focus(el);

$el.eq(0).val(text);
el.value = text;
Copy link
Member

Choose a reason for hiding this comment

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

Can you confirm if $el.eq(0).val(text) supported content editable elements? I don't recall if it did, but if it did then this would be a regression (since when content editable set you need to set innerHTML).

See related code from @ember/test-helper.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems that both jquery and JS. And yeah def need to set that innerHTML! 👍

el = document.createElement('div')
$(el).attr('contenteditable', 'true')
$(el).val('wat')
$(el).text() // or $(el).html() // ""

.on('click', handler)
.trigger('click')
.remove();
input.setAttribute('type', 'checkbox');
Copy link
Member

Choose a reason for hiding this comment

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

I think this should stay back in jQuery mode since its only ran behind a !jQueryDisabled guard

'onInjectHelpers are called after injectTestHelpers'
);
}
// [`@test #setupForTesting attaches ajax listeners`](assert) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you bring these tests back, but put a short circuit in when jQuery is disabled?

something like:

['@test asdfasdf'](assert) {
  if (jQueryDisabled) {
    assert.expect(0);
    return;
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So this one might be a bit difficult to get at the event listeners w/ documentEvents = jQuery._data(document, 'events'); if jquery is enabled since it is now using document.addEventListener in setup-for-testing. The only thing I was thinking was to track the events with a data structure of our own. Thoughts?

@wycats wycats mentioned this pull request Jan 8, 2018
48 tasks
@@ -29,6 +30,15 @@ import { get } from 'ember-metal';
export default function find(app, selector, context) {
let $el;
context = context || get(app, 'rootElement');
$el = app.$(selector, context);
return $el;
if (jQueryDisabled) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So to allow this to work in all cases, find needs to accept an element or selector...not just a selector.

return $el;
if (jQueryDisabled) {
let rootElement = document.querySelector(context);
$el = rootElement.querySelector(selector);
Copy link
Member

Choose a reason for hiding this comment

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

This should be returned, (we don't need to wrap in an array)

Copy link
Member

Choose a reason for hiding this comment

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

Also, I think we should do:

  let result;
  if (context instanceof Element) {
    result = context.querySelector(selector);
  } else if (typeof context === 'string') {
    result = document.querySelector(`${context} ${selector}`);
  } else {
    result = document.querySelector(selector);
  }
  return result;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed! 🌮

So to support both jquery and JS, I think we need to return an array or array-like object from find. Other helpers are expecting this (like findWithAssert). Unless we wanted to go with only returning one element; however, perhaps users were using find to select multiple as show here.

}
return [];
} else {
$el = app.$(selector, context);
Copy link
Member

Choose a reason for hiding this comment

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

Can probably return this directly

// assert something
});
```

@method click
@param {String} selector jQuery selector for finding element on the DOM
@param {Object} context A DOM Element, Document, or jQuery to use as context
@param {String} selector css selector for finding element on the DOM
Copy link
Contributor

Choose a reason for hiding this comment

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

Although the functionality has not changed and still uses jquery when it's available, this docs change could be misleading, suggesting there is a breaking change. Shouldn't this state something like jQuery selector or css selector (if jQuery is not present) for finding element on the DOM?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, seems you changed it already while I wrote this!? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That seems like a good option. I have it now as @param {String|Element} target the element or selector to click on. What do you think of this? Should it be:

the element or jQuery selector or css selector (if jQuery is not preset) to click on

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems good to me

Copy link
Contributor Author

@snewcomer snewcomer left a comment

Choose a reason for hiding this comment

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

I think almost done! Lmk what you think about the conditionals I put around the tests.


setupForTesting();
// [`@test #setupForTesting attaches ajax listeners`](assert) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we want to bring back these tests, we would have to add back the jquery.on listeners in setup_for_testing. I don't think there is a way to track all of the events listening in a cross browser way (getEventListeners; however, I think no IE). We could add an explicit trackEventLIsteners method but I don't think we would want to do that either.

However, it seems to me that the below tests cover the functionality in setup_for_testing and these commented out tests could be deleted.

https://github.com/emberjs/ember.js/blob/master/packages/ember-testing/tests/helpers_test.js#L1074

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@rwjblue lmk what you think about this remaining issue.

Copy link
Member

Choose a reason for hiding this comment

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

@snewcomer - Can you delete them?

@@ -17,7 +17,7 @@ import { focus, fireEvent } from '../events';

@method click
@param {String} selector jQuery selector for finding element on the DOM
@param {Object} context A DOM Element, Document, or jQuery to use as context
@param {Object} context A DOM Element, Document, or css to use as context
Copy link
Contributor Author

Choose a reason for hiding this comment

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

need to revert this

@@ -21,8 +21,8 @@
the DOM
@param {String} [context] (optional) jQuery selector that will limit the
selector argument to find only within the context's children
@return {Object} jQuery object representing the results of the query
@throws {Error} throws error if jQuery object returned has a length of 0
@return {Object} DOM element representing the results of the query
Copy link
Contributor Author

Choose a reason for hiding this comment

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

need to revert this.

window.visit('/').then(() => {
expectAssertion(() => window.find('.name'),
/If not using jQuery, please import and use methods from @ember\/test-helpers/);
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This asserts that assert is thrown

@rwjblue
Copy link
Member

rwjblue commented Jan 11, 2018

I left one inline comment, and other than that we need to squash down the commits into one and this should be good to go...

@public
*/
export default function find(app, selector, context) {
if (jQueryDisabled) {
assert('If not using jQuery, please import and use methods from @ember/test-helpers');
Copy link
Contributor

@ro0gr ro0gr Jan 11, 2018

Choose a reason for hiding this comment

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

which helper exactly can be used? I think @ember/test-helpers doesn't provide any alternatives to find.

Copy link
Member

Choose a reason for hiding this comment

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

@ro0gr - Usages of find should be replaced by this.element.querySelector or this.element.querySelectorAll...

Copy link
Contributor

Choose a reason for hiding this comment

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

but the old good acceptance tests don't have this.element. Should this assertion have a reference to setupTest api?

Copy link
Member

Choose a reason for hiding this comment

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

FWIW - By the time this hits a release version, the guides will all have been updated to reference the new style (work progressing in emberjs/guides#2145).

For now, lets update the assertion to tell the user that find is not available when jQuery is disabled without giving a more detailed recourse (we can tweak the message when we have better docs to cross link to)...

What do y'all think?

@snewcomer snewcomer force-pushed the no-jquery-testing branch 3 times, most recently from 371ee49 to 59d6680 Compare January 12, 2018 05:17
@snewcomer
Copy link
Contributor Author

@rwjblue It looks like the tests are passing but for a focus-in test in ember-glimmer.

@rwjblue rwjblue merged commit d7a4778 into emberjs:master Jan 14, 2018
@snewcomer snewcomer deleted the no-jquery-testing branch May 28, 2018 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants