From b9af5567cbc69708b8378d3461d6649067782eea Mon Sep 17 00:00:00 2001 From: Shashwat <91shashwat@gmail.com> Date: Sun, 13 Mar 2016 00:52:56 +0100 Subject: [PATCH] Removed 'ember-application-visit' --- FEATURES.md | 10 +- features.json | 1 - .../lib/system/application-instance.js | 521 +++++++------ .../lib/system/application.js | 410 +++++----- .../tests/system/initializers_test.js | 65 +- .../tests/system/visit_test.js | 711 +++++++++--------- packages/ember-routing/lib/system/route.js | 6 +- .../ember-views/lib/mixins/view_support.js | 30 +- .../ember-views/tests/views/component_test.js | 12 - 9 files changed, 842 insertions(+), 924 deletions(-) diff --git a/FEATURES.md b/FEATURES.md index 17bd5b643dd..40d8d0c422a 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -10,14 +10,6 @@ for a detailed explanation. Add `isRegistered` to `Ember.libraries`. This convenience method checks whether a library is registered with Ember or not. -* `ember-application-visit` - - Provides an API for creating an application instance and specifying - an initial URL that it should route to. This is useful for testing - (you can have multiple instances of an app without having to run - serially and call `reset()` each time), as well as being critical to - for FastBoot. - * `ember-routing-routable-components` Implements RFC https://github.com/emberjs/rfcs/pull/38, adding support for @@ -37,4 +29,4 @@ for a detailed explanation. * `ember-test-helpers-fire-native-events` Makes ember test helpers (`fillIn`, `click`, `triggerEvent` ...) fire native javascript events instead - of `jQuery.Event`s, maching more closely app's real usage. \ No newline at end of file + of `jQuery.Event`s, maching more closely app's real usage. diff --git a/features.json b/features.json index ec317b21140..c6f5d40401d 100644 --- a/features.json +++ b/features.json @@ -1,7 +1,6 @@ { "features": { "features-stripped-test": null, - "ember-application-visit": true, "ember-test-helpers-fire-native-events": true, "ember-routing-route-configured-query-params": null, "ember-libraries-isregistered": null, diff --git a/packages/ember-application/lib/system/application-instance.js b/packages/ember-application/lib/system/application-instance.js index 0487a97a7bf..cd32fceb507 100644 --- a/packages/ember-application/lib/system/application-instance.js +++ b/packages/ember-application/lib/system/application-instance.js @@ -4,7 +4,6 @@ */ import { deprecate } from 'ember-metal/debug'; -import isEnabled from 'ember-metal/features'; import { get } from 'ember-metal/property_get'; import { set } from 'ember-metal/property_set'; import symbol from 'ember-metal/symbol'; @@ -83,12 +82,6 @@ const ApplicationInstance = EngineInstance.extend({ init() { this._super(...arguments); - let application = this.application; - - if (!isEnabled('ember-application-visit')) { - set(this, 'rootElement', get(application, 'rootElement')); - } - // Register this instance in the per-instance registry. // // Why do we need to register the instance in the first place? @@ -138,39 +131,31 @@ const ApplicationInstance = EngineInstance.extend({ _bootSync(options) { if (this._booted) { return this; } - if (isEnabled('ember-application-visit')) { - options = new BootOptions(options); + options = new BootOptions(options); - let registry = this.__registry__; + let registry = this.__registry__; - registry.register('-environment:main', options.toEnvironment(), { instantiate: false }); - registry.injection('view', '_environment', '-environment:main'); - registry.injection('route', '_environment', '-environment:main'); + registry.register('-environment:main', options.toEnvironment(), { instantiate: false }); + registry.injection('view', '_environment', '-environment:main'); + registry.injection('route', '_environment', '-environment:main'); - registry.register('renderer:-dom', options.renderer); + registry.register('renderer:-dom', options.renderer); - if (options.rootElement) { - this.rootElement = options.rootElement; - } else { - this.rootElement = this.application.rootElement; - } + if (options.rootElement) { + this.rootElement = options.rootElement; + } else { + this.rootElement = this.application.rootElement; + } - if (options.location) { - let router = get(this, 'router'); - set(router, 'location', options.location); - } + if (options.location) { + let router = get(this, 'router'); + set(router, 'location', options.location); + } - this.application.runInstanceInitializers(this); + this.application.runInstanceInitializers(this); - if (options.isInteractive) { - this.setupEventDispatcher(); - } - } else { - this.application.runInstanceInitializers(this); - - if (environment.hasDOM) { - this.setupEventDispatcher(); - } + if (options.isInteractive) { + this.setupEventDispatcher(); } this._booted = true; @@ -254,275 +239,271 @@ const ApplicationInstance = EngineInstance.extend({ dispatcher.setup(customEvents, this.rootElement); return dispatcher; + }, + + /** + Returns the current URL of the app instance. This is useful when your + app does not update the browsers URL bar (i.e. it uses the `'none'` + location adapter). + + @public + @return {String} the current URL + */ + getURL() { + let router = get(this, 'router'); + return get(router, 'url'); + }, + + // `instance.visit(url)` should eventually replace `instance.handleURL()`; + // the test helpers can probably be switched to use this implementation too + + /** + Navigate the instance to a particular URL. This is useful in tests, for + example, or to tell the app to start at a particular URL. This method + returns a promise that resolves with the app instance when the transition + is complete, or rejects if the transion was aborted due to an error. + + @public + @param url {String} the destination URL + @return {Promise} + */ + visit(url) { + this.setupRouter(); + + let router = get(this, 'router'); + + let handleResolve = () => { + // Resolve only after rendering is complete + return new RSVP.Promise((resolve) => { + // TODO: why is this necessary? Shouldn't 'actions' queue be enough? + // Also, aren't proimses supposed to be async anyway? + run.next(null, resolve, this); + }); + }; + + let handleReject = (error) => { + if (error.error) { + throw error.error; + } else if (error.name === 'TransitionAborted' && router.router.activeTransition) { + return router.router.activeTransition.then(handleResolve, handleReject); + } else if (error.name === 'TransitionAborted') { + throw new Error(error.message); + } else { + throw error; + } + }; + + // Keeps the location adapter's internal URL in-sync + get(router, 'location').setURL(url); + + return router.handleURL(url).then(handleResolve, handleReject); } }); -if (isEnabled('ember-application-visit')) { - ApplicationInstance.reopen({ - /** - Returns the current URL of the app instance. This is useful when your - app does not update the browsers URL bar (i.e. it uses the `'none'` - location adapter). - - @public - @return {String} the current URL - */ - getURL() { - let router = get(this, 'router'); - return get(router, 'url'); - }, +/** + A list of boot-time configuration options for customizing the behavior of + an `Ember.ApplicationInstance`. - // `instance.visit(url)` should eventually replace `instance.handleURL()`; - // the test helpers can probably be switched to use this implementation too + This is an interface class that exists purely to document the available + options; you do not need to construct it manually. Simply pass a regular + JavaScript object containing the desired options into methods that require + one of these options object: - /** - Navigate the instance to a particular URL. This is useful in tests, for - example, or to tell the app to start at a particular URL. This method - returns a promise that resolves with the app instance when the transition - is complete, or rejects if the transion was aborted due to an error. + ```javascript + MyApp.visit("/", { location: "none", rootElement: "#container" }); + ``` - @public - @param url {String} the destination URL - @return {Promise} - */ - visit(url) { - this.setupRouter(); + Not all combinations of the supported options are valid. See the documentation + on `Ember.Application#visit` for the supported configurations. - let router = get(this, 'router'); + Internal, experimental or otherwise unstable flags are marked as private. - let handleResolve = () => { - // Resolve only after rendering is complete - return new RSVP.Promise((resolve) => { - // TODO: why is this necessary? Shouldn't 'actions' queue be enough? - // Also, aren't proimses supposed to be async anyway? - run.next(null, resolve, this); - }); - }; - - let handleReject = (error) => { - if (error.error) { - throw error.error; - } else if (error.name === 'TransitionAborted' && router.router.activeTransition) { - return router.router.activeTransition.then(handleResolve, handleReject); - } else if (error.name === 'TransitionAborted') { - throw new Error(error.message); - } else { - throw error; - } - }; - - // Keeps the location adapter's internal URL in-sync - get(router, 'location').setURL(url); - - return router.handleURL(url).then(handleResolve, handleReject); - } - }); + @class BootOptions + @namespace Ember.ApplicationInstance + @public +*/ +BootOptions = function BootOptions(options = {}) { + let internalOptions = options[INTERNAL_BOOT_OPTIONS] || {}; + + this.renderer = null; /** - A list of boot-time configuration options for customizing the behavior of - an `Ember.ApplicationInstance`. + Provide a specific instance of jQuery. This is useful in conjunction with + the `document` option, as it allows you to use a copy of `jQuery` that is + appropriately bound to the foreign `document` (e.g. a jsdom). - This is an interface class that exists purely to document the available - options; you do not need to construct it manually. Simply pass a regular - JavaScript object containing the desired options into methods that require - one of these options object: + This is highly experimental and support very incomplete at the moment. - ```javascript - MyApp.visit("/", { location: "none", rootElement: "#container" }); - ``` + @property jQuery + @type Object + @default auto-detected + @private + */ + this.jQuery = jQuery; // This default is overridable below - Not all combinations of the supported options are valid. See the documentation - on `Ember.Application#visit` for the supported configurations. + /** + Interactive mode: whether we need to set up event delegation and invoke + lifecycle callbacks on Components. - Internal, experimental or otherwise unstable flags are marked as private. + @property isInteractive + @type boolean + @default auto-detected + @private + */ + this.isInteractive = environment.hasDOM; // This default is overridable below + + /** + Run in a full browser environment. + + When this flag is set to `false`, it will disable most browser-specific + and interactive features. Specifically: + + * It does not use `jQuery` to append the root view; the `rootElement` + (either specified as a subsequent option or on the application itself) + must already be an `Element` in the given `document` (as opposed to a + string selector). + + * It does not set up an `EventDispatcher`. + + * It does not run any `Component` lifecycle hooks (such as `didInsertElement`). - @class BootOptions - @namespace Ember.ApplicationInstance + * It sets the `location` option to `"none"`. (If you would like to use + the location adapter specified in the app's router instead, you can also + specify `{ location: null }` to specifically opt-out.) + + @property isBrowser + @type boolean + @default auto-detected @public */ - BootOptions = function BootOptions(options = {}) { - let internalOptions = options[INTERNAL_BOOT_OPTIONS] || {}; - - this.renderer = null; - - /** - Provide a specific instance of jQuery. This is useful in conjunction with - the `document` option, as it allows you to use a copy of `jQuery` that is - appropriately bound to the foreign `document` (e.g. a jsdom). - - This is highly experimental and support very incomplete at the moment. - - @property jQuery - @type Object - @default auto-detected - @private - */ - this.jQuery = jQuery; // This default is overridable below - - /** - Interactive mode: whether we need to set up event delegation and invoke - lifecycle callbacks on Components. - - @property isInteractive - @type boolean - @default auto-detected - @private - */ - this.isInteractive = environment.hasDOM; // This default is overridable below - - /** - Run in a full browser environment. - - When this flag is set to `false`, it will disable most browser-specific - and interactive features. Specifically: - - * It does not use `jQuery` to append the root view; the `rootElement` - (either specified as a subsequent option or on the application itself) - must already be an `Element` in the given `document` (as opposed to a - string selector). - - * It does not set up an `EventDispatcher`. - - * It does not run any `Component` lifecycle hooks (such as `didInsertElement`). - - * It sets the `location` option to `"none"`. (If you would like to use - the location adapter specified in the app's router instead, you can also - specify `{ location: null }` to specifically opt-out.) - - @property isBrowser - @type boolean - @default auto-detected - @public - */ - if (options.isBrowser !== undefined) { - this.isBrowser = !!options.isBrowser; - } else { - this.isBrowser = environment.hasDOM; - } + if (options.isBrowser !== undefined) { + this.isBrowser = !!options.isBrowser; + } else { + this.isBrowser = environment.hasDOM; + } - if (!this.isBrowser) { - this.jQuery = null; - this.isInteractive = false; - this.location = 'none'; - } + if (!this.isBrowser) { + this.jQuery = null; + this.isInteractive = false; + this.location = 'none'; + } - /** - Disable rendering completely. + /** + Disable rendering completely. - When this flag is set to `true`, it will disable the entire rendering - pipeline. Essentially, this puts the app into "routing-only" mode. No - templates will be rendered, and no Components will be created. + When this flag is set to `true`, it will disable the entire rendering + pipeline. Essentially, this puts the app into "routing-only" mode. No + templates will be rendered, and no Components will be created. - @property shouldRender - @type boolean - @default true - @public - */ - if (options.shouldRender !== undefined) { - this.shouldRender = !!options.shouldRender; - } else { - this.shouldRender = true; - } + @property shouldRender + @type boolean + @default true + @public + */ + if (options.shouldRender !== undefined) { + this.shouldRender = !!options.shouldRender; + } else { + this.shouldRender = true; + } - if (!this.shouldRender) { - this.jQuery = null; - this.isInteractive = false; - } + if (!this.shouldRender) { + this.jQuery = null; + this.isInteractive = false; + } - /** - If present, render into the given `Document` object instead of the - global `window.document` object. - - In practice, this is only useful in non-browser environment or in - non-interactive mode, because Ember's `jQuery` dependency is - implicitly bound to the current document, causing event delegation - to not work properly when the app is rendered into a foreign - document object (such as an iframe's `contentDocument`). - - In non-browser mode, this could be a "`Document`-like" object as - Ember only interact with a small subset of the DOM API in non- - interactive mode. While the exact requirements have not yet been - formalized, the `SimpleDOM` library's implementation is known to - work. - - @property document - @type Document - @default the global `document` object - @public - */ - if (options.document) { - this.document = options.document; - } else { - this.document = (typeof document !== 'undefined') ? document : null; - } + /** + If present, render into the given `Document` object instead of the + global `window.document` object. + + In practice, this is only useful in non-browser environment or in + non-interactive mode, because Ember's `jQuery` dependency is + implicitly bound to the current document, causing event delegation + to not work properly when the app is rendered into a foreign + document object (such as an iframe's `contentDocument`). + + In non-browser mode, this could be a "`Document`-like" object as + Ember only interact with a small subset of the DOM API in non- + interactive mode. While the exact requirements have not yet been + formalized, the `SimpleDOM` library's implementation is known to + work. + + @property document + @type Document + @default the global `document` object + @public + */ + if (options.document) { + this.document = options.document; + } else { + this.document = (typeof document !== 'undefined') ? document : null; + } - /** - If present, overrides the application's `rootElement` property on - the instance. This is useful for testing environment, where you - might want to append the root view to a fixture area. + /** + If present, overrides the application's `rootElement` property on + the instance. This is useful for testing environment, where you + might want to append the root view to a fixture area. - In non-browser mode, because Ember does not have access to jQuery, - this options must be specified as a DOM `Element` object instead of - a selector string. + In non-browser mode, because Ember does not have access to jQuery, + this options must be specified as a DOM `Element` object instead of + a selector string. - See the documentation on `Ember.Applications`'s `rootElement` for - details. + See the documentation on `Ember.Applications`'s `rootElement` for + details. - @property rootElement - @type String|Element - @default null - @public - */ - if (options.rootElement) { - this.rootElement = options.rootElement; - } + @property rootElement + @type String|Element + @default null + @public + */ + if (options.rootElement) { + this.rootElement = options.rootElement; + } - // Set these options last to give the user a chance to override the - // defaults from the "combo" options like `isBrowser` (although in - // practice, the resulting combination is probably invalid) - - /** - If present, overrides the router's `location` property with this - value. This is useful for environments where trying to modify the - URL would be inappropriate. - - @property location - @type string - @default null - @public - */ - if (options.location !== undefined) { - this.location = options.location; - } + // Set these options last to give the user a chance to override the + // defaults from the "combo" options like `isBrowser` (although in + // practice, the resulting combination is probably invalid) - if (options.jQuery !== undefined) { - this.jQuery = options.jQuery; - } + /** + If present, overrides the router's `location` property with this + value. This is useful for environments where trying to modify the + URL would be inappropriate. - if (options.isInteractive !== undefined) { - this.isInteractive = !!options.isInteractive; - } + @property location + @type string + @default null + @public + */ + if (options.location !== undefined) { + this.location = options.location; + } + if (options.jQuery !== undefined) { + this.jQuery = options.jQuery; + } - if (internalOptions.renderer) { - this.renderer = internalOptions.renderer; - } else { - this.renderer = { - create() { - return new Renderer(new DOMHelper(options.document), { destinedForDOM: options.isInteractive }); - } - }; - } - }; - - BootOptions.prototype.toEnvironment = function() { - let env = assign({}, environment); - // For compatibility with existing code - env.hasDOM = this.isBrowser; - env.options = this; - return env; - }; -} + if (options.isInteractive !== undefined) { + this.isInteractive = !!options.isInteractive; + } + + + if (internalOptions.renderer) { + this.renderer = internalOptions.renderer; + } else { + this.renderer = { + create() { + return new Renderer(new DOMHelper(options.document), { destinedForDOM: options.isInteractive }); + } + }; + } +}; + +BootOptions.prototype.toEnvironment = function() { + let env = assign({}, environment); + // For compatibility with existing code + env.hasDOM = this.isBrowser; + env.options = this; + return env; +}; Object.defineProperty(ApplicationInstance.prototype, 'container', { configurable: true, diff --git a/packages/ember-application/lib/system/application.js b/packages/ember-application/lib/system/application.js index 42cba32889e..03fd17eb993 100644 --- a/packages/ember-application/lib/system/application.js +++ b/packages/ember-application/lib/system/application.js @@ -4,7 +4,6 @@ */ import Ember from 'ember-metal'; // Ember.libraries, LOG_VERSION, Namespace, BOOTED import { assert, debug, deprecate } from 'ember-metal/debug'; -import isEnabled from 'ember-metal/features'; import { get } from 'ember-metal/property_get'; import { runLoadHooks } from 'ember-runtime/system/lazy_load'; import run from 'ember-metal/run_loop'; @@ -363,22 +362,13 @@ const Application = Engine.extend({ this._readinessDeferrals = 1; this._booted = false; - if (isEnabled('ember-application-visit')) { - this.autoboot = this._globalsMode = !!this.autoboot; - - if (this._globalsMode) { - this._prepareForGlobalsMode(); - } - - if (this.autoboot) { - this.waitForDOMReady(); - } - } else { - // Force-assign these flags to their default values when the feature is - // disabled, this ensures we can rely on their values in other paths. - this.autoboot = this._globalsMode = true; + this.autoboot = this._globalsMode = !!this.autoboot; + if (this._globalsMode) { this._prepareForGlobalsMode(); + } + + if (this.autoboot) { this.waitForDOMReady(); } }, @@ -751,35 +741,27 @@ const Application = Engine.extend({ Ember.BOOTED = true; } - if (isEnabled('ember-application-visit')) { - // See documentation on `_autoboot()` for details - if (this.autoboot) { - let instance; - - if (this._globalsMode) { - // If we already have the __deprecatedInstance__ lying around, boot it to - // avoid unnecessary work - instance = this.__deprecatedInstance__; - } else { - // Otherwise, build an instance and boot it. This is currently unreachable, - // because we forced _globalsMode to === autoboot; but having this branch - // allows us to locally toggle that flag for weeding out legacy globals mode - // dependencies independently - instance = this.buildInstance(); - } - - instance._bootSync(); - - // TODO: App.ready() is not called when autoboot is disabled, is this correct? - this.ready(); - - instance.startRouting(); + // See documentation on `_autoboot()` for details + if (this.autoboot) { + let instance; + + if (this._globalsMode) { + // If we already have the __deprecatedInstance__ lying around, boot it to + // avoid unnecessary work + instance = this.__deprecatedInstance__; + } else { + // Otherwise, build an instance and boot it. This is currently unreachable, + // because we forced _globalsMode to === autoboot; but having this branch + // allows us to locally toggle that flag for weeding out legacy globals mode + // dependencies independently + instance = this.buildInstance(); } - } else { - let instance = this.__deprecatedInstance__; instance._bootSync(); + + // TODO: App.ready() is not called when autoboot is disabled, is this correct? this.ready(); + instance.startRouting(); } @@ -821,225 +803,221 @@ const Application = Engine.extend({ if (this._globalsMode && this.__deprecatedInstance__) { this.__deprecatedInstance__.destroy(); } - } -}); + }, -Object.defineProperty(Application.prototype, 'registry', { - configurable: true, - enumerable: false, - get() { - return buildFakeRegistryWithDeprecations(this, 'Application'); - } -}); + /** + Boot a new instance of `Ember.ApplicationInstance` for the current + application and navigate it to the given `url`. Returns a `Promise` that + resolves with the instance when the initial routing and rendering is + complete, or rejects with any error that occured during the boot process. -if (isEnabled('ember-application-visit')) { - Application.reopen({ - /** - Boot a new instance of `Ember.ApplicationInstance` for the current - application and navigate it to the given `url`. Returns a `Promise` that - resolves with the instance when the initial routing and rendering is - complete, or rejects with any error that occured during the boot process. + When `autoboot` is disabled, calling `visit` would first cause the + application to boot, which runs the application initializers. - When `autoboot` is disabled, calling `visit` would first cause the - application to boot, which runs the application initializers. + This method also takes a hash of boot-time configuration options for + customizing the instance's behavior. See the documentation on + `Ember.ApplicationInstance.BootOptions` for details. - This method also takes a hash of boot-time configuration options for - customizing the instance's behavior. See the documentation on - `Ember.ApplicationInstance.BootOptions` for details. + `Ember.ApplicationInstance.BootOptions` is an interface class that exists + purely to document the available options; you do not need to construct it + manually. Simply pass a regular JavaScript object containing of the + desired options: - `Ember.ApplicationInstance.BootOptions` is an interface class that exists - purely to document the available options; you do not need to construct it - manually. Simply pass a regular JavaScript object containing of the - desired options: + ```javascript + MyApp.visit("/", { location: "none", rootElement: "#container" }); + ``` - ```javascript - MyApp.visit("/", { location: "none", rootElement: "#container" }); - ``` + ### Supported Scenarios - ### Supported Scenarios + While the `BootOptions` class exposes a large number of knobs, not all + combinations of them are valid; certain incompatible combinations might + result in unexpected behavior. - While the `BootOptions` class exposes a large number of knobs, not all - combinations of them are valid; certain incompatible combinations might - result in unexpected behavior. + For example, booting the instance in the full browser environment + while specifying a foriegn `document` object (e.g. `{ isBrowser: true, + document: iframe.contentDocument }`) does not work correctly today, + largely due to Ember's jQuery dependency. - For example, booting the instance in the full browser environment - while specifying a foriegn `document` object (e.g. `{ isBrowser: true, - document: iframe.contentDocument }`) does not work correctly today, - largely due to Ember's jQuery dependency. + Currently, there are three officially supported scenarios/configurations. + Usages outside of these scenarios are not guaranteed to work, but please + feel free to file bug reports documenting your experience and any issues + you encountered to help expand support. - Currently, there are three officially supported scenarios/configurations. - Usages outside of these scenarios are not guaranteed to work, but please - feel free to file bug reports documenting your experience and any issues - you encountered to help expand support. + #### Browser Applications (Manual Boot) - #### Browser Applications (Manual Boot) + The setup is largely similar to how Ember works out-of-the-box. Normally, + Ember will boot a default instance for your Application on "DOM ready". + However, you can customize this behavior by disabling `autoboot`. - The setup is largely similar to how Ember works out-of-the-box. Normally, - Ember will boot a default instance for your Application on "DOM ready". - However, you can customize this behavior by disabling `autoboot`. + For example, this allows you to render a miniture demo of your application + into a specific area on your marketing website: - For example, this allows you to render a miniture demo of your application - into a specific area on your marketing website: + ```javascript + import MyApp from 'my-app'; - ```javascript - import MyApp from 'my-app'; + $(function() { + let App = MyApp.create({ autoboot: false }); - $(function() { - let App = MyApp.create({ autoboot: false }); + let options = { + // Override the router's location adapter to prevent it from updating + // the URL in the address bar + location: 'none', - let options = { - // Override the router's location adapter to prevent it from updating - // the URL in the address bar - location: 'none', + // Override the default `rootElement` on the app to render into a + // specific `div` on the page + rootElement: '#demo' + }; - // Override the default `rootElement` on the app to render into a - // specific `div` on the page - rootElement: '#demo' - }; + // Start the app at the special demo URL + App.visit('/demo', options); + }); + ```` - // Start the app at the special demo URL - App.visit('/demo', options); - }); - ```` + Or perhaps you might want to boot two instances of your app on the same + page for a split-screen multiplayer experience: - Or perhaps you might want to boot two instances of your app on the same - page for a split-screen multiplayer experience: + ```javascript + import MyApp from 'my-app'; - ```javascript - import MyApp from 'my-app'; + $(function() { + let App = MyApp.create({ autoboot: false }); - $(function() { - let App = MyApp.create({ autoboot: false }); + let sessionId = MyApp.generateSessionID(); - let sessionId = MyApp.generateSessionID(); + let player1 = App.visit(`/matches/join?name=Player+1&session=${sessionId}`, { rootElement: '#left', location: 'none' }); + let player2 = App.visit(`/matches/join?name=Player+2&session=${sessionId}`, { rootElement: '#right', location: 'none' }); - let player1 = App.visit(`/matches/join?name=Player+1&session=${sessionId}`, { rootElement: '#left', location: 'none' }); - let player2 = App.visit(`/matches/join?name=Player+2&session=${sessionId}`, { rootElement: '#right', location: 'none' }); + Promise.all([player1, player2]).then(() => { + // Both apps have completed the initial render + $('#loading').fadeOut(); + }); + }); + ``` - Promise.all([player1, player2]).then(() => { - // Both apps have completed the initial render - $('#loading').fadeOut(); - }); + Do note that each app instance maintains their own registry/container, so + they will run in complete isolation by default. + + #### Server-Side Rendering (also known as FastBoot) + + This setup allows you to run your Ember app in a server environment using + Node.js and render its content into static HTML for SEO purposes. + + ```javascript + const HTMLSerializer = new SimpleDOM.HTMLSerializer(SimpleDOM.voidMap); + + function renderURL(url) { + let dom = new SimpleDOM.Document(); + let rootElement = dom.body; + let options = { isBrowser: false, document: dom, rootElement: rootElement }; + + return MyApp.visit(options).then(instance => { + try { + return HTMLSerializer.serialize(rootElement.firstChild); + } finally { + instance.destroy(); + } }); - ``` + } + ``` - Do note that each app instance maintains their own registry/container, so - they will run in complete isolation by default. + In this scenario, because Ember does not have access to a global `document` + object in the Node.js environment, you must provide one explicitly. In practice, + in the non-browser environment, the stand-in `document` object only need to + implement a limited subset of the full DOM API. The `SimpleDOM` library is known + to work. - #### Server-Side Rendering (also known as FastBoot) + Since there is no access to jQuery in the non-browser environment, you must also + specify a DOM `Element` object in the same `document` for the `rootElement` option + (as opposed to a selector string like `"body"`). - This setup allows you to run your Ember app in a server environment using - Node.js and render its content into static HTML for SEO purposes. + See the documentation on the `isBrowser`, `document` and `rootElement` properties + on `Ember.ApplicationInstance.BootOptions` for details. - ```javascript - const HTMLSerializer = new SimpleDOM.HTMLSerializer(SimpleDOM.voidMap); + #### Server-Side Resource Discovery - function renderURL(url) { - let dom = new SimpleDOM.Document(); - let rootElement = dom.body; - let options = { isBrowser: false, document: dom, rootElement: rootElement }; + This setup allows you to run the routing layer of your Ember app in a server + environment using Node.js and completely disable rendering. This allows you + to simulate and discover the resources (i.e. AJAX requests) needed to fufill + a given request and eagerly "push" these resources to the client. - return MyApp.visit(options).then(instance => { - try { - return HTMLSerializer.serialize(rootElement.firstChild); - } finally { - instance.destroy(); - } - }); + ```app/initializers/network-service.js + import BrowserNetworkService from 'app/services/network/browser'; + import NodeNetworkService from 'app/services/network/node'; + + // Inject a (hypothetical) service for abstracting all AJAX calls and use + // the appropiate implementaion on the client/server. This also allows the + // server to log all the AJAX calls made during a particular request and use + // that for resource-discovery purpose. + + export function initialize(application) { + if (window) { // browser + application.register('service:network', BrowserNetworkService); + } else { // node + application.register('service:network', NodeNetworkService); } - ``` - - In this scenario, because Ember does not have access to a global `document` - object in the Node.js environment, you must provide one explicitly. In practice, - in the non-browser environment, the stand-in `document` object only need to - implement a limited subset of the full DOM API. The `SimpleDOM` library is known - to work. - - Since there is no access to jQuery in the non-browser environment, you must also - specify a DOM `Element` object in the same `document` for the `rootElement` option - (as opposed to a selector string like `"body"`). - - See the documentation on the `isBrowser`, `document` and `rootElement` properties - on `Ember.ApplicationInstance.BootOptions` for details. - - #### Server-Side Resource Discovery - - This setup allows you to run the routing layer of your Ember app in a server - environment using Node.js and completely disable rendering. This allows you - to simulate and discover the resources (i.e. AJAX requests) needed to fufill - a given request and eagerly "push" these resources to the client. - - ```app/initializers/network-service.js - import BrowserNetworkService from 'app/services/network/browser'; - import NodeNetworkService from 'app/services/network/node'; - - // Inject a (hypothetical) service for abstracting all AJAX calls and use - // the appropiate implementaion on the client/server. This also allows the - // server to log all the AJAX calls made during a particular request and use - // that for resource-discovery purpose. - - export function initialize(application) { - if (window) { // browser - application.register('service:network', BrowserNetworkService); - } else { // node - application.register('service:network', NodeNetworkService); - } - application.inject('route', 'network', 'service:network'); - }; + application.inject('route', 'network', 'service:network'); + }; - export default { - name: 'network-service', - initialize: initialize - }; - ``` + export default { + name: 'network-service', + initialize: initialize + }; + ``` - ```app/routes/post.js - import Ember from 'ember'; + ```app/routes/post.js + import Ember from 'ember'; - // An example of how the (hypothetical) service is used in routes. + // An example of how the (hypothetical) service is used in routes. - export default Ember.Route.extend({ - model(params) { - return this.network.fetch(`/api/posts/${params.post_id}.json`); - }, + export default Ember.Route.extend({ + model(params) { + return this.network.fetch(`/api/posts/${params.post_id}.json`); + }, - afterModel(post) { - if (post.isExternalContent) { - return this.network.fetch(`/api/external/?url=${post.externalURL}`); - } else { - return post; - } + afterModel(post) { + if (post.isExternalContent) { + return this.network.fetch(`/api/external/?url=${post.externalURL}`); + } else { + return post; } - }); - ``` + } + }); + ``` - ```javascript - // Finally, put all the pieces together + ```javascript + // Finally, put all the pieces together - function discoverResourcesFor(url) { - return MyApp.visit(url, { isBrowser: false, shouldRender: false }).then(instance => { - let networkService = instance.lookup('service:network'); - return networkService.requests; // => { "/api/posts/123.json": "..." } - }); - } - ``` - - @public - @method visit - @param url {String} The initial URL to navigate to - @param options {Ember.ApplicationInstance.BootOptions} - @return {Promise} - */ - visit(url, options) { - return this.boot().then(() => { - return this.buildInstance().boot(options).then((instance) => { - return instance.visit(url); - }); + function discoverResourcesFor(url) { + return MyApp.visit(url, { isBrowser: false, shouldRender: false }).then(instance => { + let networkService = instance.lookup('service:network'); + return networkService.requests; // => { "/api/posts/123.json": "..." } }); } - }); -} + ``` + + @public + @method visit + @param url {String} The initial URL to navigate to + @param options {Ember.ApplicationInstance.BootOptions} + @return {Promise} + */ + visit(url, options) { + return this.boot().then(() => { + return this.buildInstance().boot(options).then((instance) => { + return instance.visit(url); + }); + }); + } +}); + +Object.defineProperty(Application.prototype, 'registry', { + configurable: true, + enumerable: false, + get() { + return buildFakeRegistryWithDeprecations(this, 'Application'); + } +}); Application.reopenClass({ /** diff --git a/packages/ember-application/tests/system/initializers_test.js b/packages/ember-application/tests/system/initializers_test.js index 91136d82967..8746b04b50e 100644 --- a/packages/ember-application/tests/system/initializers_test.js +++ b/packages/ember-application/tests/system/initializers_test.js @@ -2,7 +2,6 @@ import Ember from 'ember-metal/core'; import run from 'ember-metal/run_loop'; import Application from 'ember-application/system/application'; import jQuery from 'ember-views/system/jquery'; -import isEnabled from 'ember-metal/features'; var app; @@ -33,41 +32,39 @@ QUnit.test('initializers require proper \'name\' and \'initialize\' properties', }); }); -if (isEnabled('ember-application-visit')) { - QUnit.test('initializers that throw errors cause the boot promise to reject with the error', function() { - QUnit.expect(2); - QUnit.stop(); +QUnit.test('initializers that throw errors cause the boot promise to reject with the error', function() { + QUnit.expect(2); + QUnit.stop(); - var MyApplication = Application.extend(); - - MyApplication.initializer({ - name: 'initializer', - initialize() { throw new Error('boot failure'); } - }); - - var app = MyApplication.create({ - autoboot: false - }); + var MyApplication = Application.extend(); - try { - app.boot().then( - (app) => { - QUnit.start(); - ok(false, 'The boot promise should not resolve when there is a boot error'); - }, - (err) => { - QUnit.start(); - ok(err instanceof Error, 'The boot promise should reject with an error'); - equal(err.message, 'boot failure'); - } - ); - } catch(e) { - QUnit.start(); - ok(false, 'The boot method should not throw'); - throw e; - } - }); -} + MyApplication.initializer({ + name: 'initializer', + initialize() { throw new Error('boot failure'); } + }); + + var app = MyApplication.create({ + autoboot: false + }); + + try { + app.boot().then( + (app) => { + QUnit.start(); + ok(false, 'The boot promise should not resolve when there is a boot error'); + }, + (err) => { + QUnit.start(); + ok(err instanceof Error, 'The boot promise should reject with an error'); + equal(err.message, 'boot failure'); + } + ); + } catch(e) { + QUnit.start(); + ok(false, 'The boot method should not throw'); + throw e; + } +}); QUnit.test('initializers are passed an App', function() { var MyApplication = Application.extend(); diff --git a/packages/ember-application/tests/system/visit_test.js b/packages/ember-application/tests/system/visit_test.js index 7728759171b..7e67aa4cfcf 100644 --- a/packages/ember-application/tests/system/visit_test.js +++ b/packages/ember-application/tests/system/visit_test.js @@ -1,6 +1,5 @@ import Ember from 'ember-metal/core'; import EmberObject from 'ember-runtime/system/object'; -import isEnabled from 'ember-metal/features'; import inject from 'ember-runtime/inject'; import run from 'ember-metal/run_loop'; import RSVP, { onerrorDefault } from 'ember-runtime/ext/rsvp'; @@ -57,471 +56,469 @@ function expectAsyncError() { RSVP.off('error'); } -if (isEnabled('ember-application-visit')) { - QUnit.module('Ember.Application - visit()', { - teardown() { - RSVP.on('error', onerrorDefault); +QUnit.module('Ember.Application - visit()', { + teardown() { + RSVP.on('error', onerrorDefault); - if (instance) { - run(instance, 'destroy'); - instance = null; - } - - if (App) { - run(App, 'destroy'); - App = null; - } + if (instance) { + run(instance, 'destroy'); + instance = null; } - }); - // This tests whether the application is "autobooted" by registering an - // instance initializer and asserting it never gets run. Since this is - // inherently testing that async behavior *doesn't* happen, we set a - // 500ms timeout to verify that when autoboot is set to false, the - // instance initializer that would normally get called on DOM ready - // does not fire. - QUnit.test('Applications with autoboot set to false do not autoboot', function(assert) { - function delay(time) { - return new RSVP.Promise(resolve => Ember.run.later(resolve, time)); + if (App) { + run(App, 'destroy'); + App = null; } + } +}); + +// This tests whether the application is "autobooted" by registering an +// instance initializer and asserting it never gets run. Since this is +// inherently testing that async behavior *doesn't* happen, we set a +// 500ms timeout to verify that when autoboot is set to false, the +// instance initializer that would normally get called on DOM ready +// does not fire. +QUnit.test('Applications with autoboot set to false do not autoboot', function(assert) { + function delay(time) { + return new RSVP.Promise(resolve => Ember.run.later(resolve, time)); + } - let appBooted = 0; - let instanceBooted = 0; + let appBooted = 0; + let instanceBooted = 0; - run(function() { - createApplication(); + run(function() { + createApplication(); - App.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); - - App.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); + App.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } }); - // Continue after 500ms - return delay(500).then(() => { - assert.ok(appBooted === 0, '500ms elapsed without app being booted'); - assert.ok(instanceBooted === 0, '500ms elapsed without instances being booted'); - - return run(App, 'boot'); - }).then(() => { - assert.ok(appBooted === 1, 'app should boot when manually calling `app.boot()`'); - assert.ok(instanceBooted === 0, 'no instances should be booted automatically when manually calling `app.boot()'); + App.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } }); }); - QUnit.test('calling visit() on an app without first calling boot() should boot the app', function(assert) { - let appBooted = 0; - let instanceBooted = 0; + // Continue after 500ms + return delay(500).then(() => { + assert.ok(appBooted === 0, '500ms elapsed without app being booted'); + assert.ok(instanceBooted === 0, '500ms elapsed without instances being booted'); - run(function() { - createApplication(); + return run(App, 'boot'); + }).then(() => { + assert.ok(appBooted === 1, 'app should boot when manually calling `app.boot()`'); + assert.ok(instanceBooted === 0, 'no instances should be booted automatically when manually calling `app.boot()'); + }); +}); - App.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); +QUnit.test('calling visit() on an app without first calling boot() should boot the app', function(assert) { + let appBooted = 0; + let instanceBooted = 0; - App.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); + run(function() { + createApplication(); + + App.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } }); - return run(App, 'visit', '/').then(() => { - assert.ok(appBooted === 1, 'the app should be booted`'); - assert.ok(instanceBooted === 1, 'an instances should be booted'); + App.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } }); }); - QUnit.test('calling visit() on an already booted app should not boot it again', function(assert) { - let appBooted = 0; - let instanceBooted = 0; + return run(App, 'visit', '/').then(() => { + assert.ok(appBooted === 1, 'the app should be booted`'); + assert.ok(instanceBooted === 1, 'an instances should be booted'); + }); +}); - run(function() { - createApplication(); +QUnit.test('calling visit() on an already booted app should not boot it again', function(assert) { + let appBooted = 0; + let instanceBooted = 0; - App.initializer({ - name: 'assert-no-autoboot', - initialize() { - appBooted++; - } - }); + run(function() { + createApplication(); - App.instanceInitializer({ - name: 'assert-no-autoboot', - initialize() { - instanceBooted++; - } - }); + App.initializer({ + name: 'assert-no-autoboot', + initialize() { + appBooted++; + } }); - return run(App, 'boot').then(() => { - assert.ok(appBooted === 1, 'the app should be booted'); - assert.ok(instanceBooted === 0, 'no instances should be booted'); - - return run(App, 'visit', '/'); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 1, 'an instance should be booted'); - - return run(App, 'visit', '/'); - }).then(() => { - assert.ok(appBooted === 1, 'the app should not be booted again'); - assert.ok(instanceBooted === 2, 'another instance should be booted'); + App.instanceInitializer({ + name: 'assert-no-autoboot', + initialize() { + instanceBooted++; + } }); }); - QUnit.test('visit() rejects on application boot failure', function(assert) { - run(function() { - createApplication(); + return run(App, 'boot').then(() => { + assert.ok(appBooted === 1, 'the app should be booted'); + assert.ok(instanceBooted === 0, 'no instances should be booted'); - App.initializer({ - name: 'error', - initialize() { - throw new Error('boot failure'); - } - }); - }); + return run(App, 'visit', '/'); + }).then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 1, 'an instance should be booted'); + + return run(App, 'visit', '/'); + }).then(() => { + assert.ok(appBooted === 1, 'the app should not be booted again'); + assert.ok(instanceBooted === 2, 'another instance should be booted'); + }); +}); - expectAsyncError(); +QUnit.test('visit() rejects on application boot failure', function(assert) { + run(function() { + createApplication(); - return run(App, 'visit', '/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); + App.initializer({ + name: 'error', + initialize() { + throw new Error('boot failure'); + } }); }); - QUnit.test('visit() rejects on instance boot failure', function(assert) { - run(function() { - createApplication(); + expectAsyncError(); - App.instanceInitializer({ - name: 'error', - initialize() { - throw new Error('boot failure'); - } - }); - }); + return run(App, 'visit', '/').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'boot failure'); + }); +}); - expectAsyncError(); +QUnit.test('visit() rejects on instance boot failure', function(assert) { + run(function() { + createApplication(); - return run(App, 'visit', '/').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'boot failure'); + App.instanceInitializer({ + name: 'error', + initialize() { + throw new Error('boot failure'); + } }); }); - QUnit.test('visit() follows redirects', function(assert) { - run(function() { - createApplication(); + expectAsyncError(); - App.Router.map(function() { - this.route('a'); - this.route('b', { path: '/b/:b' }); - this.route('c', { path: '/c/:c' }); - }); + return run(App, 'visit', '/').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'boot failure'); + }); +}); - App.register('route:a', Route.extend({ - afterModel() { - this.replaceWith('b', 'zomg'); - } - })); +QUnit.test('visit() follows redirects', function(assert) { + run(function() { + createApplication(); - App.register('route:b', Route.extend({ - afterModel(params) { - this.transitionTo('c', params.b); - } - })); + App.Router.map(function() { + this.route('a'); + this.route('b', { path: '/b/:b' }); + this.route('c', { path: '/c/:c' }); }); - return run(App, 'visit', '/a').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects'); - }); + App.register('route:a', Route.extend({ + afterModel() { + this.replaceWith('b', 'zomg'); + } + })); + + App.register('route:b', Route.extend({ + afterModel(params) { + this.transitionTo('c', params.b); + } + })); }); - QUnit.test('visit() rejects if an error occured during a transition', function(assert) { - run(function() { - createApplication(); + return run(App, 'visit', '/a').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects'); + }); +}); - App.Router.map(function() { - this.route('a'); - this.route('b', { path: '/b/:b' }); - this.route('c', { path: '/c/:c' }); - }); +QUnit.test('visit() rejects if an error occured during a transition', function(assert) { + run(function() { + createApplication(); - App.register('route:a', Route.extend({ - afterModel() { - this.replaceWith('b', 'zomg'); - } - })); + App.Router.map(function() { + this.route('a'); + this.route('b', { path: '/b/:b' }); + this.route('c', { path: '/c/:c' }); + }); - App.register('route:b', Route.extend({ - afterModel(params) { - this.transitionTo('c', params.b); - } - })); + App.register('route:a', Route.extend({ + afterModel() { + this.replaceWith('b', 'zomg'); + } + })); - App.register('route:c', Route.extend({ - afterModel(params) { - throw new Error('transition failure'); - } - })); - }); + App.register('route:b', Route.extend({ + afterModel(params) { + this.transitionTo('c', params.b); + } + })); + + App.register('route:c', Route.extend({ + afterModel(params) { + throw new Error('transition failure'); + } + })); + }); - expectAsyncError(); + expectAsyncError(); - return run(App, 'visit', '/a').then(() => { - assert.ok(false, 'It should not resolve the promise'); - }, error => { - assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); - assert.equal(error.message, 'transition failure'); - }); + return run(App, 'visit', '/a').then(() => { + assert.ok(false, 'It should not resolve the promise'); + }, error => { + assert.ok(error instanceof Error, 'It should reject the promise with the boot error'); + assert.equal(error.message, 'transition failure'); }); +}); - QUnit.test('visit() chain', function(assert) { - run(function() { - createApplication(); +QUnit.test('visit() chain', function(assert) { + run(function() { + createApplication(); - App.Router.map(function() { - this.route('a'); - this.route('b'); - this.route('c'); - }); + App.Router.map(function() { + this.route('a'); + this.route('b'); + this.route('c'); }); + }); - return run(App, 'visit', '/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/'); + return run(App, 'visit', '/').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/'); - return instance.visit('/a'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/a'); + return instance.visit('/a'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/a'); - return instance.visit('/b'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/b'); + return instance.visit('/b'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/b'); - return instance.visit('/c'); - }).then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(instance.getURL(), '/c'); - }); + return instance.visit('/c'); + }).then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(instance.getURL(), '/c'); }); +}); - QUnit.test('visit() returns a promise that resolves when the view has rendered', function(assert) { - run(function() { - createApplication(); +QUnit.test('visit() returns a promise that resolves when the view has rendered', function(assert) { + run(function() { + createApplication(); - App.register('template:application', compile('

