Skip to content

Commit

Permalink
[BUGFIX beta] reimplement $.ready()
Browse files Browse the repository at this point in the history
  • Loading branch information
rreckonerr committed Sep 20, 2020
1 parent be152e2 commit 18ad68e
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 47 deletions.
13 changes: 11 additions & 2 deletions packages/@ember/application/lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,22 @@ const Application = Engine.extend({
@method waitForDOMReady
*/
waitForDOMReady() {
if (!this.$ || this.$.isReady) {
if (!hasDOM || this.documentReadyState() !== 'loading') {
schedule('actions', this, 'domReady');
} else {
this.$().ready(bind(this, 'domReady'));
let callback = function() {
document.removeEventListener('DOMContentLoaded', callback);
this.domReady();
};

document.addEventListener('DOMContentLoaded', bind(this, callback));
}
},

documentReadyState() {
return document && document.readyState;
},

/**
This is the autoboot flow:
Expand Down
78 changes: 33 additions & 45 deletions packages/@ember/application/tests/readiness_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,26 @@ import { moduleFor, ModuleBasedTestResolver, ApplicationTestCase } from 'interna
import { run } from '@ember/runloop';
import EmberApplication from '..';

let jQuery, application, Application;
let readyWasCalled, domReady, readyCallbacks;
let application, Application;
let readyWasCalled = 0;

let triggerEvent = eventName => {
let eventToDispatch;

if (typeof window.Event === 'function') {
// eslint-disable-next-line no-undef
eventToDispatch = new Event(eventName, {
bubbles: true,
cancelable: true,
});
} else {
// IE support
eventToDispatch = document.createEvent('Event');
eventToDispatch.initEvent(eventName, true, true);
}

document.dispatchEvent(eventToDispatch);
};

// We are using a small mock of jQuery because jQuery is third-party code with
// very well-defined semantics, and we want to confirm that a jQuery stub run
Expand All @@ -15,39 +33,11 @@ moduleFor(
constructor() {
super();

readyWasCalled = 0;
readyCallbacks = [];

let jQueryInstance = {
ready(callback) {
readyCallbacks.push(callback);
if (jQuery.isReady) {
domReady();
}
},
};

jQuery = function() {
return jQueryInstance;
};
jQuery.isReady = false;

let domReadyCalled = 0;
domReady = function() {
if (domReadyCalled !== 0) {
return;
}
domReadyCalled++;
for (let i = 0; i < readyCallbacks.length; i++) {
readyCallbacks[i]();
}
};

Application = EmberApplication.extend({
$: jQuery,
Resolver: ModuleBasedTestResolver,

ready() {
this._super();
readyWasCalled++;
},
});
Expand All @@ -56,52 +46,50 @@ moduleFor(
teardown() {
if (application) {
run(() => application.destroy());
jQuery = readyCallbacks = domReady = Application = application = undefined;
Application = application = undefined;
readyWasCalled = 0;
}
}

// These tests are confirming that if the callbacks passed into jQuery's ready hook is called
// synchronously during the application's initialization, we get the same behavior as if
// it was triggered after initialization.

["@test Application's ready event is called right away if jQuery is already ready"](assert) {
jQuery.isReady = true;

["@test Application's ready event is called right away if DOM is already ready"](assert) {
run(() => {
application = Application.create({ router: false });
application = Application.create({
router: false,
documentReadyState: () => 'interactive',
});

assert.equal(readyWasCalled, 0, 'ready is not called until later');
});

assert.equal(readyWasCalled, 1, 'ready was called');

domReady();
application.domReady();

assert.equal(readyWasCalled, 1, "application's ready was not called again");
}

["@test Application's ready event is called after the document becomes ready"](assert) {
run(() => {
application = Application.create({ router: false });
application = Application.create({ router: false, documentReadyState: () => 'loading' });
});

assert.equal(readyWasCalled, 0, "ready wasn't called yet");

domReady();
triggerEvent('DOMContentLoaded');

assert.equal(readyWasCalled, 1, 'ready was called now that DOM is ready');
}

["@test Application's ready event can be deferred by other components"](assert) {
run(() => {
application = Application.create({ router: false });
application = Application.create({ router: false, documentReadyState: () => 'loading' });
application.deferReadiness();
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
});

assert.equal(readyWasCalled, 0, "ready wasn't called yet");

domReady();
application.domReady();

assert.equal(readyWasCalled, 0, "ready wasn't called yet");

Expand Down

0 comments on commit 18ad68e

Please sign in to comment.