@ember/test-helpers
Version:
Helpers for testing Ember.js applications
126 lines (115 loc) • 4.91 kB
JavaScript
import ApplicationInstance from '@ember/application/instance';
import Application from '@ember/application';
import EmberObject from '@ember/object';
import { Registry } from '@ember/-internals/container';
import { RegistryProxyMixin, ContainerProxyMixin } from '@ember/-internals/runtime';
/**
* Adds methods that are normally only on registry to the container. This is largely to support the legacy APIs
* that are not using `owner` (but are still using `this.container`).
*
* @private
* @param {Object} container the container to modify
*/
function exposeRegistryMethodsWithoutDeprecations(container) {
const methods = ['register', 'unregister', 'resolve', 'normalize', 'typeInjection', 'injection', 'factoryInjection', 'factoryTypeInjection', 'has', 'options', 'optionsForType'];
for (let i = 0, l = methods.length; i < l; i++) {
const methodName = methods[i];
if (methodName && methodName in container) {
const knownMethod = methodName;
container[knownMethod] = function (...args) {
return container._registry[knownMethod](...args);
};
}
}
}
// NOTE: this is the same as what `EngineInstance`/`ApplicationInstance`
// implement, and is thus a superset of the `InternalOwner` contract from Ember
// itself.
const Owner = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin, {
_emberTestHelpersMockOwner: true,
/* eslint-disable valid-jsdoc */
/**
* Unregister a factory and its instance.
*
* Overrides `RegistryProxy#unregister` in order to clear any cached instances
* of the unregistered factory.
*
* @param {string} fullName Name of the factory to unregister.
*
* @see {@link https://github.com/emberjs/ember.js/pull/12680}
* @see {@link https://github.com/emberjs/ember.js/blob/v4.5.0-alpha.5/packages/%40ember/engine/instance.ts#L152-L167}
*/
/* eslint-enable valid-jsdoc */
unregister(fullName) {
// SAFETY: this is always present, but only the stable type definitions from
// Ember actually preserve it, since it is private API.
this['__container__'].reset(fullName);
// We overwrote this method from RegistryProxyMixin.
// SAFETY: this is always present, but only the stable type definitions from
// Ember actually preserve it, since it is private API.
this['__registry__'].unregister(fullName);
}
});
/**
* @private
* @param {Object} resolver the resolver to use with the registry
* @returns {Object} owner, container, registry
*/
function buildRegistry(resolver) {
const namespace = new Application();
// @ts-ignore: this is actually the correcct type, but there was a typo in
// Ember's docs for many years which meant that there was a matching problem
// in the types for Ember's definition of `Engine`. Once we require at least
// Ember 5.1 (in some future breaking change), this ts-ignore can be removed.
namespace.Resolver = {
create() {
return resolver;
}
};
// @ts-ignore: this is private API.
const fallbackRegistry = Application.buildRegistry(namespace);
const registry = new Registry({
fallback: fallbackRegistry
});
// @ts-ignore: this is private API.
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
// @ts-ignore: this is private API.
registry.normalizeFullName = fallbackRegistry.normalizeFullName;
// @ts-ignore: this is private API.
registry.makeToString = fallbackRegistry.makeToString;
// @ts-ignore: this is private API.
registry.describe = fallbackRegistry.describe;
const owner = Owner.create({
// @ts-ignore -- we do not have type safety for `Object.extend` so the type
// of `Owner` here is just `EmberObject`, but we *do* constrain it to allow
// only types from the actual class, so these fields are not accepted.
// However, we can see that they are valid, based on the definition of
// `Owner` above given that it fulfills the `InternalOwner` contract and
// also extends it just as `EngineInstance` does internally.
//
// NOTE: we use an `ignore` directive rather than `expect-error` because in
// *some* versions of the types, we *do* have (at least some of) this
// safety, and maximal backwards compatibility means we have to account for
// that.
__registry__: registry,
__container__: null
});
// @ts-ignore: this is private API.
const container = registry.container({
owner: owner
});
// @ts-ignore: this is private API.
owner.__container__ = container;
exposeRegistryMethodsWithoutDeprecations(container);
return {
registry,
container,
owner
};
}
export { buildRegistry as default };
//# sourceMappingURL=build-registry.js.map