From 0dc02ac285977fd14e776d362c6fafeeae1b4cfa Mon Sep 17 00:00:00 2001 From: Godfrey Chan Date: Wed, 27 May 2015 02:09:11 -0700 Subject: [PATCH] Instance initializers should run before `App.ready` The original complaint is that routing begins before instance initializers are run, which means that some routes instances are created *before* the instance initializers are run, which means that you cannot reliably setup injections for routes in instance initializers, which are important for e.g. `store:main`. Since `App.ready` is guaranteed to run before routing begins, this effectively guarantees that instance initializers are run before routing begins. Fixes #11172 --- .../lib/system/application.js | 29 ++++++++------- .../tests/system/application_test.js | 35 +++++++++++++++++++ .../system/instance_initializers_test.js | 27 ++++++++++++++ 3 files changed, 76 insertions(+), 15 deletions(-) diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index 42cd0e07162..443ec59e1d4 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -291,11 +291,13 @@ var Application = Namespace.extend(DeferredMixin, { // tamper with the default `Ember.Router`. // 2.0TODO: Can we move this into a globals-mode-only library? this.Router = (this.Router || Router).extend(); - this.waitForDOMReady(this.buildDefaultInstance()); + this.buildDefaultInstance(); + this.waitForDOMReady(); } } else { this.Router = (this.Router || Router).extend(); - this.waitForDOMReady(this.buildDefaultInstance()); + this.buildDefaultInstance(); + this.waitForDOMReady(); } }, @@ -357,13 +359,13 @@ var Application = Namespace.extend(DeferredMixin, { loading. @private - @method scheduleInitialize + @method waitForDOMReady */ - waitForDOMReady(_instance) { + waitForDOMReady() { if (!this.$ || this.$.isReady) { - run.schedule('actions', this, 'domReady', _instance); + run.schedule('actions', this, 'domReady'); } else { - this.$().ready(run.bind(this, 'domReady', _instance)); + this.$().ready(run.bind(this, 'domReady')); } }, @@ -552,16 +554,12 @@ var Application = Namespace.extend(DeferredMixin, { to defer readiness until the auth token has been retrieved. @private - @method _initialize + @method domReady */ - domReady(_instance) { + domReady() { if (this.isDestroyed) { return; } - var app = this; - - this.boot().then(function() { - app.runInstanceInitializers(_instance); - }); + this.boot(); return this; }, @@ -718,6 +716,7 @@ var Application = Namespace.extend(DeferredMixin, { this.__deprecatedInstance__.setupEventDispatcher(); } + this.runInstanceInitializers(this.__deprecatedInstance__); this.ready(); // user hook this.__deprecatedInstance__.startRouting(); @@ -734,8 +733,8 @@ var Application = Namespace.extend(DeferredMixin, { }, /** - Called when the Application has become ready. - The call will be delayed until the DOM has become ready. + Called when the Application has become ready, immediately before routing + begins. The call will be delayed until the DOM has become ready. @event ready */ diff --git a/packages/ember-application/tests/system/application_test.js b/packages/ember-application/tests/system/application_test.js index ad4908db081..ebf94068b7c 100644 --- a/packages/ember-application/tests/system/application_test.js +++ b/packages/ember-application/tests/system/application_test.js @@ -9,6 +9,7 @@ import View from "ember-views/views/view"; import Controller from "ember-runtime/controllers/controller"; import NoneLocation from "ember-routing/location/none_location"; import EmberObject from "ember-runtime/system/object"; +import EmberRoute from "ember-routing/system/route"; import jQuery from "ember-views/system/jquery"; import compile from "ember-template-compiler/system/compile"; @@ -127,6 +128,40 @@ QUnit.test('initialized application go to initial route', function() { equal(jQuery('#qunit-fixture h1').text(), "Hi from index"); }); +QUnit.test("ready hook is called before routing begins", function() { + expect(2); + + run(function() { + function registerRoute(application, name, callback) { + var route = EmberRoute.extend({ + activate: callback + }); + + application.register('route:' + name, route); + } + + var MyApplication = Application.extend({ + ready() { + registerRoute(this, 'index', function() { + ok(true, 'last-minite route is activated'); + }); + } + }); + + app = MyApplication.create({ + rootElement: '#qunit-fixture' + }); + + app.Router.reopen({ + location: 'none' + }); + + registerRoute(app, 'application', function() { + ok(true, 'normal route is activated'); + }); + }); +}); + QUnit.test("initialize application via initialize call", function() { run(function() { app = Application.create({ diff --git a/packages/ember-application/tests/system/instance_initializers_test.js b/packages/ember-application/tests/system/instance_initializers_test.js index 02731bce6c9..0bdfa71ab37 100644 --- a/packages/ember-application/tests/system/instance_initializers_test.js +++ b/packages/ember-application/tests/system/instance_initializers_test.js @@ -340,6 +340,33 @@ if (Ember.FEATURES.isEnabled('ember-application-instance-initializers')) { }); }); + QUnit.test("initializers are run before ready hook", function() { + expect(2); + + var readyWasCalled = false; + + var MyApplication = Application.extend({ + ready() { + ok(true, 'ready is called'); + readyWasCalled = true; + } + }); + + MyApplication.instanceInitializer({ + name: 'initializer', + initialize() { + ok(!readyWasCalled, 'ready is not yet called'); + } + }); + + run(function() { + app = MyApplication.create({ + router: false, + rootElement: '#qunit-fixture' + }); + }); + }); + if (initializeContextFeatureEnabled) { QUnit.test("initializers should be executed in their own context", function() { expect(1);