Hello world

')); - }); + App.register('template:application', compile('

Hello world

')); + }); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); + assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - return run(App, 'visit', '/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(jQuery('#qunit-fixture > .ember-view h1').text(), 'Hello world', 'the application was rendered once the promise resolves'); - }); + return run(App, 'visit', '/').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(jQuery('#qunit-fixture > .ember-view h1').text(), 'Hello world', 'the application was rendered once the promise resolves'); }); +}); - QUnit.test('Views created via visit() are not added to the global views hash', function(assert) { - run(function() { - createApplication(); +QUnit.test('Views created via visit() are not added to the global views hash', function(assert) { + run(function() { + createApplication(); - App.register('template:application', compile('

Hello world

{{component "x-child"}}')); + App.register('template:application', compile('

Hello world

{{component "x-child"}}')); - App.register('view:application', View.extend({ - elementId: 'my-cool-app' - })); + App.register('view:application', View.extend({ + elementId: 'my-cool-app' + })); - App.register('component:x-child', View.extend({ - elementId: 'child-view' - })); - }); + App.register('component:x-child', View.extend({ + elementId: 'child-view' + })); + }); - assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); + assert.strictEqual(jQuery('#qunit-fixture').children().length, 0, 'there are no elements in the fixture element'); - return run(App, 'visit', '/').then(instance => { - assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); - assert.equal(jQuery('#qunit-fixture > #my-cool-app h1').text(), 'Hello world', 'the application was rendered once the promise resolves'); - assert.strictEqual(View.views['my-cool-app'], undefined, 'view was not registered globally'); + return run(App, 'visit', '/').then(instance => { + assert.ok(instance instanceof ApplicationInstance, 'promise is resolved with an ApplicationInstance'); + assert.equal(jQuery('#qunit-fixture > #my-cool-app h1').text(), 'Hello world', 'the application was rendered once the promise resolves'); + assert.strictEqual(View.views['my-cool-app'], undefined, 'view was not registered globally'); - function lookup(fullName) { - return instance.lookup(fullName); - } + function lookup(fullName) { + return instance.lookup(fullName); + } - assert.ok(lookup('-view-registry:main')['my-cool-app'] instanceof View, 'view was registered on the instance\'s view registry'); - assert.ok(lookup('-view-registry:main')['child-view'] instanceof View, 'child view was registered on the instance\'s view registry'); - }); + assert.ok(lookup('-view-registry:main')['my-cool-app'] instanceof View, 'view was registered on the instance\'s view registry'); + assert.ok(lookup('-view-registry:main')['child-view'] instanceof View, 'child view was registered on the instance\'s view registry'); }); +}); - QUnit.module('Ember.Application - visit() Integration Tests', { - teardown() { - if (instances) { - run(instances, 'forEach', (i) => i.destroy()); - instances = []; - } +QUnit.module('Ember.Application - visit() Integration Tests', { + teardown() { + if (instances) { + run(instances, 'forEach', (i) => i.destroy()); + instances = []; + } - if (App) { - run(App, 'destroy'); - App = null; - } + if (App) { + run(App, 'destroy'); + App = null; } - }); + } +}); - QUnit.test('Ember Islands-style setup', function(assert) { - let xFooInitCalled = false; - let xFooDidInsertElementCalled = false; +QUnit.test('Ember Islands-style setup', function(assert) { + let xFooInitCalled = false; + let xFooDidInsertElementCalled = false; - let xBarInitCalled = false; - let xBarDidInsertElementCalled = false; + let xBarInitCalled = false; + let xBarDidInsertElementCalled = false; - run(function() { - createApplication(true); - - App.Router.map(function() { - this.route('show', { path: '/:component_name' }); - }); - - App.register('route:show', Route.extend({ - queryParams: { - data: { refreshModel: true } - }, - - model(params) { - return { - componentName: params.component_name, - componentData: params.data ? JSON.parse(params.data) : undefined - }; - } - })); + run(function() { + createApplication(true); - let Counter = EmberObject.extend({ - value: 0, + App.Router.map(function() { + this.route('show', { path: '/:component_name' }); + }); - increment() { - this.incrementProperty('value'); - } - }); + App.register('route:show', Route.extend({ + queryParams: { + data: { refreshModel: true } + }, - App.register('service:isolated-counter', Counter); - App.register('service:shared-counter', Counter.create(), { instantiate: false }); + model(params) { + return { + componentName: params.component_name, + componentData: params.data ? JSON.parse(params.data) : undefined + }; + } + })); - App.register('template:show', compile('{{component model.componentName model=model.componentData}}')); + let Counter = EmberObject.extend({ + value: 0, - App.register('template:components/x-foo', compile(` -

X-Foo

-

Hello {{model.name}}, I have been clicked {{isolatedCounter.value}} times ({{sharedCounter.value}} times combined)!

- `)); + increment() { + this.incrementProperty('value'); + } + }); - App.register('component:x-foo', Component.extend({ - tagName: 'x-foo', + App.register('service:isolated-counter', Counter); + App.register('service:shared-counter', Counter.create(), { instantiate: false }); - isolatedCounter: inject.service(), - sharedCounter: inject.service(), + App.register('template:show', compile('{{component model.componentName model=model.componentData}}')); - init() { - this._super(); - xFooInitCalled = true; - }, + App.register('template:components/x-foo', compile(` +

X-Foo

+

Hello {{model.name}}, I have been clicked {{isolatedCounter.value}} times ({{sharedCounter.value}} times combined)!

+ `)); - didInsertElement() { - xFooDidInsertElementCalled = true; - }, + App.register('component:x-foo', Component.extend({ + tagName: 'x-foo', - click() { - this.get('isolatedCounter').increment(); - this.get('sharedCounter').increment(); - } - })); + isolatedCounter: inject.service(), + sharedCounter: inject.service(), - App.register('template:components/x-bar', compile(` -

X-Bar

- - `)); + init() { + this._super(); + xFooInitCalled = true; + }, - App.register('component:x-bar', Component.extend({ - counter: inject.service('shared-counter'), + didInsertElement() { + xFooDidInsertElementCalled = true; + }, - actions: { - incrementCounter() { - this.get('counter').increment(); - } - }, + click() { + this.get('isolatedCounter').increment(); + this.get('sharedCounter').increment(); + } + })); - init() { - this._super(); - xBarInitCalled = true; - }, + App.register('template:components/x-bar', compile(` +

X-Bar

+ + `)); - didInsertElement() { - xBarDidInsertElementCalled = true; + App.register('component:x-bar', Component.extend({ + counter: inject.service('shared-counter'), + + actions: { + incrementCounter() { + this.get('counter').increment(); } - })); - }); + }, + + init() { + this._super(); + xBarInitCalled = true; + }, - let $foo = jQuery('
').appendTo('#qunit-fixture'); - let $bar = jQuery('
').appendTo('#qunit-fixture'); + didInsertElement() { + xBarDidInsertElementCalled = true; + } + })); + }); - let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); + let $foo = jQuery('
').appendTo('#qunit-fixture'); + let $bar = jQuery('
').appendTo('#qunit-fixture'); - return RSVP.all([ - run(App, 'visit', `/x-foo?data=${data}`, { rootElement: $foo[0] }), - run(App, 'visit', '/x-bar', { rootElement: $bar[0] }) - ]).then(() => { - assert.ok(xFooInitCalled); - assert.ok(xFooDidInsertElementCalled); + let data = encodeURIComponent(JSON.stringify({ name: 'Godfrey' })); - assert.ok(xBarInitCalled); - assert.ok(xBarDidInsertElementCalled); + return RSVP.all([ + run(App, 'visit', `/x-foo?data=${data}`, { rootElement: $foo[0] }), + run(App, 'visit', '/x-bar', { rootElement: $bar[0] }) + ]).then(() => { + assert.ok(xFooInitCalled); + assert.ok(xFooDidInsertElementCalled); - assert.equal($foo.find('h1').text(), 'X-Foo'); - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 0 times (0 times combined)!'); - assert.ok($foo.text().indexOf('X-Bar') === -1); + assert.ok(xBarInitCalled); + assert.ok(xBarDidInsertElementCalled); - assert.equal($bar.find('h1').text(), 'X-Bar'); - assert.equal($bar.find('button').text(), 'Join 0 others in clicking me!'); - assert.ok($bar.text().indexOf('X-Foo') === -1); + assert.equal($foo.find('h1').text(), 'X-Foo'); + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 0 times (0 times combined)!'); + assert.ok($foo.text().indexOf('X-Bar') === -1); - run(function() { - $foo.find('x-foo').click(); - }); + assert.equal($bar.find('h1').text(), 'X-Bar'); + assert.equal($bar.find('button').text(), 'Join 0 others in clicking me!'); + assert.ok($bar.text().indexOf('X-Foo') === -1); - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (1 times combined)!'); - assert.equal($bar.find('button').text(), 'Join 1 others in clicking me!'); + run(function() { + $foo.find('x-foo').click(); + }); - run(function() { - $bar.find('button').click(); - $bar.find('button').click(); - }); + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (1 times combined)!'); + assert.equal($bar.find('button').text(), 'Join 1 others in clicking me!'); - assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (3 times combined)!'); - assert.equal($bar.find('button').text(), 'Join 3 others in clicking me!'); + run(function() { + $bar.find('button').click(); + $bar.find('button').click(); }); - }); - QUnit.skip('Test setup', function(assert) { + assert.equal($foo.find('p').text(), 'Hello Godfrey, I have been clicked 1 times (3 times combined)!'); + assert.equal($bar.find('button').text(), 'Join 3 others in clicking me!'); }); +}); - QUnit.skip('iframe setup', function(assert) { - }); -} +QUnit.skip('Test setup', function(assert) { +}); + +QUnit.skip('iframe setup', function(assert) { +}); diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js index 06d9d0b8841..5a1384eea04 100644 --- a/packages/ember-routing/lib/system/route.js +++ b/packages/ember-routing/lib/system/route.js @@ -1220,11 +1220,7 @@ var Route = EmberObject.extend(ActionHandler, Evented, { this.setupController(controller, context, transition); - if (isEnabled('ember-application-visit')) { - if (!this._environment || this._environment.options.shouldRender) { - this.renderTemplate(controller, context); - } - } else { + if (!this._environment || this._environment.options.shouldRender) { this.renderTemplate(controller, context); } }, diff --git a/packages/ember-views/lib/mixins/view_support.js b/packages/ember-views/lib/mixins/view_support.js index 7d87703568d..fe1538787e2 100644 --- a/packages/ember-views/lib/mixins/view_support.js +++ b/packages/ember-views/lib/mixins/view_support.js @@ -7,7 +7,6 @@ import { guidFor } from 'ember-metal/utils'; import { computed } from 'ember-metal/computed'; import { Mixin } from 'ember-metal/mixin'; import { POST_INIT } from 'ember-runtime/system/core_object'; -import isEnabled from 'ember-metal/features'; import symbol from 'ember-metal/symbol'; import { getOwner } from 'container/owner'; @@ -258,31 +257,22 @@ export default Mixin.create({ @private */ appendTo(selector) { - if (isEnabled('ember-application-visit')) { - let $ = this._environment ? this._environment.options.jQuery : jQuery; + let $ = this._environment ? this._environment.options.jQuery : jQuery; - if ($) { - let target = $(selector); - - assert('You tried to append to (' + selector + ') but that isn\'t in the DOM', target.length > 0); - assert('You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.', !target.is('.ember-view') && !target.parents().is('.ember-view')); - - this.renderer.appendTo(this, target[0]); - } else { - let target = selector; - - assert('You tried to append to a selector string (' + selector + ') in an environment without jQuery', typeof target !== 'string'); - assert('You tried to append to a non-Element (' + selector + ') in an environment without jQuery', typeof selector.appendChild === 'function'); - - this.renderer.appendTo(this, target); - } - } else { - let target = jQuery(selector); + if ($) { + let target = $(selector); assert('You tried to append to (' + selector + ') but that isn\'t in the DOM', target.length > 0); assert('You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead.', !target.is('.ember-view') && !target.parents().is('.ember-view')); this.renderer.appendTo(this, target[0]); + } else { + let target = selector; + + assert('You tried to append to a selector string (' + selector + ') in an environment without jQuery', typeof target !== 'string'); + assert('You tried to append to a non-Element (' + selector + ') in an environment without jQuery', typeof selector.appendChild === 'function'); + + this.renderer.appendTo(this, target); } return this; diff --git a/packages/ember-views/tests/views/component_test.js b/packages/ember-views/tests/views/component_test.js index e7248f3270f..697a37ead54 100644 --- a/packages/ember-views/tests/views/component_test.js +++ b/packages/ember-views/tests/views/component_test.js @@ -6,7 +6,6 @@ import inject from 'ember-runtime/inject'; import { get } from 'ember-metal/property_get'; import Application from 'ember-application/system/application'; import ApplicationInstance from 'ember-application/system/application-instance'; -import isEnabled from 'ember-metal/features'; import EmberView from 'ember-views/views/view'; import Component from 'ember-views/components/component'; @@ -300,9 +299,6 @@ QUnit.module('Ember.Component - tagless components assertions', { QUnit.test('throws an error if an event function is defined in a tagless component', function() { app = run(Application, 'create', { rootElement: '#qunit-fixture', autoboot: false }); - if (!isEnabled('ember-application-visit')) { - run(app.__deprecatedInstance__, 'destroy'); - } run(function() { appInstance = ApplicationInstance.create({ application: app }); @@ -329,10 +325,6 @@ QUnit.test('throws an error if an Application custom event handler is defined in } }); - if (!isEnabled('ember-application-visit')) { - run(app.__deprecatedInstance__, 'destroy'); - } - run(function() { appInstance = ApplicationInstance.create({ application: app }); appInstance.setupEventDispatcher(); @@ -352,10 +344,6 @@ QUnit.test('throws an error if an Application custom event handler is defined in QUnit.test('throws an error if an ApplicationInstance custom event handler is defined in a tagless component', function() { app = run(Application, 'create', { rootElement: '#qunit-fixture', autoboot: false }); - if (!isEnabled('ember-application-visit')) { - run(app.__deprecatedInstance__, 'destroy'); - } - run(function() { appInstance = ApplicationInstance.create({ application: app,