From 56a1da5b3b56ed84f6de2193a4fb0c01c0c7d4f2 Mon Sep 17 00:00:00 2001 From: Volodymyr Radchenko Date: Sun, 20 Sep 2020 09:44:32 +0300 Subject: [PATCH 1/2] CHORE: combine two test cases into one Since `jQuery.isReady = false;` is set before each test case. --- .../application/tests/readiness_test.js | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/@ember/application/tests/readiness_test.js b/packages/@ember/application/tests/readiness_test.js index 97a1406346e..1368671c0a1 100644 --- a/packages/@ember/application/tests/readiness_test.js +++ b/packages/@ember/application/tests/readiness_test.js @@ -96,6 +96,7 @@ moduleFor( run(() => { application = Application.create({ router: false }); application.deferReadiness(); + assert.equal(readyWasCalled, 0, "ready wasn't called yet"); }); assert.equal(readyWasCalled, 0, "ready wasn't called yet"); @@ -110,28 +111,6 @@ moduleFor( }); assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced'); - } - - ["@test Application's ready event can be deferred by other components (jQuery.isReady === false)"]( - assert - ) { - jQuery.isReady = false; - - run(() => { - application = Application.create({ router: false }); - application.deferReadiness(); - assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - }); - - domReady(); - - assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - - run(() => { - application.advanceReadiness(); - }); - - assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced'); expectAssertion(() => { application.deferReadiness(); From 88c59a4be85d0b83cc1ac807ea14a95a8f315a54 Mon Sep 17 00:00:00 2001 From: Volodymyr Radchenko Date: Thu, 10 Sep 2020 13:29:39 +0300 Subject: [PATCH 2/2] [BUGFIX beta] reimplement $.ready() --- .../@ember/application/lib/application.js | 20 ++++- .../application/tests/readiness_test.js | 86 +++++++++---------- tests/docs/expected.js | 1 + 3 files changed, 60 insertions(+), 47 deletions(-) diff --git a/packages/@ember/application/lib/application.js b/packages/@ember/application/lib/application.js index 13183a45ad2..5721e0fe011 100644 --- a/packages/@ember/application/lib/application.js +++ b/packages/@ember/application/lib/application.js @@ -7,7 +7,7 @@ import { ENV } from '@ember/-internals/environment'; import { hasDOM } from '@ember/-internals/browser-environment'; import { assert, isTesting } from '@ember/debug'; import { DEBUG } from '@glimmer/env'; -import { bind, join, once, run, schedule } from '@ember/runloop'; +import { join, once, run, schedule } from '@ember/runloop'; import { libraries, processAllNamespaces, @@ -205,6 +205,15 @@ const Application = Engine.extend({ */ rootElement: 'body', + /** + + @property _document + @type Document | null + @default 'window.document' + @private + */ + _document: hasDOM ? window.document : null, + /** The `Ember.EventDispatcher` responsible for delegating events to this application's views. @@ -483,10 +492,15 @@ const Application = Engine.extend({ @method waitForDOMReady */ waitForDOMReady() { - if (!this.$ || this.$.isReady) { + if (this._document === null || this._document.readyState !== 'loading') { schedule('actions', this, 'domReady'); } else { - this.$().ready(bind(this, 'domReady')); + let callback = () => { + this._document.removeEventListener('DOMContentLoaded', callback); + run(this, 'domReady'); + }; + + this._document.addEventListener('DOMContentLoaded', callback); } }, diff --git a/packages/@ember/application/tests/readiness_test.js b/packages/@ember/application/tests/readiness_test.js index 1368671c0a1..ba66745404d 100644 --- a/packages/@ember/application/tests/readiness_test.js +++ b/packages/@ember/application/tests/readiness_test.js @@ -2,52 +2,39 @@ 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, _document, callbacks; +let readyWasCalled = 0; + +const dispatchEvent = (eventName) => { + callbacks[eventName].forEach((callback) => callback()); +}; + +const removeEventListener = (eventName, callbackToRemove) => { + callbacks[eventName] = callbacks[eventName].filter((callback) => callback !== callbackToRemove); +}; + +const addEventListener = (eventName, callback) => { + callbacks[eventName] ? callbacks[eventName].push(callback) : (callbacks[eventName] = [callback]); +}; -// 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 -// in a more minimal server environment that implements this behavior will be -// sufficient for Ember's requirements. moduleFor( 'Application readiness', class extends ApplicationTestCase { 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](); - } + callbacks = []; + _document = { + removeEventListener, + addEventListener, }; Application = EmberApplication.extend({ - $: jQuery, Resolver: ModuleBasedTestResolver, + _document, ready() { + this._super(); readyWasCalled++; }, }); @@ -56,52 +43,59 @@ moduleFor( teardown() { if (application) { run(() => application.destroy()); - jQuery = readyCallbacks = domReady = Application = application = undefined; + Application = application = _document = callbacks = 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) { + _document.readyState = 'interactive'; run(() => { - application = Application.create({ router: false }); + application = Application.create({ + router: false, + }); assert.equal(readyWasCalled, 0, 'ready is not called until later'); }); assert.equal(readyWasCalled, 1, 'ready was called'); - domReady(); + application.domReady(); + assert.equal(callbacks['DOMContentLoaded'], undefined); assert.equal(readyWasCalled, 1, "application's ready was not called again"); } ["@test Application's ready event is called after the document becomes ready"](assert) { + _document.readyState = 'loading'; + run(() => { application = Application.create({ router: false }); + assert.equal(callbacks['DOMContentLoaded'].length, 1); }); assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - domReady(); + dispatchEvent('DOMContentLoaded'); + assert.equal(callbacks['DOMContentLoaded'].length, 0); assert.equal(readyWasCalled, 1, 'ready was called now that DOM is ready'); } ["@test Application's ready event can be deferred by other components"](assert) { + _document.readyState = 'loading'; + run(() => { application = Application.create({ router: false }); application.deferReadiness(); assert.equal(readyWasCalled, 0, "ready wasn't called yet"); + assert.equal(callbacks['DOMContentLoaded'].length, 1); }); assert.equal(readyWasCalled, 0, "ready wasn't called yet"); - domReady(); + application.domReady(); assert.equal(readyWasCalled, 0, "ready wasn't called yet"); @@ -112,6 +106,10 @@ moduleFor( assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced'); + dispatchEvent('DOMContentLoaded'); + + assert.equal(callbacks['DOMContentLoaded'].length, 0); + expectAssertion(() => { application.deferReadiness(); }); diff --git a/tests/docs/expected.js b/tests/docs/expected.js index f0e0e5ae1c2..e68d3ccdad1 100644 --- a/tests/docs/expected.js +++ b/tests/docs/expected.js @@ -22,6 +22,7 @@ module.exports = { '_applicationInstances', '_deserializeQueryParam', '_deserializeQueryParams', + '_document', '_fullyScopeQueryParams', '_getHashPath', '_getObjectsOnNamespaces',