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

Use Application.create().buildInstance() if possible. #237

Merged
merged 3 commits into from
Nov 10, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions addon-test-support/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var __application__;

export function setApplication(application) {
__application__ = application;
}

export function getApplication() {
return __application__;
}
112 changes: 11 additions & 101 deletions addon-test-support/build-owner.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,18 @@
/* globals requirejs */
import global from './global';
import { Promise } from 'rsvp';

import ApplicationInstance from '@ember/application/instance';
import Application from '@ember/application';
import EmberObject from '@ember/object';
import legacyBuildRegistry from './legacy-0-6-x/build-registry';

import require from 'require';
import Ember from 'ember';
import { getResolver } from './resolver';

const Owner = (function() {
// this module only supports Ember 2.4+ but is evaluated
// on older Ember versions (which we support via the legacy-0-6 API)
// and calling `.extend` with undefined is an issue
if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) {
return EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin);
export default function({ application, resolver }) {
if (application) {
return application.boot().then(app => app.buildInstance().boot());
}

return EmberObject.extend();
})();

// different than the legacy-0-6-x version (build-registry.js)
// in the following ways:
//
// * fewer fallbacks (supports only Ember 2.4+)
// * returns "owner" (instead of a POJO with registry/container)
// * directly calls getResolver if one was not provided
export default function(resolver = getResolver()) {
let fallbackRegistry, registry, container;
let namespace = EmberObject.create({
Resolver: {
create() {
return resolver;
},
},
});

function register(name, factory) {
let thingToRegisterWith = registry || container;
let existingFactory = container.factoryFor
? container.factoryFor(name)
: container.lookupFactory(name);

if (!existingFactory) {
thingToRegisterWith.register(name, factory);
}
}

fallbackRegistry = Application.buildRegistry(namespace);
fallbackRegistry.register('component-lookup:main', Ember.ComponentLookup);

registry = new Ember.Registry({
fallback: fallbackRegistry,
});

// Ember.ApplicationInstance was exposed in Ember 2.8
if (ApplicationInstance && ApplicationInstance.setupRegistry) {
ApplicationInstance.setupRegistry(registry);
}

// these properties are set on the fallback registry by `buildRegistry`
// and on the primary registry within the ApplicationInstance constructor
// but we need to manually recreate them since ApplicationInstance's are not
// exposed externally
registry.normalizeFullName = fallbackRegistry.normalizeFullName;
registry.makeToString = fallbackRegistry.makeToString;
registry.describe = fallbackRegistry.describe;

let owner = Owner.create({
__registry__: registry,
__container__: null,
});

container = registry.container({ owner: owner });
owner.__container__ = container;

// TODO: this manual Ember Data setup should be removed in favor of
// running the applications `initializers` to ensure the container is
// properly setup, this would only need to be done once per test suite
if (
(typeof require.has === 'function' && require.has('ember-data/setup-container')) ||
requirejs.entries['ember-data/setup-container']
) {
// ember-data is a proper ember-cli addon since 2.3; if no 'import
// 'ember-data'' is present somewhere in the tests, there is also no `DS`
// available on the globalContext and hence ember-data wouldn't be setup
// correctly for the tests; that's why we import and call setupContainer
// here; also see https://github.com/emberjs/data/issues/4071 for context
let setupContainer = require('ember-data/setup-container')['default'];
setupContainer(registry);
} else if (global.DS) {
let DS = global.DS;
if (DS._setupContainer) {
DS._setupContainer(registry);
} else {
register('transform:boolean', DS.BooleanTransform);
register('transform:date', DS.DateTransform);
register('transform:number', DS.NumberTransform);
register('transform:string', DS.StringTransform);
register('serializer:-default', DS.JSONSerializer);
register('serializer:-rest', DS.RESTSerializer);
register('adapter:-rest', DS.RESTAdapter);
}
if (!resolver) {
throw new Error(
'You must set up the ember-test-helpers environment with either `setResolver` or `setApplication` before running any tests.'
);
}

return owner;
let { owner } = legacyBuildRegistry(resolver);
return Promise.resolve(owner);
}
1 change: 1 addition & 0 deletions addon-test-support/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export { default as TestModuleForComponent } from './legacy-0-6-x/test-module-fo
export { default as TestModuleForModel } from './legacy-0-6-x/test-module-for-model';

export { setResolver } from './resolver';
export { setApplication } from './application';
export {
default as setupContext,
getContext,
Expand Down
13 changes: 9 additions & 4 deletions addon-test-support/legacy-0-6-x/build-registry.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ function exposeRegistryMethodsWithoutDeprecations(container) {

var Owner = (function() {
if (Ember._RegistryProxyMixin && Ember._ContainerProxyMixin) {
return EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin);
return EmberObject.extend(Ember._RegistryProxyMixin, Ember._ContainerProxyMixin, {
_emberTestHelpersMockOwner: true,
});
}

return EmberObject.extend();
return EmberObject.extend({
_emberTestHelpersMockOwner: true,
});
})();

export default function(resolver) {
Expand Down Expand Up @@ -136,7 +140,8 @@ export default function(resolver) {
}

return {
registry: registry,
container: container,
registry,
container,
owner,
};
}
4 changes: 0 additions & 4 deletions addon-test-support/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,5 @@ export function setResolver(resolver) {
}

export function getResolver() {
if (__resolver__ == null) {
throw new Error('you must set a resolver with `testResolver.set(resolver)`');
}

return __resolver__;
}
33 changes: 27 additions & 6 deletions addon-test-support/setup-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import Ember from 'ember';
import { Promise } from 'rsvp';
import { assert } from '@ember/debug';
import global from './global';
import { getResolver } from './resolver';
import { getApplication } from './application';

let __test_context__;

Expand Down Expand Up @@ -61,10 +63,30 @@ export default function(context, options = {}) {

return new Promise(resolve => {
// ensure "real" async and not "fake" RSVP based async
next(() => {
let resolver = options.resolver;
let owner = buildOwner(resolver);

next(resolve);
})
.then(() => {
let { resolver } = options;
let buildOwnerOptions;

// This handles precendence, specifying a specific option of
// resolver always trumps whatever is auto-detected, then we fallback to
// the suite-wide registrations
//
// At some later time this can be extended to support specifying a custom
// engine or application...
if (resolver) {
buildOwnerOptions = { resolver };
} else {
buildOwnerOptions = {
resolver: getResolver(),
application: getApplication(),
};
}

return buildOwner(buildOwnerOptions);
})
.then(owner => {
context.owner = owner;

context.set = function(key, value) {
Expand Down Expand Up @@ -110,7 +132,6 @@ export default function(context, options = {}) {
_setupAJAXHooks();
_setupPromiseListeners();

resolve(context);
return context;
});
});
}
11 changes: 9 additions & 2 deletions addon-test-support/setup-rendering-context.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,15 @@ export default function(context) {
next(() => {
let { owner } = context;

let dispatcher = owner.lookup('event_dispatcher:main') || Ember.EventDispatcher.create();
dispatcher.setup({}, '#ember-testing');
// When the host app uses `setApplication` (instead of `setResolver`) the event dispatcher has
// already been setup via `applicationInstance.boot()` in `./build-owner`. If using
// `setResolver` (instead of `setApplication`) a "mock owner" is created by extending
// `Ember._ContainerProxyMixin` and `Ember._RegistryProxyMixin` in this scenario we need to
// manually start the event dispatcher.
if (owner._emberTestHelpersMockOwner) {
let dispatcher = owner.lookup('event_dispatcher:main') || Ember.EventDispatcher.create();
dispatcher.setup({}, '#ember-testing');
}

let OutletView = owner.factoryFor
? owner.factoryFor('view:-outlet')
Expand Down
11 changes: 10 additions & 1 deletion tests/dummy/app/resolver.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
import Resolver from 'ember-resolver';

export default Resolver;
export let registry = Object.create(null);
export function setRegistry(newRegistry) {
registry = newRegistry;
}

export default Resolver.extend({
resolve(fullName) {
return registry[fullName] || this._super(...arguments);
},
});
Copy link
Member

Choose a reason for hiding this comment

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

is that going to be required for all apps?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, absolutely not! This is only a thing needed to test things internally here. Basically the setResolverRegistry test helper function (just here in the tests of this repo) resets the list of "known" modules so that we can test things like this.owner.register "wins" over what is resolved, and whatnot.

19 changes: 6 additions & 13 deletions tests/helpers/resolver.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import Ember from 'ember';
import { run } from '@ember/runloop';
import { dasherize } from '@ember/string';
import AppResolver from '../../resolver';
import AppResolver, { setRegistry } from '../../resolver';
import config from '../../config/environment';
import { setResolver } from 'ember-test-helpers';
import { setResolver, setApplication } from 'ember-test-helpers';
import require from 'require';
import App from '../../app';

const Resolver = AppResolver.extend({
registry: {},

resolve(fullName) {
return this.registry[fullName] || this._super(...arguments);
},
});

const resolver = Resolver.create();
const resolver = AppResolver.create();

resolver.namespace = {
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
};

setResolver(resolver);
setApplication(App.create({ autoboot: false }));

export function setResolverRegistry(registry) {
run(resolver, 'set', 'registry', registry);
setRegistry(registry);
}

export default {
Expand Down