(function() {
/*!
* @overview Ember - JavaScript Application Framework
* @copyright Copyright 2011-2018 Tilde Inc. and contributors
* Portions Copyright 2006-2011 Strobe Inc.
* Portions Copyright 2008-2011 Apple Inc. All rights reserved.
* @license Licensed under MIT license
* See https://raw.github.com/emberjs/ember.js/master/LICENSE
* @version 3.7.0
*/
/*globals process */
var enifed, requireModule, Ember;
// Used in @ember/-internals/environment/lib/global.js
mainContext = this; // eslint-disable-line no-undef
(function() {
function missingModule(name, referrerName) {
if (referrerName) {
throw new Error('Could not find module ' + name + ' required by: ' + referrerName);
} else {
throw new Error('Could not find module ' + name);
}
}
function internalRequire(_name, referrerName) {
var name = _name;
var mod = registry[name];
if (!mod) {
name = name + '/index';
mod = registry[name];
}
var exports = seen[name];
if (exports !== undefined) {
return exports;
}
exports = seen[name] = {};
if (!mod) {
missingModule(_name, referrerName);
}
var deps = mod.deps;
var callback = mod.callback;
var reified = new Array(deps.length);
for (var i = 0; i < deps.length; i++) {
if (deps[i] === 'exports') {
reified[i] = exports;
} else if (deps[i] === 'require') {
reified[i] = requireModule;
} else {
reified[i] = internalRequire(deps[i], name);
}
}
callback.apply(this, reified);
return exports;
}
var isNode =
typeof window === 'undefined' &&
typeof process !== 'undefined' &&
{}.toString.call(process) === '[object process]';
if (!isNode) {
Ember = this.Ember = this.Ember || {};
}
if (typeof Ember === 'undefined') {
Ember = {};
}
if (typeof Ember.__loader === 'undefined') {
var registry = Object.create(null);
var seen = Object.create(null);
enifed = function(name, deps, callback) {
var value = {};
if (!callback) {
value.deps = [];
value.callback = deps;
} else {
value.deps = deps;
value.callback = callback;
}
registry[name] = value;
};
requireModule = function(name) {
return internalRequire(name, null);
};
// setup `require` module
requireModule['default'] = requireModule;
requireModule.has = function registryHas(moduleName) {
return !!registry[moduleName] || !!registry[moduleName + '/index'];
};
requireModule._eak_seen = registry;
Ember.__loader = {
define: enifed,
require: requireModule,
registry: registry,
};
} else {
enifed = Ember.__loader.define;
requireModule = Ember.__loader.require;
}
})();
enifed('@ember/application/tests/application_instance_test', ['@ember/engine', '@ember/application', '@ember/application/instance', '@ember/runloop', '@ember/-internals/container', 'internal-test-helpers', '@ember/-internals/runtime', '@ember/debug'], function (_engine, _application, _instance, _runloop, _container, _internalTestHelpers, _runtime, _debug) {
'use strict';
const originalDebug = (0, _debug.getDebugFunction)('debug');
const noop = function () {};
let application, appInstance;
(0, _internalTestHelpers.moduleFor)('ApplicationInstance', class extends _internalTestHelpers.AbstractTestCase {
constructor() {
(0, _debug.setDebugFunction)('debug', noop);
super();
document.getElementById('qunit-fixture').innerHTML = `
HI
HI
`;
application = (0, _runloop.run)(() => _application.default.create({ rootElement: '#one', router: null }));
}
teardown() {
(0, _debug.setDebugFunction)('debug', originalDebug);
if (appInstance) {
(0, _runloop.run)(appInstance, 'destroy');
appInstance = null;
}
if (application) {
(0, _runloop.run)(application, 'destroy');
application = null;
}
document.getElementById('qunit-fixture').innerHTML = '';
}
['@test an application instance can be created based upon an application'](assert) {
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
assert.ok(appInstance, 'instance should be created');
assert.equal(appInstance.application, application, 'application should be set to parent');
}
['@test customEvents added to the application before setupEventDispatcher'](assert) {
assert.expect(1);
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
appInstance.setupRegistry();
application.customEvents = {
awesome: 'sauce'
};
let eventDispatcher = appInstance.lookup('event_dispatcher:main');
eventDispatcher.setup = function (events) {
assert.equal(events.awesome, 'sauce');
};
appInstance.setupEventDispatcher();
}
['@test customEvents added to the application before setupEventDispatcher'](assert) {
assert.expect(1);
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
appInstance.setupRegistry();
application.customEvents = {
awesome: 'sauce'
};
let eventDispatcher = appInstance.lookup('event_dispatcher:main');
eventDispatcher.setup = function (events) {
assert.equal(events.awesome, 'sauce');
};
appInstance.setupEventDispatcher();
}
['@test customEvents added to the application instance before setupEventDispatcher'](assert) {
assert.expect(1);
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
appInstance.setupRegistry();
appInstance.customEvents = {
awesome: 'sauce'
};
let eventDispatcher = appInstance.lookup('event_dispatcher:main');
eventDispatcher.setup = function (events) {
assert.equal(events.awesome, 'sauce');
};
appInstance.setupEventDispatcher();
}
['@test unregistering a factory clears all cached instances of that factory'](assert) {
assert.expect(5);
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
let PostController1 = (0, _internalTestHelpers.factory)();
let PostController2 = (0, _internalTestHelpers.factory)();
appInstance.register('controller:post', PostController1);
let postController1 = appInstance.lookup('controller:post');
let postController1Factory = appInstance.factoryFor('controller:post');
assert.ok(postController1 instanceof PostController1, 'precond - lookup creates instance');
assert.equal(PostController1, postController1Factory.class, 'precond - factoryFor().class matches');
appInstance.unregister('controller:post');
appInstance.register('controller:post', PostController2);
let postController2 = appInstance.lookup('controller:post');
let postController2Factory = appInstance.factoryFor('controller:post');
assert.ok(postController2 instanceof PostController2, 'lookup creates instance');
assert.equal(PostController2, postController2Factory.class, 'factoryFor().class matches');
assert.notStrictEqual(postController1, postController2, 'lookup creates a brand new instance, because the previous one was reset');
}
['@skip unregistering a factory clears caches with source of that factory'](assert) {
assert.expect(1);
appInstance = (0, _runloop.run)(() => _instance.default.create({ application }));
let PostController1 = (0, _internalTestHelpers.factory)();
let PostController2 = (0, _internalTestHelpers.factory)();
appInstance.register('controller:post', PostController1);
appInstance.lookup('controller:post');
let postControllerLookupWithSource = appInstance.lookup('controller:post', {
source: 'doesnt-even-matter'
});
appInstance.unregister('controller:post');
appInstance.register('controller:post', PostController2);
// The cache that is source-specific is not cleared
assert.ok(postControllerLookupWithSource !== appInstance.lookup('controller:post', {
source: 'doesnt-even-matter'
}), 'lookup with source creates a new instance');
}
['@test can build and boot a registered engine'](assert) {
assert.expect(11);
let ChatEngine = _engine.default.extend();
let chatEngineInstance;
application.register('engine:chat', ChatEngine);
(0, _runloop.run)(() => {
appInstance = _instance.default.create({ application });
appInstance.setupRegistry();
chatEngineInstance = appInstance.buildChildEngineInstance('chat');
});
return chatEngineInstance.boot().then(() => {
assert.ok(true, 'boot successful');
let registrations = ['route:basic', 'service:-routing', 'service:-glimmer-environment'];
registrations.forEach(key => {
assert.strictEqual(chatEngineInstance.resolveRegistration(key), appInstance.resolveRegistration(key), `Engine and parent app share registrations for '${key}'`);
});
let singletons = ['router:main', _container.privatize`-bucket-cache:main`, '-view-registry:main', '-environment:main', 'service:-document', 'event_dispatcher:main'];
let env = appInstance.lookup('-environment:main');
singletons.push(env.isInteractive ? 'renderer:-dom' : 'renderer:-inert');
singletons.forEach(key => {
assert.strictEqual(chatEngineInstance.lookup(key), appInstance.lookup(key), `Engine and parent app share singleton '${key}'`);
});
});
}
['@test can build a registry via ApplicationInstance.setupRegistry() -- simulates ember-test-helpers'](assert) {
let namespace = _runtime.Object.create({
Resolver: { create: function () {} }
});
let registry = _application.default.buildRegistry(namespace);
_instance.default.setupRegistry(registry);
assert.equal(registry.resolve('service:-document'), document);
}
});
});
enifed('@ember/application/tests/application_test', ['ember/version', '@ember/-internals/environment', '@ember/-internals/metal', '@ember/debug', '@ember/application', '@ember/-internals/routing', '@ember/-internals/views', '@ember/controller', '@ember/-internals/runtime', '@ember/-internals/glimmer', '@ember/-internals/container', '@ember/polyfills', 'internal-test-helpers', '@ember/runloop'], function (_version, _environment, _metal, _debug, _application, _routing, _views, _controller, _runtime, _glimmer, _container, _polyfills, _internalTestHelpers, _runloop) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application, autobooting multiple apps', class extends _internalTestHelpers.ApplicationTestCase {
get fixture() {
return `
HI
HI
`;
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
rootElement: '#one',
router: null,
autoboot: true
});
}
createSecondApplication(options) {
let myOptions = (0, _polyfills.assign)(this.applicationOptions, options);
return this.secondApp = _application.default.create(myOptions);
}
teardown() {
super.teardown();
if (this.secondApp) {
this.runTask(() => this.secondApp.destroy());
}
}
[`@test you can make a new application in a non-overlapping element`](assert) {
let app = this.runTask(() => this.createSecondApplication({
rootElement: '#two'
}));
this.runTask(() => app.destroy());
assert.ok(true, 'should not raise');
}
[`@test you cannot make a new application that is a parent of an existing application`]() {
expectAssertion(() => {
this.runTask(() => this.createSecondApplication({
rootElement: this.applicationOptions.rootElement
}));
});
}
[`@test you cannot make a new application that is a descendant of an existing application`]() {
expectAssertion(() => {
this.runTask(() => this.createSecondApplication({
rootElement: '#one-child'
}));
});
}
[`@test you cannot make a new application that is a duplicate of an existing application`]() {
expectAssertion(() => {
this.runTask(() => this.createSecondApplication({
rootElement: '#one'
}));
});
}
[`@test you cannot make two default applications without a rootElement error`]() {
expectAssertion(() => {
this.runTask(() => this.createSecondApplication());
});
}
}); /*globals EmberDev */
(0, _internalTestHelpers.moduleFor)('Application', class extends _internalTestHelpers.ApplicationTestCase {
[`@test builds a registry`](assert) {
let { application } = this;
assert.strictEqual(application.resolveRegistration('application:main'), application, `application:main is registered`);
assert.deepEqual(application.registeredOptionsForType('component'), { singleton: false }, `optionsForType 'component'`);
assert.deepEqual(application.registeredOptionsForType('view'), { singleton: false }, `optionsForType 'view'`);
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'controller:basic');
(0, _internalTestHelpers.verifyRegistration)(assert, application, '-view-registry:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'view', '_viewRegistry', '-view-registry:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'route', '_topLevelViewTemplate', 'template:-outlet');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'route:basic');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'event_dispatcher:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'router:main', 'namespace', 'application:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'view:-outlet', 'namespace', 'application:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'location:auto');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'location:hash');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'location:history');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'location:none');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'controller', 'target', 'router:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'controller', 'namespace', 'application:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, _container.privatize`-bucket-cache:main`);
(0, _internalTestHelpers.verifyInjection)(assert, application, 'router', '_bucketCache', _container.privatize`-bucket-cache:main`);
(0, _internalTestHelpers.verifyInjection)(assert, application, 'route', '_bucketCache', _container.privatize`-bucket-cache:main`);
(0, _internalTestHelpers.verifyInjection)(assert, application, 'route', '_router', 'router:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'component:-text-field');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'component:-text-area');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'component:-checkbox');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'component:link-to');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'service:-routing');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'service:-routing', 'router', 'router:main');
// DEBUGGING
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'resolver-for-debugging:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'container-debug-adapter:main', 'resolver', 'resolver-for-debugging:main');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'data-adapter:main', 'containerDebugAdapter', 'container-debug-adapter:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'container-debug-adapter:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'component-lookup:main');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'service:-glimmer-environment');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'service:-dom-changes');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'service:-dom-tree-construction');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'service:-glimmer-environment', 'appendOperations', 'service:-dom-tree-construction');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'service:-glimmer-environment', 'updateOperations', 'service:-dom-changes');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'renderer', 'env', 'service:-glimmer-environment');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'view:-outlet');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'renderer:-dom');
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'renderer:-inert');
(0, _internalTestHelpers.verifyRegistration)(assert, application, _container.privatize`template:components/-default`);
(0, _internalTestHelpers.verifyRegistration)(assert, application, 'template:-outlet');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'view:-outlet', 'template', 'template:-outlet');
(0, _internalTestHelpers.verifyInjection)(assert, application, 'template', 'compiler', _container.privatize`template-compiler:main`);
assert.deepEqual(application.registeredOptionsForType('helper'), { instantiate: false }, `optionsForType 'helper'`);
}
});
(0, _internalTestHelpers.moduleFor)('Application, default resolver with autoboot', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
constructor() {
super(...arguments);
this.originalLookup = _environment.context.lookup;
}
teardown() {
_environment.context.lookup = this.originalLookup;
super.teardown();
(0, _glimmer.setTemplates)({});
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
autoboot: true
});
}
[`@test acts like a namespace`](assert) {
this.application = this.runTask(() => this.createApplication());
let Foo = this.application.Foo = _runtime.Object.extend();
assert.equal(Foo.toString(), 'TestApp.Foo', 'Classes pick up their parent namespace');
}
[`@test can specify custom router`](assert) {
let MyRouter = _routing.Router.extend();
this.runTask(() => {
this.createApplication();
this.application.Router = MyRouter;
});
assert.ok(this.application.__deprecatedInstance__.lookup('router:main') instanceof MyRouter, 'application resolved the correct router');
}
[`@test Minimal Application initialized with just an application template`]() {
this.setupFixture('');
this.runTask(() => this.createApplication());
this.assertInnerHTML('Hello World');
}
});
(0, _internalTestHelpers.moduleFor)('Application, autobooting', class extends _internalTestHelpers.AutobootApplicationTestCase {
constructor() {
super(...arguments);
this.originalLogVersion = _environment.ENV.LOG_VERSION;
this.originalDebug = (0, _debug.getDebugFunction)('debug');
this.originalWarn = (0, _debug.getDebugFunction)('warn');
}
teardown() {
(0, _debug.setDebugFunction)('warn', this.originalWarn);
(0, _debug.setDebugFunction)('debug', this.originalDebug);
_environment.ENV.LOG_VERSION = this.originalLogVersion;
super.teardown();
}
[`@test initialized application goes to initial route`]() {
this.runTask(() => {
this.createApplication();
this.addTemplate('application', '{{outlet}}');
this.addTemplate('index', '
Hi from index
');
});
this.assertText('Hi from index');
}
[`@test ready hook is called before routing begins`](assert) {
assert.expect(2);
this.runTask(() => {
function registerRoute(application, name, callback) {
let route = _routing.Route.extend({
activate: callback
});
application.register('route:' + name, route);
}
let MyApplication = _application.default.extend({
ready() {
registerRoute(this, 'index', () => {
assert.ok(true, 'last-minute route is activated');
});
}
});
let app = this.createApplication({}, MyApplication);
registerRoute(app, 'application', () => assert.ok(true, 'normal route is activated'));
});
}
[`@test initialize application via initialize call`](assert) {
this.runTask(() => this.createApplication());
// This is not a public way to access the container; we just
// need to make some assertions about the created router
let router = this.applicationInstance.lookup('router:main');
assert.equal(router instanceof _routing.Router, true, 'Router was set from initialize call');
assert.equal(router.location instanceof _routing.NoneLocation, true, 'Location was set from location implementation name');
}
[`@test initialize application with stateManager via initialize call from Router class`](assert) {
this.runTask(() => {
this.createApplication();
this.addTemplate('application', '
Hello!
');
});
// This is not a public way to access the container; we just
// need to make some assertions about the created router
let router = this.application.__deprecatedInstance__.lookup('router:main');
assert.equal(router instanceof _routing.Router, true, 'Router was set from initialize call');
this.assertText('Hello!');
}
[`@test Application Controller backs the appplication template`]() {
this.runTask(() => {
this.createApplication();
this.addTemplate('application', '
{{greeting}}
');
this.add('controller:application', _controller.default.extend({
greeting: 'Hello!'
}));
});
this.assertText('Hello!');
}
[`@test enable log of libraries with an ENV var`](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
let messages = [];
_environment.ENV.LOG_VERSION = true;
(0, _debug.setDebugFunction)('debug', message => messages.push(message));
_metal.libraries.register('my-lib', '2.0.0a');
this.runTask(() => this.createApplication());
assert.equal(messages[1], 'Ember : ' + _version.default);
if (_views.jQueryDisabled) {
assert.equal(messages[2], 'my-lib : ' + '2.0.0a');
} else {
assert.equal(messages[2], 'jQuery : ' + (0, _views.jQuery)().jquery);
assert.equal(messages[3], 'my-lib : ' + '2.0.0a');
}
_metal.libraries.deRegister('my-lib');
}
[`@test disable log of version of libraries with an ENV var`](assert) {
let logged = false;
_environment.ENV.LOG_VERSION = false;
(0, _debug.setDebugFunction)('debug', () => logged = true);
this.runTask(() => this.createApplication());
assert.ok(!logged, 'library version logging skipped');
}
[`@test can resolve custom router`](assert) {
let CustomRouter = _routing.Router.extend();
this.runTask(() => {
this.createApplication();
this.add('router:main', CustomRouter);
});
assert.ok(this.application.__deprecatedInstance__.lookup('router:main') instanceof CustomRouter, 'application resolved the correct router');
}
[`@test does not leak itself in onLoad._loaded`](assert) {
assert.equal(_application._loaded.application, undefined);
this.runTask(() => this.createApplication());
assert.equal(_application._loaded.application, this.application);
this.runTask(() => this.application.destroy());
assert.equal(_application._loaded.application, undefined);
}
[`@test can build a registry via Application.buildRegistry() --- simulates ember-test-helpers`](assert) {
let namespace = _runtime.Object.create({
Resolver: { create: function () {} }
});
let registry = _application.default.buildRegistry(namespace);
assert.equal(registry.resolve('application:main'), namespace);
}
});
(0, _internalTestHelpers.moduleFor)('Application#buildRegistry', class extends _internalTestHelpers.AbstractTestCase {
[`@test can build a registry via Application.buildRegistry() --- simulates ember-test-helpers`](assert) {
let namespace = _runtime.Object.create({
Resolver: { create() {} }
});
let registry = _application.default.buildRegistry(namespace);
assert.equal(registry.resolve('application:main'), namespace);
}
});
(0, _internalTestHelpers.moduleFor)('Application - instance tracking', class extends _internalTestHelpers.ApplicationTestCase {
['@test tracks built instance'](assert) {
let instance = this.application.buildInstance();
(0, _runloop.run)(() => {
this.application.destroy();
});
assert.ok(instance.isDestroyed, 'instance was destroyed');
}
['@test tracks built instances'](assert) {
let instanceA = this.application.buildInstance();
let instanceB = this.application.buildInstance();
(0, _runloop.run)(() => {
this.application.destroy();
});
assert.ok(instanceA.isDestroyed, 'instanceA was destroyed');
assert.ok(instanceB.isDestroyed, 'instanceB was destroyed');
}
});
});
enifed('@ember/application/tests/bootstrap-test', ['@ember/polyfills', 'internal-test-helpers'], function (_polyfills, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application with default resolver and autoboot', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
get fixture() {
return `
`;
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
autoboot: true,
rootElement: '#app'
});
}
['@test templates in script tags are extracted at application creation'](assert) {
this.runTask(() => this.createApplication());
assert.equal(document.getElementById('app').textContent, 'Hello World!');
}
});
});
enifed('@ember/application/tests/dependency_injection/custom_resolver_test', ['@ember/application/globals-resolver', '@ember/polyfills', 'internal-test-helpers'], function (_globalsResolver, _polyfills, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application with extended default resolver and autoboot', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
get applicationOptions() {
let applicationTemplate = this.compile(`
Fallback
`);
let Resolver = _globalsResolver.default.extend({
resolveTemplate(resolvable) {
if (resolvable.fullNameWithoutType === 'application') {
return applicationTemplate;
} else {
return this._super(resolvable);
}
}
});
return (0, _polyfills.assign)(super.applicationOptions, {
Resolver,
autoboot: true
});
}
[`@test a resolver can be supplied to application`]() {
this.runTask(() => this.createApplication());
this.assertText('Fallback');
}
});
});
enifed('@ember/application/tests/dependency_injection/default_resolver_test', ['internal-test-helpers', '@ember/-internals/environment', '@ember/controller', '@ember/service', '@ember/-internals/runtime', '@ember/-internals/routing', '@ember/-internals/glimmer', '@ember/debug'], function (_internalTestHelpers, _environment, _controller, _service, _runtime, _routing, _glimmer, _debug) {
'use strict';
/* globals EmberDev */
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - Integration - default resolver', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
beforeEach() {
this.runTask(() => this.createApplication());
return this.visit('/');
}
get privateRegistry() {
return this.application.__registry__;
}
/*
* This first batch of tests are integration tests against the public
* applicationInstance API.
*/
[`@test the default resolver looks up templates in Ember.TEMPLATES`](assert) {
let fooTemplate = this.addTemplate('foo', `foo template`);
let fooBarTemplate = this.addTemplate('fooBar', `fooBar template`);
let fooBarBazTemplate = this.addTemplate('fooBar/baz', `fooBar/baz template`);
assert.equal(this.applicationInstance.factoryFor('template:foo').class, fooTemplate, 'resolves template:foo');
assert.equal(this.applicationInstance.factoryFor('template:fooBar').class, fooBarTemplate, 'resolves template:foo_bar');
assert.equal(this.applicationInstance.factoryFor('template:fooBar.baz').class, fooBarBazTemplate, 'resolves template:foo_bar.baz');
}
[`@test the default resolver looks up basic name as no prefix`](assert) {
let instance = this.applicationInstance.lookup('controller:basic');
assert.ok(_controller.default.detect(instance), 'locator looks up correct controller');
}
[`@test the default resolver looks up arbitrary types on the namespace`](assert) {
let Class = this.application.FooManager = _runtime.Object.extend();
let resolvedClass = this.application.resolveRegistration('manager:foo');
assert.equal(Class, resolvedClass, 'looks up FooManager on application');
}
[`@test the default resolver resolves models on the namespace`](assert) {
let Class = this.application.Post = _runtime.Object.extend();
let factoryClass = this.applicationInstance.factoryFor('model:post').class;
assert.equal(Class, factoryClass, 'looks up Post model on application');
}
[`@test the default resolver resolves *:main on the namespace`](assert) {
let Class = this.application.FooBar = _runtime.Object.extend();
let factoryClass = this.applicationInstance.factoryFor('foo-bar:main').class;
assert.equal(Class, factoryClass, 'looks up FooBar type without name on application');
}
[`@test the default resolver resolves container-registered helpers`](assert) {
let shorthandHelper = (0, _glimmer.helper)(() => {});
let helper = _glimmer.Helper.extend();
this.application.register('helper:shorthand', shorthandHelper);
this.application.register('helper:complete', helper);
let lookedUpShorthandHelper = this.applicationInstance.factoryFor('helper:shorthand').class;
assert.ok(lookedUpShorthandHelper.isHelperFactory, 'shorthand helper isHelper');
let lookedUpHelper = this.applicationInstance.factoryFor('helper:complete').class;
assert.ok(lookedUpHelper.isHelperFactory, 'complete helper is factory');
assert.ok(helper.detect(lookedUpHelper), 'looked up complete helper');
}
[`@test the default resolver resolves container-registered helpers via lookupFor`](assert) {
let shorthandHelper = (0, _glimmer.helper)(() => {});
let helper = _glimmer.Helper.extend();
this.application.register('helper:shorthand', shorthandHelper);
this.application.register('helper:complete', helper);
let lookedUpShorthandHelper = this.applicationInstance.factoryFor('helper:shorthand').class;
assert.ok(lookedUpShorthandHelper.isHelperFactory, 'shorthand helper isHelper');
let lookedUpHelper = this.applicationInstance.factoryFor('helper:complete').class;
assert.ok(lookedUpHelper.isHelperFactory, 'complete helper is factory');
assert.ok(helper.detect(lookedUpHelper), 'looked up complete helper');
}
[`@test the default resolver resolves helpers on the namespace`](assert) {
let ShorthandHelper = (0, _glimmer.helper)(() => {});
let CompleteHelper = _glimmer.Helper.extend();
this.application.ShorthandHelper = ShorthandHelper;
this.application.CompleteHelper = CompleteHelper;
let resolvedShorthand = this.application.resolveRegistration('helper:shorthand');
let resolvedComplete = this.application.resolveRegistration('helper:complete');
assert.equal(resolvedShorthand, ShorthandHelper, 'resolve fetches the shorthand helper factory');
assert.equal(resolvedComplete, CompleteHelper, 'resolve fetches the complete helper factory');
}
[`@test the default resolver resolves to the same instance, no matter the notation `](assert) {
this.application.NestedPostController = _controller.default.extend({});
assert.equal(this.applicationInstance.lookup('controller:nested-post'), this.applicationInstance.lookup('controller:nested_post'), 'looks up NestedPost controller on application');
}
[`@test the default resolver throws an error if the fullName to resolve is invalid`]() {
expectAssertion(() => {
this.applicationInstance.resolveRegistration(undefined);
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration(null);
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration('');
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration('');
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration(':');
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration('model');
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration('model:');
}, /fullName must be a proper full name/);
expectAssertion(() => {
this.applicationInstance.resolveRegistration(':type');
}, /fullName must be a proper full name/);
}
/*
* The following are integration tests against the private registry API.
*/
[`@test lookup description`](assert) {
this.application.toString = () => 'App';
assert.equal(this.privateRegistry.describe('controller:foo'), 'App.FooController', 'Type gets appended at the end');
assert.equal(this.privateRegistry.describe('controller:foo.bar'), 'App.FooBarController', 'dots are removed');
assert.equal(this.privateRegistry.describe('model:foo'), 'App.Foo', "models don't get appended at the end");
}
[`@test assertion for routes without isRouteFactory property`]() {
this.application.FooRoute = _glimmer.Component.extend();
expectAssertion(() => {
this.privateRegistry.resolve(`route:foo`);
}, /to resolve to an Ember.Route/, 'Should assert');
}
[`@test no assertion for routes that extend from Route`](assert) {
assert.expect(0);
this.application.FooRoute = _routing.Route.extend();
this.privateRegistry.resolve(`route:foo`);
}
[`@test deprecation warning for service factories without isServiceFactory property`]() {
expectAssertion(() => {
this.application.FooService = _runtime.Object.extend();
this.privateRegistry.resolve('service:foo');
}, /Expected service:foo to resolve to an Ember.Service but instead it was TestApp\.FooService\./);
}
[`@test no deprecation warning for service factories that extend from Service`](assert) {
assert.expect(0);
this.application.FooService = _service.default.extend();
this.privateRegistry.resolve('service:foo');
}
[`@test deprecation warning for component factories without isComponentFactory property`]() {
expectAssertion(() => {
this.application.FooComponent = _runtime.Object.extend();
this.privateRegistry.resolve('component:foo');
}, /Expected component:foo to resolve to an Ember\.Component but instead it was TestApp\.FooComponent\./);
}
[`@test no deprecation warning for component factories that extend from Component`]() {
expectNoDeprecation();
this.application.FooView = _glimmer.Component.extend();
this.privateRegistry.resolve('component:foo');
}
[`@test knownForType returns each item for a given type found`](assert) {
this.application.FooBarHelper = 'foo';
this.application.BazQuxHelper = 'bar';
let found = this.privateRegistry.resolver.knownForType('helper');
assert.deepEqual(found, {
'helper:foo-bar': true,
'helper:baz-qux': true
});
}
[`@test knownForType is not required to be present on the resolver`](assert) {
delete this.privateRegistry.resolver.knownForType;
this.privateRegistry.resolver.knownForType('helper', () => {});
assert.ok(true, 'does not error');
}
});
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - Integration - default resolver w/ other namespace', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
beforeEach() {
this.UserInterface = _environment.context.lookup.UserInterface = _runtime.Namespace.create();
this.runTask(() => this.createApplication());
return this.visit('/');
}
teardown() {
let UserInterfaceNamespace = _runtime.Namespace.NAMESPACES_BY_ID['UserInterface'];
if (UserInterfaceNamespace) {
this.runTask(() => {
UserInterfaceNamespace.destroy();
});
}
super.teardown();
}
[`@test the default resolver can look things up in other namespaces`](assert) {
this.UserInterface.NavigationController = _controller.default.extend();
let nav = this.applicationInstance.lookup('controller:userInterface/navigation');
assert.ok(nav instanceof this.UserInterface.NavigationController, 'the result should be an instance of the specified class');
}
});
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - Integration - default resolver', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
constructor() {
super();
this._originalLookup = _environment.context.lookup;
this._originalInfo = (0, _debug.getDebugFunction)('info');
}
beforeEach() {
this.runTask(() => this.createApplication());
return this.visit('/');
}
teardown() {
(0, _debug.setDebugFunction)('info', this._originalInfo);
_environment.context.lookup = this._originalLookup;
super.teardown();
}
[`@test the default resolver logs hits if 'LOG_RESOLVER' is set`](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
assert.expect(3);
this.application.LOG_RESOLVER = true;
this.application.ScoobyDoo = _runtime.Object.extend();
this.application.toString = () => 'App';
(0, _debug.setDebugFunction)('info', function (symbol, name, padding, lookupDescription) {
assert.equal(symbol, '[✓]', 'proper symbol is printed when a module is found');
assert.equal(name, 'doo:scooby', 'proper lookup value is logged');
assert.equal(lookupDescription, 'App.ScoobyDoo');
});
this.applicationInstance.resolveRegistration('doo:scooby');
}
[`@test the default resolver logs misses if 'LOG_RESOLVER' is set`](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
assert.expect(3);
this.application.LOG_RESOLVER = true;
this.application.toString = () => 'App';
(0, _debug.setDebugFunction)('info', function (symbol, name, padding, lookupDescription) {
assert.equal(symbol, '[ ]', 'proper symbol is printed when a module is not found');
assert.equal(name, 'doo:scooby', 'proper lookup value is logged');
assert.equal(lookupDescription, 'App.ScoobyDoo');
});
this.applicationInstance.resolveRegistration('doo:scooby');
}
[`@test doesn't log without LOG_RESOLVER`](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
let infoCount = 0;
this.application.ScoobyDoo = _runtime.Object.extend();
(0, _debug.setDebugFunction)('info', () => infoCount = infoCount + 1);
this.applicationInstance.resolveRegistration('doo:scooby');
this.applicationInstance.resolveRegistration('doo:scrappy');
assert.equal(infoCount, 0, 'console.info should not be called if LOG_RESOLVER is not set');
}
});
});
enifed('@ember/application/tests/dependency_injection/normalization_test', ['@ember/runloop', '@ember/application', 'internal-test-helpers'], function (_runloop, _application, _internalTestHelpers) {
'use strict';
let application, registry;
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - normalize', class extends _internalTestHelpers.AbstractTestCase {
constructor() {
super();
application = (0, _runloop.run)(_application.default, 'create');
registry = application.__registry__;
}
teardown() {
super.teardown();
(0, _runloop.run)(application, 'destroy');
application = undefined;
registry = undefined;
}
['@test normalization'](assert) {
assert.ok(registry.normalize, 'registry#normalize is present');
assert.equal(registry.normalize('foo:bar'), 'foo:bar');
assert.equal(registry.normalize('controller:posts'), 'controller:posts');
assert.equal(registry.normalize('controller:posts_index'), 'controller:postsIndex');
assert.equal(registry.normalize('controller:posts.index'), 'controller:postsIndex');
assert.equal(registry.normalize('controller:posts-index'), 'controller:postsIndex');
assert.equal(registry.normalize('controller:posts.post.index'), 'controller:postsPostIndex');
assert.equal(registry.normalize('controller:posts_post.index'), 'controller:postsPostIndex');
assert.equal(registry.normalize('controller:posts.post_index'), 'controller:postsPostIndex');
assert.equal(registry.normalize('controller:posts.post-index'), 'controller:postsPostIndex');
assert.equal(registry.normalize('controller:postsIndex'), 'controller:postsIndex');
assert.equal(registry.normalize('controller:blogPosts.index'), 'controller:blogPostsIndex');
assert.equal(registry.normalize('controller:blog/posts.index'), 'controller:blog/postsIndex');
assert.equal(registry.normalize('controller:blog/posts-index'), 'controller:blog/postsIndex');
assert.equal(registry.normalize('controller:blog/posts.post.index'), 'controller:blog/postsPostIndex');
assert.equal(registry.normalize('controller:blog/posts_post.index'), 'controller:blog/postsPostIndex');
assert.equal(registry.normalize('controller:blog/posts_post-index'), 'controller:blog/postsPostIndex');
assert.equal(registry.normalize('template:blog/posts_index'), 'template:blog/posts_index');
}
['@test normalization is indempotent'](assert) {
let examples = ['controller:posts', 'controller:posts.post.index', 'controller:blog/posts.post_index', 'template:foo_bar'];
examples.forEach(example => {
assert.equal(registry.normalize(registry.normalize(example)), registry.normalize(example));
});
}
});
});
enifed('@ember/application/tests/dependency_injection/to_string_test', ['@ember/polyfills', '@ember/-internals/utils', '@ember/-internals/runtime', 'internal-test-helpers'], function (_polyfills, _utils, _runtime, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - DefaultResolver#toString', class extends _internalTestHelpers.DefaultResolverApplicationTestCase {
constructor() {
super();
this.runTask(() => this.createApplication());
this.application.Post = _runtime.Object.extend();
}
beforeEach() {
return this.visit('/');
}
['@test factories'](assert) {
let PostFactory = this.applicationInstance.factoryFor('model:post').class;
assert.equal(PostFactory.toString(), 'TestApp.Post', 'expecting the model to be post');
}
['@test instances'](assert) {
let post = this.applicationInstance.lookup('model:post');
let guid = (0, _utils.guidFor)(post);
assert.equal(post.toString(), '', 'expecting the model to be post');
}
});
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection - Resolver#toString', class extends _internalTestHelpers.ApplicationTestCase {
beforeEach() {
return this.visit('/');
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
Resolver: class extends _internalTestHelpers.ModuleBasedTestResolver {
makeToString(_, fullName) {
return fullName;
}
}
});
}
['@test toString called on a resolver'](assert) {
this.add('model:peter', _runtime.Object.extend());
let peter = this.applicationInstance.lookup('model:peter');
let guid = (0, _utils.guidFor)(peter);
assert.equal(peter.toString(), ``, 'expecting the supermodel to be peter');
}
});
});
enifed('@ember/application/tests/dependency_injection_test', ['@ember/-internals/environment', '@ember/runloop', '@ember/-internals/runtime', '@ember/application', 'internal-test-helpers'], function (_environment, _runloop, _runtime, _application, _internalTestHelpers) {
'use strict';
let originalLookup = _environment.context.lookup;
let registry, locator, application;
(0, _internalTestHelpers.moduleFor)('Application Dependency Injection', class extends _internalTestHelpers.AbstractTestCase {
constructor() {
super();
application = (0, _runloop.run)(_application.default, 'create');
application.Person = _runtime.Object.extend({});
application.Orange = _runtime.Object.extend({});
application.Email = _runtime.Object.extend({});
application.User = _runtime.Object.extend({});
application.PostIndexController = _runtime.Object.extend({});
application.register('model:person', application.Person, {
singleton: false
});
application.register('model:user', application.User, {
singleton: false
});
application.register('fruit:favorite', application.Orange);
application.register('communication:main', application.Email, {
singleton: false
});
application.register('controller:postIndex', application.PostIndexController, {
singleton: true
});
registry = application.__registry__;
locator = application.__container__;
_environment.context.lookup = {};
}
teardown() {
super.teardown();
(0, _runloop.run)(application, 'destroy');
registry = application = locator = null;
_environment.context.lookup = originalLookup;
}
['@test container lookup is normalized'](assert) {
let dotNotationController = locator.lookup('controller:post.index');
let camelCaseController = locator.lookup('controller:postIndex');
assert.ok(dotNotationController instanceof application.PostIndexController);
assert.ok(camelCaseController instanceof application.PostIndexController);
assert.equal(dotNotationController, camelCaseController);
}
['@test registered entities can be looked up later'](assert) {
assert.equal(registry.resolve('model:person'), application.Person);
assert.equal(registry.resolve('model:user'), application.User);
assert.equal(registry.resolve('fruit:favorite'), application.Orange);
assert.equal(registry.resolve('communication:main'), application.Email);
assert.equal(registry.resolve('controller:postIndex'), application.PostIndexController);
assert.equal(locator.lookup('fruit:favorite'), locator.lookup('fruit:favorite'), 'singleton lookup worked');
assert.ok(locator.lookup('model:user') !== locator.lookup('model:user'), 'non-singleton lookup worked');
}
['@test injections'](assert) {
application.inject('model', 'fruit', 'fruit:favorite');
application.inject('model:user', 'communication', 'communication:main');
let user = locator.lookup('model:user');
let person = locator.lookup('model:person');
let fruit = locator.lookup('fruit:favorite');
assert.equal(user.get('fruit'), fruit);
assert.equal(person.get('fruit'), fruit);
assert.ok(application.Email.detectInstance(user.get('communication')));
}
});
});
enifed('@ember/application/tests/initializers_test', ['@ember/polyfills', 'internal-test-helpers', '@ember/application'], function (_polyfills, _internalTestHelpers, _application) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application initializers', class extends _internalTestHelpers.AutobootApplicationTestCase {
get fixture() {
return `
ONE
TWO
`;
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
rootElement: '#one'
});
}
createSecondApplication(options, MyApplication = _application.default) {
let myOptions = (0, _polyfills.assign)(this.applicationOptions, {
rootElement: '#two'
}, options);
let secondApp = this.secondApp = MyApplication.create(myOptions);
return secondApp;
}
teardown() {
super.teardown();
if (this.secondApp) {
this.runTask(() => this.secondApp.destroy());
}
}
[`@test initializers require proper 'name' and 'initialize' properties`]() {
let MyApplication = _application.default.extend();
expectAssertion(() => {
MyApplication.initializer({ name: 'initializer' });
});
expectAssertion(() => {
MyApplication.initializer({ initialize() {} });
});
}
[`@test initializers that throw errors cause the boot promise to reject with the error`](assert) {
assert.expect(2);
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'initializer',
initialize() {
throw new Error('boot failure');
}
});
this.runTask(() => {
this.createApplication({
autoboot: false
}, MyApplication);
});
let app = this.application;
try {
this.runTask(() => {
app.boot().then(() => {
assert.ok(false, 'The boot promise should not resolve when there is a boot error');
}, error => {
assert.ok(error instanceof Error, 'The boot promise should reject with an error');
assert.equal(error.message, 'boot failure');
});
});
} catch (error) {
assert.ok(false, 'The boot method should not throw');
throw error;
}
}
[`@test initializers are passed an App`](assert) {
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'initializer',
initialize(App) {
assert.ok(App instanceof _application.default, 'initialize is passed an Application');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
}
[`@test initializers can be registered in a specified order`](assert) {
let order = [];
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'fourth',
after: 'third',
initialize() {
order.push('fourth');
}
});
MyApplication.initializer({
name: 'second',
after: 'first',
before: 'third',
initialize() {
order.push('second');
}
});
MyApplication.initializer({
name: 'fifth',
after: 'fourth',
before: 'sixth',
initialize() {
order.push('fifth');
}
});
MyApplication.initializer({
name: 'first',
before: 'second',
initialize() {
order.push('first');
}
});
MyApplication.initializer({
name: 'third',
initialize() {
order.push('third');
}
});
MyApplication.initializer({
name: 'sixth',
initialize() {
order.push('sixth');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']);
}
[`@test initializers can be registered in a specified order as an array`](assert) {
let order = [];
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'third',
initialize() {
order.push('third');
}
});
MyApplication.initializer({
name: 'second',
after: 'first',
before: ['third', 'fourth'],
initialize() {
order.push('second');
}
});
MyApplication.initializer({
name: 'fourth',
after: ['second', 'third'],
initialize() {
order.push('fourth');
}
});
MyApplication.initializer({
name: 'fifth',
after: 'fourth',
before: 'sixth',
initialize() {
order.push('fifth');
}
});
MyApplication.initializer({
name: 'first',
before: ['second'],
initialize() {
order.push('first');
}
});
MyApplication.initializer({
name: 'sixth',
initialize() {
order.push('sixth');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']);
}
[`@test initializers can have multiple dependencies`](assert) {
let order = [];
let MyApplication = _application.default.extend();
let a = {
name: 'a',
before: 'b',
initialize() {
order.push('a');
}
};
let b = {
name: 'b',
initialize() {
order.push('b');
}
};
let c = {
name: 'c',
after: 'b',
initialize() {
order.push('c');
}
};
let afterB = {
name: 'after b',
after: 'b',
initialize() {
order.push('after b');
}
};
let afterC = {
name: 'after c',
after: 'c',
initialize() {
order.push('after c');
}
};
MyApplication.initializer(b);
MyApplication.initializer(a);
MyApplication.initializer(afterC);
MyApplication.initializer(afterB);
MyApplication.initializer(c);
this.runTask(() => this.createApplication({}, MyApplication));
assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b');
assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c');
assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB');
assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC');
}
[`@test initializers set on Application subclasses are not shared between apps`](assert) {
let firstInitializerRunCount = 0;
let secondInitializerRunCount = 0;
let FirstApp = _application.default.extend();
FirstApp.initializer({
name: 'first',
initialize() {
firstInitializerRunCount++;
}
});
let SecondApp = _application.default.extend();
SecondApp.initializer({
name: 'second',
initialize() {
secondInitializerRunCount++;
}
});
this.runTask(() => this.createApplication({}, FirstApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer only was run');
assert.equal(secondInitializerRunCount, 0, 'first initializer only was run');
this.runTask(() => this.createSecondApplication({}, SecondApp));
assert.equal(firstInitializerRunCount, 1, 'second initializer only was run');
assert.equal(secondInitializerRunCount, 1, 'second initializer only was run');
}
[`@test initializers are concatenated`](assert) {
let firstInitializerRunCount = 0;
let secondInitializerRunCount = 0;
let FirstApp = _application.default.extend();
FirstApp.initializer({
name: 'first',
initialize() {
firstInitializerRunCount++;
}
});
let SecondApp = FirstApp.extend();
SecondApp.initializer({
name: 'second',
initialize() {
secondInitializerRunCount++;
}
});
this.runTask(() => this.createApplication({}, FirstApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created');
assert.equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created');
firstInitializerRunCount = 0;
this.runTask(() => this.createSecondApplication({}, SecondApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created');
assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created');
}
[`@test initializers are per-app`](assert) {
assert.expect(2);
let FirstApp = _application.default.extend();
FirstApp.initializer({
name: 'abc',
initialize() {}
});
expectAssertion(() => {
FirstApp.initializer({
name: 'abc',
initialize() {}
});
});
let SecondApp = _application.default.extend();
SecondApp.instanceInitializer({
name: 'abc',
initialize() {}
});
assert.ok(true, 'Two apps can have initializers named the same.');
}
[`@test initializers are executed in their own context`](assert) {
assert.expect(1);
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'coolInitializer',
myProperty: 'cool',
initialize() {
assert.equal(this.myProperty, 'cool', 'should have access to its own context');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
}
});
});
enifed('@ember/application/tests/instance_initializers_test', ['@ember/polyfills', 'internal-test-helpers', '@ember/application/instance', '@ember/application'], function (_polyfills, _internalTestHelpers, _instance, _application) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application instance initializers', class extends _internalTestHelpers.AutobootApplicationTestCase {
get fixture() {
return `
ONE
TWO
`;
}
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
rootElement: '#one'
});
}
createSecondApplication(options, MyApplication = _application.default) {
let myOptions = (0, _polyfills.assign)(this.applicationOptions, {
rootElement: '#two'
}, options);
let secondApp = this.secondApp = MyApplication.create(myOptions);
return secondApp;
}
teardown() {
super.teardown();
if (this.secondApp) {
this.runTask(() => this.secondApp.destroy());
}
}
[`@test initializers require proper 'name' and 'initialize' properties`]() {
let MyApplication = _application.default.extend();
expectAssertion(() => {
MyApplication.instanceInitializer({ name: 'initializer' });
});
expectAssertion(() => {
MyApplication.instanceInitializer({ initialize() {} });
});
this.runTask(() => this.createApplication({}, MyApplication));
}
[`@test initializers are passed an app instance`](assert) {
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'initializer',
initialize(instance) {
assert.ok(instance instanceof _instance.default, 'initialize is passed an application instance');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
}
[`@test initializers can be registered in a specified order`](assert) {
let order = [];
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'fourth',
after: 'third',
initialize() {
order.push('fourth');
}
});
MyApplication.instanceInitializer({
name: 'second',
after: 'first',
before: 'third',
initialize() {
order.push('second');
}
});
MyApplication.instanceInitializer({
name: 'fifth',
after: 'fourth',
before: 'sixth',
initialize() {
order.push('fifth');
}
});
MyApplication.instanceInitializer({
name: 'first',
before: 'second',
initialize() {
order.push('first');
}
});
MyApplication.instanceInitializer({
name: 'third',
initialize() {
order.push('third');
}
});
MyApplication.instanceInitializer({
name: 'sixth',
initialize() {
order.push('sixth');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']);
}
[`@test initializers can be registered in a specified order as an array`](assert) {
let order = [];
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'third',
initialize() {
order.push('third');
}
});
MyApplication.instanceInitializer({
name: 'second',
after: 'first',
before: ['third', 'fourth'],
initialize() {
order.push('second');
}
});
MyApplication.instanceInitializer({
name: 'fourth',
after: ['second', 'third'],
initialize() {
order.push('fourth');
}
});
MyApplication.instanceInitializer({
name: 'fifth',
after: 'fourth',
before: 'sixth',
initialize() {
order.push('fifth');
}
});
MyApplication.instanceInitializer({
name: 'first',
before: ['second'],
initialize() {
order.push('first');
}
});
MyApplication.instanceInitializer({
name: 'sixth',
initialize() {
order.push('sixth');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
assert.deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']);
}
[`@test initializers can have multiple dependencies`](assert) {
let order = [];
let MyApplication = _application.default.extend();
let a = {
name: 'a',
before: 'b',
initialize() {
order.push('a');
}
};
let b = {
name: 'b',
initialize() {
order.push('b');
}
};
let c = {
name: 'c',
after: 'b',
initialize() {
order.push('c');
}
};
let afterB = {
name: 'after b',
after: 'b',
initialize() {
order.push('after b');
}
};
let afterC = {
name: 'after c',
after: 'c',
initialize() {
order.push('after c');
}
};
MyApplication.instanceInitializer(b);
MyApplication.instanceInitializer(a);
MyApplication.instanceInitializer(afterC);
MyApplication.instanceInitializer(afterB);
MyApplication.instanceInitializer(c);
this.runTask(() => this.createApplication({}, MyApplication));
assert.ok(order.indexOf(a.name) < order.indexOf(b.name), 'a < b');
assert.ok(order.indexOf(b.name) < order.indexOf(c.name), 'b < c');
assert.ok(order.indexOf(b.name) < order.indexOf(afterB.name), 'b < afterB');
assert.ok(order.indexOf(c.name) < order.indexOf(afterC.name), 'c < afterC');
}
[`@test initializers set on Application subclasses should not be shared between apps`](assert) {
let firstInitializerRunCount = 0;
let secondInitializerRunCount = 0;
let FirstApp = _application.default.extend();
FirstApp.instanceInitializer({
name: 'first',
initialize() {
firstInitializerRunCount++;
}
});
let SecondApp = _application.default.extend();
SecondApp.instanceInitializer({
name: 'second',
initialize() {
secondInitializerRunCount++;
}
});
this.runTask(() => this.createApplication({}, FirstApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer only was run');
assert.equal(secondInitializerRunCount, 0, 'first initializer only was run');
this.runTask(() => this.createSecondApplication({}, SecondApp));
assert.equal(firstInitializerRunCount, 1, 'second initializer only was run');
assert.equal(secondInitializerRunCount, 1, 'second initializer only was run');
}
[`@test initializers are concatenated`](assert) {
let firstInitializerRunCount = 0;
let secondInitializerRunCount = 0;
let FirstApp = _application.default.extend();
FirstApp.instanceInitializer({
name: 'first',
initialize() {
firstInitializerRunCount++;
}
});
let SecondApp = FirstApp.extend();
SecondApp.instanceInitializer({
name: 'second',
initialize() {
secondInitializerRunCount++;
}
});
this.runTask(() => this.createApplication({}, FirstApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created');
assert.equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created');
firstInitializerRunCount = 0;
this.runTask(() => this.createSecondApplication({}, SecondApp));
assert.equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created');
assert.equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created');
}
[`@test initializers are per-app`](assert) {
assert.expect(2);
let FirstApp = _application.default.extend();
FirstApp.instanceInitializer({
name: 'abc',
initialize() {}
});
expectAssertion(function () {
FirstApp.instanceInitializer({
name: 'abc',
initialize() {}
});
});
this.runTask(() => this.createApplication({}, FirstApp));
let SecondApp = _application.default.extend();
SecondApp.instanceInitializer({
name: 'abc',
initialize() {}
});
this.runTask(() => this.createSecondApplication({}, SecondApp));
assert.ok(true, 'Two apps can have initializers named the same.');
}
[`@test initializers are run before ready hook`](assert) {
assert.expect(2);
let MyApplication = _application.default.extend({
ready() {
assert.ok(true, 'ready is called');
readyWasCalled = false;
}
});
let readyWasCalled = false;
MyApplication.instanceInitializer({
name: 'initializer',
initialize() {
assert.ok(!readyWasCalled, 'ready is not yet called');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
}
[`@test initializers are executed in their own context`](assert) {
assert.expect(1);
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'coolInitializer',
myProperty: 'cool',
initialize() {
assert.equal(this.myProperty, 'cool', 'should have access to its own context');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
}
[`@test initializers get an instance on app reset`](assert) {
assert.expect(2);
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'giveMeAnInstance',
initialize(instance) {
assert.ok(!!instance, 'Initializer got an instance');
}
});
this.runTask(() => this.createApplication({}, MyApplication));
this.runTask(() => this.application.reset());
}
});
});
enifed('@ember/application/tests/lazy_load_test', ['@ember/runloop', '@ember/application', 'internal-test-helpers'], function (_runloop, _application, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Lazy Loading', class extends _internalTestHelpers.AbstractTestCase {
afterEach() {
let keys = Object.keys(_application._loaded);
for (let i = 0; i < keys.length; i++) {
delete _application._loaded[keys[i]];
}
}
['@test if a load hook is registered, it is executed when runLoadHooks are exected'](assert) {
let count = 0;
(0, _runloop.run)(function () {
(0, _application.onLoad)('__test_hook__', function (object) {
count += object;
});
});
(0, _runloop.run)(function () {
(0, _application.runLoadHooks)('__test_hook__', 1);
});
assert.equal(count, 1, 'the object was passed into the load hook');
}
['@test if runLoadHooks was already run, it executes newly added hooks immediately'](assert) {
let count = 0;
(0, _runloop.run)(() => {
(0, _application.onLoad)('__test_hook__', object => count += object);
});
(0, _runloop.run)(() => (0, _application.runLoadHooks)('__test_hook__', 1));
count = 0;
(0, _runloop.run)(() => {
(0, _application.onLoad)('__test_hook__', object => count += object);
});
assert.equal(count, 1, 'the original object was passed into the load hook');
}
["@test hooks in ENV.EMBER_LOAD_HOOKS['hookName'] get executed"](assert) {
// Note that the necessary code to perform this test is run before
// the Ember lib is loaded in tests/index.html
(0, _runloop.run)(() => {
(0, _application.runLoadHooks)('__before_ember_test_hook__', 1);
});
assert.equal(window.ENV.__test_hook_count__, 1, 'the object was passed into the load hook');
}
['@test load hooks trigger a custom event'](assert) {
if (typeof window === 'object' && typeof window.dispatchEvent === 'function' && typeof CustomEvent === 'function') {
let eventObject = 'super duper awesome events';
window.addEventListener('__test_hook_for_events__', function (e) {
assert.ok(true, 'custom event was fired');
assert.equal(e.detail, eventObject, 'event details are provided properly');
});
(0, _runloop.run)(() => {
(0, _application.runLoadHooks)('__test_hook_for_events__', eventObject);
});
} else {
assert.expect(0);
}
}
});
});
enifed('@ember/application/tests/logging_test', ['internal-test-helpers', '@ember/controller', '@ember/-internals/routing', '@ember/polyfills'], function (_internalTestHelpers, _controller, _routing, _polyfills) {
'use strict';
/*globals EmberDev */
class LoggingApplicationTestCase extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
this.logs = {};
/* eslint-disable no-console */
this._originalLogger = console.info;
console.info = (_, { fullName }) => {
if (!this.logs.hasOwnProperty(fullName)) {
this.logs[fullName] = 0;
}
/* eslint-ensable no-console */
this.logs[fullName]++;
};
this.router.map(function () {
this.route('posts', { resetNamespace: true });
});
}
teardown() {
/* eslint-disable no-console */
console.info = this._originalLogger;
/* eslint-enable no-console */
super.teardown();
}
}
(0, _internalTestHelpers.moduleFor)('Application with LOG_ACTIVE_GENERATION=true', class extends LoggingApplicationTestCase {
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
LOG_ACTIVE_GENERATION: true
});
}
['@test log class generation if logging enabled'](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
return this.visit('/posts').then(() => {
assert.equal(Object.keys(this.logs).length, 4, 'expected logs');
});
}
['@test actively generated classes get logged'](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
return this.visit('/posts').then(() => {
assert.equal(this.logs['controller:application'], 1, 'expected: ApplicationController was generated');
assert.equal(this.logs['controller:posts'], 1, 'expected: PostsController was generated');
assert.equal(this.logs['route:application'], 1, 'expected: ApplicationRoute was generated');
assert.equal(this.logs['route:posts'], 1, 'expected: PostsRoute was generated');
});
}
['@test predefined classes do not get logged'](assert) {
this.add('controller:application', _controller.default.extend());
this.add('controller:posts', _controller.default.extend());
this.add('route:application', _routing.Route.extend());
this.add('route:posts', _routing.Route.extend());
return this.visit('/posts').then(() => {
assert.ok(!this.logs['controller:application'], 'did not expect: ApplicationController was generated');
assert.ok(!this.logs['controller:posts'], 'did not expect: PostsController was generated');
assert.ok(!this.logs['route:application'], 'did not expect: ApplicationRoute was generated');
assert.ok(!this.logs['route:posts'], 'did not expect: PostsRoute was generated');
});
}
});
(0, _internalTestHelpers.moduleFor)('Application when LOG_ACTIVE_GENERATION=false', class extends LoggingApplicationTestCase {
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
LOG_ACTIVE_GENERATION: false
});
}
[`@test do NOT log class generation if logging disabled`](assert) {
return this.visit('/posts').then(() => {
assert.equal(Object.keys(this.logs).length, 0, 'expected logs');
});
}
});
(0, _internalTestHelpers.moduleFor)('Application with LOG_VIEW_LOOKUPS=true', class extends LoggingApplicationTestCase {
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
LOG_VIEW_LOOKUPS: true
});
}
[`@test log when template and view are missing when flag is active`](assert) {
if (EmberDev && EmberDev.runningProdBuild) {
assert.ok(true, 'Logging does not occur in production builds');
return;
}
this.addTemplate('application', '{{outlet}}');
return this.visit('/').then(() => this.visit('/posts')).then(() => {
assert.equal(this.logs['template:application'], undefined, 'expected: Should not log template:application since it exists.');
assert.equal(this.logs['template:index'], 1, 'expected: Could not find "index" template or view.');
assert.equal(this.logs['template:posts'], 1, 'expected: Could not find "posts" template or view.');
});
}
});
(0, _internalTestHelpers.moduleFor)('Application with LOG_VIEW_LOOKUPS=false', class extends LoggingApplicationTestCase {
get applicationOptions() {
return (0, _polyfills.assign)(super.applicationOptions, {
LOG_VIEW_LOOKUPS: false
});
}
[`@test do not log when template and view are missing when flag is not true`](assert) {
return this.visit('/posts').then(() => {
assert.equal(Object.keys(this.logs).length, 0, 'expected no logs');
});
}
[`@test do not log which views are used with templates when flag is not true`](assert) {
return this.visit('/posts').then(() => {
assert.equal(Object.keys(this.logs).length, 0, 'expected no logs');
});
}
});
});
enifed('@ember/application/tests/readiness_test', ['internal-test-helpers', '@ember/runloop', '@ember/application'], function (_internalTestHelpers, _runloop, _application) {
'use strict';
let jQuery, application, Application;
let readyWasCalled, domReady, readyCallbacks;
// We are using a small mock of jQuery because jQuery is third-party code with
// very well-defined semantics, and we want to confirm that a jQuery stub run
// in a more minimal server environment that implements this behavior will be
// sufficient for Ember's requirements.
(0, _internalTestHelpers.moduleFor)('Application readiness', class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
readyWasCalled = 0;
readyCallbacks = [];
let jQueryInstance = {
ready(callback) {
readyCallbacks.push(callback);
if (jQuery.isReady) {
domReady();
}
}
};
jQuery = function () {
return jQueryInstance;
};
jQuery.isReady = false;
let domReadyCalled = 0;
domReady = function () {
if (domReadyCalled !== 0) {
return;
}
domReadyCalled++;
for (let i = 0; i < readyCallbacks.length; i++) {
readyCallbacks[i]();
}
};
Application = _application.default.extend({
$: jQuery,
ready() {
readyWasCalled++;
}
});
}
teardown() {
if (application) {
(0, _runloop.run)(() => application.destroy());
jQuery = readyCallbacks = domReady = Application = application = undefined;
}
}
// These tests are confirming that if the callbacks passed into jQuery's ready hook is called
// synchronously during the application's initialization, we get the same behavior as if
// it was triggered after initialization.
["@test Application's ready event is called right away if jQuery is already ready"](assert) {
jQuery.isReady = true;
(0, _runloop.run)(() => {
application = Application.create({ router: false });
assert.equal(readyWasCalled, 0, 'ready is not called until later');
});
assert.equal(readyWasCalled, 1, 'ready was called');
domReady();
assert.equal(readyWasCalled, 1, "application's ready was not called again");
}
["@test Application's ready event is called after the document becomes ready"](assert) {
(0, _runloop.run)(() => {
application = Application.create({ router: false });
});
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
domReady();
assert.equal(readyWasCalled, 1, 'ready was called now that DOM is ready');
}
["@test Application's ready event can be deferred by other components"](assert) {
(0, _runloop.run)(() => {
application = Application.create({ router: false });
application.deferReadiness();
});
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
domReady();
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
(0, _runloop.run)(() => {
application.advanceReadiness();
assert.equal(readyWasCalled, 0);
});
assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced');
}
["@test Application's ready event can be deferred by other components"](assert) {
jQuery.isReady = false;
(0, _runloop.run)(() => {
application = Application.create({ router: false });
application.deferReadiness();
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
});
domReady();
assert.equal(readyWasCalled, 0, "ready wasn't called yet");
(0, _runloop.run)(() => {
application.advanceReadiness();
});
assert.equal(readyWasCalled, 1, 'ready was called now all readiness deferrals are advanced');
expectAssertion(() => {
application.deferReadiness();
});
}
});
});
enifed('@ember/application/tests/reset_test', ['@ember/runloop', '@ember/-internals/metal', '@ember/controller', '@ember/-internals/routing', 'internal-test-helpers'], function (_runloop, _metal, _controller, _routing, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application - resetting', class extends _internalTestHelpers.AutobootApplicationTestCase {
['@test Brings its own run-loop if not provided'](assert) {
assert.expect(0);
(0, _runloop.run)(() => this.createApplication());
this.application.reset();
}
['@test Does not bring its own run loop if one is already provided'](assert) {
assert.expect(3);
let didBecomeReady = false;
(0, _runloop.run)(() => this.createApplication());
(0, _runloop.run)(() => {
this.application.ready = () => {
didBecomeReady = true;
};
this.application.reset();
this.application.deferReadiness();
assert.ok(!didBecomeReady, 'app is not ready');
});
assert.ok(!didBecomeReady, 'app is not ready');
(0, _runloop.run)(this.application, 'advanceReadiness');
assert.ok(didBecomeReady, 'app is ready');
}
['@test When an application is reset, new instances of controllers are generated'](assert) {
(0, _runloop.run)(() => {
this.createApplication();
this.add('controller:academic', _controller.default.extend());
});
let firstController = this.applicationInstance.lookup('controller:academic');
let secondController = this.applicationInstance.lookup('controller:academic');
this.application.reset();
let thirdController = this.applicationInstance.lookup('controller:academic');
assert.strictEqual(firstController, secondController, 'controllers looked up in succession should be the same instance');
assert.ok(firstController.isDestroying, 'controllers are destroyed when their application is reset');
assert.notStrictEqual(firstController, thirdController, 'controllers looked up after the application is reset should not be the same instance');
}
['@test When an application is reset, the eventDispatcher is destroyed and recreated'](assert) {
let eventDispatcherWasSetup = 0;
let eventDispatcherWasDestroyed = 0;
let mockEventDispatcher = {
setup() {
eventDispatcherWasSetup++;
},
destroy() {
eventDispatcherWasDestroyed++;
}
};
(0, _runloop.run)(() => {
this.createApplication();
this.add('event_dispatcher:main', {
create: () => mockEventDispatcher
});
assert.equal(eventDispatcherWasSetup, 0);
assert.equal(eventDispatcherWasDestroyed, 0);
});
assert.equal(eventDispatcherWasSetup, 1);
assert.equal(eventDispatcherWasDestroyed, 0);
this.application.reset();
assert.equal(eventDispatcherWasDestroyed, 1);
assert.equal(eventDispatcherWasSetup, 2, 'setup called after reset');
}
['@test When an application is reset, the router URL is reset to `/`'](assert) {
(0, _runloop.run)(() => {
this.createApplication();
this.add('router:main', _routing.Router.extend({
location: 'none'
}));
this.router.map(function () {
this.route('one');
this.route('two');
});
});
let initialRouter, initialApplicationController;
return this.visit('/one').then(() => {
initialApplicationController = this.applicationInstance.lookup('controller:application');
initialRouter = this.applicationInstance.lookup('router:main');
let location = initialRouter.get('location');
assert.equal(location.getURL(), '/one');
assert.equal((0, _metal.get)(initialApplicationController, 'currentPath'), 'one');
this.application.reset();
return this.application._bootPromise;
}).then(() => {
let applicationController = this.applicationInstance.lookup('controller:application');
assert.strictEqual(applicationController, undefined, 'application controller no longer exists');
return this.visit('/one');
}).then(() => {
let applicationController = this.applicationInstance.lookup('controller:application');
let router = this.applicationInstance.lookup('router:main');
let location = router.get('location');
assert.notEqual(initialRouter, router, 'a different router instance was created');
assert.notEqual(initialApplicationController, applicationController, 'a different application controller is created');
assert.equal(location.getURL(), '/one');
assert.equal((0, _metal.get)(applicationController, 'currentPath'), 'one');
});
}
['@test When an application with advance/deferReadiness is reset, the app does correctly become ready after reset'](assert) {
let readyCallCount = 0;
(0, _runloop.run)(() => {
this.createApplication({
ready() {
readyCallCount++;
}
});
this.application.deferReadiness();
assert.equal(readyCallCount, 0, 'ready has not yet been called');
});
(0, _runloop.run)(this.application, 'advanceReadiness');
assert.equal(readyCallCount, 1, 'ready was called once');
this.application.reset();
assert.equal(readyCallCount, 2, 'ready was called twice');
}
});
});
enifed('@ember/application/tests/visit_test', ['internal-test-helpers', '@ember/service', '@ember/-internals/runtime', '@ember/runloop', '@ember/application', '@ember/application/instance', '@ember/engine', '@ember/-internals/routing', '@ember/-internals/glimmer', 'ember-template-compiler', '@ember/-internals/environment'], function (_internalTestHelpers, _service, _runtime, _runloop, _application, _instance, _engine, _routing, _glimmer, _emberTemplateCompiler, _environment) {
'use strict';
function expectAsyncError() {
_runtime.RSVP.off('error');
}
(0, _internalTestHelpers.moduleFor)('Application - visit()', class extends _internalTestHelpers.ApplicationTestCase {
teardown() {
_runtime.RSVP.on('error', _runtime.onerrorDefault);
_environment.ENV._APPLICATION_TEMPLATE_WRAPPER = false;
super.teardown();
}
createApplication(options) {
return super.createApplication(options, _application.default.extend());
}
assertEmptyFixture(message) {
this.assert.strictEqual(document.getElementById('qunit-fixture').children.length, 0, `there are no elements in the fixture element ${message ? message : ''}`);
}
[`@test does not add serialize-mode markers by default`](assert) {
let templateContent = '
Hi, Mom!
';
this.addTemplate('index', templateContent);
let rootElement = document.createElement('div');
let bootOptions = {
isBrowser: false,
rootElement
};
_environment.ENV._APPLICATION_TEMPLATE_WRAPPER = false;
return this.visit('/', bootOptions).then(() => {
assert.equal(rootElement.innerHTML, templateContent, 'without serialize flag renders as expected');
});
}
[`@test _renderMode: rehydration`](assert) {
assert.expect(2);
let indexTemplate = '
Hi, Mom!
';
this.addTemplate('index', indexTemplate);
let rootElement = document.createElement('div');
let bootOptions = {
isBrowser: false,
rootElement,
_renderMode: 'serialize'
};
_environment.ENV._APPLICATION_TEMPLATE_WRAPPER = false;
return this.visit('/', bootOptions).then(instance => {
assert.ok((0, _glimmer.isSerializationFirstNode)(instance.rootElement.firstChild), 'glimmer-vm comment node was not found');
}).then(() => {
return this.runTask(() => {
this.applicationInstance.destroy();
this.applicationInstance = null;
});
}).then(() => {
bootOptions = {
isBrowser: false,
rootElement,
_renderMode: 'rehydrate'
};
this.application.visit('/', bootOptions).then(instance => {
assert.equal(instance.rootElement.innerHTML, indexTemplate, 'was not properly rehydrated');
});
});
}
// 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.
[`@test Applications with autoboot set to false do not autoboot`](assert) {
function delay(time) {
return new _runtime.RSVP.Promise(resolve => (0, _runloop.later)(resolve, time));
}
let appBooted = 0;
let instanceBooted = 0;
this.application.initializer({
name: 'assert-no-autoboot',
initialize() {
appBooted++;
}
});
this.application.instanceInitializer({
name: 'assert-no-autoboot',
initialize() {
instanceBooted++;
}
});
assert.ok(!this.applicationInstance, 'precond - no instance');
assert.ok(appBooted === 0, 'precond - not booted');
assert.ok(instanceBooted === 0, 'precond - not booted');
// 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 this.runTask(() => this.application.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()');
});
}
[`@test calling visit() on an app without first calling boot() should boot the app`](assert) {
let appBooted = 0;
let instanceBooted = 0;
this.application.initializer({
name: 'assert-no-autoboot',
initialize() {
appBooted++;
}
});
this.application.instanceInitializer({
name: 'assert-no-autoboot',
initialize() {
instanceBooted++;
}
});
return this.visit('/').then(() => {
assert.ok(appBooted === 1, 'the app should be booted`');
assert.ok(instanceBooted === 1, 'an instances should be booted');
});
}
[`@test calling visit() on an already booted app should not boot it again`](assert) {
let appBooted = 0;
let instanceBooted = 0;
this.application.initializer({
name: 'assert-no-autoboot',
initialize() {
appBooted++;
}
});
this.application.instanceInitializer({
name: 'assert-no-autoboot',
initialize() {
instanceBooted++;
}
});
return this.runTask(() => this.application.boot()).then(() => {
assert.ok(appBooted === 1, 'the app should be booted');
assert.ok(instanceBooted === 0, 'no instances should be booted');
return this.visit('/');
}).then(() => {
assert.ok(appBooted === 1, 'the app should not be booted again');
assert.ok(instanceBooted === 1, 'an instance should be booted');
/*
* Destroy the instance.
*/
return this.runTask(() => {
this.applicationInstance.destroy();
this.applicationInstance = null;
});
}).then(() => {
/*
* Visit on the application a second time. The application should remain
* booted, but a new instance will be created.
*/
return this.application.visit('/').then(instance => {
this.applicationInstance = instance;
});
}).then(() => {
assert.ok(appBooted === 1, 'the app should not be booted again');
assert.ok(instanceBooted === 2, 'another instance should be booted');
});
}
[`@test visit() rejects on application boot failure`](assert) {
this.application.initializer({
name: 'error',
initialize() {
throw new Error('boot failure');
}
});
expectAsyncError();
return this.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');
});
}
[`@test visit() rejects on instance boot failure`](assert) {
this.application.instanceInitializer({
name: 'error',
initialize() {
throw new Error('boot failure');
}
});
expectAsyncError();
return this.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');
});
}
[`@test visit() follows redirects`](assert) {
this.router.map(function () {
this.route('a');
this.route('b', { path: '/b/:b' });
this.route('c', { path: '/c/:c' });
});
this.add('route:a', _routing.Route.extend({
afterModel() {
this.replaceWith('b', 'zomg');
}
}));
this.add('route:b', _routing.Route.extend({
afterModel(params) {
this.transitionTo('c', params.b);
}
}));
/*
* First call to `visit` is `this.application.visit` and returns the
* applicationInstance.
*/
return this.visit('/a').then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(instance.getURL(), '/c/zomg', 'It should follow all redirects');
});
}
[`@test visit() rejects if an error occurred during a transition`](assert) {
this.router.map(function () {
this.route('a');
this.route('b', { path: '/b/:b' });
this.route('c', { path: '/c/:c' });
});
this.add('route:a', _routing.Route.extend({
afterModel() {
this.replaceWith('b', 'zomg');
}
}));
this.add('route:b', _routing.Route.extend({
afterModel(params) {
this.transitionTo('c', params.b);
}
}));
this.add('route:c', _routing.Route.extend({
afterModel() {
throw new Error('transition failure');
}
}));
expectAsyncError();
return this.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');
});
}
[`@test visit() chain`](assert) {
this.router.map(function () {
this.route('a');
this.route('b');
this.route('c');
});
return this.visit('/').then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(instance.getURL(), '/');
return instance.visit('/a');
}).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(instance.getURL(), '/a');
return instance.visit('/b');
}).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(instance.getURL(), '/b');
return instance.visit('/c');
}).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(instance.getURL(), '/c');
});
}
[`@test visit() returns a promise that resolves when the view has rendered`](assert) {
this.addTemplate('application', `
Hello world
`);
this.assertEmptyFixture();
return this.visit('/').then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.equal(this.element.textContent, 'Hello world', 'the application was rendered once the promise resolves');
});
}
[`@test visit() returns a promise that resolves without rendering when shouldRender is set to false`](assert) {
assert.expect(3);
this.addTemplate('application', '
Hello world
');
this.assertEmptyFixture();
return this.visit('/', { shouldRender: false }).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
this.assertEmptyFixture('after visit');
});
}
[`@test visit() renders a template when shouldRender is set to true`](assert) {
assert.expect(3);
this.addTemplate('application', '
Hello world
');
this.assertEmptyFixture();
return this.visit('/', { shouldRender: true }).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.strictEqual(document.querySelector('#qunit-fixture').children.length, 1, 'there is 1 element in the fixture element after visit');
});
}
[`@test visit() returns a promise that resolves without rendering when shouldRender is set to false with Engines`](assert) {
assert.expect(3);
this.router.map(function () {
this.mount('blog');
});
this.addTemplate('application', '
Hello world
');
// Register engine
let BlogEngine = _engine.default.extend();
this.add('engine:blog', BlogEngine);
// Register engine route map
let BlogMap = function () {};
this.add('route-map:blog', BlogMap);
this.assertEmptyFixture();
return this.visit('/blog', { shouldRender: false }).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
this.assertEmptyFixture('after visit');
});
}
[`@test visit() does not setup the event_dispatcher:main if isInteractive is false (with Engines) GH#15615`](assert) {
assert.expect(3);
this.router.map(function () {
this.mount('blog');
});
this.addTemplate('application', '
Hello world
{{outlet}}');
this.add('event_dispatcher:main', {
create() {
throw new Error('should not happen!');
}
});
// Register engine
let BlogEngine = _engine.default.extend({
init(...args) {
this._super.apply(this, args);
this.register('template:application', (0, _emberTemplateCompiler.compile)('{{cache-money}}'));
this.register('template:components/cache-money', (0, _emberTemplateCompiler.compile)(`
Dis cache money
`));
this.register('component:cache-money', _glimmer.Component.extend({}));
}
});
this.add('engine:blog', BlogEngine);
// Register engine route map
let BlogMap = function () {};
this.add('route-map:blog', BlogMap);
this.assertEmptyFixture();
return this.visit('/blog', { isInteractive: false }).then(instance => {
assert.ok(instance instanceof _instance.default, 'promise is resolved with an ApplicationInstance');
assert.strictEqual(this.element.querySelector('p').textContent, 'Dis cache money', 'Engine component is resolved');
});
}
[`@test visit() on engine resolves engine component`](assert) {
assert.expect(2);
this.router.map(function () {
this.mount('blog');
});
// Register engine
let BlogEngine = _engine.default.extend({
init(...args) {
this._super.apply(this, args);
this.register('template:application', (0, _emberTemplateCompiler.compile)('{{cache-money}}'));
this.register('template:components/cache-money', (0, _emberTemplateCompiler.compile)(`
`);
this.addTemplate('index', `{{index-wrapper}}`);
this.runTask(() => {
this.application.advanceReadiness();
});
let { application: { testHelpers: { wait, triggerEvent } } } = this;
return wait().then(() => {
return triggerEvent('.input', '#limited', 'keydown', {
keyCode: 13
});
}).then(() => {
assert.equal(event.keyCode, 13, 'options were passed');
assert.equal(event.type, 'keydown', 'correct event was triggered');
assert.equal(event.target.getAttribute('id'), 'inside-scope', 'triggered on the correct element');
});
}
});
(0, _internalTestHelpers.moduleFor)('ember-testing: debugging helpers', class extends HelpersApplicationTestCase {
afterEach() {
super.afterEach();
(0, _debug.setDebugFunction)('info', originalInfo);
}
constructor() {
super();
this.runTask(() => {
this.application.advanceReadiness();
});
}
[`@test pauseTest pauses`](assert) {
assert.expect(1);
// overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391)
(0, _debug.setDebugFunction)('info', noop);
let { andThen, pauseTest } = this.application.testHelpers;
andThen(() => {
_test.default.adapter.asyncStart = () => {
assert.ok(true, 'Async start should be called after waiting for other helpers');
};
});
pauseTest();
}
[`@test resumeTest resumes paused tests`](assert) {
assert.expect(1);
// overwrite info to supress the console output (see https://github.com/emberjs/ember.js/issues/16391)
(0, _debug.setDebugFunction)('info', noop);
let { application: { testHelpers: { pauseTest, resumeTest } } } = this;
(0, _runloop.later)(() => resumeTest(), 20);
return pauseTest().then(() => {
assert.ok(true, 'pauseTest promise was resolved');
});
}
[`@test resumeTest throws if nothing to resume`](assert) {
assert.expect(1);
assert.throws(() => {
this.application.testHelpers.resumeTest();
}, /Testing has not been paused. There is nothing to resume./);
}
});
(0, _internalTestHelpers.moduleFor)('ember-testing: routing helpers', class extends HelpersTestCase {
constructor() {
super();
this.runTask(() => {
this.createApplication();
this.application.setupForTesting();
this.application.injectTestHelpers();
this.router.map(function () {
this.route('posts', { resetNamespace: true }, function () {
this.route('new');
this.route('edit', { resetNamespace: true });
});
});
});
this.runTask(() => {
this.application.advanceReadiness();
});
}
[`@test currentRouteName for '/'`](assert) {
assert.expect(3);
let { application: { testHelpers } } = this;
return testHelpers.visit('/').then(() => {
assert.equal(testHelpers.currentRouteName(), 'index', `should equal 'index'.`);
assert.equal(testHelpers.currentPath(), 'index', `should equal 'index'.`);
assert.equal(testHelpers.currentURL(), '/', `should equal '/'.`);
});
}
[`@test currentRouteName for '/posts'`](assert) {
assert.expect(3);
let { application: { testHelpers } } = this;
return testHelpers.visit('/posts').then(() => {
assert.equal(testHelpers.currentRouteName(), 'posts.index', `should equal 'posts.index'.`);
assert.equal(testHelpers.currentPath(), 'posts.index', `should equal 'posts.index'.`);
assert.equal(testHelpers.currentURL(), '/posts', `should equal '/posts'.`);
});
}
[`@test currentRouteName for '/posts/new'`](assert) {
assert.expect(3);
let { application: { testHelpers } } = this;
return testHelpers.visit('/posts/new').then(() => {
assert.equal(testHelpers.currentRouteName(), 'posts.new', `should equal 'posts.new'.`);
assert.equal(testHelpers.currentPath(), 'posts.new', `should equal 'posts.new'.`);
assert.equal(testHelpers.currentURL(), '/posts/new', `should equal '/posts/new'.`);
});
}
[`@test currentRouteName for '/posts/edit'`](assert) {
assert.expect(3);
let { application: { testHelpers } } = this;
return testHelpers.visit('/posts/edit').then(() => {
assert.equal(testHelpers.currentRouteName(), 'edit', `should equal 'edit'.`);
assert.equal(testHelpers.currentPath(), 'posts.edit', `should equal 'posts.edit'.`);
assert.equal(testHelpers.currentURL(), '/posts/edit', `should equal '/posts/edit'.`);
});
}
});
(0, _internalTestHelpers.moduleFor)('ember-testing: pendingRequests', class extends HelpersApplicationTestCase {
trigger(type, xhr) {
(0, _views.jQuery)(document).trigger(type, xhr);
}
[`@test pendingRequests is maintained for ajaxSend and ajaxComplete events`](assert) {
let done = assert.async();
assert.equal((0, _pending_requests.pendingRequests)(), 0);
let xhr = { some: 'xhr' };
this.trigger('ajaxSend', xhr);
assert.equal((0, _pending_requests.pendingRequests)(), 1, 'Ember.Test.pendingRequests was incremented');
this.trigger('ajaxComplete', xhr);
setTimeout(function () {
assert.equal((0, _pending_requests.pendingRequests)(), 0, 'Ember.Test.pendingRequests was decremented');
done();
}, 0);
}
[`@test pendingRequests is ignores ajaxComplete events from past setupForTesting calls`](assert) {
assert.equal((0, _pending_requests.pendingRequests)(), 0);
let xhr = { some: 'xhr' };
this.trigger('ajaxSend', xhr);
assert.equal((0, _pending_requests.pendingRequests)(), 1, 'Ember.Test.pendingRequests was incremented');
(0, _setup_for_testing.default)();
assert.equal((0, _pending_requests.pendingRequests)(), 0, 'Ember.Test.pendingRequests was reset');
let altXhr = { some: 'more xhr' };
this.trigger('ajaxSend', altXhr);
assert.equal((0, _pending_requests.pendingRequests)(), 1, 'Ember.Test.pendingRequests was incremented');
this.trigger('ajaxComplete', xhr);
assert.equal((0, _pending_requests.pendingRequests)(), 1, 'Ember.Test.pendingRequests is not impressed with your unexpected complete');
}
[`@test pendingRequests is reset by setupForTesting`](assert) {
(0, _pending_requests.incrementPendingRequests)();
(0, _setup_for_testing.default)();
assert.equal((0, _pending_requests.pendingRequests)(), 0, 'pendingRequests is reset');
}
});
(0, _internalTestHelpers.moduleFor)('ember-testing: async router', class extends HelpersTestCase {
constructor() {
super();
this.runTask(() => {
this.createApplication();
this.router.map(function () {
this.route('user', { resetNamespace: true }, function () {
this.route('profile');
this.route('edit');
});
});
// Emulate a long-running unscheduled async operation.
let resolveLater = () => new _runtime.RSVP.Promise(resolve => {
/*
* The wait() helper has a 10ms tick. We should resolve() after
* at least one tick to test whether wait() held off while the
* async router was still loading. 20ms should be enough.
*/
(0, _runloop.later)(resolve, { firstName: 'Tom' }, 20);
});
this.add('route:user', _routing.Route.extend({
model() {
return resolveLater();
}
}));
this.add('route:user.profile', _routing.Route.extend({
beforeModel() {
return resolveLater().then(() => this.transitionTo('user.edit'));
}
}));
this.application.setupForTesting();
});
this.application.injectTestHelpers();
this.runTask(() => {
this.application.advanceReadiness();
});
}
[`@test currentRouteName for '/user'`](assert) {
assert.expect(4);
let { application: { testHelpers } } = this;
return testHelpers.visit('/user').then(() => {
assert.equal(testHelpers.currentRouteName(), 'user.index', `should equal 'user.index'.`);
assert.equal(testHelpers.currentPath(), 'user.index', `should equal 'user.index'.`);
assert.equal(testHelpers.currentURL(), '/user', `should equal '/user'.`);
let userRoute = this.applicationInstance.lookup('route:user');
assert.equal(userRoute.get('controller.model.firstName'), 'Tom', `should equal 'Tom'.`);
});
}
[`@test currentRouteName for '/user/profile'`](assert) {
assert.expect(4);
let { application: { testHelpers } } = this;
return testHelpers.visit('/user/profile').then(() => {
assert.equal(testHelpers.currentRouteName(), 'user.edit', `should equal 'user.edit'.`);
assert.equal(testHelpers.currentPath(), 'user.edit', `should equal 'user.edit'.`);
assert.equal(testHelpers.currentURL(), '/user/edit', `should equal '/user/edit'.`);
let userRoute = this.applicationInstance.lookup('route:user');
assert.equal(userRoute.get('controller.model.firstName'), 'Tom', `should equal 'Tom'.`);
});
}
});
(0, _internalTestHelpers.moduleFor)('ember-testing: can override built-in helpers', class extends HelpersTestCase {
constructor() {
super();
this.runTask(() => {
this.createApplication();
this.application.setupForTesting();
});
this._originalVisitHelper = _test.default._helpers.visit;
this._originalFindHelper = _test.default._helpers.find;
}
teardown() {
_test.default._helpers.visit = this._originalVisitHelper;
_test.default._helpers.find = this._originalFindHelper;
super.teardown();
}
[`@test can override visit helper`](assert) {
assert.expect(1);
_test.default.registerHelper('visit', () => {
assert.ok(true, 'custom visit helper was called');
});
this.application.injectTestHelpers();
return this.application.testHelpers.visit();
}
[`@test can override find helper`](assert) {
assert.expect(1);
_test.default.registerHelper('find', () => {
assert.ok(true, 'custom find helper was called');
return ['not empty array'];
});
this.application.injectTestHelpers();
return this.application.testHelpers.findWithAssert('.who-cares');
}
});
}
});
enifed('ember-testing/tests/integration_test', ['internal-test-helpers', 'ember-testing/lib/test', '@ember/-internals/runtime', '@ember/-internals/routing', '@ember/-internals/views'], function (_internalTestHelpers, _test, _runtime, _routing, _views) {
'use strict';
(0, _internalTestHelpers.moduleFor)('ember-testing Integration tests of acceptance', class extends _internalTestHelpers.AutobootApplicationTestCase {
constructor() {
super();
this.modelContent = [];
this._originalAdapter = _test.default.adapter;
this.runTask(() => {
this.createApplication();
this.addTemplate('people', `
{{#each model as |person|}}
{{person.firstName}}
{{/each}}
`);
this.router.map(function () {
this.route('people', { path: '/' });
});
this.add('route:people', _routing.Route.extend({
model: () => this.modelContent
}));
this.application.setupForTesting();
});
this.runTask(() => {
this.application.reset();
});
this.application.injectTestHelpers();
}
teardown() {
super.teardown();
_test.default.adapter = this._originalAdapter;
}
[`@test template is bound to empty array of people`](assert) {
if (!_views.jQueryDisabled) {
this.runTask(() => this.application.advanceReadiness());
window.visit('/').then(() => {
let rows = window.find('.name').length;
assert.equal(rows, 0, 'successfully stubbed an empty array of people');
});
} else {
this.runTask(() => this.application.advanceReadiness());
window.visit('/').then(() => {
expectAssertion(() => window.find('.name'), 'If jQuery is disabled, please import and use helpers from @ember/test-helpers [https://github.com/emberjs/ember-test-helpers]. Note: `find` is not an available helper.');
});
}
}
[`@test template is bound to array of 2 people`](assert) {
if (!_views.jQueryDisabled) {
this.modelContent = (0, _runtime.A)([]);
this.modelContent.pushObject({ firstName: 'x' });
this.modelContent.pushObject({ firstName: 'y' });
this.runTask(() => this.application.advanceReadiness());
window.visit('/').then(() => {
let rows = window.find('.name').length;
assert.equal(rows, 2, 'successfully stubbed a non empty array of people');
});
} else {
assert.expect(0);
}
}
[`@test 'visit' can be called without advanceReadiness.`](assert) {
if (!_views.jQueryDisabled) {
window.visit('/').then(() => {
let rows = window.find('.name').length;
assert.equal(rows, 0, 'stubbed an empty array of people without calling advanceReadiness.');
});
} else {
assert.expect(0);
}
}
});
});
enifed('ember-testing/tests/reexports_test', ['ember', 'internal-test-helpers'], function (_ember, _internalTestHelpers) {
'use strict';
class ReexportsTestCase extends _internalTestHelpers.AbstractTestCase {}
[
// ember-testing
['Test', 'ember-testing'], ['Test.Adapter', 'ember-testing', 'Adapter'], ['Test.QUnitAdapter', 'ember-testing', 'QUnitAdapter'], ['setupForTesting', 'ember-testing']].forEach(reexport => {
let [path, moduleId, exportName] = reexport;
// default path === exportName if none present
if (!exportName) {
exportName = path;
}
ReexportsTestCase.prototype[`@test Ember.${path} exports correctly`] = function (assert) {
(0, _internalTestHelpers.confirmExport)(_ember.default, assert, path, moduleId, exportName);
};
});
(0, _internalTestHelpers.moduleFor)('ember-testing reexports', ReexportsTestCase);
});
enifed('ember-testing/tests/test/waiters-test', ['ember-testing/lib/test/waiters', 'internal-test-helpers'], function (_waiters, _internalTestHelpers) {
'use strict';
class Waiters {
constructor() {
this._waiters = [];
}
add() {
this._waiters.push([...arguments]);
}
register() {
this.forEach((...args) => {
(0, _waiters.registerWaiter)(...args);
});
}
unregister() {
this.forEach((...args) => {
(0, _waiters.unregisterWaiter)(...args);
});
}
forEach(callback) {
for (let i = 0; i < this._waiters.length; i++) {
let args = this._waiters[i];
callback(...args);
}
}
check() {
this.register();
let result = (0, _waiters.checkWaiters)();
this.unregister();
return result;
}
}
(0, _internalTestHelpers.moduleFor)('ember-testing: waiters', class extends _internalTestHelpers.AbstractTestCase {
constructor() {
super();
this.waiters = new Waiters();
}
teardown() {
this.waiters.unregister();
}
['@test registering a waiter'](assert) {
assert.expect(2);
let obj = { foo: true };
this.waiters.add(obj, function () {
assert.ok(this.foo, 'has proper `this` context');
return true;
});
this.waiters.add(function () {
assert.ok(true, 'is called');
return true;
});
this.waiters.check();
}
['@test unregistering a waiter'](assert) {
assert.expect(2);
let obj = { foo: true };
this.waiters.add(obj, function () {
assert.ok(true, 'precond - waiter with context is registered');
return true;
});
this.waiters.add(function () {
assert.ok(true, 'precond - waiter without context is registered');
return true;
});
this.waiters.check();
this.waiters.unregister();
(0, _waiters.checkWaiters)();
}
['@test checkWaiters returns false if all waiters return true'](assert) {
assert.expect(3);
this.waiters.add(function () {
assert.ok(true, 'precond - waiter is registered');
return true;
});
this.waiters.add(function () {
assert.ok(true, 'precond - waiter is registered');
return true;
});
assert.notOk(this.waiters.check(), 'checkWaiters returns true if all waiters return true');
}
['@test checkWaiters returns true if any waiters return false'](assert) {
assert.expect(3);
this.waiters.add(function () {
assert.ok(true, 'precond - waiter is registered');
return true;
});
this.waiters.add(function () {
assert.ok(true, 'precond - waiter is registered');
return false;
});
assert.ok(this.waiters.check(), 'checkWaiters returns false if any waiters return false');
}
['@test checkWaiters short circuits after first falsey waiter'](assert) {
assert.expect(2);
this.waiters.add(function () {
assert.ok(true, 'precond - waiter is registered');
return false;
});
this.waiters.add(function () {
assert.notOk(true, 'waiter should not be called');
});
assert.ok(this.waiters.check(), 'checkWaiters returns false if any waiters return false');
}
});
});
enifed('ember/tests/application_lifecycle_test', ['internal-test-helpers', '@ember/application', '@ember/-internals/routing', '@ember/-internals/glimmer', '@ember/debug'], function (_internalTestHelpers, _application, _routing, _glimmer, _debug) {
'use strict';
const originalDebug = (0, _debug.getDebugFunction)('debug');
const noop = function () {};
(0, _internalTestHelpers.moduleFor)('Application Lifecycle - route hooks', class extends _internalTestHelpers.AutobootApplicationTestCase {
createApplication() {
let application = super.createApplication(...arguments);
this.add('router:main', _routing.Router.extend({
location: 'none'
}));
return application;
}
constructor() {
(0, _debug.setDebugFunction)('debug', noop);
super();
let menuItem = this.menuItem = {};
this.runTask(() => {
this.createApplication();
let SettingRoute = _routing.Route.extend({
setupController() {
this.controller.set('selectedMenuItem', menuItem);
},
deactivate() {
this.controller.set('selectedMenuItem', null);
}
});
this.add('route:index', SettingRoute);
this.add('route:application', SettingRoute);
});
}
teardown() {
(0, _debug.setDebugFunction)('debug', originalDebug);
}
get indexController() {
return this.applicationInstance.lookup('controller:index');
}
get applicationController() {
return this.applicationInstance.lookup('controller:application');
}
[`@test Resetting the application allows controller properties to be set when a route deactivates`](assert) {
let { indexController, applicationController } = this;
assert.equal(indexController.get('selectedMenuItem'), this.menuItem);
assert.equal(applicationController.get('selectedMenuItem'), this.menuItem);
this.application.reset();
assert.equal(indexController.get('selectedMenuItem'), null);
assert.equal(applicationController.get('selectedMenuItem'), null);
}
[`@test Destroying the application resets the router before the appInstance is destroyed`](assert) {
let { indexController, applicationController } = this;
assert.equal(indexController.get('selectedMenuItem'), this.menuItem);
assert.equal(applicationController.get('selectedMenuItem'), this.menuItem);
this.runTask(() => {
this.application.destroy();
});
assert.equal(indexController.get('selectedMenuItem'), null);
assert.equal(applicationController.get('selectedMenuItem'), null);
}
});
(0, _internalTestHelpers.moduleFor)('Application Lifecycle', class extends _internalTestHelpers.AutobootApplicationTestCase {
createApplication() {
let application = super.createApplication(...arguments);
this.add('router:main', _routing.Router.extend({
location: 'none'
}));
return application;
}
[`@test Destroying a route after the router does create an undestroyed 'toplevelView'`](assert) {
this.runTask(() => {
this.createApplication();
this.addTemplate('index', `Index!`);
this.addTemplate('application', `Application! {{outlet}}`);
});
let router = this.applicationInstance.lookup('router:main');
let route = this.applicationInstance.lookup('route:index');
this.runTask(() => router.destroy());
assert.equal(router._toplevelView, null, 'the toplevelView was cleared');
this.runTask(() => route.destroy());
assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized');
this.runTask(() => this.application.destroy());
assert.equal(router._toplevelView, null, 'the toplevelView was not reinitialized');
}
[`@test initializers can augment an applications customEvents hash`](assert) {
assert.expect(1);
let MyApplication = _application.default.extend();
MyApplication.initializer({
name: 'customize-things',
initialize(application) {
application.customEvents = {
wowza: 'wowza'
};
}
});
this.runTask(() => {
this.createApplication({}, MyApplication);
this.add('component:foo-bar', _glimmer.Component.extend({
wowza() {
assert.ok(true, 'fired the event!');
}
}));
this.addTemplate('application', `{{foo-bar}}`);
this.addTemplate('components/foo-bar', ``);
});
this.$('#wowza-thingy').trigger('wowza');
}
[`@test instanceInitializers can augment an the customEvents hash`](assert) {
assert.expect(1);
let MyApplication = _application.default.extend();
MyApplication.instanceInitializer({
name: 'customize-things',
initialize(application) {
application.customEvents = {
herky: 'jerky'
};
}
});
this.runTask(() => {
this.createApplication({}, MyApplication);
this.add('component:foo-bar', _glimmer.Component.extend({
jerky() {
assert.ok(true, 'fired the event!');
}
}));
this.addTemplate('application', `{{foo-bar}}`);
this.addTemplate('components/foo-bar', ``);
});
this.$('#herky-thingy').trigger('herky');
}
});
});
enifed('ember/tests/component_context_test', ['@ember/controller', '@ember/-internals/glimmer', 'internal-test-helpers'], function (_controller, _glimmer, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application Lifecycle - Component Context', class extends _internalTestHelpers.ApplicationTestCase {
['@test Components with a block should have the proper content when a template is provided'](assert) {
this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
text: 'inner'
}),
template: `{{text}}-{{yield}}`
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'inner-outer', 'The component is composed correctly');
});
}
['@test Components with a block should yield the proper content without a template provided'](assert) {
this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
text: 'inner'
})
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'outer', 'The component is composed correctly');
});
}
['@test Components without a block should have the proper content when a template is provided'](assert) {
this.addTemplate('application', `
{{my-component}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
text: 'inner'
}),
template: '{{text}}'
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'inner', 'The component is composed correctly');
});
}
['@test Components without a block should have the proper content'](assert) {
this.addTemplate('application', `
{{my-component}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
didInsertElement() {
this.element.innerHTML = 'Some text inserted';
}
})
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'Some text inserted', 'The component is composed correctly');
});
}
['@test properties of a component without a template should not collide with internal structures [DEPRECATED]'](assert) {
this.addTemplate('application', `
{{my-component data=foo}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer',
foo: 'Some text inserted'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
didInsertElement() {
this.element.innerHTML = this.get('data');
}
})
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'Some text inserted', 'The component is composed correctly');
});
}
['@test attrs property of a component without a template should not collide with internal structures'](assert) {
this.addTemplate('application', `
{{my-component attrs=foo}}
`);
this.add('controller:application', _controller.default.extend({
text: 'outer',
foo: 'Some text inserted'
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
didInsertElement() {
this.element.innerHTML = this.get('attrs.attrs.value');
}
})
});
return this.visit('/').then(() => {
let text = (0, _internalTestHelpers.getTextOf)(this.element.querySelector('#wrapper'));
assert.equal(text, 'Some text inserted', 'The component is composed correctly');
});
}
['@test Components trigger actions in the parents context when called from within a block'](assert) {
this.addTemplate('application', `
`);
this.add('controller:application', _controller.default.extend({
actions: {
fizzbuzz() {
assert.ok(true, 'action triggered on parent');
}
}
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({})
});
return this.visit('/').then(() => {
this.$('#fizzbuzz', '#wrapper').click();
});
}
['@test Components trigger actions in the components context when called from within its template'](assert) {
this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`);
this.add('controller:application', _controller.default.extend({
actions: {
fizzbuzz() {
assert.ok(false, 'action on the wrong context');
}
}
}));
this.addComponent('my-component', {
ComponentClass: _glimmer.Component.extend({
actions: {
fizzbuzz() {
assert.ok(true, 'action triggered on component');
}
}
}),
template: `Fizzbuzz`
});
return this.visit('/').then(() => {
this.$('#fizzbuzz', '#wrapper').click();
});
}
});
});
enifed('ember/tests/component_registration_test', ['@ember/application', '@ember/controller', '@ember/-internals/glimmer', 'ember-template-compiler', 'internal-test-helpers', '@ember/-internals/environment'], function (_application, _controller, _glimmer, _emberTemplateCompiler, _internalTestHelpers, _environment) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application Lifecycle - Component Registration', class extends _internalTestHelpers.ApplicationTestCase {
// This is necessary for this.application.instanceInitializer to not leak between tests
createApplication(options) {
return super.createApplication(options, _application.default.extend());
}
['@test The helper becomes the body of the component']() {
this.addTemplate('components/expand-it', '
hello {{yield}}
');
this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}');
return this.visit('/').then(() => {
this.assertText('Hello world hello world');
this.assertComponentElement(this.element.firstElementChild, {
tagName: 'div',
content: '
hello world
'
});
});
}
['@test The helper becomes the body of the component (ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS = true;)']() {
_environment.ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS = true;
this.addTemplate('components/expand-it', '
hello {{yield}}
');
this.addTemplate('application', 'Hello world {{#expand-it}}world{{/expand-it}}');
return this.visit('/').then(() => {
this.assertInnerHTML('Hello world
hello world
');
_environment.ENV._TEMPLATE_ONLY_GLIMMER_COMPONENTS = false;
});
}
['@test If a component is registered, it is used'](assert) {
this.addTemplate('components/expand-it', '
hello {{yield}}
');
this.addTemplate('application', `Hello world {{#expand-it}}world{{/expand-it}}`);
this.application.instanceInitializer({
name: 'expand-it-component',
initialize(applicationInstance) {
applicationInstance.register('component:expand-it', _glimmer.Component.extend({
classNames: 'testing123'
}));
}
});
return this.visit('/').then(() => {
let text = this.$('div.testing123').text().trim();
assert.equal(text, 'hello world', 'The component is composed correctly');
});
}
['@test Late-registered components can be rendered with custom `layout` property'](assert) {
this.addTemplate('application', `
there goes {{my-hero}}
`);
this.application.instanceInitializer({
name: 'my-hero-component',
initialize(applicationInstance) {
applicationInstance.register('component:my-hero', _glimmer.Component.extend({
classNames: 'testing123',
layout: (0, _emberTemplateCompiler.compile)('watch him as he GOES')
}));
}
});
return this.visit('/').then(() => {
let text = this.$('#wrapper').text().trim();
assert.equal(text, 'there goes watch him as he GOES', 'The component is composed correctly');
});
}
['@test Late-registered components can be rendered with template registered on the container'](assert) {
this.addTemplate('application', `
hello world {{sally-rutherford}}-{{#sally-rutherford}}!!!{{/sally-rutherford}}
`);
this.application.instanceInitializer({
name: 'sally-rutherford-component-template',
initialize(applicationInstance) {
applicationInstance.register('template:components/sally-rutherford', (0, _emberTemplateCompiler.compile)('funkytowny{{yield}}'));
}
});
this.application.instanceInitializer({
name: 'sally-rutherford-component',
initialize(applicationInstance) {
applicationInstance.register('component:sally-rutherford', _glimmer.Component);
}
});
return this.visit('/').then(() => {
let text = this.$('#wrapper').text().trim();
assert.equal(text, 'hello world funkytowny-funkytowny!!!', 'The component is composed correctly');
});
}
['@test Late-registered components can be rendered with ONLY the template registered on the container'](assert) {
this.addTemplate('application', `
hello world {{borf-snorlax}}-{{#borf-snorlax}}!!!{{/borf-snorlax}}
`);
this.application.instanceInitializer({
name: 'borf-snorlax-component-template',
initialize(applicationInstance) {
applicationInstance.register('template:components/borf-snorlax', (0, _emberTemplateCompiler.compile)('goodfreakingTIMES{{yield}}'));
}
});
return this.visit('/').then(() => {
let text = this.$('#wrapper').text().trim();
assert.equal(text, 'hello world goodfreakingTIMES-goodfreakingTIMES!!!', 'The component is composed correctly');
});
}
['@test Assigning layoutName to a component should setup the template as a layout'](assert) {
assert.expect(1);
this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`);
this.addTemplate('foo-bar-baz', '{{text}}-{{yield}}');
this.application.instanceInitializer({
name: 'application-controller',
initialize(applicationInstance) {
applicationInstance.register('controller:application', _controller.default.extend({
text: 'outer'
}));
}
});
this.application.instanceInitializer({
name: 'my-component-component',
initialize(applicationInstance) {
applicationInstance.register('component:my-component', _glimmer.Component.extend({
text: 'inner',
layoutName: 'foo-bar-baz'
}));
}
});
return this.visit('/').then(() => {
let text = this.$('#wrapper').text().trim();
assert.equal(text, 'inner-outer', 'The component is composed correctly');
});
}
['@test Assigning layoutName and layout to a component should use the `layout` value'](assert) {
assert.expect(1);
this.addTemplate('application', `
{{#my-component}}{{text}}{{/my-component}}
`);
this.addTemplate('foo-bar-baz', 'No way!');
this.application.instanceInitializer({
name: 'application-controller-layout',
initialize(applicationInstance) {
applicationInstance.register('controller:application', _controller.default.extend({
text: 'outer'
}));
}
});
this.application.instanceInitializer({
name: 'my-component-component-layout',
initialize(applicationInstance) {
applicationInstance.register('component:my-component', _glimmer.Component.extend({
text: 'inner',
layoutName: 'foo-bar-baz',
layout: (0, _emberTemplateCompiler.compile)('{{text}}-{{yield}}')
}));
}
});
return this.visit('/').then(() => {
let text = this.$('#wrapper').text().trim();
assert.equal(text, 'inner-outer', 'The component is composed correctly');
});
}
['@test Using name of component that does not exist']() {
this.addTemplate('application', `
{{#no-good}} {{/no-good}}
`);
// TODO: Use the async form of expectAssertion here when it is available
expectAssertion(() => {
this.visit('/');
}, /.* named "no-good" .*/);
return this.runLoopSettled();
}
});
});
enifed('ember/tests/controller_test', ['@ember/controller', 'internal-test-helpers', '@ember/-internals/glimmer'], function (_controller, _internalTestHelpers, _glimmer) {
'use strict';
/*
In Ember 1.x, controllers subtly affect things like template scope
and action targets in exciting and often inscrutable ways. This test
file contains integration tests that verify the correct behavior of
the many parts of the system that change and rely upon controller scope,
from the runtime up to the templating layer.
*/
(0, _internalTestHelpers.moduleFor)('Template scoping examples', class extends _internalTestHelpers.ApplicationTestCase {
['@test Actions inside an outlet go to the associated controller'](assert) {
this.add('controller:index', _controller.default.extend({
actions: {
componentAction() {
assert.ok(true, 'controller received the action');
}
}
}));
this.addComponent('component-with-action', {
ComponentClass: _glimmer.Component.extend({
classNames: ['component-with-action'],
click() {
this.action();
}
})
});
this.addTemplate('index', '{{component-with-action action=(action "componentAction")}}');
return this.visit('/').then(() => {
this.runTask(() => this.$('.component-with-action').click());
});
}
});
});
enifed('ember/tests/error_handler_test', ['@ember/debug', '@ember/runloop', '@ember/-internals/error-handling', 'rsvp', 'internal-test-helpers'], function (_debug, _runloop, _errorHandling, _rsvp, _internalTestHelpers) {
'use strict';
let WINDOW_ONERROR;
function runThatThrowsSync(message = 'Error for testing error handling') {
return (0, _runloop.run)(() => {
throw new Error(message);
});
}
(0, _internalTestHelpers.moduleFor)('error_handler', class extends _internalTestHelpers.AbstractTestCase {
beforeEach() {
// capturing this outside of module scope to ensure we grab
// the test frameworks own window.onerror to reset it
WINDOW_ONERROR = window.onerror;
}
afterEach() {
(0, _debug.setTesting)(_debug.isTesting);
window.onerror = WINDOW_ONERROR;
(0, _errorHandling.setOnerror)(undefined);
}
['@test by default there is no onerror - sync run'](assert) {
assert.strictEqual((0, _errorHandling.getOnerror)(), undefined, 'precond - there should be no Ember.onerror set by default');
assert.throws(runThatThrowsSync, Error, 'errors thrown sync are catchable');
}
['@test when Ember.onerror (which rethrows) is registered - sync run'](assert) {
assert.expect(2);
(0, _errorHandling.setOnerror)(function (error) {
assert.ok(true, 'onerror called');
throw error;
});
assert.throws(runThatThrowsSync, Error, 'error is thrown');
}
['@test when Ember.onerror (which does not rethrow) is registered - sync run'](assert) {
assert.expect(2);
(0, _errorHandling.setOnerror)(function () {
assert.ok(true, 'onerror called');
});
runThatThrowsSync();
assert.ok(true, 'no error was thrown, Ember.onerror can intercept errors');
}
['@test does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - sync run'](assert) {
(0, _debug.setTesting)(true);
let error = new Error('the error');
assert.throws(() => {
(0, _runloop.run)(() => {
throw error;
});
}, error);
}
['@test does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - sync run'](assert) {
(0, _debug.setTesting)(false);
let error = new Error('the error');
assert.throws(() => {
(0, _runloop.run)(() => {
throw error;
});
}, error);
}
['@test does not swallow exceptions (Ember.testing = false, Ember.onerror which rethrows) - sync run'](assert) {
assert.expect(2);
(0, _debug.setTesting)(false);
(0, _errorHandling.setOnerror)(function (error) {
assert.ok(true, 'Ember.onerror was called');
throw error;
});
let error = new Error('the error');
assert.throws(() => {
(0, _runloop.run)(() => {
throw error;
});
}, error);
}
['@test Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - sync run'](assert) {
assert.expect(1);
(0, _debug.setTesting)(false);
(0, _errorHandling.setOnerror)(function () {
assert.ok(true, 'Ember.onerror was called');
});
let error = new Error('the error');
try {
(0, _runloop.run)(() => {
throw error;
});
} catch (e) {
assert.notOk(true, 'Ember.onerror that does not rethrow is intentionally swallowing errors, try / catch wrapping does not see error');
}
}
['@test does not swallow exceptions by default (Ember.testing = true, no Ember.onerror) - async run'](assert) {
let done = assert.async();
let caughtByWindowOnerror;
(0, _debug.setTesting)(true);
window.onerror = function (message) {
caughtByWindowOnerror = message;
// prevent "bubbling" and therefore failing the test
return true;
};
(0, _runloop.later)(() => {
throw new Error('the error');
}, 10);
setTimeout(() => {
assert.pushResult({
result: /the error/.test(caughtByWindowOnerror),
actual: caughtByWindowOnerror,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
done();
}, 20);
}
['@test does not swallow exceptions by default (Ember.testing = false, no Ember.onerror) - async run'](assert) {
let done = assert.async();
let caughtByWindowOnerror;
(0, _debug.setTesting)(false);
window.onerror = function (message) {
caughtByWindowOnerror = message;
// prevent "bubbling" and therefore failing the test
return true;
};
(0, _runloop.later)(() => {
throw new Error('the error');
}, 10);
setTimeout(() => {
assert.pushResult({
result: /the error/.test(caughtByWindowOnerror),
actual: caughtByWindowOnerror,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
done();
}, 20);
}
['@test Ember.onerror can intercept errors (aka swallow) by not rethrowing (Ember.testing = false) - async run'](assert) {
let done = assert.async();
(0, _debug.setTesting)(false);
window.onerror = function () {
assert.notOk(true, 'window.onerror is never invoked when Ember.onerror intentionally swallows errors');
// prevent "bubbling" and therefore failing the test
return true;
};
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called with the error');
});
(0, _runloop.later)(() => {
throw thrown;
}, 10);
setTimeout(done, 20);
}
[`@test errors in promise constructor when Ember.onerror which does not rethrow is present - rsvp`](assert) {
assert.expect(1);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
new _rsvp.default.Promise(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise constructor when Ember.onerror which does rethrow is present - rsvp`](assert) {
assert.expect(2);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
new _rsvp.default.Promise(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise constructor when Ember.onerror which does not rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(1);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
new _rsvp.default.Promise(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise constructor when Ember.onerror which does rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(2);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
new _rsvp.default.Promise(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise .then callback when Ember.onerror which does not rethrow is present - rsvp`](assert) {
assert.expect(1);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
_rsvp.default.resolve().then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise .then callback when Ember.onerror which does rethrow is present - rsvp`](assert) {
assert.expect(2);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
_rsvp.default.resolve().then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise .then callback when Ember.onerror which does not rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(1);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
_rsvp.default.resolve().then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in promise .then callback when Ember.onerror which does rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(2);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
_rsvp.default.resolve().then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 10));
}
[`@test errors in async promise .then callback when Ember.onerror which does not rethrow is present - rsvp`](assert) {
assert.expect(1);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
new _rsvp.default.Promise(resolve => setTimeout(resolve, 10)).then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 20));
}
[`@test errors in async promise .then callback when Ember.onerror which does rethrow is present - rsvp`](assert) {
assert.expect(2);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
new _rsvp.default.Promise(resolve => setTimeout(resolve, 10)).then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 20));
}
[`@test errors in async promise .then callback when Ember.onerror which does not rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(1);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
});
new _rsvp.default.Promise(resolve => setTimeout(resolve, 10)).then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 20));
}
[`@test errors in async promise .then callback when Ember.onerror which does rethrow is present (Ember.testing = false) - rsvp`](assert) {
assert.expect(2);
(0, _debug.setTesting)(false);
let thrown = new Error('the error');
(0, _errorHandling.setOnerror)(function (error) {
assert.strictEqual(error, thrown, 'Ember.onerror is called for errors thrown in RSVP promises');
throw error;
});
window.onerror = function (message) {
assert.pushResult({
result: /the error/.test(message),
actual: message,
expected: 'to include `the error`',
message: 'error should bubble out to window.onerror, and therefore fail tests (due to QUnit implementing window.onerror)'
});
// prevent "bubbling" and therefore failing the test
return true;
};
new _rsvp.default.Promise(resolve => setTimeout(resolve, 10)).then(() => {
throw thrown;
});
// RSVP.Promise's are configured to settle within the run loop, this
// ensures that run loop has completed
return new _rsvp.default.Promise(resolve => setTimeout(resolve, 20));
}
});
});
enifed('ember/tests/helpers/helper_registration_test', ['internal-test-helpers', '@ember/controller', '@ember/service', '@ember/-internals/glimmer'], function (_internalTestHelpers, _controller, _service, _glimmer) {
'use strict';
(0, _internalTestHelpers.moduleFor)('Application Lifecycle - Helper Registration', class extends _internalTestHelpers.ApplicationTestCase {
['@test Unbound dashed helpers registered on the container can be late-invoked'](assert) {
this.addTemplate('application', `
{{x-borf}} {{x-borf 'YES'}}
`);
let myHelper = (0, _glimmer.helper)(params => params[0] || 'BORF');
this.application.register('helper:x-borf', myHelper);
return this.visit('/').then(() => {
assert.equal(this.$('#wrapper').text(), 'BORF YES', 'The helper was invoked from the container');
});
}
['@test Bound helpers registered on the container can be late-invoked'](assert) {
this.addTemplate('application', `
{{x-reverse}} {{x-reverse foo}}
`);
this.add('controller:application', _controller.default.extend({
foo: 'alex'
}));
this.application.register('helper:x-reverse', (0, _glimmer.helper)(function ([value]) {
return value ? value.split('').reverse().join('') : '--';
}));
return this.visit('/').then(() => {
assert.equal(this.$('#wrapper').text(), '-- xela', 'The bound helper was invoked from the container');
});
}
['@test Undashed helpers registered on the container can be invoked'](assert) {
this.addTemplate('application', `
{{omg}}|{{yorp 'boo'}}|{{yorp 'ya'}}
`);
this.application.register('helper:omg', (0, _glimmer.helper)(() => 'OMG'));
this.application.register('helper:yorp', (0, _glimmer.helper)(([value]) => value));
return this.visit('/').then(() => {
assert.equal(this.$('#wrapper').text(), 'OMG|boo|ya', 'The helper was invoked from the container');
});
}
['@test Helpers can receive injections'](assert) {
this.addTemplate('application', `
{{full-name}}
`);
let serviceCalled = false;
this.add('service:name-builder', _service.default.extend({
build() {
serviceCalled = true;
}
}));
this.add('helper:full-name', _glimmer.Helper.extend({
nameBuilder: (0, _service.inject)('name-builder'),
compute() {
this.get('nameBuilder').build();
}
}));
return this.visit('/').then(() => {
assert.ok(serviceCalled, 'service was injected, method called');
});
}
});
});
enifed('ember/tests/helpers/link_to_test', ['internal-test-helpers', '@ember/controller', '@ember/-internals/runtime', '@ember/-internals/metal', '@ember/instrumentation', '@ember/-internals/routing'], function (_internalTestHelpers, _controller, _runtime, _metal, _instrumentation, _routing) {
'use strict';
// IE includes the host name
function normalizeUrl(url) {
return url.replace(/https?:\/\/[^\/]+/, '');
}
function shouldNotBeActive(assert, element) {
checkActive(assert, element, false);
}
function shouldBeActive(assert, element) {
checkActive(assert, element, true);
}
function checkActive(assert, element, active) {
let classList = element.attr('class');
assert.equal(classList.indexOf('active') > -1, active, `${element} active should be ${active}`);
}
(0, _internalTestHelpers.moduleFor)('The {{link-to}} helper - basic tests', class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
this.router.map(function () {
this.route('about');
});
this.addTemplate('index', `
{{#link-to 'index' id='home-link'}}Home{{/link-to}}
{{#link-to 'about' id='self-link'}}Self{{/link-to}}
`);
}
['@test The {{link-to}} helper moves into the named route'](assert) {
return this.visit('/').then(() => {
assert.equal(this.$('h3.home').length, 1, 'The home template was rendered');
assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class');
return this.click('#about-link');
}).then(() => {
assert.equal(this.$('h3.about').length, 1, 'The about template was rendered');
assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class');
});
}
[`@test the {{link-to}} helper doesn't add an href when the tagName isn't 'a'`](assert) {
this.addTemplate('index', `
{{#link-to 'about' id='about-link' tagName='div'}}About{{/link-to}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#about-link').attr('href'), undefined, 'there is no href attribute');
});
}
[`@test the {{link-to}} applies a 'disabled' class when disabled`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link-static" disabledWhen="shouldDisable"}}About{{/link-to}}
{{#link-to "about" id="about-link-dynamic" disabledWhen=dynamicDisabledWhen}}About{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
shouldDisable: true,
dynamicDisabledWhen: 'shouldDisable'
}));
return this.visit('/').then(() => {
assert.equal(this.$('#about-link-static.disabled').length, 1, 'The static link is disabled when its disabledWhen is true');
assert.equal(this.$('#about-link-dynamic.disabled').length, 1, 'The dynamic link is disabled when its disabledWhen is true');
let controller = this.applicationInstance.lookup('controller:index');
this.runTask(() => controller.set('dynamicDisabledWhen', false));
assert.equal(this.$('#about-link-dynamic.disabled').length, 0, 'The dynamic link is re-enabled when its disabledWhen becomes false');
});
}
[`@test the {{link-to}} doesn't apply a 'disabled' class if disabledWhen is not provided`](assert) {
this.addTemplate('index', `{{#link-to "about" id="about-link"}}About{{/link-to}}`);
return this.visit('/').then(() => {
assert.ok(!this.$('#about-link').hasClass('disabled'), 'The link is not disabled if disabledWhen not provided');
});
}
[`@test the {{link-to}} helper supports a custom disabledClass`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link" disabledWhen=true disabledClass="do-not-want"}}About{{/link-to}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class');
});
}
[`@test the {{link-to}} helper supports a custom disabledClass set via bound param`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link" disabledWhen=true disabledClass=disabledClass}}About{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
disabledClass: 'do-not-want'
}));
return this.visit('/').then(() => {
assert.equal(this.$('#about-link.do-not-want').length, 1, 'The link can apply a custom disabled class via bound param');
});
}
[`@test the {{link-to}} helper does not respond to clicks when disabledWhen`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link" disabledWhen=true}}About{{/link-to}}
`);
return this.visit('/').then(() => {
return this.click('#about-link');
}).then(() => {
assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur');
});
}
[`@test the {{link-to}} helper does not respond to clicks when disabled`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link" disabled=true}}About{{/link-to}}
`);
return this.visit('/').then(() => {
return this.click('#about-link');
}).then(() => {
assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur');
});
}
[`@test the {{link-to}} helper responds to clicks according to its disabledWhen bound param`](assert) {
this.addTemplate('index', `
{{#link-to "about" id="about-link" disabledWhen=disabledWhen}}About{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
disabledWhen: true
}));
return this.visit('/').then(() => {
return this.click('#about-link');
}).then(() => {
assert.equal(this.$('h3.about').length, 0, 'Transitioning did not occur');
let controller = this.applicationInstance.lookup('controller:index');
controller.set('disabledWhen', false);
return this.runLoopSettled();
}).then(() => {
return this.click('#about-link');
}).then(() => {
assert.equal(this.$('h3.about').length, 1, 'Transitioning did occur when disabledWhen became false');
});
}
[`@test The {{link-to}} helper supports a custom activeClass`](assert) {
this.addTemplate('index', `
Home
{{#link-to 'about' id='about-link'}}About{{/link-to}}
{{#link-to 'index' id='self-link' activeClass='zomg-active'}}Self{{/link-to}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('h3.home').length, 1, 'The home template was rendered');
assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class');
});
}
[`@test The {{link-to}} helper supports a custom activeClass from a bound param`](assert) {
this.addTemplate('index', `
Home
{{#link-to 'about' id='about-link'}}About{{/link-to}}
{{#link-to 'index' id='self-link' activeClass=activeClass}}Self{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
activeClass: 'zomg-active'
}));
return this.visit('/').then(() => {
assert.equal(this.$('h3.home').length, 1, 'The home template was rendered');
assert.equal(this.$('#self-link.zomg-active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#about-link:not(.active)').length, 1, 'The other link was rendered without active class');
});
}
[`@test The {{link-to}} helper supports 'classNameBindings' with custom values [GH #11699]`](assert) {
this.addTemplate('index', `
Home
{{#link-to 'about' id='about-link' classNameBindings='foo:foo-is-true:foo-is-false'}}About{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
foo: false
}));
return this.visit('/').then(() => {
assert.equal(this.$('#about-link.foo-is-false').length, 1, 'The about-link was rendered with the falsy class');
let controller = this.applicationInstance.lookup('controller:index');
this.runTask(() => controller.set('foo', true));
assert.equal(this.$('#about-link.foo-is-true').length, 1, 'The about-link was rendered with the truthy class after toggling the property');
});
}
});
(0, _internalTestHelpers.moduleFor)('The {{link-to}} helper - location hooks', class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
this.updateCount = 0;
this.replaceCount = 0;
let testContext = this;
this.add('location:none', _routing.NoneLocation.extend({
setURL() {
testContext.updateCount++;
return this._super(...arguments);
},
replaceURL() {
testContext.replaceCount++;
return this._super(...arguments);
}
}));
this.router.map(function () {
this.route('about');
});
this.addTemplate('index', `
{{outlet}}`);
this.addTemplate('index.about', `
{{#link-to 'item' id='other-link' current-when='index'}}ITEM{{/link-to}}
`);
return this.visit('/about').then(() => {
assert.equal(this.$('#other-link.active').length, 1, 'The link is active since current-when is a parent route');
});
}
[`@test The {{link-to}} helper does not disregard current-when when it is given explicitly for a route`](assert) {
this.router.map(function () {
this.route('index', { path: '/' }, function () {
this.route('about');
});
this.route('items', function () {
this.route('item');
});
});
this.addTemplate('index', `
Home
{{outlet}}`);
this.addTemplate('index.about', `
{{#link-to 'items' id='other-link' current-when='index'}}ITEM{{/link-to}}
`);
return this.visit('/about').then(() => {
assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route');
});
}
['@test The {{link-to}} helper does not disregard current-when when it is set via a bound param'](assert) {
this.router.map(function () {
this.route('index', { path: '/' }, function () {
this.route('about');
});
this.route('items', function () {
this.route('item');
});
});
this.add('controller:index.about', _controller.default.extend({
currentWhen: 'index'
}));
this.addTemplate('index', `
Home
{{outlet}}`);
this.addTemplate('index.about', `{{#link-to 'items' id='other-link' current-when=currentWhen}}ITEM{{/link-to}}`);
return this.visit('/about').then(() => {
assert.equal(this.$('#other-link.active').length, 1, 'The link is active when current-when is given for explicitly for a route');
});
}
['@test The {{link-to}} helper supports multiple current-when routes'](assert) {
this.router.map(function () {
this.route('index', { path: '/' }, function () {
this.route('about');
});
this.route('item');
this.route('foo');
});
this.addTemplate('index', `
Home
{{outlet}}`);
this.addTemplate('index.about', `{{#link-to 'item' id='link1' current-when='item index'}}ITEM{{/link-to}}`);
this.addTemplate('item', `{{#link-to 'item' id='link2' current-when='item index'}}ITEM{{/link-to}}`);
this.addTemplate('foo', `{{#link-to 'item' id='link3' current-when='item index'}}ITEM{{/link-to}}`);
return this.visit('/about').then(() => {
assert.equal(this.$('#link1.active').length, 1, 'The link is active since current-when contains the parent route');
return this.visit('/item');
}).then(() => {
assert.equal(this.$('#link2.active').length, 1, 'The link is active since you are on the active route');
return this.visit('/foo');
}).then(() => {
assert.equal(this.$('#link3.active').length, 0, 'The link is not active since current-when does not contain the active route');
});
}
['@test The {{link-to}} helper supports boolean values for current-when'](assert) {
this.router.map(function () {
this.route('index', { path: '/' }, function () {
this.route('about');
});
this.route('item');
});
this.addTemplate('index.about', `
{{#link-to 'index' id='index-link' current-when=isCurrent}}index{{/link-to}}
{{#link-to 'item' id='about-link' current-when=true}}ITEM{{/link-to}}
`);
this.add('controller:index.about', _controller.default.extend({ isCurrent: false }));
return this.visit('/about').then(() => {
assert.ok(this.$('#about-link').hasClass('active'), 'The link is active since current-when is true');
assert.notOk(this.$('#index-link').hasClass('active'), 'The link is not active since current-when is false');
let controller = this.applicationInstance.lookup('controller:index.about');
this.runTask(() => controller.set('isCurrent', true));
assert.ok(this.$('#index-link').hasClass('active'), 'The link is active since current-when is true');
});
}
['@test The {{link-to}} helper defaults to bubbling'](assert) {
this.addTemplate('about', `
`);
return this.visit('/about').then(() => {
assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active');
assert.equal(this.$('#item-link.active').length, 0, 'The item route link is inactive');
return this.visit('/about/item');
}).then(() => {
assert.equal(this.$('#about-link.active').length, 1, 'The about route link is active');
assert.equal(this.$('#item-link.active').length, 1, 'The item route link is active');
});
}
[`@test The {{link-to}} helper works in an #each'd array of string route names`](assert) {
this.router.map(function () {
this.route('foo');
this.route('bar');
this.route('rar');
});
this.add('controller:index', _controller.default.extend({
routeNames: (0, _runtime.A)(['foo', 'bar', 'rar']),
route1: 'bar',
route2: 'foo'
}));
this.addTemplate('index', `
{{#each routeNames as |routeName|}}
{{#link-to routeName}}{{routeName}}{{/link-to}}
{{/each}}
{{#each routeNames as |r|}}
{{#link-to r}}{{r}}{{/link-to}}
{{/each}}
{{#link-to route1}}a{{/link-to}}
{{#link-to route2}}b{{/link-to}}
`);
let linksEqual = (links, expected) => {
assert.equal(links.length, expected.length, 'Has correct number of links');
let idx;
for (idx = 0; idx < links.length; idx++) {
let href = this.$(links[idx]).attr('href');
// Old IE includes the whole hostname as well
assert.equal(href.slice(-expected[idx].length), expected[idx], `Expected link to be '${expected[idx]}', but was '${href}'`);
}
};
return this.visit('/').then(() => {
linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/bar', '/foo']);
let indexController = this.applicationInstance.lookup('controller:index');
this.runTask(() => indexController.set('route1', 'rar'));
linksEqual(this.$('a'), ['/foo', '/bar', '/rar', '/foo', '/bar', '/rar', '/rar', '/foo']);
this.runTask(() => indexController.routeNames.shiftObject());
linksEqual(this.$('a'), ['/bar', '/rar', '/bar', '/rar', '/rar', '/foo']);
});
}
[`@test The non-block form {{link-to}} helper moves into the named route`](assert) {
assert.expect(3);
this.router.map(function () {
this.route('contact');
});
this.addTemplate('index', `
{{link-to 'Home' 'index' id='home-link'}}
{{link-to 'Self' 'contact' id='self-link'}}
`);
return this.visit('/').then(() => {
return this.click('#contact-link');
}).then(() => {
assert.equal(this.$('h3.contact').length, 1, 'The contact template was rendered');
assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class');
});
}
[`@test The non-block form {{link-to}} helper updates the link text when it is a binding`](assert) {
assert.expect(8);
this.router.map(function () {
this.route('contact');
});
this.add('controller:index', _controller.default.extend({
contactName: 'Jane'
}));
this.addTemplate('index', `
{{link-to 'Home' 'index' id='home-link'}}
{{link-to 'Self' 'contact' id='self-link'}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#contact-link').text(), 'Jane', 'The link title is correctly resolved');
let controller = this.applicationInstance.lookup('controller:index');
this.runTask(() => controller.set('contactName', 'Joe'));
assert.equal(this.$('#contact-link').text(), 'Joe', 'The link title is correctly updated when the bound property changes');
this.runTask(() => controller.set('contactName', 'Robert'));
assert.equal(this.$('#contact-link').text(), 'Robert', 'The link title is correctly updated when the bound property changes a second time');
return this.click('#contact-link');
}).then(() => {
assert.equal(this.$('h3.contact').length, 1, 'The contact template was rendered');
assert.equal(this.$('#self-link.active').length, 1, 'The self-link was rendered with active class');
assert.equal(this.$('#home-link:not(.active)').length, 1, 'The other link was rendered without active class');
return this.click('#home-link');
}).then(() => {
assert.equal(this.$('h3.home').length, 1, 'The index template was rendered');
assert.equal(this.$('#contact-link').text(), 'Robert', 'The link title is correctly updated when the route changes');
});
}
[`@test The non-block form {{link-to}} helper moves into the named route with context`](assert) {
assert.expect(5);
this.router.map(function () {
this.route('item', { path: '/item/:id' });
});
this.add('route:index', _routing.Route.extend({
model() {
return [{ id: 'yehuda', name: 'Yehuda Katz' }, { id: 'tom', name: 'Tom Dale' }, { id: 'erik', name: 'Erik Brynroflsson' }];
}
}));
this.addTemplate('index', `
Home
{{#each model as |person|}}
{{link-to person.name 'item' person id=person.id}}
{{/each}}
`);
this.addTemplate('item', `
Item
{{model.name}}
{{#link-to 'index' id='home-link'}}Home{{/link-to}}
`);
return this.visit('/').then(() => {
return this.click('#yehuda');
}).then(() => {
assert.equal(this.$('h3.item').length, 1, 'The item template was rendered');
assert.equal(this.$('p').text(), 'Yehuda Katz', 'The name is correct');
return this.click('#home-link');
}).then(() => {
assert.equal(normalizeUrl(this.$('li a#yehuda').attr('href')), '/item/yehuda');
assert.equal(normalizeUrl(this.$('li a#tom').attr('href')), '/item/tom');
assert.equal(normalizeUrl(this.$('li a#erik').attr('href')), '/item/erik');
});
}
[`@test The non-block form {{link-to}} performs property lookup`](assert) {
this.router.map(function () {
this.route('about');
});
this.addTemplate('index', `
{{link-to 'string' 'index' id='string-link'}}
{{link-to path foo id='path-link'}}
`);
this.add('controller:index', _controller.default.extend({
foo: 'index'
}));
return this.visit('/').then(() => {
let assertEquality = href => {
assert.equal(normalizeUrl(this.$('#string-link').attr('href')), '/');
assert.equal(normalizeUrl(this.$('#path-link').attr('href')), href);
};
assertEquality('/');
let controller = this.applicationInstance.lookup('controller:index');
this.runTask(() => controller.set('foo', 'about'));
assertEquality('/about');
});
}
[`@test The non-block form {{link-to}} protects against XSS`](assert) {
this.addTemplate('application', `{{link-to display 'index' id='link'}}`);
this.add('controller:application', _controller.default.extend({
display: 'blahzorz'
}));
return this.visit('/').then(() => {
assert.equal(this.$('#link').text(), 'blahzorz');
let controller = this.applicationInstance.lookup('controller:application');
this.runTask(() => controller.set('display', 'BLAMMO'));
assert.equal(this.$('#link').text(), 'BLAMMO');
assert.equal(this.$('b').length, 0);
});
}
[`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) {
assert.expect(1);
this.router.map(function () {
this.route('post', { path: 'post/:post_id' });
});
this.addTemplate('application', `{{#link-to 'post'}}Post{{/link-to}}`);
assert.throws(() => {
this.visit('/');
}, /(You attempted to define a `\{\{link-to "post"\}\}` but did not pass the parameters required for generating its dynamic segments.|You must provide param `post_id` to `generate`)/);
return this.runLoopSettled();
}
[`@test the {{link-to}} helper does not throw an error if its route has exited`](assert) {
assert.expect(0);
this.router.map(function () {
this.route('post', { path: 'post/:post_id' });
});
this.addTemplate('application', `
{{#link-to 'index' id='home-link'}}Home{{/link-to}}
{{#link-to 'post' defaultPost id='default-post-link'}}Default Post{{/link-to}}
{{#if currentPost}}
{{#link-to 'post' currentPost id='current-post-link'}}Current Post{{/link-to}}
{{/if}}
`);
this.add('controller:application', _controller.default.extend({
defaultPost: { id: 1 },
postController: (0, _controller.inject)('post'),
currentPost: (0, _metal.alias)('postController.model')
}));
this.add('controller:post', _controller.default.extend());
this.add('route:post', _routing.Route.extend({
model() {
return { id: 2 };
},
serialize(model) {
return { post_id: model.id };
}
}));
return this.visit('/').then(() => this.click('#default-post-link')).then(() => this.click('#home-link')).then(() => this.click('#current-post-link')).then(() => this.click('#home-link'));
}
[`@test {{link-to}} active property respects changing parent route context`](assert) {
this.router.map(function () {
this.route('things', { path: '/things/:name' }, function () {
this.route('other');
});
});
this.addTemplate('application', `
{{link-to 'OMG' 'things' 'omg' id='omg-link'}}
{{link-to 'LOL' 'things' 'lol' id='lol-link'}}
`);
return this.visit('/things/omg').then(() => {
shouldBeActive(assert, this.$('#omg-link'));
shouldNotBeActive(assert, this.$('#lol-link'));
return this.visit('/things/omg/other');
}).then(() => {
shouldBeActive(assert, this.$('#omg-link'));
shouldNotBeActive(assert, this.$('#lol-link'));
});
}
[`@test {{link-to}} populates href with default query param values even without query-params object`](assert) {
this.add('controller:index', _controller.default.extend({
queryParams: ['foo'],
foo: '123'
}));
this.addTemplate('index', `{{#link-to 'index' id='the-link'}}Index{{/link-to}}`);
return this.visit('/').then(() => {
assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href');
});
}
[`@test {{link-to}} populates href with default query param values with empty query-params object`](assert) {
this.add('controller:index', _controller.default.extend({
queryParams: ['foo'],
foo: '123'
}));
this.addTemplate('index', `
{{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#the-link').attr('href'), '/', 'link has right href');
});
}
[`@test {{link-to}} with only query-params and a block updates when route changes`](assert) {
this.router.map(function () {
this.route('about');
});
this.add('controller:application', _controller.default.extend({
queryParams: ['foo', 'bar'],
foo: '123',
bar: 'yes'
}));
this.addTemplate('application', `
{{#link-to (query-params foo='456' bar='NAW') id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href');
return this.visit('/about');
}).then(() => {
assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href');
});
}
[`@test Block-less {{link-to}} with only query-params updates when route changes`](assert) {
this.router.map(function () {
this.route('about');
});
this.add('controller:application', _controller.default.extend({
queryParams: ['foo', 'bar'],
foo: '123',
bar: 'yes'
}));
this.addTemplate('application', `
{{link-to "Index" (query-params foo='456' bar='NAW') id='the-link'}}
`);
return this.visit('/').then(() => {
assert.equal(this.$('#the-link').attr('href'), '/?bar=NAW&foo=456', 'link has right href');
return this.visit('/about');
}).then(() => {
assert.equal(this.$('#the-link').attr('href'), '/about?bar=NAW&foo=456', 'link has right href');
});
}
[`@test The {{link-to}} helper can use dynamic params`](assert) {
this.router.map(function () {
this.route('foo', { path: 'foo/:some/:thing' });
this.route('bar', { path: 'bar/:some/:thing/:else' });
});
this.add('controller:index', _controller.default.extend({
init() {
this._super(...arguments);
this.dynamicLinkParams = ['foo', 'one', 'two'];
}
}));
this.addTemplate('index', `
Home
{{#link-to params=dynamicLinkParams id="dynamic-link"}}Dynamic{{/link-to}}
`);
return this.visit('/').then(() => {
let link = this.$('#dynamic-link');
assert.equal(link.attr('href'), '/foo/one/two');
let controller = this.applicationInstance.lookup('controller:index');
this.runTask(() => {
controller.set('dynamicLinkParams', ['bar', 'one', 'two', 'three']);
});
assert.equal(link.attr('href'), '/bar/one/two/three');
});
}
[`@test GJ: {{link-to}} to a parent root model hook which performs a 'transitionTo' has correct active class #13256`](assert) {
assert.expect(1);
this.router.map(function () {
this.route('parent', function () {
this.route('child');
});
});
this.add('route:parent', _routing.Route.extend({
afterModel() {
this.transitionTo('parent.child');
}
}));
this.addTemplate('application', `
{{link-to 'Parent' 'parent' id='parent-link'}}
`);
return this.visit('/').then(() => {
return this.click('#parent-link');
}).then(() => {
shouldBeActive(assert, this.$('#parent-link'));
});
}
});
(0, _internalTestHelpers.moduleFor)('The {{link-to}} helper - loading states and warnings', class extends _internalTestHelpers.ApplicationTestCase {
[`@test link-to with null/undefined dynamic parameters are put in a loading state`](assert) {
assert.expect(19);
let warningMessage = 'This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.';
this.router.map(function () {
this.route('thing', { path: '/thing/:thing_id' });
this.route('about');
});
this.addTemplate('index', `
{{#link-to destinationRoute routeContext loadingClass='i-am-loading' id='context-link'}}
string
{{/link-to}}
{{#link-to secondRoute loadingClass=loadingClass id='static-link'}}
string
{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
destinationRoute: null,
routeContext: null,
loadingClass: 'i-am-loading'
}));
this.add('route:about', _routing.Route.extend({
activate() {
assert.ok(true, 'About was entered');
}
}));
function assertLinkStatus(link, url) {
if (url) {
assert.equal(normalizeUrl(link.attr('href')), url, 'loaded link-to has expected href');
assert.ok(!link.hasClass('i-am-loading'), 'loaded linkComponent has no loadingClass');
} else {
assert.equal(normalizeUrl(link.attr('href')), '#', "unloaded link-to has href='#'");
assert.ok(link.hasClass('i-am-loading'), 'loading linkComponent has loadingClass');
}
}
let contextLink, staticLink, controller;
return this.visit('/').then(() => {
contextLink = this.$('#context-link');
staticLink = this.$('#static-link');
controller = this.applicationInstance.lookup('controller:index');
assertLinkStatus(contextLink);
assertLinkStatus(staticLink);
return expectWarning(() => {
return this.click(contextLink[0]);
}, warningMessage);
}).then(() => {
// Set the destinationRoute (context is still null).
this.runTask(() => controller.set('destinationRoute', 'thing'));
assertLinkStatus(contextLink);
// Set the routeContext to an id
this.runTask(() => controller.set('routeContext', '456'));
assertLinkStatus(contextLink, '/thing/456');
// Test that 0 isn't interpreted as falsy.
this.runTask(() => controller.set('routeContext', 0));
assertLinkStatus(contextLink, '/thing/0');
// Set the routeContext to an object
this.runTask(() => {
controller.set('routeContext', { id: 123 });
});
assertLinkStatus(contextLink, '/thing/123');
// Set the destinationRoute back to null.
this.runTask(() => controller.set('destinationRoute', null));
assertLinkStatus(contextLink);
return expectWarning(() => {
return this.click(staticLink[0]);
}, warningMessage);
}).then(() => {
this.runTask(() => controller.set('secondRoute', 'about'));
assertLinkStatus(staticLink, '/about');
// Click the now-active link
return this.click(staticLink[0]);
});
}
});
function assertNav(options, callback, assert) {
let nav = false;
function check(event) {
assert.equal(event.defaultPrevented, options.prevented, `expected defaultPrevented=${options.prevented}`);
nav = true;
event.preventDefault();
}
try {
document.addEventListener('click', check);
callback();
} finally {
document.removeEventListener('click', check);
assert.ok(nav, 'Expected a link to be clicked');
}
}
});
enifed('ember/tests/helpers/link_to_test/link_to_transitioning_classes_test', ['@ember/-internals/runtime', '@ember/-internals/routing', 'internal-test-helpers'], function (_runtime, _routing, _internalTestHelpers) {
'use strict';
function assertHasClass(assert, selector, label) {
let testLabel = `${selector.attr('id')} should have class ${label}`;
assert.equal(selector.hasClass(label), true, testLabel);
}
function assertHasNoClass(assert, selector, label) {
let testLabel = `${selector.attr('id')} should not have class ${label}`;
assert.equal(selector.hasClass(label), false, testLabel);
}
(0, _internalTestHelpers.moduleFor)('The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes', class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
this.aboutDefer = _runtime.RSVP.defer();
this.otherDefer = _runtime.RSVP.defer();
this.newsDefer = _runtime.RSVP.defer();
let _this = this;
this.router.map(function () {
this.route('about');
this.route('other');
this.route('news');
});
this.add('route:about', _routing.Route.extend({
model() {
return _this.aboutDefer.promise;
}
}));
this.add('route:other', _routing.Route.extend({
model() {
return _this.otherDefer.promise;
}
}));
this.add('route:news', _routing.Route.extend({
model() {
return _this.newsDefer.promise;
}
}));
this.addTemplate('application', `
{{outlet}}
{{link-to 'Index' 'index' id='index-link'}}
{{link-to 'About' 'about' id='about-link'}}
{{link-to 'Other' 'other' id='other-link'}}
{{link-to 'News' 'news' activeClass=false id='news-link'}}
`);
}
beforeEach() {
return this.visit('/');
}
afterEach() {
super.afterEach();
this.aboutDefer = null;
this.otherDefer = null;
this.newsDefer = null;
}
['@test while a transition is underway'](assert) {
let $index = this.$('#index-link');
let $about = this.$('#about-link');
let $other = this.$('#other-link');
$about.click();
assertHasClass(assert, $index, 'active');
assertHasNoClass(assert, $about, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
this.runTask(() => this.aboutDefer.resolve());
assertHasNoClass(assert, $index, 'active');
assertHasClass(assert, $about, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
}
['@test while a transition is underway with activeClass is false'](assert) {
let $index = this.$('#index-link');
let $news = this.$('#news-link');
let $other = this.$('#other-link');
$news.click();
assertHasClass(assert, $index, 'active');
assertHasNoClass(assert, $news, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasClass(assert, $news, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $news, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
this.runTask(() => this.newsDefer.resolve());
assertHasNoClass(assert, $index, 'active');
assertHasNoClass(assert, $news, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $news, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $news, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
}
});
(0, _internalTestHelpers.moduleFor)(`The {{link-to}} helper: .transitioning-in .transitioning-out CSS classes - nested link-to's`, class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
this.aboutDefer = _runtime.RSVP.defer();
this.otherDefer = _runtime.RSVP.defer();
let _this = this;
this.router.map(function () {
this.route('parent-route', function () {
this.route('about');
this.route('other');
});
});
this.add('route:parent-route.about', _routing.Route.extend({
model() {
return _this.aboutDefer.promise;
}
}));
this.add('route:parent-route.other', _routing.Route.extend({
model() {
return _this.otherDefer.promise;
}
}));
this.addTemplate('application', `
{{outlet}}
{{#link-to 'index' tagName='li'}}
{{link-to 'Index' 'index' id='index-link'}}
{{/link-to}}
{{#link-to 'parent-route.about' tagName='li'}}
{{link-to 'About' 'parent-route.about' id='about-link'}}
{{/link-to}}
{{#link-to 'parent-route.other' tagName='li'}}
{{link-to 'Other' 'parent-route.other' id='other-link'}}
{{/link-to}}
`);
}
beforeEach() {
return this.visit('/');
}
resolveAbout() {
return this.runTask(() => {
this.aboutDefer.resolve();
this.aboutDefer = _runtime.RSVP.defer();
});
}
resolveOther() {
return this.runTask(() => {
this.otherDefer.resolve();
this.otherDefer = _runtime.RSVP.defer();
});
}
teardown() {
super.teardown();
this.aboutDefer = null;
this.otherDefer = null;
}
[`@test while a transition is underway with nested link-to's`](assert) {
// TODO undo changes to this test but currently this test navigates away if navigation
// outlet is not stable and the second $about.click() is triggered.
let $about = this.$('#about-link');
$about.click();
let $index = this.$('#index-link');
$about = this.$('#about-link');
let $other = this.$('#other-link');
assertHasClass(assert, $index, 'active');
assertHasNoClass(assert, $about, 'active');
assertHasNoClass(assert, $about, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
this.resolveAbout();
$index = this.$('#index-link');
$about = this.$('#about-link');
$other = this.$('#other-link');
assertHasNoClass(assert, $index, 'active');
assertHasClass(assert, $about, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
$other.click();
$index = this.$('#index-link');
$about = this.$('#about-link');
$other = this.$('#other-link');
assertHasNoClass(assert, $index, 'active');
assertHasClass(assert, $about, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $about, 'ember-transitioning-in');
assertHasClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
this.resolveOther();
$index = this.$('#index-link');
$about = this.$('#about-link');
$other = this.$('#other-link');
assertHasNoClass(assert, $index, 'active');
assertHasNoClass(assert, $about, 'active');
assertHasClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
$about.click();
$index = this.$('#index-link');
$about = this.$('#about-link');
$other = this.$('#other-link');
assertHasNoClass(assert, $index, 'active');
assertHasNoClass(assert, $about, 'active');
assertHasClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasClass(assert, $other, 'ember-transitioning-out');
this.resolveAbout();
$index = this.$('#index-link');
$about = this.$('#about-link');
$other = this.$('#other-link');
assertHasNoClass(assert, $index, 'active');
assertHasClass(assert, $about, 'active');
assertHasNoClass(assert, $other, 'active');
assertHasNoClass(assert, $index, 'ember-transitioning-in');
assertHasNoClass(assert, $about, 'ember-transitioning-in');
assertHasNoClass(assert, $other, 'ember-transitioning-in');
assertHasNoClass(assert, $index, 'ember-transitioning-out');
assertHasNoClass(assert, $about, 'ember-transitioning-out');
assertHasNoClass(assert, $other, 'ember-transitioning-out');
}
});
});
enifed('ember/tests/helpers/link_to_test/link_to_with_query_params_test', ['@ember/controller', '@ember/-internals/runtime', '@ember/-internals/routing', 'internal-test-helpers'], function (_controller, _runtime, _routing, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('The {{link-to}} helper: invoking with query params', class extends _internalTestHelpers.ApplicationTestCase {
constructor() {
super();
let indexProperties = {
foo: '123',
bar: 'abc'
};
this.add('controller:index', _controller.default.extend({
queryParams: ['foo', 'bar', 'abool'],
foo: indexProperties.foo,
bar: indexProperties.bar,
boundThing: 'OMG',
abool: true
}));
this.add('controller:about', _controller.default.extend({
queryParams: ['baz', 'bat'],
baz: 'alex',
bat: 'borf'
}));
this.indexProperties = indexProperties;
}
shouldNotBeActive(assert, selector) {
this.checkActive(assert, selector, false);
}
shouldBeActive(assert, selector) {
this.checkActive(assert, selector, true);
}
getController(name) {
return this.applicationInstance.lookup(`controller:${name}`);
}
checkActive(assert, selector, active) {
let classList = this.$(selector)[0].className;
assert.equal(classList.indexOf('active') > -1, active, selector + ' active should be ' + active.toString());
}
[`@test doesn't update controller QP properties on current route when invoked`](assert) {
this.addTemplate('index', `
{{#link-to 'index' id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
this.click('#the-link');
let indexController = this.getController('index');
assert.deepEqual(indexController.getProperties('foo', 'bar'), this.indexProperties, 'controller QP properties do not update');
});
}
[`@test doesn't update controller QP properties on current route when invoked (empty query-params obj)`](assert) {
this.addTemplate('index', `
{{#link-to 'index' (query-params) id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
this.click('#the-link');
let indexController = this.getController('index');
assert.deepEqual(indexController.getProperties('foo', 'bar'), this.indexProperties, 'controller QP properties do not update');
});
}
[`@test doesn't update controller QP properties on current route when invoked (empty query-params obj, inferred route)`](assert) {
this.addTemplate('index', `
{{#link-to (query-params) id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
this.click('#the-link');
let indexController = this.getController('index');
assert.deepEqual(indexController.getProperties('foo', 'bar'), this.indexProperties, 'controller QP properties do not update');
});
}
['@test updates controller QP properties on current route when invoked'](assert) {
this.addTemplate('index', `
{{#link-to 'index' (query-params foo='456') id="the-link"}}
Index
{{/link-to}}
`);
return this.visit('/').then(() => {
this.click('#the-link');
let indexController = this.getController('index');
assert.deepEqual(indexController.getProperties('foo', 'bar'), { foo: '456', bar: 'abc' }, 'controller QP properties updated');
});
}
['@test updates controller QP properties on current route when invoked (inferred route)'](assert) {
this.addTemplate('index', `
{{#link-to (query-params foo='456') id="the-link"}}
Index
{{/link-to}}
`);
return this.visit('/').then(() => {
this.click('#the-link');
let indexController = this.getController('index');
assert.deepEqual(indexController.getProperties('foo', 'bar'), { foo: '456', bar: 'abc' }, 'controller QP properties updated');
});
}
['@test updates controller QP properties on other route after transitioning to that route'](assert) {
this.router.map(function () {
this.route('about');
});
this.addTemplate('index', `
{{#link-to 'about' (query-params baz='lol') id='the-link'}}
About
{{/link-to}}
`);
return this.visit('/').then(() => {
let theLink = this.$('#the-link');
assert.equal(theLink.attr('href'), '/about?baz=lol');
this.runTask(() => this.click('#the-link'));
let aboutController = this.getController('about');
assert.deepEqual(aboutController.getProperties('baz', 'bat'), { baz: 'lol', bat: 'borf' }, 'about controller QP properties updated');
});
}
['@test supplied QP properties can be bound'](assert) {
this.addTemplate('index', `
{{#link-to (query-params foo=boundThing) id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
let indexController = this.getController('index');
let theLink = this.$('#the-link');
assert.equal(theLink.attr('href'), '/?foo=OMG');
this.runTask(() => indexController.set('boundThing', 'ASL'));
assert.equal(theLink.attr('href'), '/?foo=ASL');
});
}
['@test supplied QP properties can be bound (booleans)'](assert) {
this.addTemplate('index', `
{{#link-to (query-params abool=boundThing) id='the-link'}}
Index
{{/link-to}}
`);
return this.visit('/').then(() => {
let indexController = this.getController('index');
let theLink = this.$('#the-link');
assert.equal(theLink.attr('href'), '/?abool=OMG');
this.runTask(() => indexController.set('boundThing', false));
assert.equal(theLink.attr('href'), '/?abool=false');
this.click('#the-link');
assert.deepEqual(indexController.getProperties('foo', 'bar', 'abool'), { foo: '123', bar: 'abc', abool: false }, 'bound bool QP properties update');
});
}
['@test href updates when unsupplied controller QP props change'](assert) {
this.addTemplate('index', `
{{#link-to (query-params foo='lol') id='the-link'}}Index{{/link-to}}
`);
return this.visit('/').then(() => {
let indexController = this.getController('index');
let theLink = this.$('#the-link');
assert.equal(theLink.attr('href'), '/?foo=lol');
this.runTask(() => indexController.set('bar', 'BORF'));
assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol');
this.runTask(() => indexController.set('foo', 'YEAH'));
assert.equal(theLink.attr('href'), '/?bar=BORF&foo=lol');
});
}
['@test The {{link-to}} with only query params always transitions to the current route with the query params applied'](assert) {
// Test harness for bug #12033
this.addTemplate('cars', `
{{#link-to 'cars.create' id='create-link'}}Create new car{{/link-to}}
{{#link-to (query-params page='2') id='page2-link'}}Page 2{{/link-to}}
{{outlet}}
`);
this.addTemplate('cars.create', `{{#link-to 'cars' id='close-link'}}Close create form{{/link-to}}`);
this.router.map(function () {
this.route('cars', function () {
this.route('create');
});
});
this.add('controller:cars', _controller.default.extend({
queryParams: ['page'],
page: 1
}));
return this.visit('/cars/create').then(() => {
let router = this.appRouter;
let carsController = this.getController('cars');
assert.equal(router.currentRouteName, 'cars.create');
this.runTask(() => this.click('#close-link'));
assert.equal(router.currentRouteName, 'cars.index');
assert.equal(router.get('url'), '/cars');
assert.equal(carsController.get('page'), 1, 'The page query-param is 1');
this.runTask(() => this.click('#page2-link'));
assert.equal(router.currentRouteName, 'cars.index', 'The active route is still cars');
assert.equal(router.get('url'), '/cars?page=2', 'The url has been updated');
assert.equal(carsController.get('page'), 2, 'The query params have been updated');
});
}
['@test the {{link-to}} applies activeClass when query params are not changed'](assert) {
this.addTemplate('index', `
{{#link-to (query-params foo='cat') id='cat-link'}}Index{{/link-to}}
{{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}}
{{#link-to 'index' id='change-nothing'}}Index{{/link-to}}
`);
this.addTemplate('search', `
{{#link-to (query-params search='same') id='same-search'}}Index{{/link-to}}
{{#link-to (query-params search='change') id='change-search'}}Index{{/link-to}}
{{#link-to (query-params search='same' archive=true) id='same-search-add-archive'}}Index{{/link-to}}
{{#link-to (query-params archive=true) id='only-add-archive'}}Index{{/link-to}}
{{#link-to (query-params search='same' archive=true) id='both-same'}}Index{{/link-to}}
{{#link-to (query-params search='different' archive=true) id='change-one'}}Index{{/link-to}}
{{#link-to (query-params search='different' archive=false) id='remove-one'}}Index{{/link-to}}
{{outlet}}
`);
this.addTemplate('search.results', `
{{#link-to (query-params sort='title') id='same-sort-child-only'}}Index{{/link-to}}
{{#link-to (query-params search='same') id='same-search-parent-only'}}Index{{/link-to}}
{{#link-to (query-params search='change') id='change-search-parent-only'}}Index{{/link-to}}
{{#link-to (query-params search='same' sort='title') id='same-search-same-sort-child-and-parent'}}Index{{/link-to}}
{{#link-to (query-params search='same' sort='author') id='same-search-different-sort-child-and-parent'}}Index{{/link-to}}
{{#link-to (query-params search='change' sort='title') id='change-search-same-sort-child-and-parent'}}Index{{/link-to}}
{{#link-to (query-params foo='dog') id='dog-link'}}Index{{/link-to}}
`);
this.router.map(function () {
this.route('search', function () {
this.route('results');
});
});
this.add('controller:search', _controller.default.extend({
queryParams: ['search', 'archive'],
search: '',
archive: false
}));
this.add('controller:search.results', _controller.default.extend({
queryParams: ['sort', 'showDetails'],
sort: 'title',
showDetails: true
}));
return this.visit('/').then(() => {
this.shouldNotBeActive(assert, '#cat-link');
this.shouldNotBeActive(assert, '#dog-link');
return this.visit('/?foo=cat');
}).then(() => {
this.shouldBeActive(assert, '#cat-link');
this.shouldNotBeActive(assert, '#dog-link');
return this.visit('/?foo=dog');
}).then(() => {
this.shouldBeActive(assert, '#dog-link');
this.shouldNotBeActive(assert, '#cat-link');
this.shouldBeActive(assert, '#change-nothing');
return this.visit('/search?search=same');
}).then(() => {
this.shouldBeActive(assert, '#same-search');
this.shouldNotBeActive(assert, '#change-search');
this.shouldNotBeActive(assert, '#same-search-add-archive');
this.shouldNotBeActive(assert, '#only-add-archive');
this.shouldNotBeActive(assert, '#remove-one');
return this.visit('/search?search=same&archive=true');
}).then(() => {
this.shouldBeActive(assert, '#both-same');
this.shouldNotBeActive(assert, '#change-one');
return this.visit('/search/results?search=same&sort=title&showDetails=true');
}).then(() => {
this.shouldBeActive(assert, '#same-sort-child-only');
this.shouldBeActive(assert, '#same-search-parent-only');
this.shouldNotBeActive(assert, '#change-search-parent-only');
this.shouldBeActive(assert, '#same-search-same-sort-child-and-parent');
this.shouldNotBeActive(assert, '#same-search-different-sort-child-and-parent');
this.shouldNotBeActive(assert, '#change-search-same-sort-child-and-parent');
});
}
['@test the {{link-to}} applies active class when query-param is a number'](assert) {
this.addTemplate('index', `
{{#link-to (query-params page=pageNumber) id='page-link'}}
Index
{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
queryParams: ['page'],
page: 1,
pageNumber: 5
}));
return this.visit('/').then(() => {
this.shouldNotBeActive(assert, '#page-link');
return this.visit('/?page=5');
}).then(() => {
this.shouldBeActive(assert, '#page-link');
});
}
['@test the {{link-to}} applies active class when query-param is an array'](assert) {
this.addTemplate('index', `
{{#link-to (query-params pages=pagesArray) id='array-link'}}Index{{/link-to}}
{{#link-to (query-params pages=biggerArray) id='bigger-link'}}Index{{/link-to}}
{{#link-to (query-params pages=emptyArray) id='empty-link'}}Index{{/link-to}}
`);
this.add('controller:index', _controller.default.extend({
queryParams: ['pages'],
pages: [],
pagesArray: [1, 2],
biggerArray: [1, 2, 3],
emptyArray: []
}));
return this.visit('/').then(() => {
this.shouldNotBeActive(assert, '#array-link');
return this.visit('/?pages=%5B1%2C2%5D');
}).then(() => {
this.shouldBeActive(assert, '#array-link');
this.shouldNotBeActive(assert, '#bigger-link');
this.shouldNotBeActive(assert, '#empty-link');
return this.visit('/?pages=%5B2%2C1%5D');
}).then(() => {
this.shouldNotBeActive(assert, '#array-link');
this.shouldNotBeActive(assert, '#bigger-link');
this.shouldNotBeActive(assert, '#empty-link');
return this.visit('/?pages=%5B1%2C2%2C3%5D');
}).then(() => {
this.shouldBeActive(assert, '#bigger-link');
this.shouldNotBeActive(assert, '#array-link');
this.shouldNotBeActive(assert, '#empty-link');
});
}
['@test the {{link-to}} helper applies active class to the parent route'](assert) {
this.router.map(function () {
this.route('parent', function () {
this.route('child');
});
});
this.addTemplate('application', `
{{#link-to 'parent' id='parent-link'}}Parent{{/link-to}}
{{#link-to 'parent.child' id='parent-child-link'}}Child{{/link-to}}
{{#link-to 'parent' (query-params foo=cat) id='parent-link-qp'}}Parent{{/link-to}}
{{outlet}}
`);
this.add('controller:parent.child', _controller.default.extend({
queryParams: ['foo'],
foo: 'bar'
}));
return this.visit('/').then(() => {
this.shouldNotBeActive(assert, '#parent-link');
this.shouldNotBeActive(assert, '#parent-child-link');
this.shouldNotBeActive(assert, '#parent-link-qp');
return this.visit('/parent/child?foo=dog');
}).then(() => {
this.shouldBeActive(assert, '#parent-link');
this.shouldNotBeActive(assert, '#parent-link-qp');
});
}
['@test The {{link-to}} helper disregards query-params in activeness computation when current-when is specified'](assert) {
let appLink;
this.router.map(function () {
this.route('parent');
});
this.addTemplate('application', `
{{#link-to 'parent' (query-params page=1) current-when='parent' id='app-link'}}
Parent
{{/link-to}}
{{outlet}}
`);
this.addTemplate('parent', `
{{#link-to 'parent' (query-params page=1) current-when='parent' id='parent-link'}}
Parent
{{/link-to}}
{{outlet}}
`);
this.add('controller:parent', _controller.default.extend({
queryParams: ['page'],
page: 1
}));
return this.visit('/').then(() => {
appLink = this.$('#app-link');
assert.equal(appLink.attr('href'), '/parent');
this.shouldNotBeActive(assert, '#app-link');
return this.visit('/parent?page=2');
}).then(() => {
appLink = this.$('#app-link');
let router = this.appRouter;
assert.equal(appLink.attr('href'), '/parent');
this.shouldBeActive(assert, '#app-link');
assert.equal(this.$('#parent-link').attr('href'), '/parent');
this.shouldBeActive(assert, '#parent-link');
let parentController = this.getController('parent');
assert.equal(parentController.get('page'), 2);
this.runTask(() => parentController.set('page', 3));
assert.equal(router.get('location.path'), '/parent?page=3');
this.shouldBeActive(assert, '#app-link');
this.shouldBeActive(assert, '#parent-link');
this.runTask(() => this.click('#app-link'));
assert.equal(router.get('location.path'), '/parent');
});
}
['@test link-to default query params while in active transition regression test'](assert) {
this.router.map(function () {
this.route('foos');
this.route('bars');
});
let foos = _runtime.RSVP.defer();
let bars = _runtime.RSVP.defer();
this.addTemplate('application', `
{{link-to 'Foos' 'foos' id='foos-link'}}
{{link-to 'Baz Foos' 'foos' (query-params baz=true) id='baz-foos-link'}}
{{link-to 'Quux Bars' 'bars' (query-params quux=true) id='bars-link'}}
`);
this.add('controller:foos', _controller.default.extend({
queryParams: ['status'],
baz: false
}));
this.add('route:foos', _routing.Route.extend({
model() {
return foos.promise;
}
}));
this.add('controller:bars', _controller.default.extend({
queryParams: ['status'],
quux: false
}));
this.add('route:bars', _routing.Route.extend({
model() {
return bars.promise;
}
}));
return this.visit('/').then(() => {
let router = this.appRouter;
let foosLink = this.$('#foos-link');
let barsLink = this.$('#bars-link');
let bazLink = this.$('#baz-foos-link');
assert.equal(foosLink.attr('href'), '/foos');
assert.equal(bazLink.attr('href'), '/foos?baz=true');
assert.equal(barsLink.attr('href'), '/bars?quux=true');
assert.equal(router.get('location.path'), '/');
this.shouldNotBeActive(assert, '#foos-link');
this.shouldNotBeActive(assert, '#baz-foos-link');
this.shouldNotBeActive(assert, '#bars-link');
this.runTask(() => barsLink.click());
this.shouldNotBeActive(assert, '#bars-link');
this.runTask(() => foosLink.click());
this.shouldNotBeActive(assert, '#foos-link');
this.runTask(() => foos.resolve());
assert.equal(router.get('location.path'), '/foos');
this.shouldBeActive(assert, '#foos-link');
});
}
[`@test the {{link-to}} helper throws a useful error if you invoke it wrong`](assert) {
assert.expect(1);
this.addTemplate('application', `{{#link-to id='the-link'}}Index{{/link-to}}`);
expectAssertion(() => {
this.visit('/');
}, /You must provide one or more parameters to the link-to component/);
return this.runLoopSettled();
}
});
});
enifed('ember/tests/homepage_example_test', ['@ember/-internals/routing', '@ember/-internals/metal', '@ember/-internals/runtime', 'internal-test-helpers'], function (_routing, _metal, _runtime, _internalTestHelpers) {
'use strict';
(0, _internalTestHelpers.moduleFor)('The example renders correctly', class extends _internalTestHelpers.ApplicationTestCase {
['@test Render index template into application outlet'](assert) {
this.addTemplate('application', '{{outlet}}');
this.addTemplate('index', '
');
this.router.map(function () {
this.route('home', { path: '/' });
});
originalConsoleError = console.error;
}
teardown() {
super.teardown();
console.error = originalConsoleError;
}
getController(name) {
return this.applicationInstance.lookup(`controller:${name}`);
}
handleURLAborts(assert, path) {
(0, _runloop.run)(() => {
let router = this.applicationInstance.lookup('router:main');
router.handleURL(path).then(function () {
assert.ok(false, 'url: `' + path + '` was NOT to be handled');
}, function (reason) {
assert.ok(reason && reason.message === 'TransitionAborted', 'url: `' + path + '` was to be aborted');
});
});
}
get currentPath() {
return this.getController('application').get('currentPath');
}
get currentURL() {
return this.appRouter.get('currentURL');
}
handleURLRejectsWith(context, assert, path, expectedReason) {
return context.visit(path).then(() => {
assert.ok(false, 'expected handleURLing: `' + path + '` to fail');
}).catch(reason => {
assert.equal(reason.message, expectedReason);
});
}
['@test warn on URLs not included in the route set']() {
return this.visit('/').then(() => {
expectAssertion(() => {
this.visit('/what-is-this-i-dont-even');
}, /'\/what-is-this-i-dont-even' did not match any routes/);
});
}
['@test The Homepage'](assert) {
return this.visit('/').then(() => {
assert.equal(this.currentPath, 'home', 'currently on the home route');
let text = this.$('.hours').text();
assert.equal(text, 'Hours', 'the home template was rendered');
});
}
[`@test The Homepage and the Camelot page with multiple Router.map calls`](assert) {
this.router.map(function () {
this.route('camelot', { path: '/camelot' });
});
return this.visit('/camelot').then(() => {
assert.equal(this.currentPath, 'camelot');
let text = this.$('#camelot').text();
assert.equal(text, 'Is a silly place', 'the camelot template was rendered');
return this.visit('/');
}).then(() => {
assert.equal(this.currentPath, 'home');
let text = this.$('.hours').text();
assert.equal(text, 'Hours', 'the home template was rendered');
});
}
[`@test The Homepage with explicit template name in renderTemplate`](assert) {
this.add('route:home', _routing.Route.extend({
renderTemplate() {
this.render('homepage');
}
}));
return this.visit('/').then(() => {
let text = this.$('#troll').text();
assert.equal(text, 'Megatroll', 'the homepage template was rendered');
});
}
[`@test an alternate template will pull in an alternate controller`](assert) {
this.add('route:home', _routing.Route.extend({
renderTemplate() {
this.render('homepage');
}
}));
this.add('controller:homepage', _controller.default.extend({
model: {
home: 'Comes from homepage'
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'Comes from homepage', 'the homepage template was rendered');
});
}
[`@test An alternate template will pull in an alternate controller instead of controllerName`](assert) {
this.add('route:home', _routing.Route.extend({
controllerName: 'foo',
renderTemplate() {
this.render('homepage');
}
}));
this.add('controller:foo', _controller.default.extend({
model: {
home: 'Comes from foo'
}
}));
this.add('controller:homepage', _controller.default.extend({
model: {
home: 'Comes from homepage'
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'Comes from homepage', 'the homepage template was rendered');
});
}
[`@test The template will pull in an alternate controller via key/value`](assert) {
this.router.map(function () {
this.route('homepage', { path: '/' });
});
this.add('route:homepage', _routing.Route.extend({
renderTemplate() {
this.render({ controller: 'home' });
}
}));
this.add('controller:home', _controller.default.extend({
model: {
home: 'Comes from home.'
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'Comes from home.', 'the homepage template was rendered from data from the HomeController');
});
}
[`@test The Homepage with explicit template name in renderTemplate and controller`](assert) {
this.add('controller:home', _controller.default.extend({
model: {
home: 'YES I AM HOME'
}
}));
this.add('route:home', _routing.Route.extend({
renderTemplate() {
this.render('homepage');
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'YES I AM HOME', 'The homepage template was rendered');
});
}
[`@test Model passed via renderTemplate model is set as controller's model`](assert) {
this.addTemplate('bio', '
{{model.name}}
');
this.add('route:home', _routing.Route.extend({
renderTemplate() {
this.render('bio', {
model: { name: 'emberjs' }
});
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'emberjs', `Passed model was set as controller's model`);
});
}
['@test render uses templateName from route'](assert) {
this.addTemplate('the_real_home_template', '
THIS IS THE REAL HOME
');
this.add('route:home', _routing.Route.extend({
templateName: 'the_real_home_template'
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'THIS IS THE REAL HOME', 'the homepage template was rendered');
});
}
['@test defining templateName allows other templates to be rendered'](assert) {
this.addTemplate('alert', `
Invader!
`);
this.addTemplate('the_real_home_template', `
THIS IS THE REAL HOME
{{outlet 'alert'}}`);
this.add('route:home', _routing.Route.extend({
templateName: 'the_real_home_template',
actions: {
showAlert() {
this.render('alert', {
into: 'home',
outlet: 'alert'
});
}
}
}));
return this.visit('/').then(() => {
let text = this.$('p').text();
assert.equal(text, 'THIS IS THE REAL HOME', 'the homepage template was rendered');
return this.runTask(() => this.appRouter.send('showAlert'));
}).then(() => {
let text = this.$('.alert-box').text();
assert.equal(text, 'Invader!', 'Template for alert was rendered into the outlet');
});
}
['@test templateName is still used when calling render with no name and options'](assert) {
this.addTemplate('alert', `
Invader!
`);
this.addTemplate('home', `
THIS IS THE REAL HOME
{{outlet 'alert'}}`);
this.add('route:home', _routing.Route.extend({
templateName: 'alert',
renderTemplate() {
this.render({});
}
}));
return this.visit('/').then(() => {
let text = this.$('.alert-box').text();
assert.equal(text, 'Invader!', 'default templateName was rendered into outlet');
});
}
['@test The Homepage with a `setupController` hook'](assert) {
this.addTemplate('home', `
{{#each hours as |entry|}}
{{entry}}
{{/each}}
`);
this.add('route:home', _routing.Route.extend({
setupController(controller) {
controller.set('hours', ['Monday through Friday: 9am to 5pm', 'Saturday: Noon to Midnight', 'Sunday: Noon to 6pm']);
}
}));
return this.visit('/').then(() => {
let text = this.$('ul li:nth-child(3)').text();
assert.equal(text, 'Sunday: Noon to 6pm', 'The template was rendered with the hours context');
});
}
[`@test The route controller is still set when overriding the setupController hook`](assert) {
this.add('route:home', _routing.Route.extend({
setupController() {
// no-op
// importantly, we are not calling this._super
}
}));
this.add('controller:home', _controller.default.extend());
return this.visit('/').then(() => {
let homeRoute = this.applicationInstance.lookup('route:home');
let homeController = this.applicationInstance.lookup('controller:home');
assert.equal(homeRoute.controller, homeController, 'route controller is the home controller');
});
}
['@test the route controller can be specified via controllerName'](assert) {
this.addTemplate('home', '
{{myValue}}
');
this.add('route:home', _routing.Route.extend({
controllerName: 'myController'
}));
this.add('controller:myController', _controller.default.extend({
myValue: 'foo'
}));
return this.visit('/').then(() => {
let homeRoute = this.applicationInstance.lookup('route:home');
let myController = this.applicationInstance.lookup('controller:myController');
let text = this.$('p').text();
assert.equal(homeRoute.controller, myController, 'route controller is set by controllerName');
assert.equal(text, 'foo', 'The homepage template was rendered with data from the custom controller');
});
}
[`@test The route controller specified via controllerName is used in render`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('route:home', _routing.Route.extend({
controllerName: 'myController',
renderTemplate() {
this.render('alternative_home');
}
}));
this.add('controller:myController', _controller.default.extend({
myValue: 'foo'
}));
this.addTemplate('alternative_home', '
alternative home: {{myValue}}
');
return this.visit('/').then(() => {
let homeRoute = this.applicationInstance.lookup('route:home');
let myController = this.applicationInstance.lookup('controller:myController');
let text = this.$('p').text();
assert.equal(homeRoute.controller, myController, 'route controller is set by controllerName');
assert.equal(text, 'alternative home: foo', 'The homepage template was rendered with data from the custom controller');
});
}
[`@test The route controller specified via controllerName is used in render even when a controller with the routeName is available`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
});
this.addTemplate('home', '
home: {{myValue}}
');
this.add('route:home', _routing.Route.extend({
controllerName: 'myController'
}));
this.add('controller:home', _controller.default.extend({
myValue: 'home'
}));
this.add('controller:myController', _controller.default.extend({
myValue: 'myController'
}));
return this.visit('/').then(() => {
let homeRoute = this.applicationInstance.lookup('route:home');
let myController = this.applicationInstance.lookup('controller:myController');
let text = this.$('p').text();
assert.equal(homeRoute.controller, myController, 'route controller is set by controllerName');
assert.equal(text, 'home: myController', 'The homepage template was rendered with data from the custom controller');
});
}
[`@test The Homepage with a 'setupController' hook modifying other controllers`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('route:home', _routing.Route.extend({
setupController() /* controller */{
this.controllerFor('home').set('hours', ['Monday through Friday: 9am to 5pm', 'Saturday: Noon to Midnight', 'Sunday: Noon to 6pm']);
}
}));
this.addTemplate('home', '
{{#each hours as |entry|}}
{{entry}}
{{/each}}
');
return this.visit('/').then(() => {
let text = this.$('ul li:nth-child(3)').text();
assert.equal(text, 'Sunday: Noon to 6pm', 'The template was rendered with the hours context');
});
}
[`@test The Homepage with a computed model that does not get overridden`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('controller:home', _controller.default.extend({
model: (0, _metal.computed)(function () {
return ['Monday through Friday: 9am to 5pm', 'Saturday: Noon to Midnight', 'Sunday: Noon to 6pm'];
})
}));
this.addTemplate('home', '
{{#each model as |passage|}}
{{passage}}
{{/each}}
');
return this.visit('/').then(() => {
let text = this.$('ul li:nth-child(3)').text();
assert.equal(text, 'Sunday: Noon to 6pm', 'The template was rendered with the context intact');
});
}
[`@test The Homepage getting its controller context via model`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('route:home', _routing.Route.extend({
model() {
return ['Monday through Friday: 9am to 5pm', 'Saturday: Noon to Midnight', 'Sunday: Noon to 6pm'];
},
setupController(controller, model) {
assert.equal(this.controllerFor('home'), controller);
this.controllerFor('home').set('hours', model);
}
}));
this.addTemplate('home', '
{{#each hours as |entry|}}
{{entry}}
{{/each}}
');
return this.visit('/').then(() => {
let text = this.$('ul li:nth-child(3)').text();
assert.equal(text, 'Sunday: Noon to 6pm', 'The template was rendered with the hours context');
});
}
[`@test The Specials Page getting its controller context by deserializing the params hash`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
this.add('route:special', _routing.Route.extend({
model(params) {
return _runtime.Object.create({
menuItemId: params.menu_item_id
});
}
}));
this.addTemplate('special', '
{{model.menuItemId}}
');
return this.visit('/specials/1').then(() => {
let text = this.$('p').text();
assert.equal(text, '1', 'The model was used to render the template');
});
}
['@test The Specials Page defaults to looking models up via `find`']() {
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
return MenuItem.create({ id });
}
});
this.add('model:menu_item', MenuItem);
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
this.addTemplate('special', '{{model.id}}');
return this.visit('/specials/1').then(() => {
this.assertText('1', 'The model was used to render the template');
});
}
['@test The Special Page returning a promise puts the app into a loading state until the promise is resolved']() {
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
let menuItem, resolve;
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
menuItem = MenuItem.create({ id: id });
return new _rsvp.default.Promise(function (res) {
resolve = res;
});
}
});
this.add('model:menu_item', MenuItem);
this.addTemplate('special', '
{{model.id}}
');
this.addTemplate('loading', '
LOADING!
');
let visited = this.visit('/specials/1');
this.assertText('LOADING!', 'The app is in the loading state');
resolve(menuItem);
return visited.then(() => {
this.assertText('1', 'The app is now in the specials state');
});
}
[`@test The loading state doesn't get entered for promises that resolve on the same run loop`](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
return { id: id };
}
});
this.add('model:menu_item', MenuItem);
this.add('route:loading', _routing.Route.extend({
enter() {
assert.ok(false, "LoadingRoute shouldn't have been entered.");
}
}));
this.addTemplate('special', '
{{model.id}}
');
this.addTemplate('loading', '
LOADING!
');
return this.visit('/specials/1').then(() => {
let text = this.$('p').text();
assert.equal(text, '1', 'The app is now in the specials state');
});
}
["@test The Special page returning an error invokes SpecialRoute's error handler"](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
let menuItem, promise, resolve;
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
menuItem = MenuItem.create({ id: id });
promise = new _rsvp.default.Promise(res => resolve = res);
return promise;
}
});
this.add('model:menu_item', MenuItem);
this.add('route:special', _routing.Route.extend({
setup() {
throw new Error('Setup error');
},
actions: {
error(reason) {
assert.equal(reason.message, 'Setup error', 'SpecialRoute#error received the error thrown from setup');
return true;
}
}
}));
this.handleURLRejectsWith(this, assert, 'specials/1', 'Setup error');
(0, _runloop.run)(() => resolve(menuItem));
}
["@test ApplicationRoute's default error handler can be overridden"](assert) {
assert.expect(2);
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
let menuItem, resolve;
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
menuItem = MenuItem.create({ id: id });
return new _rsvp.default.Promise(res => resolve = res);
}
});
this.add('model:menu_item', MenuItem);
this.add('route:application', _routing.Route.extend({
actions: {
error(reason) {
assert.equal(reason.message, 'Setup error', 'error was correctly passed to custom ApplicationRoute handler');
return true;
}
}
}));
this.add('route:special', _routing.Route.extend({
setup() {
throw new Error('Setup error');
}
}));
this.handleURLRejectsWith(this, assert, '/specials/1', 'Setup error');
(0, _runloop.run)(() => resolve(menuItem));
}
['@test Moving from one page to another triggers the correct callbacks'](assert) {
assert.expect(3);
this.router.map(function () {
this.route('home', { path: '/' });
this.route('special', { path: '/specials/:menu_item_id' });
});
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
return MenuItem.create({ id: id });
}
});
this.add('model:menu_item', MenuItem);
this.addTemplate('home', '
Home
');
this.addTemplate('special', '
{{model.id}}
');
return this.visit('/').then(() => {
this.assertText('Home', 'The app is now in the initial state');
let promiseContext = MenuItem.create({ id: 1 });
return this.visit('/specials/1', promiseContext);
}).then(() => {
assert.equal(this.currentURL, '/specials/1');
this.assertText('1', 'The app is now transitioned');
});
}
['@test Nested callbacks are not exited when moving to siblings'](assert) {
let rootSetup = 0;
let rootRender = 0;
let rootModel = 0;
let rootSerialize = 0;
let menuItem;
let rootElement;
let MenuItem = _runtime.Object.extend();
MenuItem.reopenClass({
find(id) {
menuItem = MenuItem.create({ id: id });
return menuItem;
}
});
this.router.map(function () {
this.route('root', { path: '/' }, function () {
this.route('special', {
path: '/specials/:menu_item_id',
resetNamespace: true
});
});
});
this.add('route:root', _routing.Route.extend({
model() {
rootModel++;
return this._super(...arguments);
},
setupController() {
rootSetup++;
},
renderTemplate() {
rootRender++;
},
serialize() {
rootSerialize++;
return this._super(...arguments);
}
}));
this.add('route:loading', _routing.Route.extend({}));
this.add('route:home', _routing.Route.extend({}));
this.add('route:special', _routing.Route.extend({
model({ menu_item_id }) {
return MenuItem.find(menu_item_id);
},
setupController(controller, model) {
(0, _metal.set)(controller, 'model', model);
}
}));
this.addTemplate('root.index', '
Home
');
this.addTemplate('special', '
{{model.id}}
');
this.addTemplate('loading', '
LOADING!
');
return this.visit('/').then(() => {
rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('h3')), 'Home', 'The app is now in the initial state');
assert.equal(rootSetup, 1, 'The root setup was triggered');
assert.equal(rootRender, 1, 'The root render was triggered');
assert.equal(rootSerialize, 0, 'The root serialize was not called');
assert.equal(rootModel, 1, 'The root model was called');
let router = this.applicationInstance.lookup('router:main');
let menuItem = MenuItem.create({ id: 1 });
return router.transitionTo('special', menuItem).then(function () {
assert.equal(rootSetup, 1, 'The root setup was not triggered again');
assert.equal(rootRender, 1, 'The root render was not triggered again');
assert.equal(rootSerialize, 0, 'The root serialize was not called');
// TODO: Should this be changed?
assert.equal(rootModel, 1, 'The root model was called again');
assert.deepEqual(router.location.path, '/specials/1');
assert.equal(router.currentPath, 'root.special');
});
});
}
['@test Events are triggered on the controller if a matching action name is implemented'](assert) {
let done = assert.async();
this.router.map(function () {
this.route('home', { path: '/' });
});
let model = { name: 'Tom Dale' };
let stateIsNotCalled = true;
this.add('route:home', _routing.Route.extend({
model() {
return model;
},
actions: {
showStuff() {
stateIsNotCalled = false;
}
}
}));
this.addTemplate('home', '{{name}}');
this.add('controller:home', _controller.default.extend({
actions: {
showStuff(context) {
assert.ok(stateIsNotCalled, 'an event on the state is not triggered');
assert.deepEqual(context, { name: 'Tom Dale' }, 'an event with context is passed');
done();
}
}
}));
this.visit('/').then(() => {
document.getElementById('qunit-fixture').querySelector('a').click();
});
}
['@test Events are triggered on the current state when defined in `actions` object'](assert) {
let done = assert.async();
this.router.map(function () {
this.route('home', { path: '/' });
});
let model = { name: 'Tom Dale' };
let HomeRoute = _routing.Route.extend({
model() {
return model;
},
actions: {
showStuff(obj) {
assert.ok(this instanceof HomeRoute, 'the handler is an App.HomeRoute');
assert.deepEqual(Object.assign({}, obj), { name: 'Tom Dale' }, 'the context is correct');
done();
}
}
});
this.add('route:home', HomeRoute);
this.addTemplate('home', '{{model.name}}');
this.visit('/').then(() => {
document.getElementById('qunit-fixture').querySelector('a').click();
});
}
['@test Events defined in `actions` object are triggered on the current state when routes are nested'](assert) {
let done = assert.async();
this.router.map(function () {
this.route('root', { path: '/' }, function () {
this.route('index', { path: '/' });
});
});
let model = { name: 'Tom Dale' };
let RootRoute = _routing.Route.extend({
actions: {
showStuff(obj) {
assert.ok(this instanceof RootRoute, 'the handler is an App.HomeRoute');
assert.deepEqual(Object.assign({}, obj), { name: 'Tom Dale' }, 'the context is correct');
done();
}
}
});
this.add('route:root', RootRoute);
this.add('route:root.index', _routing.Route.extend({
model() {
return model;
}
}));
this.addTemplate('root.index', '{{model.name}}');
this.visit('/').then(() => {
document.getElementById('qunit-fixture').querySelector('a').click();
});
}
['@test Events can be handled by inherited event handlers'](assert) {
assert.expect(4);
let SuperRoute = _routing.Route.extend({
actions: {
foo() {
assert.ok(true, 'foo');
},
bar(msg) {
assert.equal(msg, 'HELLO', 'bar hander in super route');
}
}
});
let RouteMixin = _metal.Mixin.create({
actions: {
bar(msg) {
assert.equal(msg, 'HELLO', 'bar handler in mixin');
this._super(msg);
}
}
});
this.add('route:home', SuperRoute.extend(RouteMixin, {
actions: {
baz() {
assert.ok(true, 'baz', 'baz hander in route');
}
}
}));
this.addTemplate('home', `
Do fooDo bar with argDo bar
`);
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
rootElement.querySelector('.do-foo').click();
rootElement.querySelector('.do-bar-with-arg').click();
rootElement.querySelector('.do-baz').click();
});
}
['@test Actions are not triggered on the controller if a matching action name is implemented as a method'](assert) {
let done = assert.async();
this.router.map(function () {
this.route('home', { path: '/' });
});
let model = { name: 'Tom Dale' };
let stateIsNotCalled = true;
this.add('route:home', _routing.Route.extend({
model() {
return model;
},
actions: {
showStuff(context) {
assert.ok(stateIsNotCalled, 'an event on the state is not triggered');
assert.deepEqual(context, { name: 'Tom Dale' }, 'an event with context is passed');
done();
}
}
}));
this.addTemplate('home', '{{name}}');
this.add('controller:home', _controller.default.extend({
showStuff() {
stateIsNotCalled = false;
assert.ok(stateIsNotCalled, 'an event on the state is not triggered');
}
}));
this.visit('/').then(() => {
document.getElementById('qunit-fixture').querySelector('a').click();
});
}
['@test actions can be triggered with multiple arguments'](assert) {
let done = assert.async();
this.router.map(function () {
this.route('root', { path: '/' }, function () {
this.route('index', { path: '/' });
});
});
let model1 = { name: 'Tilde' };
let model2 = { name: 'Tom Dale' };
let RootRoute = _routing.Route.extend({
actions: {
showStuff(obj1, obj2) {
assert.ok(this instanceof RootRoute, 'the handler is an App.HomeRoute');
assert.deepEqual(Object.assign({}, obj1), { name: 'Tilde' }, 'the first context is correct');
assert.deepEqual(Object.assign({}, obj2), { name: 'Tom Dale' }, 'the second context is correct');
done();
}
}
});
this.add('route:root', RootRoute);
this.add('controller:root.index', _controller.default.extend({
model1: model1,
model2: model2
}));
this.addTemplate('root.index', '{{model1.name}}');
this.visit('/').then(() => {
document.getElementById('qunit-fixture').querySelector('a').click();
});
}
['@test transitioning multiple times in a single run loop only sets the URL once'](assert) {
this.router.map(function () {
this.route('root', { path: '/' });
this.route('foo');
this.route('bar');
});
return this.visit('/').then(() => {
let urlSetCount = 0;
let router = this.applicationInstance.lookup('router:main');
router.get('location').setURL = function (path) {
urlSetCount++;
(0, _metal.set)(this, 'path', path);
};
assert.equal(urlSetCount, 0);
(0, _runloop.run)(function () {
router.transitionTo('foo');
router.transitionTo('bar');
});
assert.equal(urlSetCount, 1);
assert.equal(router.get('location').getURL(), '/bar');
});
}
['@test navigating away triggers a url property change'](assert) {
assert.expect(3);
this.router.map(function () {
this.route('root', { path: '/' });
this.route('foo', { path: '/foo' });
this.route('bar', { path: '/bar' });
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
(0, _metal.addObserver)(router, 'url', function () {
assert.ok(true, 'url change event was fired');
});
['foo', 'bar', '/foo'].forEach(destination => (0, _runloop.run)(router, 'transitionTo', destination));
});
}
['@test using replaceWith calls location.replaceURL if available'](assert) {
let setCount = 0;
let replaceCount = 0;
this.router.reopen({
location: _routing.NoneLocation.create({
setURL(path) {
setCount++;
(0, _metal.set)(this, 'path', path);
},
replaceURL(path) {
replaceCount++;
(0, _metal.set)(this, 'path', path);
}
})
});
this.router.map(function () {
this.route('root', { path: '/' });
this.route('foo');
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.equal(setCount, 1);
assert.equal(replaceCount, 0);
(0, _runloop.run)(() => router.replaceWith('foo'));
assert.equal(setCount, 1, 'should not call setURL');
assert.equal(replaceCount, 1, 'should call replaceURL once');
assert.equal(router.get('location').getURL(), '/foo');
});
}
['@test using replaceWith calls setURL if location.replaceURL is not defined'](assert) {
let setCount = 0;
this.router.reopen({
location: _routing.NoneLocation.create({
setURL(path) {
setCount++;
(0, _metal.set)(this, 'path', path);
}
})
});
this.router.map(function () {
this.route('root', { path: '/' });
this.route('foo');
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.equal(setCount, 1);
(0, _runloop.run)(() => router.replaceWith('foo'));
assert.equal(setCount, 2, 'should call setURL once');
assert.equal(router.get('location').getURL(), '/foo');
});
}
['@test Route inherits model from parent route'](assert) {
assert.expect(9);
this.router.map(function () {
this.route('the-post', { path: '/posts/:post_id' }, function () {
this.route('comments');
this.route('shares', { path: '/shares/:share_id', resetNamespace: true }, function () {
this.route('share');
});
});
});
let post1 = {};
let post2 = {};
let post3 = {};
let share1 = {};
let share2 = {};
let share3 = {};
let posts = {
1: post1,
2: post2,
3: post3
};
let shares = {
1: share1,
2: share2,
3: share3
};
this.add('route:the-post', _routing.Route.extend({
model(params) {
return posts[params.post_id];
}
}));
this.add('route:the-post.comments', _routing.Route.extend({
afterModel(post /*, transition */) {
let parent_model = this.modelFor('the-post');
assert.equal(post, parent_model);
}
}));
this.add('route:shares', _routing.Route.extend({
model(params) {
return shares[params.share_id];
}
}));
this.add('route:shares.share', _routing.Route.extend({
afterModel(share /*, transition */) {
let parent_model = this.modelFor('shares');
assert.equal(share, parent_model);
}
}));
return this.visit('/posts/1/comments').then(() => {
assert.ok(true, 'url: /posts/1/comments was handled');
return this.visit('/posts/1/shares/1');
}).then(() => {
assert.ok(true, 'url: /posts/1/shares/1 was handled');
return this.visit('/posts/2/comments');
}).then(() => {
assert.ok(true, 'url: /posts/2/comments was handled');
return this.visit('/posts/2/shares/2');
}).then(() => {
assert.ok(true, 'url: /posts/2/shares/2 was handled');
return this.visit('/posts/3/comments');
}).then(() => {
assert.ok(true, 'url: /posts/3/shares was handled');
return this.visit('/posts/3/shares/3');
}).then(() => {
assert.ok(true, 'url: /posts/3/shares/3 was handled');
});
}
['@test Routes with { resetNamespace: true } inherits model from parent route'](assert) {
assert.expect(6);
this.router.map(function () {
this.route('the-post', { path: '/posts/:post_id' }, function () {
this.route('comments', { resetNamespace: true }, function () {});
});
});
let post1 = {};
let post2 = {};
let post3 = {};
let posts = {
1: post1,
2: post2,
3: post3
};
this.add('route:the-post', _routing.Route.extend({
model(params) {
return posts[params.post_id];
}
}));
this.add('route:comments', _routing.Route.extend({
afterModel(post /*, transition */) {
let parent_model = this.modelFor('the-post');
assert.equal(post, parent_model);
}
}));
return this.visit('/posts/1/comments').then(() => {
assert.ok(true, '/posts/1/comments');
return this.visit('/posts/2/comments');
}).then(() => {
assert.ok(true, '/posts/2/comments');
return this.visit('/posts/3/comments');
}).then(() => {
assert.ok(true, '/posts/3/comments');
});
}
['@test It is possible to get the model from a parent route'](assert) {
assert.expect(6);
this.router.map(function () {
this.route('the-post', { path: '/posts/:post_id' }, function () {
this.route('comments', { resetNamespace: true });
});
});
let post1 = {};
let post2 = {};
let post3 = {};
let currentPost;
let posts = {
1: post1,
2: post2,
3: post3
};
this.add('route:the-post', _routing.Route.extend({
model(params) {
return posts[params.post_id];
}
}));
this.add('route:comments', _routing.Route.extend({
model() {
assert.equal(this.modelFor('the-post'), currentPost);
}
}));
currentPost = post1;
return this.visit('/posts/1/comments').then(() => {
assert.ok(true, '/posts/1/comments has been handled');
currentPost = post2;
return this.visit('/posts/2/comments');
}).then(() => {
assert.ok(true, '/posts/2/comments has been handled');
currentPost = post3;
return this.visit('/posts/3/comments');
}).then(() => {
assert.ok(true, '/posts/3/comments has been handled');
});
}
['@test A redirection hook is provided'](assert) {
this.router.map(function () {
this.route('choose', { path: '/' });
this.route('home');
});
let chooseFollowed = 0;
let destination = 'home';
this.add('route:choose', _routing.Route.extend({
redirect() {
if (destination) {
this.transitionTo(destination);
}
},
setupController() {
chooseFollowed++;
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(chooseFollowed, 0, "The choose route wasn't entered since a transition occurred");
assert.equal(rootElement.querySelectorAll('h3.hours').length, 1, 'The home template was rendered');
assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'home');
});
}
['@test Redirecting from the middle of a route aborts the remainder of the routes'](assert) {
assert.expect(3);
this.router.map(function () {
this.route('home');
this.route('foo', function () {
this.route('bar', { resetNamespace: true }, function () {
this.route('baz');
});
});
});
this.add('route:bar', _routing.Route.extend({
redirect() {
this.transitionTo('home');
},
setupController() {
assert.ok(false, 'Should transition before setupController');
}
}));
this.add('route:bar-baz', _routing.Route.extend({
enter() {
assert.ok(false, 'Should abort transition getting to next route');
}
}));
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
this.handleURLAborts(assert, '/foo/bar/baz');
assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'home');
assert.equal(router.get('location').getURL(), '/home');
});
}
['@test Redirecting to the current target in the middle of a route does not abort initial routing'](assert) {
assert.expect(5);
this.router.map(function () {
this.route('home');
this.route('foo', function () {
this.route('bar', { resetNamespace: true }, function () {
this.route('baz');
});
});
});
let successCount = 0;
this.add('route:bar', _routing.Route.extend({
redirect() {
return this.transitionTo('bar.baz').then(function () {
successCount++;
});
},
setupController() {
assert.ok(true, "Should still invoke bar's setupController");
}
}));
this.add('route:bar.baz', _routing.Route.extend({
setupController() {
assert.ok(true, "Should still invoke bar.baz's setupController");
}
}));
return this.visit('/foo/bar/baz').then(() => {
assert.ok(true, '/foo/bar/baz has been handled');
assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'foo.bar.baz');
assert.equal(successCount, 1, 'transitionTo success handler was called once');
});
}
['@test Redirecting to the current target with a different context aborts the remainder of the routes'](assert) {
assert.expect(4);
this.router.map(function () {
this.route('home');
this.route('foo', function () {
this.route('bar', { path: 'bar/:id', resetNamespace: true }, function () {
this.route('baz');
});
});
});
let model = { id: 2 };
let count = 0;
this.add('route:bar', _routing.Route.extend({
afterModel() {
if (count++ > 10) {
assert.ok(false, 'infinite loop');
} else {
this.transitionTo('bar.baz', model);
}
}
}));
this.add('route:bar.baz', _routing.Route.extend({
setupController() {
assert.ok(true, 'Should still invoke setupController');
}
}));
return this.visit('/').then(() => {
this.handleURLAborts(assert, '/foo/bar/1/baz');
assert.equal(this.applicationInstance.lookup('controller:application').get('currentPath'), 'foo.bar.baz');
assert.equal(this.applicationInstance.lookup('router:main').get('location').getURL(), '/foo/bar/2/baz');
});
}
['@test Transitioning from a parent event does not prevent currentPath from being set'](assert) {
this.router.map(function () {
this.route('foo', function () {
this.route('bar', { resetNamespace: true }, function () {
this.route('baz');
});
this.route('qux');
});
});
this.add('route:foo', _routing.Route.extend({
actions: {
goToQux() {
this.transitionTo('foo.qux');
}
}
}));
return this.visit('/foo/bar/baz').then(() => {
assert.ok(true, '/foo/bar/baz has been handled');
let applicationController = this.applicationInstance.lookup('controller:application');
let router = this.applicationInstance.lookup('router:main');
assert.equal(applicationController.get('currentPath'), 'foo.bar.baz');
(0, _runloop.run)(() => router.send('goToQux'));
assert.equal(applicationController.get('currentPath'), 'foo.qux');
assert.equal(router.get('location').getURL(), '/foo/qux');
});
}
['@test Generated names can be customized when providing routes with dot notation'](assert) {
assert.expect(4);
this.addTemplate('index', '
Index
');
this.addTemplate('application', "
Home
{{outlet}}
");
this.addTemplate('foo', "
{{outlet}}
");
this.addTemplate('bar', "
{{outlet}}
");
this.addTemplate('bar.baz', '
{{name}}Bottom!
');
this.router.map(function () {
this.route('foo', { path: '/top' }, function () {
this.route('bar', { path: '/middle', resetNamespace: true }, function () {
this.route('baz', { path: '/bottom' });
});
});
});
this.add('route:foo', _routing.Route.extend({
renderTemplate() {
assert.ok(true, 'FooBarRoute was called');
return this._super(...arguments);
}
}));
this.add('route:bar.baz', _routing.Route.extend({
renderTemplate() {
assert.ok(true, 'BarBazRoute was called');
return this._super(...arguments);
}
}));
this.add('controller:bar', _controller.default.extend({
name: 'Bar'
}));
this.add('controller:bar.baz', _controller.default.extend({
name: 'BarBaz'
}));
return this.visit('/top/middle/bottom').then(() => {
assert.ok(true, '/top/middle/bottom has been handled');
let rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('.main .middle .bottom p')), 'BarBazBottom!', 'The templates were rendered into their appropriate parents');
});
}
["@test Child routes render into their parent route's template by default"](assert) {
this.addTemplate('index', '
Index
');
this.addTemplate('application', "
Home
{{outlet}}
");
this.addTemplate('top', "
{{outlet}}
");
this.addTemplate('middle', "
{{outlet}}
");
this.addTemplate('middle.bottom', '
Bottom!
');
this.router.map(function () {
this.route('top', function () {
this.route('middle', { resetNamespace: true }, function () {
this.route('bottom');
});
});
});
return this.visit('/top/middle/bottom').then(() => {
assert.ok(true, '/top/middle/bottom has been handled');
let rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('.main .middle .bottom p')), 'Bottom!', 'The templates were rendered into their appropriate parents');
});
}
['@test Child routes render into specified template'](assert) {
this.addTemplate('index', '
Index
');
this.addTemplate('application', "
Home
{{outlet}}
");
this.addTemplate('top', "
{{outlet}}
");
this.addTemplate('middle', "
{{outlet}}
");
this.addTemplate('middle.bottom', '
Bottom!
');
this.router.map(function () {
this.route('top', function () {
this.route('middle', { resetNamespace: true }, function () {
this.route('bottom');
});
});
});
this.add('route:middle.bottom', _routing.Route.extend({
renderTemplate() {
this.render('middle/bottom', { into: 'top' });
}
}));
return this.visit('/top/middle/bottom').then(() => {
assert.ok(true, '/top/middle/bottom has been handled');
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.querySelectorAll('.main .middle .bottom p').length, 0, 'should not render into the middle template');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('.main .middle > p')), 'Bottom!', 'The template was rendered into the top template');
});
}
['@test Rendering into specified template with slash notation'](assert) {
this.addTemplate('person.profile', 'profile {{outlet}}');
this.addTemplate('person.details', 'details!');
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('route:home', _routing.Route.extend({
renderTemplate() {
this.render('person/profile');
this.render('person/details', { into: 'person/profile' });
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'profile details!', 'The templates were rendered');
});
}
['@test Parent route context change'](assert) {
let editCount = 0;
let editedPostIds = (0, _runtime.A)();
this.addTemplate('application', '{{outlet}}');
this.addTemplate('posts', '{{outlet}}');
this.addTemplate('post', '{{outlet}}');
this.addTemplate('post/index', 'showing');
this.addTemplate('post/edit', 'editing');
this.router.map(function () {
this.route('posts', function () {
this.route('post', { path: '/:postId', resetNamespace: true }, function () {
this.route('edit');
});
});
});
this.add('route:posts', _routing.Route.extend({
actions: {
showPost(context) {
this.transitionTo('post', context);
}
}
}));
this.add('route:post', _routing.Route.extend({
model(params) {
return { id: params.postId };
},
serialize(model) {
return { postId: model.id };
},
actions: {
editPost() {
this.transitionTo('post.edit');
}
}
}));
this.add('route:post.edit', _routing.Route.extend({
model() {
let postId = this.modelFor('post').id;
editedPostIds.push(postId);
return null;
},
setup() {
this._super(...arguments);
editCount++;
}
}));
return this.visit('/posts/1').then(() => {
assert.ok(true, '/posts/1 has been handled');
let router = this.applicationInstance.lookup('router:main');
(0, _runloop.run)(() => router.send('editPost'));
(0, _runloop.run)(() => router.send('showPost', { id: '2' }));
(0, _runloop.run)(() => router.send('editPost'));
assert.equal(editCount, 2, 'set up the edit route twice without failure');
assert.deepEqual(editedPostIds, ['1', '2'], 'modelFor posts.post returns the right context');
});
}
['@test Router accounts for rootURL on page load when using history location'](assert) {
let rootURL = window.location.pathname + '/app';
let postsTemplateRendered = false;
let setHistory;
setHistory = function (obj, path) {
obj.set('history', { state: { path: path } });
};
let location = _routing.HistoryLocation.create({
initState() {
let path = rootURL + '/posts';
setHistory(this, path);
this.set('location', {
pathname: path,
href: 'http://localhost/' + path
});
},
replaceState(path) {
setHistory(this, path);
},
pushState(path) {
setHistory(this, path);
}
});
this.router.reopen({
// location: 'historyTest',
location,
rootURL: rootURL
});
this.router.map(function () {
this.route('posts', { path: '/posts' });
});
this.add('route:posts', _routing.Route.extend({
model() {},
renderTemplate() {
postsTemplateRendered = true;
}
}));
return this.visit('/').then(() => {
assert.ok(postsTemplateRendered, 'Posts route successfully stripped from rootURL');
(0, _internalTestHelpers.runDestroy)(location);
location = null;
});
}
['@test The rootURL is passed properly to the location implementation'](assert) {
assert.expect(1);
let rootURL = '/blahzorz';
this.add('location:history-test', _routing.HistoryLocation.extend({
rootURL: 'this is not the URL you are looking for',
history: {
pushState() {}
},
initState() {
assert.equal(this.get('rootURL'), rootURL);
}
}));
this.router.reopen({
location: 'history-test',
rootURL: rootURL,
// if we transition in this test we will receive failures
// if the tests are run from a static file
_doURLTransition() {
return _rsvp.default.resolve('');
}
});
return this.visit('/');
}
['@test Only use route rendered into main outlet for default into property on child'](assert) {
this.addTemplate('application', "{{outlet 'menu'}}{{outlet}}");
this.addTemplate('posts', '{{outlet}}');
this.addTemplate('posts.index', '
postsIndex
');
this.addTemplate('posts.menu', '
postsMenu
');
this.router.map(function () {
this.route('posts', function () {});
});
this.add('route:posts', _routing.Route.extend({
renderTemplate() {
this.render();
this.render('posts/menu', {
into: 'application',
outlet: 'menu'
});
}
}));
return this.visit('/posts').then(() => {
assert.ok(true, '/posts has been handled');
let rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-menu')), 'postsMenu', 'The posts/menu template was rendered');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p.posts-index')), 'postsIndex', 'The posts/index template was rendered');
});
}
['@test Generating a URL should not affect currentModel'](assert) {
this.router.map(function () {
this.route('post', { path: '/posts/:post_id' });
});
let posts = {
1: { id: 1 },
2: { id: 2 }
};
this.add('route:post', _routing.Route.extend({
model(params) {
return posts[params.post_id];
}
}));
return this.visit('/posts/1').then(() => {
assert.ok(true, '/posts/1 has been handled');
let route = this.applicationInstance.lookup('route:post');
assert.equal(route.modelFor('post'), posts[1]);
let url = this.applicationInstance.lookup('router:main').generate('post', posts[2]);
assert.equal(url, '/posts/2');
assert.equal(route.modelFor('post'), posts[1]);
});
}
["@test Nested index route is not overridden by parent's implicit index route"](assert) {
this.router.map(function () {
this.route('posts', function () {
this.route('index', { path: ':category' });
});
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
return router.transitionTo('posts', { category: 'emberjs' });
}).then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.deepEqual(router.location.path, '/posts/emberjs');
});
}
['@test Application template does not duplicate when re-rendered'](assert) {
this.addTemplate('application', '
I render once
{{outlet}}');
this.router.map(function () {
this.route('posts');
});
this.add('route:application', _routing.Route.extend({
model() {
return (0, _runtime.A)();
}
}));
return this.visit('/posts').then(() => {
assert.ok(true, '/posts has been handled');
let rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('h3.render-once')), 'I render once');
});
}
['@test Child routes should render inside the application template if the application template causes a redirect'](assert) {
this.addTemplate('application', '
');
let rootElement = document.getElementById('qunit-fixture');
return this.visit('/page/first').then(() => {
assert.ok(true, '/page/first has been handled');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'first');
assert.equal(insertionCount, 1);
return this.visit('/page/second');
}).then(() => {
assert.ok(true, '/page/second has been handled');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'second');
assert.equal(insertionCount, 1, 'view should have inserted only once');
let router = this.applicationInstance.lookup('router:main');
return (0, _runloop.run)(() => router.transitionTo('page', _runtime.Object.create({ name: 'third' })));
}).then(() => {
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'third');
assert.equal(insertionCount, 1, 'view should still have inserted only once');
});
}
['@test The template is not re-rendered when two routes present the exact same template & controller'](assert) {
this.router.map(function () {
this.route('first');
this.route('second');
this.route('third');
this.route('fourth');
});
// Note add a component to test insertion
let insertionCount = 0;
this.add('component:x-input', _glimmer.Component.extend({
didInsertElement() {
insertionCount += 1;
}
}));
let SharedRoute = _routing.Route.extend({
setupController() {
this.controllerFor('shared').set('message', 'This is the ' + this.routeName + ' message');
},
renderTemplate() {
this.render('shared', { controller: 'shared' });
}
});
this.add('route:shared', SharedRoute);
this.add('route:first', SharedRoute.extend());
this.add('route:second', SharedRoute.extend());
this.add('route:third', SharedRoute.extend());
this.add('route:fourth', SharedRoute.extend());
this.add('controller:shared', _controller.default.extend());
this.addTemplate('shared', '
{{message}}{{x-input}}
');
let rootElement = document.getElementById('qunit-fixture');
return this.visit('/first').then(() => {
assert.ok(true, '/first has been handled');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'This is the first message');
assert.equal(insertionCount, 1, 'expected one assertion');
return this.visit('/second');
}).then(() => {
assert.ok(true, '/second has been handled');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'This is the second message');
assert.equal(insertionCount, 1, 'expected one assertion');
return (0, _runloop.run)(() => {
this.applicationInstance.lookup('router:main').transitionTo('third').then(function () {
assert.ok(true, 'expected transition');
}, function (reason) {
assert.ok(false, 'unexpected transition failure: ', QUnit.jsDump.parse(reason));
});
});
}).then(() => {
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'This is the third message');
assert.equal(insertionCount, 1, 'expected one assertion');
return this.visit('fourth');
}).then(() => {
assert.ok(true, '/fourth has been handled');
assert.equal(insertionCount, 1, 'expected one assertion');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'This is the fourth message');
});
}
['@test ApplicationRoute with model does not proxy the currentPath'](assert) {
let model = {};
let currentPath;
this.router.map(function () {
this.route('index', { path: '/' });
});
this.add('route:application', _routing.Route.extend({
model() {
return model;
}
}));
this.add('controller:application', _controller.default.extend({
currentPathDidChange: (0, _metal.observer)('currentPath', function () {
currentPath = this.currentPath;
})
}));
return this.visit('/').then(() => {
assert.equal(currentPath, 'index', 'currentPath is index');
assert.equal('currentPath' in model, false, 'should have defined currentPath on controller');
});
}
['@test Promises encountered on app load put app into loading state until resolved'](assert) {
assert.expect(2);
let deferred = _rsvp.default.defer();
this.router.map(function () {
this.route('index', { path: '/' });
});
this.add('route:index', _routing.Route.extend({
model() {
return deferred.promise;
}
}));
this.addTemplate('index', '
INDEX
');
this.addTemplate('loading', '
LOADING
');
(0, _runloop.run)(() => this.visit('/'));
let rootElement = document.getElementById('qunit-fixture');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'LOADING', 'The loading state is displaying.');
(0, _runloop.run)(deferred.resolve);
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p')), 'INDEX', 'The index route is display.');
}
['@test Route should tear down multiple outlets'](assert) {
this.addTemplate('application', "{{outlet 'menu'}}{{outlet}}{{outlet 'footer'}}");
this.addTemplate('posts', '{{outlet}}');
this.addTemplate('users', 'users');
this.addTemplate('posts.index', '
postsIndex
');
this.addTemplate('posts.menu', '
postsMenu
');
this.addTemplate('posts.footer', '');
this.router.map(function () {
this.route('posts', function () {});
this.route('users', function () {});
});
this.add('route:posts', _routing.Route.extend({
renderTemplate() {
this.render('posts/menu', {
into: 'application',
outlet: 'menu'
});
this.render();
this.render('posts/footer', {
into: 'application',
outlet: 'footer'
});
}
}));
let rootElement = document.getElementById('qunit-fixture');
return this.visit('/posts').then(() => {
assert.ok(true, '/posts has been handled');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-menu')), 'postsMenu', 'The posts/menu template was rendered');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('p.posts-index')), 'postsIndex', 'The posts/index template was rendered');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-footer')), 'postsFooter', 'The posts/footer template was rendered');
return this.visit('/users');
}).then(() => {
assert.ok(true, '/users has been handled');
assert.equal(rootElement.querySelector('div.posts-menu'), null, 'The posts/menu template was removed');
assert.equal(rootElement.querySelector('p.posts-index'), null, 'The posts/index template was removed');
assert.equal(rootElement.querySelector('div.posts-footer'), null, 'The posts/footer template was removed');
});
}
['@test Route supports clearing outlet explicitly'](assert) {
this.addTemplate('application', "{{outlet}}{{outlet 'modal'}}");
this.addTemplate('posts', '{{outlet}}');
this.addTemplate('users', 'users');
this.addTemplate('posts.index', '
postsIndex {{outlet}}
');
this.addTemplate('posts.modal', '
postsModal
');
this.addTemplate('posts.extra', '
postsExtra
');
this.router.map(function () {
this.route('posts', function () {});
this.route('users', function () {});
});
this.add('route:posts', _routing.Route.extend({
actions: {
showModal() {
this.render('posts/modal', {
into: 'application',
outlet: 'modal'
});
},
hideModal() {
this.disconnectOutlet({
outlet: 'modal',
parentView: 'application'
});
}
}
}));
this.add('route:posts.index', _routing.Route.extend({
actions: {
showExtra() {
this.render('posts/extra', {
into: 'posts/index'
});
},
hideExtra() {
this.disconnectOutlet({ parentView: 'posts/index' });
}
}
}));
let rootElement = document.getElementById('qunit-fixture');
return this.visit('/posts').then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-index')), 'postsIndex', 'The posts/index template was rendered');
(0, _runloop.run)(() => router.send('showModal'));
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered');
(0, _runloop.run)(() => router.send('showExtra'));
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-extra')), 'postsExtra', 'The posts/extra template was rendered');
(0, _runloop.run)(() => router.send('hideModal'));
assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed');
(0, _runloop.run)(() => router.send('hideExtra'));
assert.equal(rootElement.querySelector('div.posts-extra'), null, 'The posts/extra template was removed');
(0, _runloop.run)(function () {
router.send('showModal');
});
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered');
(0, _runloop.run)(function () {
router.send('showExtra');
});
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-extra')), 'postsExtra', 'The posts/extra template was rendered');
return this.visit('/users');
}).then(() => {
assert.equal(rootElement.querySelector('div.posts-index'), null, 'The posts/index template was removed');
assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed');
assert.equal(rootElement.querySelector('div.posts-extra'), null, 'The posts/extra template was removed');
});
}
['@test Route supports clearing outlet using string parameter'](assert) {
this.addTemplate('application', "{{outlet}}{{outlet 'modal'}}");
this.addTemplate('posts', '{{outlet}}');
this.addTemplate('users', 'users');
this.addTemplate('posts.index', '
postsIndex {{outlet}}
');
this.addTemplate('posts.modal', '
postsModal
');
this.router.map(function () {
this.route('posts', function () {});
this.route('users', function () {});
});
this.add('route:posts', _routing.Route.extend({
actions: {
showModal() {
this.render('posts/modal', {
into: 'application',
outlet: 'modal'
});
},
hideModal() {
this.disconnectOutlet('modal');
}
}
}));
let rootElement = document.getElementById('qunit-fixture');
return this.visit('/posts').then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-index')), 'postsIndex', 'The posts/index template was rendered');
(0, _runloop.run)(() => router.send('showModal'));
assert.equal((0, _internalTestHelpers.getTextOf)(rootElement.querySelector('div.posts-modal')), 'postsModal', 'The posts/modal template was rendered');
(0, _runloop.run)(() => router.send('hideModal'));
assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed');
return this.visit('/users');
}).then(() => {
assert.equal(rootElement.querySelector('div.posts-index'), null, 'The posts/index template was removed');
assert.equal(rootElement.querySelector('div.posts-modal'), null, 'The posts/modal template was removed');
});
}
['@test Route silently fails when cleaning an outlet from an inactive view'](assert) {
assert.expect(1); // handleURL
this.addTemplate('application', '{{outlet}}');
this.addTemplate('posts', "{{outlet 'modal'}}");
this.addTemplate('modal', 'A Yo.');
this.router.map(function () {
this.route('posts');
});
this.add('route:posts', _routing.Route.extend({
actions: {
hideSelf() {
this.disconnectOutlet({
outlet: 'main',
parentView: 'application'
});
},
showModal() {
this.render('modal', { into: 'posts', outlet: 'modal' });
},
hideModal() {
this.disconnectOutlet({ outlet: 'modal', parentView: 'posts' });
}
}
}));
return this.visit('/posts').then(() => {
assert.ok(true, '/posts has been handled');
let router = this.applicationInstance.lookup('router:main');
(0, _runloop.run)(() => router.send('showModal'));
(0, _runloop.run)(() => router.send('hideSelf'));
(0, _runloop.run)(() => router.send('hideModal'));
});
}
['@test Router `willTransition` hook passes in cancellable transition'](assert) {
// Should hit willTransition 3 times, once for the initial route, and then 2 more times
// for the two handleURL calls below
if (true /* EMBER_ROUTING_ROUTER_SERVICE */) {
assert.expect(7);
this.router.reopen({
init() {
this._super(...arguments);
this.on('routeWillChange', transition => {
assert.ok(true, 'routeWillChange was called');
if (transition.intent && transition.intent.url !== '/') {
transition.abort();
}
});
}
});
} else {
assert.expect(5);
this.router.reopen({
willTransition(_, _2, transition) {
assert.ok(true, 'willTransition was called');
if (transition.intent.url !== '/') {
transition.abort();
}
}
});
}
this.router.map(function () {
this.route('nork');
this.route('about');
});
this.add('route:loading', _routing.Route.extend({
activate() {
assert.ok(false, 'LoadingRoute was not entered');
}
}));
this.add('route:nork', _routing.Route.extend({
activate() {
assert.ok(false, 'NorkRoute was not entered');
}
}));
this.add('route:about', _routing.Route.extend({
activate() {
assert.ok(false, 'AboutRoute was not entered');
}
}));
return this.visit('/').then(() => {
this.handleURLAborts(assert, '/nork');
this.handleURLAborts(assert, '/about');
});
}
['@test Aborting/redirecting the transition in `willTransition` prevents LoadingRoute from being entered'](assert) {
assert.expect(5);
this.router.map(function () {
this.route('index');
this.route('nork');
this.route('about');
});
let redirect = false;
this.add('route:index', _routing.Route.extend({
actions: {
willTransition(transition) {
assert.ok(true, 'willTransition was called');
if (redirect) {
// router.js won't refire `willTransition` for this redirect
this.transitionTo('about');
} else {
transition.abort();
}
}
}
}));
let deferred = null;
this.add('route:loading', _routing.Route.extend({
activate() {
assert.ok(deferred, 'LoadingRoute should be entered at this time');
},
deactivate() {
assert.ok(true, 'LoadingRoute was exited');
}
}));
this.add('route:nork', _routing.Route.extend({
activate() {
assert.ok(true, 'NorkRoute was entered');
}
}));
this.add('route:about', _routing.Route.extend({
activate() {
assert.ok(true, 'AboutRoute was entered');
},
model() {
if (deferred) {
return deferred.promise;
}
}
}));
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
// Attempted transitions out of index should abort.
(0, _runloop.run)(router, 'transitionTo', 'nork');
(0, _runloop.run)(router, 'handleURL', '/nork');
// Attempted transitions out of index should redirect to about
redirect = true;
(0, _runloop.run)(router, 'transitionTo', 'nork');
(0, _runloop.run)(router, 'transitionTo', 'index');
// Redirected transitions out of index to a route with a
// promise model should pause the transition and
// activate LoadingRoute
deferred = _rsvp.default.defer();
(0, _runloop.run)(router, 'transitionTo', 'nork');
(0, _runloop.run)(deferred.resolve);
});
}
['@test `didTransition` event fires on the router'](assert) {
assert.expect(3);
this.router.map(function () {
this.route('nork');
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
router.one('didTransition', function () {
assert.ok(true, 'didTransition fired on initial routing');
});
this.visit('/');
}).then(() => {
let router = this.applicationInstance.lookup('router:main');
router.one('didTransition', function () {
assert.ok(true, 'didTransition fired on the router');
assert.equal(router.get('url'), '/nork', 'The url property is updated by the time didTransition fires');
});
return this.visit('/nork');
});
}
['@test `didTransition` can be reopened'](assert) {
assert.expect(1);
this.router.map(function () {
this.route('nork');
});
if (true /* EMBER_ROUTING_ROUTER_SERVICE */) {
assert.ok(true, 'no longer a valid test');
return;
} else {
this.router.reopen({
didTransition() {
this._super(...arguments);
assert.ok(true, 'reopened didTransition was called');
}
});
}
return this.visit('/');
}
['@test `activate` event fires on the route'](assert) {
assert.expect(2);
let eventFired = 0;
this.router.map(function () {
this.route('nork');
});
this.add('route:nork', _routing.Route.extend({
init() {
this._super(...arguments);
this.on('activate', function () {
assert.equal(++eventFired, 1, 'activate event is fired once');
});
},
activate() {
assert.ok(true, 'activate hook is called');
}
}));
return this.visit('/nork');
}
['@test `deactivate` event fires on the route'](assert) {
assert.expect(2);
let eventFired = 0;
this.router.map(function () {
this.route('nork');
this.route('dork');
});
this.add('route:nork', _routing.Route.extend({
init() {
this._super(...arguments);
this.on('deactivate', function () {
assert.equal(++eventFired, 1, 'deactivate event is fired once');
});
},
deactivate() {
assert.ok(true, 'deactivate hook is called');
}
}));
return this.visit('/nork').then(() => this.visit('/dork'));
}
['@test Actions can be handled by inherited action handlers'](assert) {
assert.expect(4);
let SuperRoute = _routing.Route.extend({
actions: {
foo() {
assert.ok(true, 'foo');
},
bar(msg) {
assert.equal(msg, 'HELLO');
}
}
});
let RouteMixin = _metal.Mixin.create({
actions: {
bar(msg) {
assert.equal(msg, 'HELLO');
this._super(msg);
}
}
});
this.add('route:home', SuperRoute.extend(RouteMixin, {
actions: {
baz() {
assert.ok(true, 'baz');
}
}
}));
this.addTemplate('home', `
Do fooDo bar with argDo bar
`);
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
rootElement.querySelector('.do-foo').click();
rootElement.querySelector('.do-bar-with-arg').click();
rootElement.querySelector('.do-baz').click();
});
}
['@test transitionTo returns Transition when passed a route name'](assert) {
assert.expect(1);
this.router.map(function () {
this.route('root', { path: '/' });
this.route('bar');
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
let transition = (0, _runloop.run)(() => router.transitionTo('bar'));
assert.equal(transition instanceof _router_js.InternalTransition, true);
});
}
['@test transitionTo returns Transition when passed a url'](assert) {
assert.expect(1);
this.router.map(function () {
this.route('root', { path: '/' });
this.route('bar', function () {
this.route('baz');
});
});
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
let transition = (0, _runloop.run)(() => router.transitionTo('/bar/baz'));
assert.equal(transition instanceof _router_js.InternalTransition, true);
});
}
['@test currentRouteName is a property installed on ApplicationController that can be used in transitionTo'](assert) {
assert.expect(24);
this.router.map(function () {
this.route('index', { path: '/' });
this.route('be', function () {
this.route('excellent', { resetNamespace: true }, function () {
this.route('to', { resetNamespace: true }, function () {
this.route('each', { resetNamespace: true }, function () {
this.route('other');
});
});
});
});
});
return this.visit('/').then(() => {
let appController = this.applicationInstance.lookup('controller:application');
let router = this.applicationInstance.lookup('router:main');
function transitionAndCheck(path, expectedPath, expectedRouteName) {
if (path) {
(0, _runloop.run)(router, 'transitionTo', path);
}
assert.equal(appController.get('currentPath'), expectedPath);
assert.equal(appController.get('currentRouteName'), expectedRouteName);
}
transitionAndCheck(null, 'index', 'index');
transitionAndCheck('/be', 'be.index', 'be.index');
transitionAndCheck('/be/excellent', 'be.excellent.index', 'excellent.index');
transitionAndCheck('/be/excellent/to', 'be.excellent.to.index', 'to.index');
transitionAndCheck('/be/excellent/to/each', 'be.excellent.to.each.index', 'each.index');
transitionAndCheck('/be/excellent/to/each/other', 'be.excellent.to.each.other', 'each.other');
transitionAndCheck('index', 'index', 'index');
transitionAndCheck('be', 'be.index', 'be.index');
transitionAndCheck('excellent', 'be.excellent.index', 'excellent.index');
transitionAndCheck('to.index', 'be.excellent.to.index', 'to.index');
transitionAndCheck('each', 'be.excellent.to.each.index', 'each.index');
transitionAndCheck('each.other', 'be.excellent.to.each.other', 'each.other');
});
}
['@test Route model hook finds the same model as a manual find'](assert) {
let post;
let Post = _runtime.Object.extend();
this.add('model:post', Post);
Post.reopenClass({
find() {
post = this;
return {};
}
});
this.router.map(function () {
this.route('post', { path: '/post/:post_id' });
});
return this.visit('/post/1').then(() => {
assert.equal(Post, post);
});
}
['@test Routes can refresh themselves causing their model hooks to be re-run'](assert) {
this.router.map(function () {
this.route('parent', { path: '/parent/:parent_id' }, function () {
this.route('child');
});
});
let appcount = 0;
this.add('route:application', _routing.Route.extend({
model() {
++appcount;
}
}));
let parentcount = 0;
this.add('route:parent', _routing.Route.extend({
model(params) {
assert.equal(params.parent_id, '123');
++parentcount;
},
actions: {
refreshParent() {
this.refresh();
}
}
}));
let childcount = 0;
this.add('route:parent.child', _routing.Route.extend({
model() {
++childcount;
}
}));
let router;
return this.visit('/').then(() => {
router = this.applicationInstance.lookup('router:main');
assert.equal(appcount, 1);
assert.equal(parentcount, 0);
assert.equal(childcount, 0);
return (0, _runloop.run)(router, 'transitionTo', 'parent.child', '123');
}).then(() => {
assert.equal(appcount, 1);
assert.equal(parentcount, 1);
assert.equal(childcount, 1);
return (0, _runloop.run)(router, 'send', 'refreshParent');
}).then(() => {
assert.equal(appcount, 1);
assert.equal(parentcount, 2);
assert.equal(childcount, 2);
});
}
['@test Specifying non-existent controller name in route#render throws'](assert) {
assert.expect(1);
this.router.map(function () {
this.route('home', { path: '/' });
});
this.add('route:home', _routing.Route.extend({
renderTemplate() {
expectAssertion(() => {
this.render('homepage', {
controller: 'stefanpenneristhemanforme'
});
}, "You passed `controller: 'stefanpenneristhemanforme'` into the `render` method, but no such controller could be found.");
}
}));
return this.visit('/');
}
["@test Redirecting with null model doesn't error out"](assert) {
this.router.map(function () {
this.route('home', { path: '/' });
this.route('about', { path: '/about/:hurhurhur' });
});
this.add('route:about', _routing.Route.extend({
serialize: function (model) {
if (model === null) {
return { hurhurhur: 'TreeklesMcGeekles' };
}
}
}));
this.add('route:home', _routing.Route.extend({
beforeModel() {
this.transitionTo('about', null);
}
}));
return this.visit('/').then(() => {
let router = this.applicationInstance.lookup('router:main');
assert.equal(router.get('location.path'), '/about/TreeklesMcGeekles');
});
}
['@test rejecting the model hooks promise with a non-error prints the `message` property'](assert) {
assert.expect(5);
let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!';
let rejectedStack = 'Yeah, buddy: stack gets printed too.';
this.router.map(function () {
this.route('yippie', { path: '/' });
});
console.error = function (initialMessage, errorMessage, errorStack) {
assert.equal(initialMessage, 'Error while processing route: yippie', 'a message with the current route name is printed');
assert.equal(errorMessage, rejectedMessage, "the rejected reason's message property is logged");
assert.equal(errorStack, rejectedStack, "the rejected reason's stack property is logged");
};
this.add('route:yippie', _routing.Route.extend({
model() {
return _rsvp.default.reject({
message: rejectedMessage,
stack: rejectedStack
});
}
}));
return assert.throws(() => {
return this.visit('/');
}, function (err) {
assert.equal(err.message, rejectedMessage);
return true;
}, 'expected an exception');
}
['@test rejecting the model hooks promise with an error with `errorThrown` property prints `errorThrown.message` property'](assert) {
assert.expect(5);
let rejectedMessage = 'OMG!! SOOOOOO BAD!!!!';
let rejectedStack = 'Yeah, buddy: stack gets printed too.';
this.router.map(function () {
this.route('yippie', { path: '/' });
});
console.error = function (initialMessage, errorMessage, errorStack) {
assert.equal(initialMessage, 'Error while processing route: yippie', 'a message with the current route name is printed');
assert.equal(errorMessage, rejectedMessage, "the rejected reason's message property is logged");
assert.equal(errorStack, rejectedStack, "the rejected reason's stack property is logged");
};
this.add('route:yippie', _routing.Route.extend({
model() {
return _rsvp.default.reject({
errorThrown: { message: rejectedMessage, stack: rejectedStack }
});
}
}));
assert.throws(() => this.visit('/'), function (err) {
assert.equal(err.message, rejectedMessage);
return true;
}, 'expected an exception');
}
['@test rejecting the model hooks promise with no reason still logs error'](assert) {
assert.expect(2);
this.router.map(function () {
this.route('wowzers', { path: '/' });
});
console.error = function (initialMessage) {
assert.equal(initialMessage, 'Error while processing route: wowzers', 'a message with the current route name is printed');
};
this.add('route:wowzers', _routing.Route.extend({
model() {
return _rsvp.default.reject();
}
}));
return assert.throws(() => this.visit('/'));
}
['@test rejecting the model hooks promise with a string shows a good error'](assert) {
assert.expect(3);
let rejectedMessage = 'Supercalifragilisticexpialidocious';
this.router.map(function () {
this.route('yondo', { path: '/' });
});
console.error = function (initialMessage, errorMessage) {
assert.equal(initialMessage, 'Error while processing route: yondo', 'a message with the current route name is printed');
assert.equal(errorMessage, rejectedMessage, "the rejected reason's message property is logged");
};
this.add('route:yondo', _routing.Route.extend({
model() {
return _rsvp.default.reject(rejectedMessage);
}
}));
assert.throws(() => this.visit('/'), new RegExp(rejectedMessage), 'expected an exception');
}
["@test willLeave, willChangeContext, willChangeModel actions don't fire unless feature flag enabled"](assert) {
assert.expect(1);
this.router.map(function () {
this.route('about');
});
function shouldNotFire() {
assert.ok(false, "this action shouldn't have been received");
}
this.add('route:index', _routing.Route.extend({
actions: {
willChangeModel: shouldNotFire,
willChangeContext: shouldNotFire,
willLeave: shouldNotFire
}
}));
this.add('route:about', _routing.Route.extend({
setupController() {
assert.ok(true, 'about route was entered');
}
}));
return this.visit('/about');
}
['@test Errors in transitionTo within redirect hook are logged'](assert) {
assert.expect(4);
let actual = [];
this.router.map(function () {
this.route('yondo', { path: '/' });
this.route('stink-bomb');
});
this.add('route:yondo', _routing.Route.extend({
redirect() {
this.transitionTo('stink-bomb', { something: 'goes boom' });
}
}));
console.error = function () {
// push the arguments onto an array so we can detect if the error gets logged twice
actual.push(arguments);
};
assert.throws(() => this.visit('/'), /More context objects were passed/);
assert.equal(actual.length, 1, 'the error is only logged once');
assert.equal(actual[0][0], 'Error while processing route: yondo', 'source route is printed');
assert.ok(actual[0][1].match(/More context objects were passed than there are dynamic segments for the route: stink-bomb/), 'the error is printed');
}
['@test Errors in transition show error template if available'](assert) {
this.addTemplate('error', "
Error!
");
this.router.map(function () {
this.route('yondo', { path: '/' });
this.route('stink-bomb');
});
this.add('route:yondo', _routing.Route.extend({
redirect() {
this.transitionTo('stink-bomb', { something: 'goes boom' });
}
}));
console.error = () => {};
return this.visit('/').then(() => {
let rootElement = document.querySelector('#qunit-fixture');
assert.equal(rootElement.querySelectorAll('#error').length, 1, 'Error template was rendered.');
});
}
['@test Route#resetController gets fired when changing models and exiting routes'](assert) {
assert.expect(4);
this.router.map(function () {
this.route('a', function () {
this.route('b', { path: '/b/:id', resetNamespace: true }, function () {});
this.route('c', { path: '/c/:id', resetNamespace: true }, function () {});
});
this.route('out');
});
let calls = [];
let SpyRoute = _routing.Route.extend({
setupController() /* controller, model, transition */{
calls.push(['setup', this.routeName]);
},
resetController() /* controller */{
calls.push(['reset', this.routeName]);
}
});
this.add('route:a', SpyRoute.extend());
this.add('route:b', SpyRoute.extend());
this.add('route:c', SpyRoute.extend());
this.add('route:out', SpyRoute.extend());
let router;
return this.visit('/').then(() => {
router = this.applicationInstance.lookup('router:main');
assert.deepEqual(calls, []);
return (0, _runloop.run)(router, 'transitionTo', 'b', 'b-1');
}).then(() => {
assert.deepEqual(calls, [['setup', 'a'], ['setup', 'b']]);
calls.length = 0;
return (0, _runloop.run)(router, 'transitionTo', 'c', 'c-1');
}).then(() => {
assert.deepEqual(calls, [['reset', 'b'], ['setup', 'c']]);
calls.length = 0;
return (0, _runloop.run)(router, 'transitionTo', 'out');
}).then(() => {
assert.deepEqual(calls, [['reset', 'c'], ['reset', 'a'], ['setup', 'out']]);
});
}
['@test Exception during initialization of non-initial route is not swallowed'](assert) {
this.router.map(function () {
this.route('boom');
});
this.add('route:boom', _routing.Route.extend({
init() {
throw new Error('boom!');
}
}));
return assert.throws(() => this.visit('/boom'), /\bboom\b/);
}
['@test Exception during initialization of initial route is not swallowed'](assert) {
this.router.map(function () {
this.route('boom', { path: '/' });
});
this.add('route:boom', _routing.Route.extend({
init() {
throw new Error('boom!');
}
}));
return assert.throws(() => this.visit('/'), /\bboom\b/);
}
['@test {{outlet}} works when created after initial render'](assert) {
this.addTemplate('sample', 'Hi{{#if showTheThing}}{{outlet}}{{/if}}Bye');
this.addTemplate('sample.inner', 'Yay');
this.addTemplate('sample.inner2', 'Boo');
this.router.map(function () {
this.route('sample', { path: '/' }, function () {
this.route('inner', { path: '/' });
this.route('inner2', { path: '/2' });
});
});
let rootElement;
return this.visit('/').then(() => {
rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'HiBye', 'initial render');
(0, _runloop.run)(() => this.applicationInstance.lookup('controller:sample').set('showTheThing', true));
assert.equal(rootElement.textContent.trim(), 'HiYayBye', 'second render');
return this.visit('/2');
}).then(() => {
assert.equal(rootElement.textContent.trim(), 'HiBooBye', 'third render');
});
}
['@test Can render into a named outlet at the top level'](assert) {
this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C');
this.addTemplate('modal', 'Hello world');
this.addTemplate('index', 'The index');
this.router.map(function () {
this.route('index', { path: '/' });
});
this.add('route:application', _routing.Route.extend({
renderTemplate() {
this.render();
this.render('modal', {
into: 'application',
outlet: 'other'
});
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'initial render');
});
}
['@test Can disconnect a named outlet at the top level'](assert) {
this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C');
this.addTemplate('modal', 'Hello world');
this.addTemplate('index', 'The index');
this.router.map(function () {
this.route('index', { path: '/' });
});
this.add('route:application', _routing.Route.extend({
renderTemplate() {
this.render();
this.render('modal', {
into: 'application',
outlet: 'other'
});
},
actions: {
banish() {
this.disconnectOutlet({
parentView: 'application',
outlet: 'other'
});
}
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'initial render');
(0, _runloop.run)(this.applicationInstance.lookup('router:main'), 'send', 'banish');
assert.equal(rootElement.textContent.trim(), 'A-The index-B--C', 'second render');
});
}
['@test Can render into a named outlet at the top level, with empty main outlet'](assert) {
this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C');
this.addTemplate('modal', 'Hello world');
this.router.map(function () {
this.route('hasNoTemplate', { path: '/' });
});
this.add('route:application', _routing.Route.extend({
renderTemplate() {
this.render();
this.render('modal', {
into: 'application',
outlet: 'other'
});
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'A--B-Hello world-C', 'initial render');
});
}
['@test Can render into a named outlet at the top level, later'](assert) {
this.addTemplate('application', 'A-{{outlet}}-B-{{outlet "other"}}-C');
this.addTemplate('modal', 'Hello world');
this.addTemplate('index', 'The index');
this.router.map(function () {
this.route('index', { path: '/' });
});
this.add('route:application', _routing.Route.extend({
actions: {
launch() {
this.render('modal', {
into: 'application',
outlet: 'other'
});
}
}
}));
return this.visit('/').then(() => {
let rootElement = document.getElementById('qunit-fixture');
assert.equal(rootElement.textContent.trim(), 'A-The index-B--C', 'initial render');
(0, _runloop.run)(this.applicationInstance.lookup('router:main'), 'send', 'launch');
assert.equal(rootElement.textContent.trim(), 'A-The index-B-Hello world-C', 'second render');
});
}
["@test Can render routes with no 'main' outlet and their children"](assert) {
this.addTemplate('application', '