/*! * @overview Ember - JavaScript Application Framework * @copyright Copyright 2011-2015 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 1.11.0-beta.5.1501308c */ (function() { var enifed, requireModule, eriuqer, requirejs, Ember; var mainContext = this; (function() { Ember = this.Ember = this.Ember || {}; if (typeof Ember === 'undefined') { Ember = {}; }; function UNDEFINED() { } if (typeof Ember.__loader === 'undefined') { var registry = {}; var seen = {}; enifed = function(name, deps, callback) { var value = { }; if (!callback) { value.deps = []; value.callback = deps; } else { value.deps = deps; value.callback = callback; } registry[name] = value; }; requirejs = eriuqer = requireModule = function(name) { var s = seen[name]; if (s !== undefined) { return seen[name]; } if (s === UNDEFINED) { return undefined; } seen[name] = {}; if (!registry[name]) { throw new Error('Could not find module ' + name); } var mod = registry[name]; var deps = mod.deps; var callback = mod.callback; var reified = []; var exports; var length = deps.length; for (var i=0; i"; }; Klass.create = create; Klass.extend = extend; Klass.reopen = extend; Klass.reopenClass = reopenClass; return Klass; function create(options) { return new this.prototype.constructor(options); } function reopenClass(options) { setProperties(this, options); } function extend(options) { var Child = function(options) { Klass.call(this, options); }; var Parent = this; Child.prototype = new Parent(); Child.prototype.constructor = Child; setProperties(Child, Klass); setProperties(Child.prototype, options); Child.create = create; Child.extend = extend; Child.reopen = extend; Child.reopenClass = reopenClass; return Child; } }; exports.factory = factory; exports.setProperties = setProperties; }); enifed('container/tests/container_helper.jscs-test', function () { 'use strict'; module('JSCS - container/tests'); test('container/tests/container_helper.js should pass jscs', function() { ok(true, 'container/tests/container_helper.js should pass jscs.'); }); }); enifed('container/tests/container_helper.jshint', function () { 'use strict'; module('JSHint - container/tests'); test('container/tests/container_helper.js should pass jshint', function() { ok(true, 'container/tests/container_helper.js should pass jshint.'); }); }); enifed('container/tests/container_test', ['container/tests/container_helper', 'container/registry'], function (container_helper, Registry) { 'use strict'; var originalModelInjections; QUnit.module("Container", { setup: function() { originalModelInjections = Ember.MODEL_FACTORY_INJECTIONS; }, teardown: function() { Ember.MODEL_FACTORY_INJECTIONS = originalModelInjections; } }); QUnit.test("A registered factory returns the same instance each time", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var postController = container.lookup('controller:post'); ok(postController instanceof PostController, "The lookup is an instance of the factory"); equal(postController, container.lookup('controller:post')); }); QUnit.test("A registered factory is returned from lookupFactory", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var PostControllerFactory = container.lookupFactory('controller:post'); ok(PostControllerFactory, 'factory is returned'); ok(PostControllerFactory.create() instanceof PostController, "The return of factory.create is an instance of PostController"); }); QUnit.test("A registered factory is returned from lookupFactory is the same factory each time", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); deepEqual(container.lookupFactory('controller:post'), container.lookupFactory('controller:post'), 'The return of lookupFactory is always the same'); }); QUnit.test("A factory returned from lookupFactory has a debugkey", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var PostFactory = container.lookupFactory('controller:post'); ok(!PostFactory.container, 'factory instance receives a container'); equal(PostFactory._debugContainerKey, 'controller:post', 'factory instance receives _debugContainerKey'); }); QUnit.test("fallback for to create time injections if factory has no extend", function() { var registry = new Registry['default'](); var container = registry.container(); var AppleController = container_helper.factory(); var PostController = container_helper.factory(); PostController.extend = undefined; // remove extend registry.register('controller:apple', AppleController); registry.register('controller:post', PostController); registry.injection('controller:post', 'apple', 'controller:apple'); var postController = container.lookup('controller:post'); ok(postController.container, 'instance receives a container'); equal(postController.container, container, 'instance receives the correct container'); equal(postController._debugContainerKey, 'controller:post', 'instance receives _debugContainerKey'); ok(postController.apple instanceof AppleController, 'instance receives an apple of instance AppleController'); }); QUnit.test("The descendants of a factory returned from lookupFactory have a container and debugkey", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var instance; registry.register('controller:post', PostController); instance = container.lookupFactory('controller:post').create(); ok(instance.container, 'factory instance receives a container'); equal(instance._debugContainerKey, 'controller:post', 'factory instance receives _debugContainerKey'); ok(instance instanceof PostController, 'factory instance is instance of factory'); }); QUnit.test("A registered factory returns a fresh instance if singleton: false is passed as an option", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var postController1 = container.lookup('controller:post'); var postController2 = container.lookup('controller:post', { singleton: false }); var postController3 = container.lookup('controller:post', { singleton: false }); var postController4 = container.lookup('controller:post'); equal(postController1.toString(), postController4.toString(), "Singleton factories looked up normally return the same value"); notEqual(postController1.toString(), postController2.toString(), "Singleton factories are not equal to factories looked up with singleton: false"); notEqual(postController2.toString(), postController3.toString(), "Two factories looked up with singleton: false are not equal"); notEqual(postController3.toString(), postController4.toString(), "A singleton factory looked up after a factory called with singleton: false is not equal"); ok(postController1 instanceof PostController, "All instances are instances of the registered factory"); ok(postController2 instanceof PostController, "All instances are instances of the registered factory"); ok(postController3 instanceof PostController, "All instances are instances of the registered factory"); ok(postController4 instanceof PostController, "All instances are instances of the registered factory"); }); QUnit.test("A container lookup has access to the container", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var postController = container.lookup('controller:post'); equal(postController.container, container); }); QUnit.test("A factory type with a registered injection's instances receive that injection", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var Store = container_helper.factory(); registry.register('controller:post', PostController); registry.register('store:main', Store); registry.typeInjection('controller', 'store', 'store:main'); var postController = container.lookup('controller:post'); var store = container.lookup('store:main'); equal(postController.store, store); }); QUnit.test("An individual factory with a registered injection receives the injection", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var Store = container_helper.factory(); registry.register('controller:post', PostController); registry.register('store:main', Store); registry.injection('controller:post', 'store', 'store:main'); var postController = container.lookup('controller:post'); var store = container.lookup('store:main'); equal(store.container, container); equal(store._debugContainerKey, 'store:main'); equal(postController.container, container); equal(postController._debugContainerKey, 'controller:post'); equal(postController.store, store, 'has the correct store injected'); }); QUnit.test("A factory with both type and individual injections", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var Store = container_helper.factory(); var Router = container_helper.factory(); registry.register('controller:post', PostController); registry.register('store:main', Store); registry.register('router:main', Router); registry.injection('controller:post', 'store', 'store:main'); registry.typeInjection('controller', 'router', 'router:main'); var postController = container.lookup('controller:post'); var store = container.lookup('store:main'); var router = container.lookup('router:main'); equal(postController.store, store); equal(postController.router, router); }); QUnit.test("A factory with both type and individual factoryInjections", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var Store = container_helper.factory(); var Router = container_helper.factory(); registry.register('controller:post', PostController); registry.register('store:main', Store); registry.register('router:main', Router); registry.factoryInjection('controller:post', 'store', 'store:main'); registry.factoryTypeInjection('controller', 'router', 'router:main'); var PostControllerFactory = container.lookupFactory('controller:post'); var store = container.lookup('store:main'); var router = container.lookup('router:main'); equal(PostControllerFactory.store, store, 'PostControllerFactory has the instance of store'); equal(PostControllerFactory.router, router, 'PostControllerFactory has the route instance'); }); QUnit.test("A non-singleton instance is never cached", function() { var registry = new Registry['default'](); var container = registry.container(); var PostView = container_helper.factory(); registry.register('view:post', PostView, { singleton: false }); var postView1 = container.lookup('view:post'); var postView2 = container.lookup('view:post'); ok(postView1 !== postView2, "Non-singletons are not cached"); }); QUnit.test("A non-instantiated property is not instantiated", function() { var registry = new Registry['default'](); var container = registry.container(); var template = function() {}; registry.register('template:foo', template, { instantiate: false }); equal(container.lookup('template:foo'), template); }); QUnit.test("A failed lookup returns undefined", function() { var registry = new Registry['default'](); var container = registry.container(); equal(container.lookup('doesnot:exist'), undefined); }); QUnit.test("An invalid factory throws an error", function() { var registry = new Registry['default'](); var container = registry.container(); registry.register('controller:foo', {}); throws(function() { container.lookup('controller:foo'); }, /Failed to create an instance of \'controller:foo\'/); }); QUnit.test("Injecting a failed lookup raises an error", function() { Ember.MODEL_FACTORY_INJECTIONS = true; var registry = new Registry['default'](); var container = registry.container(); var fooInstance = {}; var fooFactory = {}; var Foo = { create: function(args) { return fooInstance; }, extend: function(args) { return fooFactory; } }; registry.register('model:foo', Foo); registry.injection('model:foo', 'store', 'store:main'); throws(function() { container.lookup('model:foo'); }); }); QUnit.test("Injecting a falsy value does not raise an error", function() { var registry = new Registry['default'](); var container = registry.container(); var ApplicationController = container_helper.factory(); registry.register('controller:application', ApplicationController); registry.register('user:current', null, { instantiate: false }); registry.injection('controller:application', 'currentUser', 'user:current'); equal(container.lookup('controller:application').currentUser, null); }); QUnit.test("Destroying the container destroys any cached singletons", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var PostView = container_helper.factory(); var template = function() {}; registry.register('controller:post', PostController); registry.register('view:post', PostView, { singleton: false }); registry.register('template:post', template, { instantiate: false }); registry.injection('controller:post', 'postView', 'view:post'); var postController = container.lookup('controller:post'); var postView = postController.postView; ok(postView instanceof PostView, "The non-singleton was injected"); container.destroy(); ok(postController.isDestroyed, "Singletons are destroyed"); ok(!postView.isDestroyed, "Non-singletons are not destroyed"); }); QUnit.test("The container can use a registry hook to resolve factories lazily", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.resolver = function(fullName) { if (fullName === 'controller:post') { return PostController; } }; var postController = container.lookup('controller:post'); ok(postController instanceof PostController, "The correct factory was provided"); }); QUnit.test("The container normalizes names before resolving", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.normalizeFullName = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); var postController = container.lookup('controller:normalized'); ok(postController instanceof PostController, "Normalizes the name before resolving"); }); QUnit.test("The container normalizes names when looking factory up", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); registry.normalizeFullName = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); var fact = container.lookupFactory('controller:normalized'); equal(fact.toString() === PostController.extend().toString(), true, "Normalizes the name when looking factory up"); }); QUnit.test("The container can get options that should be applied to a given factory", function() { var registry = new Registry['default'](); var container = registry.container(); var PostView = container_helper.factory(); registry.resolver = function(fullName) { if (fullName === 'view:post') { return PostView; } }; registry.options('view:post', { instantiate: true, singleton: false }); var postView1 = container.lookup('view:post'); var postView2 = container.lookup('view:post'); ok(postView1 instanceof PostView, "The correct factory was provided"); ok(postView2 instanceof PostView, "The correct factory was provided"); ok(postView1 !== postView2, "The two lookups are different"); }); QUnit.test("The container can get options that should be applied to all factories for a given type", function() { var registry = new Registry['default'](); var container = registry.container(); var PostView = container_helper.factory(); registry.resolver = function(fullName) { if (fullName === 'view:post') { return PostView; } }; registry.optionsForType('view', { singleton: false }); var postView1 = container.lookup('view:post'); var postView2 = container.lookup('view:post'); ok(postView1 instanceof PostView, "The correct factory was provided"); ok(postView2 instanceof PostView, "The correct factory was provided"); ok(postView1 !== postView2, "The two lookups are different"); }); QUnit.test("factory resolves are cached", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var resolveWasCalled = []; registry.resolve = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); container.lookupFactory('controller:post'); deepEqual(resolveWasCalled, ['controller:post']); container.lookupFactory('controller:post'); deepEqual(resolveWasCalled, ['controller:post']); }); QUnit.test("factory for non extendables (MODEL) resolves are cached", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = container_helper.factory(); var resolveWasCalled = []; registry.resolve = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); container.lookupFactory('model:post'); deepEqual(resolveWasCalled, ['model:post']); container.lookupFactory('model:post'); deepEqual(resolveWasCalled, ['model:post']); }); QUnit.test("factory for non extendables resolves are cached", function() { var registry = new Registry['default'](); var container = registry.container(); var PostController = {}; var resolveWasCalled = []; registry.resolve = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); container.lookupFactory('foo:post'); deepEqual(resolveWasCalled, ['foo:post']); container.lookupFactory('foo:post'); deepEqual(resolveWasCalled, ['foo:post']); }); QUnit.test("The `_onLookup` hook is called on factories when looked up the first time", function() { expect(2); var registry = new Registry['default'](); var container = registry.container(); var Apple = container_helper.factory(); Apple.reopenClass({ _onLookup: function(fullName) { equal(fullName, 'apple:main', 'calls lazy injection method with the lookup full name'); equal(this, Apple, 'calls lazy injection method in the factory context'); } }); registry.register('apple:main', Apple); container.lookupFactory('apple:main'); container.lookupFactory('apple:main'); }); QUnit.test("A factory's lazy injections are validated when first instantiated", function() { var registry = new Registry['default'](); var container = registry.container(); var Apple = container_helper.factory(); var Orange = container_helper.factory(); Apple.reopenClass({ _lazyInjections: function() { return ['orange:main', 'banana:main']; } }); registry.register('apple:main', Apple); registry.register('orange:main', Orange); throws(function() { container.lookup('apple:main'); }, /Attempting to inject an unknown injection: `banana:main`/); }); QUnit.test("Lazy injection validations are cached", function() { expect(1); var registry = new Registry['default'](); var container = registry.container(); var Apple = container_helper.factory(); var Orange = container_helper.factory(); Apple.reopenClass({ _lazyInjections: function() { ok(true, 'should call lazy injection method'); return ['orange:main']; } }); registry.register('apple:main', Apple); registry.register('orange:main', Orange); container.lookup('apple:main'); container.lookup('apple:main'); }); }); enifed('container/tests/container_test.jscs-test', function () { 'use strict'; module('JSCS - container/tests'); test('container/tests/container_test.js should pass jscs', function() { ok(true, 'container/tests/container_test.js should pass jscs.'); }); }); enifed('container/tests/container_test.jshint', function () { 'use strict'; module('JSHint - container/tests'); test('container/tests/container_test.js should pass jshint', function() { ok(true, 'container/tests/container_test.js should pass jshint.'); }); }); enifed('container/tests/registry_test', ['container/tests/container_helper', 'container'], function (container_helper, _container) { 'use strict'; var originalModelInjections; QUnit.module("Registry", { setup: function() { originalModelInjections = Ember.MODEL_FACTORY_INJECTIONS; }, teardown: function() { Ember.MODEL_FACTORY_INJECTIONS = originalModelInjections; } }); QUnit.test("A registered factory is returned from resolve", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var PostControllerFactory = registry.resolve('controller:post'); ok(PostControllerFactory, 'factory is returned'); ok(PostControllerFactory.create() instanceof PostController, "The return of factory.create is an instance of PostController"); }); QUnit.test("The registered factory returned from resolve is the same factory each time", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); deepEqual(registry.resolve('controller:post'), registry.resolve('controller:post'), 'The return of resolve is always the same'); }); QUnit.test("A registered factory returns true for `has` if an item is registered", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); equal(registry.has('controller:post'), true, "The `has` method returned true for registered factories"); equal(registry.has('controller:posts'), false, "The `has` method returned false for unregistered factories"); }); QUnit.test("Throw exception when trying to inject `type:thing` on all type(s)", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); throws(function() { registry.typeInjection('controller', 'injected', 'controller:post'); }, 'Cannot inject a `controller:post` on other controller(s).'); }); QUnit.test("The registry can take a hook to resolve factories lazily", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.resolver = function(fullName) { if (fullName === 'controller:post') { return PostController; } }; strictEqual(registry.resolve('controller:post'), PostController, "The correct factory was provided"); }); QUnit.test("The registry respects the resolver hook for `has`", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.resolver = function(fullName) { if (fullName === 'controller:post') { return PostController; } }; ok(registry.has('controller:post'), "the `has` method uses the resolver hook"); }); QUnit.test("The registry normalizes names when resolving", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.normalizeFullName = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); var type = registry.resolve('controller:normalized'); strictEqual(type, PostController, "Normalizes the name when resolving"); }); QUnit.test("The registry normalizes names when checking if the factory is registered", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.normalizeFullName = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); var isPresent = registry.has('controller:normalized'); equal(isPresent, true, "Normalizes the name when checking if the factory or instance is present"); }); QUnit.test("validateFullName throws an error if name is incorrect", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.normalize = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); throws(function() { registry.resolve('post'); }, 'TypeError: Invalid Fullname, expected: `type:name` got: post'); }); QUnit.test("The registry normalizes names when injecting", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); var user = { name: 'Stef' }; registry.normalize = function(fullName) { return 'controller:post'; }; registry.register('controller:post', PostController); registry.register('user:post', user, { instantiate: false }); registry.injection('controller:post', 'user', 'controller:normalized'); deepEqual(registry.resolve('controller:post'), user, "Normalizes the name when injecting"); }); QUnit.test("cannot register an `undefined` factory", function() { var registry = new _container.Registry(); throws(function() { registry.register('controller:apple', undefined); }, ''); }); QUnit.test("can re-register a factory", function() { var registry = new _container.Registry(); var FirstApple = container_helper.factory('first'); var SecondApple = container_helper.factory('second'); registry.register('controller:apple', FirstApple); registry.register('controller:apple', SecondApple); ok(registry.resolve('controller:apple').create() instanceof SecondApple); }); QUnit.test("cannot re-register a factory if it has been resolved", function() { var registry = new _container.Registry(); var FirstApple = container_helper.factory('first'); var SecondApple = container_helper.factory('second'); registry.register('controller:apple', FirstApple); strictEqual(registry.resolve('controller:apple'), FirstApple); throws(function() { registry.register('controller:apple', SecondApple); }, 'Cannot re-register: `controller:apple`, as it has already been resolved.'); strictEqual(registry.resolve('controller:apple'), FirstApple); }); QUnit.test('registry.has should not accidentally cause injections on that factory to be run. (Mitigate merely on observing)', function() { expect(1); var registry = new _container.Registry(); var FirstApple = container_helper.factory('first'); var SecondApple = container_helper.factory('second'); SecondApple.extend = function(a, b, c) { ok(false, 'should not extend or touch the injected model, merely to inspect existence of another'); }; registry.register('controller:apple', FirstApple); registry.register('controller:second-apple', SecondApple); registry.injection('controller:apple', 'badApple', 'controller:second-apple'); ok(registry.has('controller:apple')); }); QUnit.test('once resolved, always return the same result', function() { expect(1); var registry = new _container.Registry(); registry.resolver = function() { return 'bar'; }; var Bar = registry.resolve('models:bar'); registry.resolver = function() { return 'not bar'; }; equal(registry.resolve('models:bar'), Bar); }); QUnit.test("factory resolves are cached", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); var resolveWasCalled = []; registry.resolver = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); registry.resolve('controller:post'); deepEqual(resolveWasCalled, ['controller:post']); registry.resolve('controller:post'); deepEqual(resolveWasCalled, ['controller:post']); }); QUnit.test("factory for non extendables (MODEL) resolves are cached", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); var resolveWasCalled = []; registry.resolver = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); registry.resolve('model:post'); deepEqual(resolveWasCalled, ['model:post']); registry.resolve('model:post'); deepEqual(resolveWasCalled, ['model:post']); }); QUnit.test("factory for non extendables resolves are cached", function() { var registry = new _container.Registry(); var PostController = {}; var resolveWasCalled = []; registry.resolver = function(fullName) { resolveWasCalled.push(fullName); return PostController; }; deepEqual(resolveWasCalled, []); registry.resolve('foo:post'); deepEqual(resolveWasCalled, ['foo:post']); registry.resolve('foo:post'); deepEqual(resolveWasCalled, ['foo:post']); }); QUnit.test("registry.container creates an associated container", function() { var registry = new _container.Registry(); var PostController = container_helper.factory(); registry.register('controller:post', PostController); var container = registry.container(); var postController = container.lookup('controller:post'); ok(postController instanceof PostController, "The lookup is an instance of the registered factory"); strictEqual(registry._defaultContainer, container, "_defaultContainer is set to the first created container and used for Ember 1.x Container compatibility"); }); QUnit.test("`resolve` can be handled by a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); var PostController = container_helper.factory(); fallback.register('controller:post', PostController); var PostControllerFactory = registry.resolve('controller:post'); ok(PostControllerFactory, 'factory is returned'); ok(PostControllerFactory.create() instanceof PostController, "The return of factory.create is an instance of PostController"); }); QUnit.test("`has` can be handled by a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); var PostController = container_helper.factory(); fallback.register('controller:post', PostController); equal(registry.has('controller:post'), true, "Fallback registry is checked for registration"); }); QUnit.test("`getInjections` includes injections from a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); equal(registry.getInjections('model:user').length, 0, "No injections in the primary registry"); fallback.injection('model:user', 'post', 'model:post'); equal(registry.getInjections('model:user').length, 1, "Injections from the fallback registry are merged"); }); QUnit.test("`getTypeInjections` includes type injections from a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); equal(registry.getTypeInjections('model').length, 0, "No injections in the primary registry"); fallback.injection('model', 'source', 'source:main'); equal(registry.getTypeInjections('model').length, 1, "Injections from the fallback registry are merged"); }); QUnit.test("`getFactoryInjections` includes factory injections from a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); equal(registry.getFactoryInjections('model:user').length, 0, "No factory injections in the primary registry"); fallback.factoryInjection('model:user', 'store', 'store:main'); equal(registry.getFactoryInjections('model:user').length, 1, "Factory injections from the fallback registry are merged"); }); QUnit.test("`getFactoryTypeInjections` includes factory type injections from a fallback registry", function() { var fallback = new _container.Registry(); var registry = new _container.Registry({ fallback: fallback }); equal(registry.getFactoryTypeInjections('model').length, 0, "No factory type injections in the primary registry"); fallback.factoryInjection('model', 'store', 'store:main'); equal(registry.getFactoryTypeInjections('model').length, 1, "Factory type injections from the fallback registry are merged"); }); }); enifed('container/tests/registry_test.jscs-test', function () { 'use strict'; module('JSCS - container/tests'); test('container/tests/registry_test.js should pass jscs', function() { ok(true, 'container/tests/registry_test.js should pass jscs.'); }); }); enifed('container/tests/registry_test.jshint', function () { 'use strict'; module('JSHint - container/tests'); test('container/tests/registry_test.js should pass jshint', function() { ok(true, 'container/tests/registry_test.js should pass jshint.'); }); }); enifed('ember-application.jscs-test', function () { 'use strict'; module('JSCS - .'); test('ember-application.js should pass jscs', function() { ok(true, 'ember-application.js should pass jscs.'); }); }); enifed('ember-application.jshint', function () { 'use strict'; module('JSHint - .'); test('ember-application.js should pass jshint', function() { ok(true, 'ember-application.js should pass jshint.'); }); }); enifed('ember-application/ext/controller.jscs-test', function () { 'use strict'; module('JSCS - ember-application/ext'); test('ember-application/ext/controller.js should pass jscs', function() { ok(true, 'ember-application/ext/controller.js should pass jscs.'); }); }); enifed('ember-application/ext/controller.jshint', function () { 'use strict'; module('JSHint - ember-application/ext'); test('ember-application/ext/controller.js should pass jshint', function() { ok(true, 'ember-application/ext/controller.js should pass jshint.'); }); }); enifed('ember-application/system/application-instance.jscs-test', function () { 'use strict'; module('JSCS - ember-application/system'); test('ember-application/system/application-instance.js should pass jscs', function() { ok(true, 'ember-application/system/application-instance.js should pass jscs.'); }); }); enifed('ember-application/system/application-instance.jshint', function () { 'use strict'; module('JSHint - ember-application/system'); test('ember-application/system/application-instance.js should pass jshint', function() { ok(true, 'ember-application/system/application-instance.js should pass jshint.'); }); }); enifed('ember-application/system/application.jscs-test', function () { 'use strict'; module('JSCS - ember-application/system'); test('ember-application/system/application.js should pass jscs', function() { ok(true, 'ember-application/system/application.js should pass jscs.'); }); }); enifed('ember-application/system/application.jshint', function () { 'use strict'; module('JSHint - ember-application/system'); test('ember-application/system/application.js should pass jshint', function() { ok(true, 'ember-application/system/application.js should pass jshint.'); }); }); enifed('ember-application/system/resolver.jscs-test', function () { 'use strict'; module('JSCS - ember-application/system'); test('ember-application/system/resolver.js should pass jscs', function() { ok(true, 'ember-application/system/resolver.js should pass jscs.'); }); }); enifed('ember-application/system/resolver.jshint', function () { 'use strict'; module('JSHint - ember-application/system'); test('ember-application/system/resolver.js should pass jshint', function() { ok(true, 'ember-application/system/resolver.js should pass jshint.'); }); }); enifed('ember-application/tests/system/application_test', ['ember-metal/core', 'ember-metal/run_loop', 'ember-application/system/application', 'ember-application/system/resolver', 'ember-routing/system/router', 'ember-views/views/view', 'ember-runtime/controllers/controller', 'ember-routing/location/none_location', 'ember-runtime/system/object', 'ember-views/system/jquery', 'ember-template-compiler/system/compile'], function (Ember, run, Application, DefaultResolver, Router, View, Controller, NoneLocation, EmberObject, jQuery, compile) { 'use strict'; /*globals EmberDev */ var trim = jQuery['default'].trim; var app, application, originalLookup, originalDebug; QUnit.module("Ember.Application", { setup: function() { originalLookup = Ember['default'].lookup; originalDebug = Ember['default'].debug; jQuery['default']("#qunit-fixture").html("
HI
HI
"); run['default'](function() { application = Application['default'].create({ rootElement: '#one', router: null }); }); }, teardown: function() { jQuery['default']("#qunit-fixture").empty(); Ember['default'].debug = originalDebug; Ember['default'].lookup = originalLookup; if (application) { run['default'](application, 'destroy'); } if (app) { run['default'](app, 'destroy'); } } }); QUnit.test("you can make a new application in a non-overlapping element", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#two', router: null }); }); run['default'](app, 'destroy'); ok(true, "should not raise"); }); QUnit.test("you cannot make a new application that is a parent of an existing application", function() { expectAssertion(function() { run['default'](function() { Application['default'].create({ rootElement: '#qunit-fixture' }); }); }); }); QUnit.test("you cannot make a new application that is a descendent of an existing application", function() { expectAssertion(function() { run['default'](function() { Application['default'].create({ rootElement: '#one-child' }); }); }); }); QUnit.test("you cannot make a new application that is a duplicate of an existing application", function() { expectAssertion(function() { run['default'](function() { Application['default'].create({ rootElement: '#one' }); }); }); }); QUnit.test("you cannot make two default applications without a rootElement error", function() { expectAssertion(function() { run['default'](function() { Application['default'].create({ router: false }); }); }); }); QUnit.test("acts like a namespace", function() { var lookup = Ember['default'].lookup = {}; var app; run['default'](function() { app = lookup.TestApp = Application['default'].create({ rootElement: '#two', router: false }); }); Ember['default'].BOOTED = false; app.Foo = EmberObject['default'].extend(); equal(app.Foo.toString(), "TestApp.Foo", "Classes pick up their parent namespace"); }); QUnit.module("Ember.Application initialization", { teardown: function() { if (app) { run['default'](app, 'destroy'); } Ember['default'].TEMPLATES = {}; } }); QUnit.test('initialized application go to initial route', function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); app.Router.reopen({ location: 'none' }); app.register('template:application', compile['default']("{{outlet}}") ); Ember['default'].TEMPLATES.index = compile['default']( "

Hi from index

" ); }); equal(jQuery['default']('#qunit-fixture h1').text(), "Hi from index"); }); QUnit.test("initialize application via initialize call", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); app.Router.reopen({ location: 'none' }); app.ApplicationView = View['default'].extend({ template: function() { return "

Hello!

"; } }); }); // This is not a public way to access the container; we just // need to make some assertions about the created router var router = app.__container__.lookup('router:main'); equal(router instanceof Router['default'], true, "Router was set from initialize call"); equal(router.location instanceof NoneLocation['default'], true, "Location was set from location implementation name"); }); QUnit.test("initialize application with stateManager via initialize call from Router class", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); app.Router.reopen({ location: 'none' }); app.register('template:application', function() { return "

Hello!

"; }); }); var router = app.__container__.lookup('router:main'); equal(router instanceof Router['default'], true, "Router was set from initialize call"); equal(jQuery['default']("#qunit-fixture h1").text(), "Hello!"); }); QUnit.test("ApplicationView is inserted into the page", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); app.ApplicationView = View['default'].extend({ render: function(buffer) { buffer.push("

Hello!

"); } }); app.ApplicationController = Controller['default'].extend(); app.Router.reopen({ location: 'none' }); }); equal(jQuery['default']("#qunit-fixture h1").text(), "Hello!"); }); QUnit.test("Minimal Application initialized with just an application template", function() { jQuery['default']('#qunit-fixture').html(''); run['default'](function () { app = Application['default'].create({ rootElement: '#qunit-fixture' }); }); equal(trim(jQuery['default']('#qunit-fixture').text()), 'Hello World'); }); QUnit.test('enable log of libraries with an ENV var', function() { if (EmberDev && EmberDev.runningProdBuild) { ok(true, 'Logging does not occur in production builds'); return; } var debug = Ember['default'].debug; var messages = []; Ember['default'].LOG_VERSION = true; Ember['default'].debug = function(message) { messages.push(message); }; Ember['default'].libraries.register("my-lib", "2.0.0a"); run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); }); equal(messages[1], "Ember : " + Ember['default'].VERSION); equal(messages[2], "jQuery : " + jQuery['default']().jquery); equal(messages[3], "my-lib : " + "2.0.0a"); Ember['default'].libraries.deRegister("my-lib"); Ember['default'].LOG_VERSION = false; Ember['default'].debug = debug; }); QUnit.test('disable log version of libraries with an ENV var', function() { var logged = false; Ember['default'].LOG_VERSION = false; Ember['default'].debug = function(message) { logged = true; }; jQuery['default']("#qunit-fixture").empty(); run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); app.Router.reopen({ location: 'none' }); }); ok(!logged, 'library version logging skipped'); }); QUnit.test("can resolve custom router", function() { var CustomRouter = Router['default'].extend(); var CustomResolver = DefaultResolver['default'].extend({ resolveMain: function(parsedName) { if (parsedName.type === "router") { return CustomRouter; } else { return this._super(parsedName); } } }); app = run['default'](function() { return Application['default'].create({ Resolver: CustomResolver }); }); ok(app.__container__.lookup('router:main') instanceof CustomRouter, 'application resolved the correct router'); }); QUnit.test("can specify custom router", function() { var CustomRouter = Router['default'].extend(); app = run['default'](function() { return Application['default'].create({ Router: CustomRouter }); }); ok(app.__container__.lookup('router:main') instanceof CustomRouter, 'application resolved the correct router'); }); QUnit.test("throws helpful error if `app.then` is used", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); }); expectDeprecation(function() { run['default'](app, 'then', function() { return this; }); }, /Do not use `.then` on an instance of Ember.Application. Please use the `.ready` hook instead./); }); QUnit.test("registers controls onto to container", function() { run['default'](function() { app = Application['default'].create({ rootElement: '#qunit-fixture' }); }); ok(app.__container__.lookup('view:select'), "Select control is registered into views"); }); }); enifed('ember-application/tests/system/application_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/application_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/application_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/application_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/application_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/application_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/controller_test', ['ember-runtime/controllers/controller', 'ember-application/ext/controller', 'ember-runtime/system/container', 'ember-runtime/system/native_array', 'ember-runtime/controllers/array_controller', 'ember-metal/computed'], function (Controller, __dep1__, system__container, native_array, ArrayController, computed) { 'use strict'; /*jshint newcap:false */ QUnit.module("Controller dependencies"); QUnit.test("If a controller specifies a dependency, but does not have a container it should error", function() { var AController = Controller['default'].extend({ needs: 'posts' }); expectAssertion(function() { AController.create(); }, /specifies `needs`, but does not have a container. Please ensure this controller was instantiated with a container./); }); QUnit.test("If a controller specifies a dependency, it is accessible", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:post', Controller['default'].extend({ needs: 'posts' })); registry.register('controller:posts', Controller['default'].extend()); var postController = container.lookup('controller:post'); var postsController = container.lookup('controller:posts'); equal(postsController, postController.get('controllers.posts'), "controller.posts must be auto synthesized"); }); QUnit.test("If a controller specifies an unavailable dependency, it raises", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:post', Controller['default'].extend({ needs: ['comments'] })); throws(function() { container.lookup('controller:post'); }, /controller:comments/); registry.register('controller:blog', Controller['default'].extend({ needs: ['posts', 'comments'] })); throws(function() { container.lookup('controller:blog'); }, /controller:posts, controller:comments/); }); QUnit.test("Mixin sets up controllers if there is needs before calling super", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:other', ArrayController['default'].extend({ needs: 'posts', model: computed.computed.alias('controllers.posts') })); registry.register('controller:another', ArrayController['default'].extend({ needs: 'posts', modelBinding: 'controllers.posts' })); registry.register('controller:posts', ArrayController['default'].extend()); container.lookup('controller:posts').set('model', native_array.A(['a','b','c'])); deepEqual(['a','b','c'], container.lookup('controller:other').toArray()); deepEqual(['a','b','c'], container.lookup('controller:another').toArray()); }); QUnit.test("raises if trying to get a controller that was not pre-defined in `needs`", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:foo', Controller['default'].extend()); registry.register('controller:bar', Controller['default'].extend({ needs: 'foo' })); var fooController = container.lookup('controller:foo'); var barController = container.lookup('controller:bar'); throws(function() { fooController.get('controllers.bar'); }, /#needs does not include `bar`/, 'throws if controllers is accesed but needs not defined'); equal(barController.get('controllers.foo'), fooController, 'correctly needed controllers should continue to work'); throws(function() { barController.get('controllers.baz'); }, /#needs does not include `baz`/, 'should throw if no such controller was needed'); }); QUnit.test("setting the value of a controller dependency should not be possible", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:post', Controller['default'].extend({ needs: 'posts' })); registry.register('controller:posts', Controller['default'].extend()); var postController = container.lookup('controller:post'); container.lookup('controller:posts'); throws(function() { postController.set('controllers.posts', 'epic-self-troll'); }, /You cannot overwrite the value of `controllers.posts` of .+/, 'should raise when attempting to set the value of a controller dependency property'); postController.set('controllers.posts.title', "A Troll's Life"); equal(postController.get('controllers.posts.title'), "A Troll's Life", "can set the value of controllers.posts.title"); }); QUnit.test("raises if a dependency with a period is requested", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('controller:big.bird', Controller['default'].extend()); registry.register('controller:foo', Controller['default'].extend({ needs: 'big.bird' })); expectAssertion(function() { container.lookup('controller:foo'); }, /needs must not specify dependencies with periods in their names \(big\.bird\)/, 'throws if periods used'); }); QUnit.test("can unit test controllers with `needs` dependencies by stubbing their `controllers` properties", function() { expect(1); var BrotherController = Controller['default'].extend({ needs: 'sister', foo: computed.computed.alias('controllers.sister.foo') }); var broController = BrotherController.create({ controllers: { sister: { foo: 5 } } }); equal(broController.get('foo'), 5, "`needs` dependencies can be stubbed"); }); }); enifed('ember-application/tests/system/controller_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/controller_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/controller_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/controller_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/controller_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/controller_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/dependency_injection/custom_resolver_test', ['ember-views/system/jquery', 'ember-metal/run_loop', 'ember-application/system/application', 'ember-application/system/resolver'], function (jQuery, run, Application, DefaultResolver) { 'use strict'; var application; QUnit.module("Ember.Application Dependency Injection – customResolver", { setup: function() { function fallbackTemplate() { return "

Fallback

"; } var Resolver = DefaultResolver['default'].extend({ resolveTemplate: function(resolvable) { var resolvedTemplate = this._super(resolvable); if (resolvedTemplate) { return resolvedTemplate; } return fallbackTemplate; } }); application = run['default'](function() { return Application['default'].create({ Resolver: Resolver, rootElement: '#qunit-fixture' }); }); }, teardown: function() { run['default'](application, 'destroy'); } }); QUnit.test("a resolver can be supplied to application", function() { equal(jQuery['default']("h1", application.rootElement).text(), "Fallback"); }); }); enifed('ember-application/tests/system/dependency_injection/custom_resolver_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/custom_resolver_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/dependency_injection/custom_resolver_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/dependency_injection/custom_resolver_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/custom_resolver_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/dependency_injection/custom_resolver_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/dependency_injection/default_resolver_test', ['ember-metal/core', 'ember-metal/run_loop', 'ember-metal/logger', 'ember-runtime/controllers/controller', 'ember-runtime/system/object', 'ember-runtime/system/namespace', 'ember-application/system/application', 'ember-htmlbars/helpers'], function (Ember, run, Logger, Controller, EmberObject, Namespace, Application, helpers) { 'use strict'; var registry, locator, application, originalLookup, originalLoggerInfo; QUnit.module("Ember.Application Dependency Injection - default resolver", { setup: function() { originalLookup = Ember['default'].lookup; application = run['default'](Application['default'], 'create'); registry = application.registry; locator = application.__container__; originalLoggerInfo = Logger['default'].info; }, teardown: function() { Ember['default'].TEMPLATES = {}; Ember['default'].lookup = originalLookup; run['default'](application, 'destroy'); var UserInterfaceNamespace = Namespace['default'].NAMESPACES_BY_ID['UserInterface']; if (UserInterfaceNamespace) { run['default'](UserInterfaceNamespace, 'destroy'); } Logger['default'].info = originalLoggerInfo; } }); QUnit.test('the default resolver can look things up in other namespaces', function() { var UserInterface = Ember['default'].lookup.UserInterface = Namespace['default'].create(); UserInterface.NavigationController = Controller['default'].extend(); var nav = locator.lookup('controller:userInterface/navigation'); ok(nav instanceof UserInterface.NavigationController, "the result should be an instance of the specified class"); }); QUnit.test('the default resolver looks up templates in Ember.TEMPLATES', function() { function fooTemplate() {} function fooBarTemplate() {} function fooBarBazTemplate() {} Ember['default'].TEMPLATES['foo'] = fooTemplate; Ember['default'].TEMPLATES['fooBar'] = fooBarTemplate; Ember['default'].TEMPLATES['fooBar/baz'] = fooBarBazTemplate; equal(locator.lookup('template:foo'), fooTemplate, "resolves template:foo"); equal(locator.lookup('template:fooBar'), fooBarTemplate, "resolves template:foo_bar"); equal(locator.lookup('template:fooBar.baz'), fooBarBazTemplate, "resolves template:foo_bar.baz"); }); QUnit.test('the default resolver looks up basic name as no prefix', function() { ok(Controller['default'].detect(locator.lookup('controller:basic')), 'locator looksup correct controller'); }); function detectEqual(first, second, message) { ok(first.detect(second), message); } QUnit.test('the default resolver looks up arbitrary types on the namespace', function() { application.FooManager = EmberObject['default'].extend({}); detectEqual(application.FooManager, registry.resolver('manager:foo'), "looks up FooManager on application"); }); QUnit.test("the default resolver resolves models on the namespace", function() { application.Post = EmberObject['default'].extend({}); detectEqual(application.Post, locator.lookupFactory('model:post'), "looks up Post model on application"); }); QUnit.test("the default resolver resolves *:main on the namespace", function() { application.FooBar = EmberObject['default'].extend({}); detectEqual(application.FooBar, locator.lookupFactory('foo-bar:main'), "looks up FooBar type without name on application"); }); QUnit.test("the default resolver resolves helpers", function() { expect(2); function fooresolvertestHelper() { ok(true, 'found fooresolvertestHelper'); } function barBazResolverTestHelper() { ok(true, 'found barBazResolverTestHelper'); } helpers.registerHelper('fooresolvertest', fooresolvertestHelper); helpers.registerHelper('bar-baz-resolver-test', barBazResolverTestHelper); fooresolvertestHelper(); barBazResolverTestHelper(); }); QUnit.test("the default resolver resolves container-registered helpers", function() { function gooresolvertestHelper() { return 'GOO'; } function gooGazResolverTestHelper() { return 'GAZ'; } application.register('helper:gooresolvertest', gooresolvertestHelper); application.register('helper:goo-baz-resolver-test', gooGazResolverTestHelper); equal(gooresolvertestHelper, locator.lookup('helper:gooresolvertest'), "looks up gooresolvertest helper"); equal(gooGazResolverTestHelper, locator.lookup('helper:goo-baz-resolver-test'), "looks up gooGazResolverTestHelper helper"); }); QUnit.test("the default resolver throws an error if the fullName to resolve is invalid", function() { throws(function() { registry.resolve(undefined);}, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve(null); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve(''); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve(''); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve(':'); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve('model'); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve('model:'); }, TypeError, /Invalid fullName/ ); throws(function() { registry.resolve(':type'); }, TypeError, /Invalid fullName/ ); }); QUnit.test("the default resolver logs hits if `LOG_RESOLVER` is set", function() { expect(3); application.LOG_RESOLVER = true; application.ScoobyDoo = EmberObject['default'].extend(); application.toString = function() { return 'App'; }; Logger['default'].info = function(symbol, name, padding, lookupDescription) { equal(symbol, '[✓]', 'proper symbol is printed when a module is found'); equal(name, 'doo:scooby', 'proper lookup value is logged'); equal(lookupDescription, 'App.ScoobyDoo'); }; registry.resolve('doo:scooby'); }); QUnit.test("the default resolver logs misses if `LOG_RESOLVER` is set", function() { expect(3); application.LOG_RESOLVER = true; application.toString = function() { return 'App'; }; Logger['default'].info = function(symbol, name, padding, lookupDescription) { equal(symbol, '[ ]', 'proper symbol is printed when a module is not found'); equal(name, 'doo:scooby', 'proper lookup value is logged'); equal(lookupDescription, 'App.ScoobyDoo'); }; registry.resolve('doo:scooby'); }); QUnit.test("doesn't log without LOG_RESOLVER", function() { var infoCount = 0; application.ScoobyDoo = EmberObject['default'].extend(); Logger['default'].info = function(symbol, name) { infoCount = infoCount + 1; }; registry.resolve('doo:scooby'); registry.resolve('doo:scrappy'); equal(infoCount, 0, 'Logger.info should not be called if LOG_RESOLVER is not set'); }); QUnit.test("lookup description", function() { application.toString = function() { return 'App'; }; equal(registry.describe('controller:foo'), 'App.FooController', 'Type gets appended at the end'); equal(registry.describe('controller:foo.bar'), 'App.FooBarController', 'dots are removed'); equal(registry.describe('model:foo'), 'App.Foo', "models don't get appended at the end"); }); }); enifed('ember-application/tests/system/dependency_injection/default_resolver_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/default_resolver_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/dependency_injection/default_resolver_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/dependency_injection/default_resolver_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/default_resolver_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/dependency_injection/default_resolver_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/dependency_injection/normalization_test', ['ember-metal/run_loop', 'ember-metal/array', 'ember-application/system/application'], function (run, array, Application) { 'use strict'; var application, registry; QUnit.module("Ember.Application Dependency Injection – normalization", { setup: function() { application = run['default'](Application['default'], 'create'); registry = application.registry; }, teardown: function() { run['default'](application, 'destroy'); } }); QUnit.test('normalization', function() { ok(registry.normalize, 'registry#normalize is present'); equal(registry.normalize('foo:bar'), 'foo:bar'); equal(registry.normalize('controller:posts'), 'controller:posts'); equal(registry.normalize('controller:posts_index'), 'controller:postsIndex'); equal(registry.normalize('controller:posts.index'), 'controller:postsIndex'); equal(registry.normalize('controller:posts.post.index'), 'controller:postsPostIndex'); equal(registry.normalize('controller:posts_post.index'), 'controller:postsPostIndex'); equal(registry.normalize('controller:posts.post_index'), 'controller:postsPostIndex'); equal(registry.normalize('controller:postsIndex'), 'controller:postsIndex'); equal(registry.normalize('controller:blogPosts.index'), 'controller:blogPostsIndex'); equal(registry.normalize('controller:blog/posts.index'), 'controller:blog/postsIndex'); equal(registry.normalize('controller:blog/posts.post.index'), 'controller:blog/postsPostIndex'); equal(registry.normalize('controller:blog/posts_post.index'), 'controller:blog/postsPostIndex'); equal(registry.normalize('template:blog/posts_index'), 'template:blog/posts_index'); }); QUnit.test('normalization is indempotent', function() { var examples = ['controller:posts', 'controller:posts.post.index', 'controller:blog/posts.post_index', 'template:foo_bar']; array.forEach.call(examples, function (example) { equal(registry.normalize(registry.normalize(example)), registry.normalize(example)); }); }); }); enifed('ember-application/tests/system/dependency_injection/normalization_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/normalization_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/dependency_injection/normalization_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/dependency_injection/normalization_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/normalization_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/dependency_injection/normalization_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/dependency_injection/to_string_test', ['ember-metal/core', 'ember-metal/run_loop', 'ember-application/system/application', 'ember-runtime/system/object', 'ember-application/system/resolver', 'ember-metal/utils'], function (Ember, run, Application, EmberObject, DefaultResolver, utils) { 'use strict'; var originalLookup, App, originalModelInjections; QUnit.module("Ember.Application Dependency Injection – toString", { setup: function() { originalModelInjections = Ember['default'].MODEL_FACTORY_INJECTIONS; Ember['default'].MODEL_FACTORY_INJECTIONS = true; originalLookup = Ember['default'].lookup; run['default'](function() { App = Application['default'].create(); Ember['default'].lookup = { App: App }; }); App.Post = EmberObject['default'].extend(); }, teardown: function() { Ember['default'].lookup = originalLookup; run['default'](App, 'destroy'); Ember['default'].MODEL_FACTORY_INJECTIONS = originalModelInjections; } }); QUnit.test("factories", function() { var PostFactory = App.__container__.lookupFactory('model:post'); equal(PostFactory.toString(), 'App.Post', 'expecting the model to be post'); }); QUnit.test("instances", function() { var post = App.__container__.lookup('model:post'); var guid = utils.guidFor(post); equal(post.toString(), '', 'expecting the model to be post'); }); QUnit.test("with a custom resolver", function() { run['default'](App, 'destroy'); run['default'](function() { App = Application['default'].create({ Resolver: DefaultResolver['default'].extend({ makeToString: function(factory, fullName) { return fullName; } }) }); }); App.registry.register('model:peter', EmberObject['default'].extend()); var peter = App.__container__.lookup('model:peter'); var guid = utils.guidFor(peter); equal(peter.toString(), '', 'expecting the supermodel to be peter'); }); }); enifed('ember-application/tests/system/dependency_injection/to_string_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/to_string_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/dependency_injection/to_string_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/dependency_injection/to_string_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system/dependency_injection'); test('ember-application/tests/system/dependency_injection/to_string_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/dependency_injection/to_string_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/dependency_injection_test', ['ember-metal/run_loop', 'ember-runtime/system/object', 'ember-application/system/application'], function (run, EmberObject, Application) { 'use strict'; var EmberApplication = Application['default']; var originalLookup = Ember.lookup; var registry, locator, lookup, application, originalModelInjections; QUnit.module("Ember.Application Dependency Injection", { setup: function() { originalModelInjections = Ember.MODEL_FACTORY_INJECTIONS; Ember.MODEL_FACTORY_INJECTIONS = true; application = run['default'](EmberApplication, 'create'); application.Person = EmberObject['default'].extend({}); application.Orange = EmberObject['default'].extend({}); application.Email = EmberObject['default'].extend({}); application.User = EmberObject['default'].extend({}); application.PostIndexController = EmberObject['default'].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__; lookup = Ember.lookup = {}; }, teardown: function() { run['default'](application, 'destroy'); application = locator = null; Ember.lookup = originalLookup; Ember.MODEL_FACTORY_INJECTIONS = originalModelInjections; } }); QUnit.test('container lookup is normalized', function() { var dotNotationController = locator.lookup('controller:post.index'); var camelCaseController = locator.lookup('controller:postIndex'); ok(dotNotationController instanceof application.PostIndexController); ok(camelCaseController instanceof application.PostIndexController); equal(dotNotationController, camelCaseController); }); QUnit.test('registered entities can be looked up later', function() { equal(registry.resolve('model:person'), application.Person); equal(registry.resolve('model:user'), application.User); equal(registry.resolve('fruit:favorite'), application.Orange); equal(registry.resolve('communication:main'), application.Email); equal(registry.resolve('controller:postIndex'), application.PostIndexController); equal(locator.lookup('fruit:favorite'), locator.lookup('fruit:favorite'), 'singleton lookup worked'); ok(locator.lookup('model:user') !== locator.lookup('model:user'), 'non-singleton lookup worked'); }); QUnit.test('injections', function() { application.inject('model', 'fruit', 'fruit:favorite'); application.inject('model:user', 'communication', 'communication:main'); var user = locator.lookup('model:user'); var person = locator.lookup('model:person'); var fruit = locator.lookup('fruit:favorite'); equal(user.get('fruit'), fruit); equal(person.get('fruit'), fruit); ok(application.Email.detectInstance(user.get('communication'))); }); }); enifed('ember-application/tests/system/dependency_injection_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/dependency_injection_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/dependency_injection_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/dependency_injection_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/dependency_injection_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/dependency_injection_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/initializers_test', ['ember-metal/run_loop', 'ember-application/system/application', 'ember-metal/array', 'ember-views/system/jquery', 'container/registry'], function (run, Application, array, jQuery, Registry) { 'use strict'; var app; QUnit.module("Ember.Application initializers", { setup: function() { }, teardown: function() { if (app) { run['default'](function() { app.destroy(); }); } } }); QUnit.test("initializers require proper 'name' and 'initialize' properties", function() { var MyApplication = Application['default'].extend(); expectAssertion(function() { run['default'](function() { MyApplication.initializer({ name: 'initializer' }); }); }); expectAssertion(function() { run['default'](function() { MyApplication.initializer({ initialize: Ember.K }); }); }); }); QUnit.test("initializers are passed a registry and App", function() { var MyApplication = Application['default'].extend(); MyApplication.initializer({ name: 'initializer', initialize: function(registry, App) { ok(registry instanceof Registry['default'], "initialize is passed a registry"); ok(App instanceof Application['default'], "initialize is passed an Application"); } }); run['default'](function() { app = MyApplication.create({ router: false, rootElement: '#qunit-fixture' }); }); }); QUnit.test("initializers can be registered in a specified order", function() { var order = []; var MyApplication = Application['default'].extend(); MyApplication.initializer({ name: 'fourth', after: 'third', initialize: function(registry) { order.push('fourth'); } }); MyApplication.initializer({ name: 'second', after: 'first', before: 'third', initialize: function(registry) { order.push('second'); } }); MyApplication.initializer({ name: 'fifth', after: 'fourth', before: 'sixth', initialize: function(registry) { order.push('fifth'); } }); MyApplication.initializer({ name: 'first', before: 'second', initialize: function(registry) { order.push('first'); } }); MyApplication.initializer({ name: 'third', initialize: function(registry) { order.push('third'); } }); MyApplication.initializer({ name: 'sixth', initialize: function(registry) { order.push('sixth'); } }); run['default'](function() { app = MyApplication.create({ router: false, rootElement: '#qunit-fixture' }); }); deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); }); QUnit.test("initializers can be registered in a specified order as an array", function() { var order = []; var MyApplication = Application['default'].extend(); MyApplication.initializer({ name: 'third', initialize: function(registry) { order.push('third'); } }); MyApplication.initializer({ name: 'second', after: 'first', before: ['third', 'fourth'], initialize: function(registry) { order.push('second'); } }); MyApplication.initializer({ name: 'fourth', after: ['second', 'third'], initialize: function(registry) { order.push('fourth'); } }); MyApplication.initializer({ name: 'fifth', after: 'fourth', before: 'sixth', initialize: function(registry) { order.push('fifth'); } }); MyApplication.initializer({ name: 'first', before: ['second'], initialize: function(registry) { order.push('first'); } }); MyApplication.initializer({ name: 'sixth', initialize: function(registry) { order.push('sixth'); } }); run['default'](function() { app = MyApplication.create({ router: false, rootElement: '#qunit-fixture' }); }); deepEqual(order, ['first', 'second', 'third', 'fourth', 'fifth', 'sixth']); }); QUnit.test("initializers can have multiple dependencies", function () { var order = []; var a = { name: "a", before: "b", initialize: function(registry) { order.push('a'); } }; var b = { name: "b", initialize: function(registry) { order.push('b'); } }; var c = { name: "c", after: "b", initialize: function(registry) { order.push('c'); } }; var afterB = { name: "after b", after: "b", initialize: function(registry) { order.push("after b"); } }; var afterC = { name: "after c", after: "c", initialize: function(registry) { order.push("after c"); } }; Application['default'].initializer(b); Application['default'].initializer(a); Application['default'].initializer(afterC); Application['default'].initializer(afterB); Application['default'].initializer(c); run['default'](function() { app = Application['default'].create({ router: false, rootElement: '#qunit-fixture' }); }); ok(array.indexOf.call(order, a.name) < array.indexOf.call(order, b.name), 'a < b'); ok(array.indexOf.call(order, b.name) < array.indexOf.call(order, c.name), 'b < c'); ok(array.indexOf.call(order, b.name) < array.indexOf.call(order, afterB.name), 'b < afterB'); ok(array.indexOf.call(order, c.name) < array.indexOf.call(order, afterC.name), 'c < afterC'); }); QUnit.test("initializers set on Application subclasses should not be shared between apps", function() { var firstInitializerRunCount = 0; var secondInitializerRunCount = 0; var FirstApp = Application['default'].extend(); FirstApp.initializer({ name: 'first', initialize: function(registry) { firstInitializerRunCount++; } }); var SecondApp = Application['default'].extend(); SecondApp.initializer({ name: 'second', initialize: function(registry) { secondInitializerRunCount++; } }); jQuery['default']('#qunit-fixture').html('
'); run['default'](function() { FirstApp.create({ router: false, rootElement: '#qunit-fixture #first' }); }); equal(firstInitializerRunCount, 1, 'first initializer only was run'); equal(secondInitializerRunCount, 0, 'first initializer only was run'); run['default'](function() { SecondApp.create({ router: false, rootElement: '#qunit-fixture #second' }); }); equal(firstInitializerRunCount, 1, 'second initializer only was run'); equal(secondInitializerRunCount, 1, 'second initializer only was run'); }); QUnit.test("initializers are concatenated", function() { var firstInitializerRunCount = 0; var secondInitializerRunCount = 0; var FirstApp = Application['default'].extend(); FirstApp.initializer({ name: 'first', initialize: function(registry) { firstInitializerRunCount++; } }); var SecondApp = FirstApp.extend(); SecondApp.initializer({ name: 'second', initialize: function(registry) { secondInitializerRunCount++; } }); jQuery['default']('#qunit-fixture').html('
'); run['default'](function() { FirstApp.create({ router: false, rootElement: '#qunit-fixture #first' }); }); equal(firstInitializerRunCount, 1, 'first initializer only was run when base class created'); equal(secondInitializerRunCount, 0, 'first initializer only was run when base class created'); firstInitializerRunCount = 0; run['default'](function() { SecondApp.create({ router: false, rootElement: '#qunit-fixture #second' }); }); equal(firstInitializerRunCount, 1, 'first initializer was run when subclass created'); equal(secondInitializerRunCount, 1, 'second initializers was run when subclass created'); }); QUnit.test("initializers are per-app", function() { expect(0); var FirstApp = Application['default'].extend(); FirstApp.initializer({ name: 'shouldNotCollide', initialize: function(registry) {} }); var SecondApp = Application['default'].extend(); SecondApp.initializer({ name: 'shouldNotCollide', initialize: function(registry) {} }); }); }); enifed('ember-application/tests/system/initializers_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/initializers_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/initializers_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/initializers_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/initializers_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/initializers_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/instance_initializers_test', ['ember-metal/run_loop', 'ember-application/system/application', 'ember-application/system/application-instance', 'ember-metal/array', 'ember-views/system/jquery'], function (run, Application, ApplicationInstance, array, jQuery) { 'use strict'; var app, initializeContextFeatureEnabled; }); enifed('ember-application/tests/system/instance_initializers_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/instance_initializers_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/instance_initializers_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/instance_initializers_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/instance_initializers_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/instance_initializers_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/logging_test', ['ember-metal/run_loop', 'ember-application/system/application', 'ember-views/views/view', 'ember-runtime/controllers/controller', 'ember-routing/system/route', 'ember-runtime/ext/rsvp', 'ember-metal/keys', 'ember-template-compiler/system/compile', 'ember-routing'], function (run, Application, View, Controller, Route, RSVP, keys, compile) { 'use strict'; /*globals EmberDev */ var App, logs, originalLogger; QUnit.module("Ember.Application – logging of generated classes", { setup: function() { logs = {}; originalLogger = Ember.Logger.info; Ember.Logger.info = function() { var fullName = arguments[1].fullName; logs[fullName] = logs[fullName] || 0; logs[fullName]++; }; run['default'](function() { App = Application['default'].create({ LOG_ACTIVE_GENERATION: true }); App.Router.reopen({ location: 'none' }); App.Router.map(function() { this.resource("posts"); }); App.deferReadiness(); }); }, teardown: function() { Ember.Logger.info = originalLogger; run['default'](App, 'destroy'); logs = App = null; } }); function visit(path) { QUnit.stop(); var promise = run['default'](function() { return new RSVP['default'].Promise(function(resolve, reject) { var router = App.__container__.lookup('router:main'); resolve(router.handleURL(path).then(function(value) { QUnit.start(); ok(true, 'visited: `' + path + '`'); return value; }, function(reason) { QUnit.start(); ok(false, 'failed to visit:`' + path + '` reason: `' + QUnit.jsDump.parse(reason)); throw reason; })); }); }); return { then: function(resolve, reject) { run['default'](promise, 'then', resolve, reject); } }; } QUnit.test("log class generation if logging enabled", function() { if (EmberDev && EmberDev.runningProdBuild) { ok(true, 'Logging does not occur in production builds'); return; } run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(Ember.keys(logs).length, 6, 'expected logs'); }); }); QUnit.test("do NOT log class generation if logging disabled", function() { App.reopen({ LOG_ACTIVE_GENERATION: false }); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(keys['default'](logs).length, 0, 'expected no logs'); }); }); QUnit.test("actively generated classes get logged", function() { if (EmberDev && EmberDev.runningProdBuild) { ok(true, 'Logging does not occur in production builds'); return; } run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(logs['controller:application'], 1, 'expected: ApplicationController was generated'); equal(logs['controller:posts'], 1, 'expected: PostsController was generated'); equal(logs['route:application'], 1, 'expected: ApplicationRoute was generated'); equal(logs['route:posts'], 1, 'expected: PostsRoute was generated'); }); }); QUnit.test("predefined classes do not get logged", function() { App.ApplicationController = Controller['default'].extend(); App.PostsController = Controller['default'].extend(); App.ApplicationRoute = Route['default'].extend(); App.PostsRoute = Route['default'].extend(); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { ok(!logs['controller:application'], 'did not expect: ApplicationController was generated'); ok(!logs['controller:posts'], 'did not expect: PostsController was generated'); ok(!logs['route:application'], 'did not expect: ApplicationRoute was generated'); ok(!logs['route:posts'], 'did not expect: PostsRoute was generated'); }); }); QUnit.module("Ember.Application – logging of view lookups", { setup: function() { logs = {}; originalLogger = Ember.Logger.info; Ember.Logger.info = function() { var fullName = arguments[1].fullName; logs[fullName] = logs[fullName] || 0; logs[fullName]++; }; run['default'](function() { App = Application['default'].create({ LOG_VIEW_LOOKUPS: true }); App.Router.reopen({ location: 'none' }); App.Router.map(function() { this.resource("posts"); }); App.deferReadiness(); }); }, teardown: function() { Ember.Logger.info = originalLogger; run['default'](App, 'destroy'); logs = App = null; } }); QUnit.test("log when template and view are missing when flag is active", function() { if (EmberDev && EmberDev.runningProdBuild) { ok(true, 'Logging does not occur in production builds'); return; } App.register('template:application', compile['default']("{{outlet}}")); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(logs['template:application'], undefined, 'expected: Should not log template:application since it exists.'); equal(logs['template:index'], 1, 'expected: Could not find "index" template or view.'); equal(logs['template:posts'], 1, 'expected: Could not find "posts" template or view.'); }); }); QUnit.test("do not log when template and view are missing when flag is not true", function() { App.reopen({ LOG_VIEW_LOOKUPS: false }); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(keys['default'](logs).length, 0, 'expected no logs'); }); }); QUnit.test("log which view is used with a template", function() { if (EmberDev && EmberDev.runningProdBuild) { ok(true, 'Logging does not occur in production builds'); return; } App.register('template:application', compile['default']('{{outlet}}')); App.register('template:foo', function() { return 'Template with custom view'; }); App.register('view:posts', View['default'].extend({ templateName: 'foo' })); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(logs['view:application'], 1, 'expected: Should log use of default view'); equal(logs['view:index'], undefined, 'expected: Should not log when index is not present.'); equal(logs['view:posts'], 1, 'expected: Rendering posts with PostsView.'); }); }); QUnit.test("do not log which views are used with templates when flag is not true", function() { App.reopen({ LOG_VIEW_LOOKUPS: false }); run['default'](App, 'advanceReadiness'); visit('/posts').then(function() { equal(keys['default'](logs).length, 0, 'expected no logs'); }); }); }); enifed('ember-application/tests/system/logging_test.jscs-test', function () { 'use strict'; module('JSCS - ember-application/tests/system'); test('ember-application/tests/system/logging_test.js should pass jscs', function() { ok(true, 'ember-application/tests/system/logging_test.js should pass jscs.'); }); }); enifed('ember-application/tests/system/logging_test.jshint', function () { 'use strict'; module('JSHint - ember-application/tests/system'); test('ember-application/tests/system/logging_test.js should pass jshint', function() { ok(true, 'ember-application/tests/system/logging_test.js should pass jshint.'); }); }); enifed('ember-application/tests/system/readiness_test', ['ember-metal/run_loop', 'ember-application/system/application'], function (run, EmberApplication) { 'use strict'; var jQuery, application, Application; var 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. QUnit.module("Application readiness", { setup: function() { readyWasCalled = 0; readyCallbacks = []; var jQueryInstance = { ready: function(callback) { readyCallbacks.push(callback); if (jQuery.isReady) { domReady(); } } }; jQuery = function() { return jQueryInstance; }; jQuery.isReady = false; var domReadyCalled = 0; domReady = function() { if (domReadyCalled !== 0) { return; } domReadyCalled++; var i; for (i=0; i 0) { QUnit.deepEqual(templateNames, [], "Ember.TEMPLATES should be empty"); this.env.Ember.TEMPLATES = {}; } } }, restore: function(){} }; exports['default'] = RemainingTemplateAssert; }); enifed('ember-dev/test-helper/remaining-view', ['exports'], function (exports) { 'use strict'; /* globals QUnit */ var RemainingViewAssert = function(env){ this.env = env; }; RemainingViewAssert.prototype = { reset: function(){}, inject: function(){}, assert: function(){ if (this.env.Ember && this.env.Ember.View) { var viewIds = [], id; for (id in this.env.Ember.View.views) { if (this.env.Ember.View.views[id] != null) { viewIds.push(id); } } if (viewIds.length > 0) { QUnit.deepEqual(viewIds, [], "Ember.View.views should be empty"); this.env.Ember.View.views = []; } } }, restore: function(){} }; exports['default'] = RemainingViewAssert; }); enifed('ember-dev/test-helper/run-loop', ['exports'], function (exports) { 'use strict'; /* globals QUnit */ function RunLoopAssertion(env){ this.env = env; } RunLoopAssertion.prototype = { reset: function(){}, inject: function(){}, assert: function(){ var run = this.env.Ember.run; if (run.currentRunLoop) { QUnit.ok(false, "Should not be in a run loop at end of test"); while (run.currentRunLoop) { run.end(); } } if (run.hasScheduledTimers()) { QUnit.ok(false, "Ember run should not have scheduled timers at end of test"); run.cancelTimers(); } }, restore: function(){} }; exports['default'] = RunLoopAssertion; }); enifed('ember-dev/test-helper/setup-qunit', ['exports'], function (exports) { 'use strict'; /* globals QUnit */ function setupQUnit(assertion, _qunitGlobal) { var qunitGlobal = QUnit; if (_qunitGlobal) { qunitGlobal = _qunitGlobal; } var originalModule = qunitGlobal.module; qunitGlobal.module = function(name, _options) { var options = _options || {}; var originalSetup = options.setup || function() { }; var originalTeardown = options.teardown || function() { }; options.setup = function() { assertion.reset(); assertion.inject(); originalSetup.call(this); }; options.teardown = function() { originalTeardown.call(this); assertion.assert(); assertion.restore(); }; return originalModule(name, options); }; } exports['default'] = setupQUnit; }); enifed('ember-dev/test-helper/utils', ['exports'], function (exports) { 'use strict'; exports.buildCompositeAssert = buildCompositeAssert; function callForEach(prop, func) { return function() { for (var i=0, l=this[prop].length;i") }); appendView(view); equal(view.element.firstChild.hasAttribute('disabled'), true, 'attribute is output'); equal(view.element.firstChild.disabled, true, 'boolean property is set true'); }); QUnit.test("disabled property can be set false with a blank string", function() { view = EmberView['default'].create({ context: { isDisabled: '' }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.hasAttribute('disabled'), false, 'attribute is not output'); equal(view.element.firstChild.disabled, false, 'boolean property is set false'); }); QUnit.test("disabled property can be set false", function() { view = EmberView['default'].create({ context: { isDisabled: false }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is not output"); equal(view.element.firstChild.disabled, false, 'boolean property is set false'); }); QUnit.test("disabled property can be set true with a string", function() { view = EmberView['default'].create({ context: { isDisabled: "oh, no a string" }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.hasAttribute('disabled'), true, 'attribute is output'); equal(view.element.firstChild.disabled, true, 'boolean property is set true'); }); QUnit.test("disabled attribute turns a value to a string", function() { view = EmberView['default'].create({ context: { isDisabled: false }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.hasAttribute('disabled'), true, 'attribute is output'); equal(view.element.firstChild.disabled, true, 'boolean property is set true'); }); QUnit.test("disabled attribute preserves a blank string value", function() { view = EmberView['default'].create({ context: { isDisabled: '' }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is not output"); equal(view.element.firstChild.disabled, false, 'boolean property is set false'); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/boolean_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/boolean_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/boolean_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/boolean_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/boolean_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/boolean_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/class_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-template-compiler/system/compile', 'htmlbars-test-helpers'], function (EmberView, run, compile, htmlbars_test_helpers) { 'use strict'; var view; function appendView(view) { run['default'](function() { view.appendTo('#qunit-fixture'); }); } var isInlineIfEnabled = false; isInlineIfEnabled = true; // jscs:disable validateIndentation QUnit.module("ember-htmlbars: class attribute", { teardown: function() { if (view) { run['default'](view, view.destroy); } } }); QUnit.test("class renders before didInsertElement", function() { var matchingElement; view = EmberView['default'].create({ didInsertElement: function() { matchingElement = this.$('div.blue'); }, context: { color: 'blue' }, template: compile['default']("
Hi!
") }); appendView(view); equal(view.element.firstChild.className, 'blue', "attribute is output"); equal(matchingElement.length, 1, 'element is in the DOM when didInsertElement'); }); QUnit.test("class property can contain multiple classes", function() { view = EmberView['default'].create({ context: { classes: 'large blue' }, template: compile['default']("
") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
', "attribute is output"); ok(view.$('.large')[0], 'first class found'); ok(view.$('.blue')[0], 'second class found'); }); QUnit.test("class property is removed when updated with a null value", function() { view = EmberView['default'].create({ context: { "class": 'large' }, template: compile['default']("
") }); appendView(view); equal(view.element.firstChild.className, 'large', "attribute is output"); run['default'](view, view.set, 'context.class', null); equal(view.element.firstChild.className, '', "attribute is removed"); }); QUnit.test("class attribute concats bound values", function() { view = EmberView['default'].create({ context: { size: 'large', color: 'blue' }, template: compile['default']("
") }); appendView(view); ok(view.element.firstChild.className, 'large blue round', 'classes are set'); }); if (isInlineIfEnabled) { QUnit.test("class attribute accepts nested helpers, and updates", function() { view = EmberView['default'].create({ context: { size: 'large', hasColor: true, hasShape: false, shape: 'round' }, template: compile['default']("
") }); appendView(view); ok(view.element.firstChild.className, 'large blue no-shape', 'classes are set'); run['default'](view, view.set, 'context.hasColor', false); run['default'](view, view.set, 'context.hasShape', true); ok(view.element.firstChild.className, 'large round', 'classes are updated'); }); } QUnit.test("class attribute can accept multiple classes from a single value, and update", function() { view = EmberView['default'].create({ context: { size: 'large small' }, template: compile['default']("
") }); appendView(view); ok(view.element.firstChild.className, 'large small', 'classes are set'); run['default'](view, view.set, 'context.size', 'medium'); ok(view.element.firstChild.className, 'medium', 'classes are updated'); }); QUnit.test("class attribute can grok concatted classes, and update", function() { view = EmberView['default'].create({ context: { size: 'large', prefix: 'pre-pre pre', postfix: 'post' }, template: compile['default']("
") }); appendView(view); ok(view.element.firstChild.className, 'btn-large pre-pre pre-post whoop', 'classes are set'); run['default'](view, view.set, 'context.prefix', ''); ok(view.element.firstChild.className, 'btn-large -post whoop', 'classes are updated'); }); QUnit.test("class attribute stays in order", function() { view = EmberView['default'].create({ context: { showA: 'a', showB: 'b' }, template: compile['default']("
") }); appendView(view); run['default'](view, view.set, 'context.showB', false); run['default'](view, view.set, 'context.showB', true); ok(view.element.firstChild.className, 'r b a c', 'classes are in the right order'); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/class_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/class_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/class_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/class_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/class_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/class_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/data_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-runtime/system/object', 'ember-template-compiler/system/compile', 'ember-views/system/renderer', 'htmlbars-test-helpers', 'ember-htmlbars/env', 'ember-runtime/tests/utils'], function (EmberView, run, EmberObject, compile, Renderer, htmlbars_test_helpers, env, utils) { 'use strict'; var view, originalSetAttribute, setAttributeCalls, renderer; QUnit.module("ember-htmlbars: data attribute", { teardown: function() { utils.runDestroy(view); } }); QUnit.test("property is output", function() { view = EmberView['default'].create({ context: { name: 'erik' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is output"); }); QUnit.test("property set before didInsertElement", function() { var matchingElement; view = EmberView['default'].create({ didInsertElement: function() { matchingElement = this.$('div[data-name=erik]'); }, context: { name: 'erik' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is output"); equal(matchingElement.length, 1, 'element is in the DOM when didInsertElement'); }); QUnit.test("quoted attributes are concatenated", function() { view = EmberView['default'].create({ context: { firstName: 'max', lastName: 'jackson' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is output"); }); QUnit.test("quoted attributes are updated when changed", function() { view = EmberView['default'].create({ context: { firstName: 'max', lastName: 'jackson' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is output"); run['default'](view, view.set, 'context.firstName', 'james'); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is output"); }); QUnit.test("quoted attributes are not removed when value is null", function() { view = EmberView['default'].create({ context: { firstName: 'max', lastName: 'jackson' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); equal(view.element.firstChild.getAttribute('data-name'), 'max', "precond - attribute is output"); run['default'](view, view.set, 'context.firstName', null); equal(view.element.firstChild.getAttribute('data-name'), '', "attribute is output"); }); QUnit.test("unquoted attributes are removed when value is null", function() { view = EmberView['default'].create({ context: { firstName: 'max' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); equal(view.element.firstChild.getAttribute('data-name'), 'max', "precond - attribute is output"); run['default'](view, view.set, 'context.firstName', null); ok(!view.element.firstChild.hasAttribute('data-name'), "attribute is removed output"); }); QUnit.test("unquoted attributes that are null are not added", function() { view = EmberView['default'].create({ context: { firstName: null }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is not present"); }); QUnit.test("unquoted attributes are added when changing from null", function() { view = EmberView['default'].create({ context: { firstName: null }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is not present"); run['default'](view, view.set, 'context.firstName', 'max'); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is added output"); }); QUnit.test("property value is directly added to attribute", function() { view = EmberView['default'].create({ context: { name: '"" data-foo="blah"' }, template: compile['default']("
Hi!
") }); utils.runAppend(view); equal(view.element.firstChild.getAttribute('data-name'), '"" data-foo="blah"', "attribute is output"); }); QUnit.test("path is output", function() { view = EmberView['default'].create({ context: { name: { firstName: 'erik' } }, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is output"); }); QUnit.test("changed property updates", function() { var context = EmberObject['default'].create({ name: 'erik' }); view = EmberView['default'].create({ context: context, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is output"); run['default'](context, context.set, 'name', 'mmun'); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is updated output"); }); QUnit.test("updates are scheduled in the render queue", function() { expect(4); var context = EmberObject['default'].create({ name: 'erik' }); view = EmberView['default'].create({ context: context, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is output"); run['default'](function() { run['default'].schedule('render', function() { htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is not updated sync"); }); context.set('name', 'mmun'); run['default'].schedule('render', function() { htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is updated output"); }); }); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "attribute is updated output"); }); QUnit.test("updates fail silently after an element is destroyed", function() { var context = EmberObject['default'].create({ name: 'erik' }); view = EmberView['default'].create({ context: context, template: compile['default']("
Hi!
") }); utils.runAppend(view); htmlbars_test_helpers.equalInnerHTML(view.element, '
Hi!
', "precond - attribute is output"); run['default'](function() { context.set('name', 'mmun'); utils.runDestroy(view); }); }); QUnit.module('ember-htmlbars: {{attribute}} helper -- setAttribute', { setup: function() { renderer = new Renderer['default'](env.domHelper); originalSetAttribute = env.domHelper.setAttribute; env.domHelper.setAttribute = function(element, name, value) { if (name.substr(0, 5) === 'data-') { setAttributeCalls.push([name, value]); } originalSetAttribute.call(env.domHelper, element, name, value); }; setAttributeCalls = []; }, teardown: function() { env.domHelper.setAttribute = originalSetAttribute; utils.runDestroy(view); } }); QUnit.test('calls setAttribute for new values', function() { var context = EmberObject['default'].create({ name: 'erik' }); view = EmberView['default'].create({ renderer: renderer, context: context, template: compile['default']("
Hi!
") }); utils.runAppend(view); run['default'](context, context.set, 'name', 'mmun'); var expected = [ ['data-name', 'erik'], ['data-name', 'mmun'] ]; deepEqual(setAttributeCalls, expected); }); QUnit.test('does not call setAttribute if the same value is set', function() { var context = EmberObject['default'].create({ name: 'erik' }); view = EmberView['default'].create({ renderer: renderer, context: context, template: compile['default']("
Hi!
") }); utils.runAppend(view); run['default'](function() { context.set('name', 'mmun'); context.set('name', 'erik'); }); var expected = [ ['data-name', 'erik'] ]; deepEqual(setAttributeCalls, expected); }); }); enifed('ember-htmlbars/tests/attr_nodes/data_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/data_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/data_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/data_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/data_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/data_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/href_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-template-compiler/system/compile', 'htmlbars-test-helpers'], function (EmberView, run, compile, htmlbars_test_helpers) { 'use strict'; var view; function appendView(view) { run['default'](function() { view.appendTo('#qunit-fixture'); }); } // jscs:disable validateIndentation QUnit.module("ember-htmlbars: href attribute", { teardown: function() { if (view) { run['default'](view, view.destroy); } } }); QUnit.test("href is set", function() { view = EmberView['default'].create({ context: { url: 'http://example.com' }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/href_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/href_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/href_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/href_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/href_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/href_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/property_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-template-compiler/system/compile'], function (EmberView, run, compile) { 'use strict'; var view; function appendView(view) { run['default'](function() { view.appendTo('#qunit-fixture'); }); } function canSetFalsyMaxLength() { var input = document.createElement('input'); input.maxLength = 0; return input.maxLength === 0; } // jscs:disable validateIndentation QUnit.module("ember-htmlbars: property", { teardown: function() { if (view) { run['default'](view, view.destroy); } } }); QUnit.test("maxlength sets the property and attribute", function() { view = EmberView['default'].create({ context: { length: 5 }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.maxLength, 5); Ember.run(view, view.set, 'context.length', 1); equal(view.element.firstChild.maxLength, 1); }); QUnit.test("quoted maxlength sets the property and attribute", function() { view = EmberView['default'].create({ context: { length: 5 }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.maxLength, '5'); if (canSetFalsyMaxLength()) { Ember.run(view, view.set, 'context.length', null); equal(view.element.firstChild.maxLength, 0); } else { Ember.run(view, view.set, 'context.length', 1); equal(view.element.firstChild.maxLength, 1); } }); QUnit.test("array value can be set as property", function() { view = EmberView['default'].create({ context: {}, template: compile['default']("") }); appendView(view); Ember.run(view, view.set, 'context.items', [4,5]); ok(true, "no legacy assertion prohibited setting an array"); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/property_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/property_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/property_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/property_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/property_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/property_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/sanitized_test', ['ember-views/views/view', 'ember-template-compiler/system/compile', 'ember-htmlbars/utils/string', 'ember-runtime/tests/utils', 'ember-metal/environment'], function (EmberView, compile, string, utils, environment) { 'use strict'; /* jshint scripturl:true */ var view; QUnit.module("ember-htmlbars: sanitized attribute", { teardown: function() { utils.runDestroy(view); } }); // jscs:disable validateIndentation var badTags = [ { tag: 'a', attr: 'href', unquotedTemplate: compile['default'](""), quotedTemplate: compile['default'](""), multipartTemplate: compile['default']("") }, { tag: 'body', attr: 'background', unquotedTemplate: compile['default'](""), quotedTemplate: compile['default'](""), multipartTemplate: compile['default']("") }, { tag: 'link', attr: 'href', unquotedTemplate: compile['default'](""), quotedTemplate: compile['default'](""), multipartTemplate: compile['default']("") }, { tag: 'img', attr: 'src', unquotedTemplate: compile['default'](""), quotedTemplate: compile['default'](""), multipartTemplate: compile['default']("") }, { tag: 'iframe', attr: 'src', // Setting an iframe with a bad protocol results in the browser // being redirected. in IE8. Skip the iframe tests on that platform. skip: (environment['default'].hasDOM && document.documentMode && document.documentMode <= 8), unquotedTemplate: compile['default'](""), quotedTemplate: compile['default'](""), multipartTemplate: compile['default']("") } ]; for (var i=0, l=badTags.length; i") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); Ember.run(view, view.set, 'context.viewBoxString', null); equal(view.element.getAttribute('svg'), null, "attribute is removed"); }); QUnit.test("quoted viewBox property is output", function() { var viewBoxString = '0 0 100 100'; view = EmberView['default'].create({ context: { viewBoxString: viewBoxString }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); }); QUnit.test("quoted viewBox property is concat", function() { var viewBoxString = '100 100'; view = EmberView['default'].create({ context: { viewBoxString: viewBoxString }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); var newViewBoxString = '200 200'; Ember.run(view, view.set, 'context.viewBoxString', newViewBoxString); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); }); QUnit.test("class is output", function() { view = EmberView['default'].create({ context: { color: 'blue' }, template: compile['default']("") }); appendView(view); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); Ember.run(view, view.set, 'context.color', 'red'); htmlbars_test_helpers.equalInnerHTML(view.element, '', "attribute is output"); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/svg_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/svg_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/svg_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/svg_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/svg_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/svg_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/value_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-template-compiler/system/compile'], function (EmberView, run, compile) { 'use strict'; var view; function appendView(view) { run['default'](function() { view.appendTo('#qunit-fixture'); }); } // jscs:disable validateIndentation QUnit.module("ember-htmlbars: value attribute", { teardown: function() { if (view) { run['default'](view, view.destroy); } } }); QUnit.test("property is output", function() { view = EmberView['default'].create({ context: { name: 'rick' }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.tagName, 'INPUT', "input element is created"); equal(view.element.firstChild.value, "rick", 'property is set true'); }); QUnit.test("string property is output", function() { view = EmberView['default'].create({ context: { name: 'rick' }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.tagName, 'INPUT', "input element is created"); equal(view.element.firstChild.value, "rick", 'property is set true'); }); QUnit.test("blank property is output", function() { view = EmberView['default'].create({ context: { name: '' }, template: compile['default']("") }); appendView(view); equal(view.element.firstChild.tagName, 'INPUT', "input element is created"); equal(view.element.firstChild.value, "", 'property is set true'); }); // jscs:enable validateIndentation }); enifed('ember-htmlbars/tests/attr_nodes/value_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/value_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/value_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/attr_nodes/value_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/attr_nodes'); test('ember-htmlbars/tests/attr_nodes/value_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/attr_nodes/value_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/compat/handlebars_get_test', ['ember-metal/core', 'ember-views/views/metamorph_view', 'ember-views/views/view', 'ember-htmlbars/compat/handlebars-get', 'ember-runtime/system/container', 'ember-runtime/tests/utils', 'ember-htmlbars/compat'], function (Ember, _MetamorphView, EmberView, handlebarsGet, system__container, utils, EmberHandlebars) { 'use strict'; var compile = EmberHandlebars['default'].compile; var originalLookup = Ember['default'].lookup; var TemplateTests, registry, container, lookup, view; QUnit.module("ember-htmlbars: Ember.Handlebars.get", { setup: function() { Ember['default'].lookup = lookup = {}; registry = new system__container.Registry(); container = registry.container(); registry.optionsForType('template', { instantiate: false }); registry.optionsForType('helper', { instantiate: false }); registry.register('view:default', _MetamorphView['default']); registry.register('view:toplevel', EmberView['default'].extend()); }, teardown: function() { utils.runDestroy(container); utils.runDestroy(view); registry = container = view = null; Ember['default'].lookup = lookup = originalLookup; TemplateTests = null; } }); QUnit.test('it can lookup a path from the current context', function() { expect(1); registry.register('helper:handlebars-get', function(path, options) { var context = options.contexts && options.contexts[0] || this; ignoreDeprecation(function() { equal(handlebarsGet['default'](context, path, options), 'bar'); }); }); view = EmberView['default'].create({ container: container, controller: { foo: 'bar' }, template: compile('{{handlebars-get "foo"}}') }); utils.runAppend(view); }); QUnit.test('it can lookup a path from the current keywords', function() { expect(1); registry.register('helper:handlebars-get', function(path, options) { var context = options.contexts && options.contexts[0] || this; ignoreDeprecation(function() { equal(handlebarsGet['default'](context, path, options), 'bar'); }); }); view = EmberView['default'].create({ container: container, controller: { foo: 'bar' }, template: compile('{{#with foo as bar}}{{handlebars-get "bar"}}{{/with}}') }); utils.runAppend(view); }); QUnit.test('it can lookup a path from globals', function() { expect(1); lookup.Blammo = { foo: 'blah' }; registry.register('helper:handlebars-get', function(path, options) { var context = options.contexts && options.contexts[0] || this; ignoreDeprecation(function() { equal(handlebarsGet['default'](context, path, options), lookup.Blammo.foo); }); }); view = EmberView['default'].create({ container: container, controller: { }, template: compile('{{handlebars-get "Blammo.foo"}}') }); utils.runAppend(view); }); QUnit.test('it raises a deprecation warning on use', function() { expect(1); registry.register('helper:handlebars-get', function(path, options) { var context = options.contexts && options.contexts[0] || this; expectDeprecation(function() { handlebarsGet['default'](context, path, options); }, 'Usage of Ember.Handlebars.get is deprecated, use a Component or Ember.Handlebars.makeBoundHelper instead.'); }); view = EmberView['default'].create({ container: container, controller: { foo: 'bar' }, template: compile('{{handlebars-get "foo"}}') }); utils.runAppend(view); }); }); enifed('ember-htmlbars/tests/compat/handlebars_get_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/handlebars_get_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/compat/handlebars_get_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/compat/handlebars_get_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/handlebars_get_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/compat/handlebars_get_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/compat/helper_test', ['ember-htmlbars/compat/helper', 'ember-views/views/view', 'ember-views/views/component', 'ember-htmlbars/system/make-view-helper', 'ember-htmlbars/helpers', 'ember-template-compiler/system/compile', 'ember-runtime/tests/utils'], function (compat__helper, EmberView, Component, makeViewHelper, helpers, compile, utils) { 'use strict'; var view; QUnit.module('ember-htmlbars: Handlebars compatible helpers', { teardown: function() { utils.runDestroy(view); delete helpers['default'].test; delete helpers['default']['view-helper']; } }); QUnit.test('wraps provided function so that original path params are provided to the helper', function() { expect(2); function someHelper(param1, param2, options) { equal(param1, 'blammo'); equal(param2, 'blazzico'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{test "blammo" "blazzico"}}') }); utils.runAppend(view); }); QUnit.test('combines `env` and `options` for the wrapped helper', function() { expect(1); function someHelper(options) { equal(options.data.view, view); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{test}}') }); utils.runAppend(view); }); QUnit.test('adds `hash` into options `options` for the wrapped helper', function() { expect(1); function someHelper(options) { equal(options.hash.bestFriend, 'Jacquie'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{test bestFriend="Jacquie"}}') }); utils.runAppend(view); }); QUnit.test('bound `hash` params are provided with their original paths', function() { expect(1); function someHelper(options) { equal(options.hash.bestFriend, 'value'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'Jacquie' }, template: compile['default']('{{test bestFriend=value}}') }); utils.runAppend(view); }); QUnit.test('bound ordered params are provided with their original paths', function() { expect(2); function someHelper(param1, param2, options) { equal(param1, 'first'); equal(param2, 'second'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { first: 'blammo', second: 'blazzico' }, template: compile['default']('{{test first second}}') }); utils.runAppend(view); }); QUnit.test('allows unbound usage within an element', function() { expect(4); function someHelper(param1, param2, options) { equal(param1, 'blammo'); equal(param2, 'blazzico'); return "class='foo'"; } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('
Bar
') }); expectDeprecation(function() { utils.runAppend(view); }, 'Returning a string of attributes from a helper inside an element is deprecated.'); equal(view.$('.foo').length, 1, 'class attribute was added by helper'); }); QUnit.test('registering a helper created from `Ember.Handlebars.makeViewHelper` does not double wrap the helper', function() { expect(1); var ViewHelperComponent = Component['default'].extend({ layout: compile['default']('woot!') }); var helper = makeViewHelper['default'](ViewHelperComponent); compat__helper.registerHandlebarsCompatibleHelper('view-helper', helper); view = EmberView['default'].extend({ template: compile['default']('{{view-helper}}') }).create(); utils.runAppend(view); equal(view.$().text(), 'woot!'); }); QUnit.test('does not add `options.fn` if no block was specified', function() { expect(1); function someHelper(options) { ok(!options.fn, '`options.fn` is not present when block is not specified'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{test}}') }); utils.runAppend(view); }); QUnit.test('does not return helper result if block was specified', function() { expect(1); function someHelper(options) { return 'asdf'; } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{#test}}lkj;{{/test}}') }); utils.runAppend(view); equal(view.$().text(), ''); }); QUnit.test('allows usage of the template fn', function() { expect(1); function someHelper(options) { options.fn(); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'foo' }, template: compile['default']('{{#test}}foo{{/test}}') }); utils.runAppend(view); equal(view.$().text(), 'foo'); }); QUnit.test('ordered param types are added to options.types', function() { expect(3); function someHelper(param1, param2, param3, options) { equal(options.types[0], 'NUMBER'); equal(options.types[1], 'ID'); equal(options.types[2], 'STRING'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { first: 'blammo', second: 'blazzico' }, template: compile['default']('{{test 1 two "3"}}') }); utils.runAppend(view); }); QUnit.test('`hash` params are to options.hashTypes', function() { expect(3); function someHelper(options) { equal(options.hashTypes.string, 'STRING'); equal(options.hashTypes.number, 'NUMBER'); equal(options.hashTypes.id, 'ID'); } compat__helper.registerHandlebarsCompatibleHelper('test', someHelper); view = EmberView['default'].create({ controller: { value: 'Jacquie' }, template: compile['default']('{{test string="foo" number=42 id=someBoundThing}}') }); utils.runAppend(view); }); }); enifed('ember-htmlbars/tests/compat/helper_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/helper_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/compat/helper_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/compat/helper_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/helper_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/compat/helper_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/compat/make-view-helper_test', ['ember-views/views/view', 'container/registry', 'ember-template-compiler/system/compile', 'ember-htmlbars/system/make-view-helper', 'ember-views/views/component', 'ember-runtime/tests/utils'], function (EmberView, Registry, compile, makeViewHelper, Component, utils) { 'use strict'; var registry, container, view; QUnit.module('ember-htmlbars: makeViewHelper compat', { setup: function() { registry = new Registry['default'](); container = registry.container(); registry.optionsForType('helper', { instantiate: false }); }, teardown: function() { utils.runDestroy(container); utils.runDestroy(view); registry = container = view = null; } }); QUnit.test('makeViewHelper', function() { expect(1); var ViewHelperComponent = Component['default'].extend({ layout: compile['default']('woot!') }); var helper = makeViewHelper['default'](ViewHelperComponent); registry.register('helper:view-helper', helper); view = EmberView['default'].extend({ template: compile['default']('{{view-helper}}'), container: container }).create(); utils.runAppend(view); equal(view.$().text(), 'woot!'); }); }); enifed('ember-htmlbars/tests/compat/make-view-helper_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/make-view-helper_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/compat/make-view-helper_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/compat/make-view-helper_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/make-view-helper_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/compat/make-view-helper_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/compat/make_bound_helper_test', ['ember-views/views/view', 'ember-metal/run_loop', 'ember-runtime/system/object', 'ember-runtime/system/native_array', 'ember-views/views/simple_bound_view', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-runtime/tests/utils', 'ember-runtime/system/string', 'ember-htmlbars/compat'], function (EmberView, run, EmberObject, native_array, SimpleBoundView, property_get, property_set, utils, string, EmberHandlebars) { 'use strict'; /*jshint newcap:false*/ var compile, helpers, helper; compile = EmberHandlebars['default'].compile; helpers = EmberHandlebars['default'].helpers; helper = EmberHandlebars['default'].helper; var view; var originalLookup = Ember.lookup; function registerRepeatHelper() { expectDeprecationInHTMLBars(); helper('repeat', function(value, options) { var count = options.hash.count || 1; var a = []; while (a.length < count) { a.push(value); } return a.join(''); }); } function expectDeprecationInHTMLBars() { // leave this empty function as a place holder to // enable a deprecation notice } QUnit.module("ember-htmlbars: makeBoundHelper", { setup: function() { }, teardown: function() { utils.runDestroy(view); Ember.lookup = originalLookup; } }); QUnit.test("primitives should work correctly [DEPRECATED]", function() { expectDeprecation('Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); expectDeprecation('Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead.'); view = EmberView['default'].create({ prims: Ember.A(["string", 12]), template: compile('{{#each view.prims}}{{#if this}}inside-if{{/if}}{{#with this}}inside-with{{/with}}{{/each}}') }); utils.runAppend(view); equal(view.$().text(), 'inside-ifinside-withinside-ifinside-with'); }); QUnit.test("should update bound helpers when properties change", function() { expectDeprecationInHTMLBars(); helper('capitalize', function(value) { return value.toUpperCase(); }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ name: "Brogrammer" }), template: compile("{{capitalize name}}") }); utils.runAppend(view); equal(view.$().text(), 'BROGRAMMER', "helper output is correct"); run['default'](function() { property_set.set(view, 'controller.name', 'wes'); }); equal(view.$().text(), 'WES', "helper output updated"); }); QUnit.test("should update bound helpers in a subexpression when properties change", function() { expectDeprecationInHTMLBars(); helper('dasherize', function(value) { return string.dasherize(value); }); view = EmberView['default'].create({ controller: { prop: "isThing" }, template: compile("
{{prop}}
") }); utils.runAppend(view); equal(view.$('div[data-foo="is-thing"]').text(), 'isThing', "helper output is correct"); run['default'](view, 'set', 'controller.prop', 'notThing'); equal(view.$('div[data-foo="not-thing"]').text(), 'notThing', "helper output is correct"); }); QUnit.test("should allow for computed properties with dependencies", function() { expectDeprecationInHTMLBars(); helper('capitalizeName', function(value) { return property_get.get(value, 'name').toUpperCase(); }, 'name'); view = EmberView['default'].create({ controller: EmberObject['default'].create({ person: EmberObject['default'].create({ name: 'Brogrammer' }) }), template: compile("{{capitalizeName person}}") }); utils.runAppend(view); equal(view.$().text(), 'BROGRAMMER', "helper output is correct"); run['default'](function() { property_set.set(view, 'controller.person.name', 'wes'); }); equal(view.$().text(), 'WES', "helper output updated"); }); QUnit.test("bound helpers should support options", function() { registerRepeatHelper(); view = EmberView['default'].create({ controller: EmberObject['default'].create({ text: 'ab' }), template: compile("{{repeat text count=3}}") }); utils.runAppend(view); equal(view.$().text(), 'ababab', "helper output is correct"); }); QUnit.test("bound helpers should support keywords", function() { expectDeprecationInHTMLBars(); helper('capitalize', function(value) { return value.toUpperCase(); }); view = EmberView['default'].create({ text: 'ab', template: compile("{{capitalize view.text}}") }); utils.runAppend(view); equal(view.$().text(), 'AB', "helper output is correct"); }); QUnit.test("bound helpers should support global paths [DEPRECATED]", function() { expectDeprecationInHTMLBars(); helper('capitalize', function(value) { return value.toUpperCase(); }); Ember.lookup = { Text: 'ab' }; view = EmberView['default'].create({ template: compile("{{capitalize Text}}") }); expectDeprecation(function() { utils.runAppend(view); }, /Global lookup of Text from a Handlebars template is deprecated/); equal(view.$().text(), 'AB', "helper output is correct"); }); QUnit.test("bound helper should support this keyword", function() { expectDeprecationInHTMLBars(); helper('capitalize', function(value) { return property_get.get(value, 'text').toUpperCase(); }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ text: 'ab' }), template: compile("{{capitalize this}}") }); utils.runAppend(view); equal(view.$().text(), 'AB', "helper output is correct"); }); QUnit.test("bound helpers should support bound options", function() { registerRepeatHelper(); view = EmberView['default'].create({ controller: EmberObject['default'].create({ text: 'ab', numRepeats: 3 }), template: compile('{{repeat text countBinding="numRepeats"}}') }); utils.runAppend(view); equal(view.$().text(), 'ababab', "helper output is correct"); run['default'](function() { view.set('controller.numRepeats', 4); }); equal(view.$().text(), 'abababab', "helper correctly re-rendered after bound option was changed"); run['default'](function() { view.set('controller.numRepeats', 2); view.set('controller.text', "YES"); }); equal(view.$().text(), 'YESYES', "helper correctly re-rendered after both bound option and property changed"); }); QUnit.test("bound helpers should support unquoted values as bound options", function() { registerRepeatHelper(); view = EmberView['default'].create({ controller: EmberObject['default'].create({ text: 'ab', numRepeats: 3 }), template: compile('{{repeat text count=numRepeats}}') }); utils.runAppend(view); equal(view.$().text(), 'ababab', "helper output is correct"); run['default'](function() { view.set('controller.numRepeats', 4); }); equal(view.$().text(), 'abababab', "helper correctly re-rendered after bound option was changed"); run['default'](function() { view.set('controller.numRepeats', 2); view.set('controller.text', "YES"); }); equal(view.$().text(), 'YESYES', "helper correctly re-rendered after both bound option and property changed"); }); QUnit.test("bound helpers should support multiple bound properties", function() { expectDeprecationInHTMLBars(); helper('combine', function() { return [].slice.call(arguments, 0, -1).join(''); }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ thing1: 'ZOID', thing2: 'BERG' }), template: compile('{{combine thing1 thing2}}') }); utils.runAppend(view); equal(view.$().text(), 'ZOIDBERG', "helper output is correct"); run['default'](function() { view.set('controller.thing2', "NERD"); }); equal(view.$().text(), 'ZOIDNERD', "helper correctly re-rendered after second bound helper property changed"); run['default'](function() { view.get('controller').setProperties({ thing1: "WOOT", thing2: "YEAH" }); }); equal(view.$().text(), 'WOOTYEAH', "helper correctly re-rendered after both bound helper properties changed"); }); QUnit.test("bound helpers should expose property names in options.data.properties", function() { expectDeprecationInHTMLBars(); helper('echo', function() { var options = arguments[arguments.length - 1]; var values = [].slice.call(arguments, 0, -1); var a = []; for (var i = 0; i < values.length; ++i) { var propertyName = options.data.properties[i]; a.push(propertyName); } return a.join(' '); }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ thing1: 'ZOID', thing2: 'BERG', thing3: EmberObject['default'].create({ foo: 123 }) }), template: compile('{{echo thing1 thing2 thing3.foo}}') }); utils.runAppend(view); equal(view.$().text(), 'thing1 thing2 thing3.foo', "helper output is correct"); }); QUnit.test("bound helpers can be invoked with zero args", function() { expectDeprecationInHTMLBars(); helper('troll', function(options) { return options.hash.text || "TROLOLOL"; }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ trollText: "yumad" }), template: compile('{{troll}} and {{troll text="bork"}}') }); utils.runAppend(view); equal(view.$().text(), 'TROLOLOL and bork', "helper output is correct"); }); QUnit.test("bound helpers should not be invoked with blocks", function() { registerRepeatHelper(); view = EmberView['default'].create({ controller: EmberObject['default'].create({}), template: compile("{{#repeat}}Sorry, Charlie{{/repeat}}") }); expectAssertion(function() { utils.runAppend(view); }, /registerBoundHelper-generated helpers do not support use with Handlebars blocks/i); }); QUnit.test("should observe dependent keys passed to registerBoundHelper", function() { try { expectDeprecationInHTMLBars(); var simplyObject = EmberObject['default'].create({ firstName: 'Jim', lastName: 'Owen', birthday: EmberObject['default'].create({ year: '2009' }) }); helper('fullName', function(value) { return [ value.get('firstName'), value.get('lastName'), value.get('birthday.year') ].join(' '); }, 'firstName', 'lastName', 'birthday.year'); view = EmberView['default'].create({ template: compile('{{fullName this}}'), context: simplyObject }); utils.runAppend(view); equal(view.$().text(), 'Jim Owen 2009', 'simply render the helper'); run['default'](simplyObject, simplyObject.set, 'firstName', 'Tom'); equal(view.$().text(), 'Tom Owen 2009', 'render the helper after prop change'); run['default'](simplyObject, simplyObject.set, 'birthday.year', '1692'); equal(view.$().text(), 'Tom Owen 1692', 'render the helper after path change'); } finally { delete helpers['fullName']; } }); QUnit.test("shouldn't treat raw numbers as bound paths", function() { expectDeprecationInHTMLBars(); helper('sum', function(a, b) { return a + b; }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ aNumber: 1 }), template: compile("{{sum aNumber 1}} {{sum 0 aNumber}} {{sum 5 6}}") }); utils.runAppend(view); equal(view.$().text(), '2 1 11', "helper output is correct"); run['default'](view, 'set', 'controller.aNumber', 5); equal(view.$().text(), '6 5 11', "helper still updates as expected"); }); QUnit.test("shouldn't treat quoted strings as bound paths", function() { expectDeprecationInHTMLBars(); var helperCount = 0; helper('combine', function(a, b, opt) { helperCount++; return a + b; }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ word: "jerkwater", loo: "unused" }), template: compile("{{combine word 'loo'}} {{combine '' word}} {{combine 'will' \"didi\"}}") }); utils.runAppend(view); equal(view.$().text(), 'jerkwaterloo jerkwater willdidi', "helper output is correct"); run['default'](view, 'set', 'controller.word', 'bird'); equal(view.$().text(), 'birdloo bird willdidi', "helper still updates as expected"); run['default'](view, 'set', 'controller.loo', 'soup-de-doo'); equal(view.$().text(), 'birdloo bird willdidi', "helper still updates as expected"); equal(helperCount, 5, "changing controller property with same name as quoted string doesn't re-render helper"); }); QUnit.test("bound helpers can handle nulls in array (with primitives) [DEPRECATED]", function() { expectDeprecationInHTMLBars(); helper('reverse', function(val) { return val ? val.split('').reverse().join('') : "NOPE"; }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ things: native_array.A([null, 0, undefined, false, "OMG"]) }), template: compile("{{#each things}}{{this}}|{{reverse this}} {{/each}}{{#each thing in things}}{{thing}}|{{reverse thing}} {{/each}}") }); expectDeprecation(function() { utils.runAppend(view); }, 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); equal(view.$().text(), '|NOPE 0|NOPE |NOPE false|NOPE OMG|GMO |NOPE 0|NOPE |NOPE false|NOPE OMG|GMO ', "helper output is correct"); run['default'](function() { view.get('controller.things').pushObject('blorg'); view.get('controller.things').shiftObject(); }); equal(view.$().text(), '0|NOPE |NOPE false|NOPE OMG|GMO blorg|grolb 0|NOPE |NOPE false|NOPE OMG|GMO blorg|grolb ', "helper output is still correct"); }); QUnit.test("bound helpers can handle nulls in array (with objects)", function() { expectDeprecationInHTMLBars(); helper('print-foo', function(val) { return val ? property_get.get(val, 'foo') : "NOPE"; }); view = EmberView['default'].create({ controller: EmberObject['default'].create({ things: native_array.A([null, { foo: 5 }]) }), template: compile("{{#each things}}{{foo}}|{{print-foo this}} {{/each}}{{#each thing in things}}{{thing.foo}}|{{print-foo thing}} {{/each}}") }); expectDeprecation(function() { utils.runAppend(view); }, 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); equal(view.$().text(), '|NOPE 5|5 |NOPE 5|5 ', "helper output is correct"); run['default'](view.get('controller.things'), 'pushObject', { foo: 6 }); equal(view.$().text(), '|NOPE 5|5 6|6 |NOPE 5|5 6|6 ', "helper output is correct"); }); QUnit.test("bound helpers can handle `this` keyword when it's a non-object", function() { expectDeprecationInHTMLBars(); helper("shout", function(value) { return value + '!'; }); view = EmberView['default'].create({ context: 'alex', template: compile("{{shout this}}") }); utils.runAppend(view); equal(view.$().text(), 'alex!', "helper output is correct"); run['default'](function() { property_set.set(view, 'context', ''); }); equal(view.$().text(), '!', "helper output is correct"); run['default'](function() { property_set.set(view, 'context', 'wallace'); }); equal(view.$().text(), 'wallace!', "helper output is correct"); }); QUnit.test("should have correct argument types", function() { expectDeprecationInHTMLBars(); helper('getType', function(value) { return typeof value; }); view = EmberView['default'].create({ controller: EmberObject['default'].create(), template: compile('{{getType null}}, {{getType undefProp}}, {{getType "string"}}, {{getType 1}}, {{getType}}') }); utils.runAppend(view); equal(view.$().text(), 'undefined, undefined, string, number, object', "helper output is correct"); }); QUnit.test("when no parameters are bound, no new views are created", function() { registerRepeatHelper(); var originalRender = SimpleBoundView['default'].prototype.render; var renderWasCalled = false; SimpleBoundView['default'].prototype.render = function() { renderWasCalled = true; return originalRender.apply(this, arguments); }; try { view = EmberView['default'].create({ template: compile('{{repeat "a"}}'), controller: EmberObject['default'].create() }); utils.runAppend(view); } finally { SimpleBoundView['default'].prototype.render = originalRender; } ok(!renderWasCalled, 'simple bound view should not have been created and rendered'); equal(view.$().text(), 'a'); }); QUnit.test('when no hash parameters are bound, no new views are created', function() { registerRepeatHelper(); var originalRender = SimpleBoundView['default'].prototype.render; var renderWasCalled = false; SimpleBoundView['default'].prototype.render = function() { renderWasCalled = true; return originalRender.apply(this, arguments); }; try { view = EmberView['default'].create({ template: compile('{{repeat "a" count=3}}'), controller: EmberObject['default'].create() }); utils.runAppend(view); } finally { SimpleBoundView['default'].prototype.render = originalRender; } ok(!renderWasCalled, 'simple bound view should not have been created and rendered'); equal(view.$().text(), 'aaa'); }); }); enifed('ember-htmlbars/tests/compat/make_bound_helper_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/make_bound_helper_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/compat/make_bound_helper_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/compat/make_bound_helper_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/make_bound_helper_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/compat/make_bound_helper_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/compat/precompile_test', ['ember-htmlbars/compat'], function (EmberHandlebars) { 'use strict'; var precompile = EmberHandlebars['default'].precompile; var template = 'Hello World'; var result; QUnit.module("ember-htmlbars: Ember.Handlebars.precompile"); QUnit.test("precompile creates an object when asObject isn't defined", function() { result = precompile(template); equal(typeof(result), "object"); }); QUnit.test("precompile creates an object when asObject is true", function() { result = precompile(template, true); equal(typeof(result), "object"); }); QUnit.test("precompile creates a string when asObject is false", function() { result = precompile(template, false); equal(typeof(result), "string"); }); }); enifed('ember-htmlbars/tests/compat/precompile_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/precompile_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/compat/precompile_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/compat/precompile_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/compat'); test('ember-htmlbars/tests/compat/precompile_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/compat/precompile_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/helpers/bind_attr_test', ['ember-metal/core', 'ember-metal/run_loop', 'ember-runtime/system/namespace', 'ember-views/views/view', 'ember-views/views/metamorph_view', 'ember-runtime/system/object', 'ember-runtime/system/native_array', 'ember-metal/computed', 'ember-metal/observer', 'ember-runtime/system/container', 'ember-metal/property_set', 'ember-runtime/tests/utils', 'ember-htmlbars/helpers', 'ember-template-compiler/system/compile'], function (Ember, run, Namespace, EmberView, _MetamorphView, EmberObject, native_array, computed, observer, system__container, property_set, utils, helpers, compile) { 'use strict'; /*jshint newcap:false*/ var view; var originalLookup = Ember['default'].lookup; var TemplateTests, registry, container, lookup; /** This module specifically tests integration with Handlebars and Ember-specific Handlebars extensions. If you add additional template support to View, you should create a new file in which to test. */ QUnit.module("ember-htmlbars: {{bind-attr}}", { setup: function() { Ember['default'].lookup = lookup = {}; lookup.TemplateTests = TemplateTests = Namespace['default'].create(); registry = new system__container.Registry(); container = registry.container(); registry.optionsForType('template', { instantiate: false }); registry.register('view:default', _MetamorphView['default']); registry.register('view:toplevel', EmberView['default'].extend()); }, teardown: function() { utils.runDestroy(container); utils.runDestroy(view); registry = container = view = null; Ember['default'].lookup = lookup = originalLookup; TemplateTests = null; } }); QUnit.test("should be able to bind element attributes using {{bind-attr}}", function() { var template = compile['default']('view.content.title}}'); view = EmberView['default'].create({ template: template, content: EmberObject['default'].create({ url: "http://www.emberjs.com/assets/images/logo.png", title: "The SproutCore Logo" }) }); utils.runAppend(view); equal(view.$('img').attr('src'), "http://www.emberjs.com/assets/images/logo.png", "sets src attribute"); equal(view.$('img').attr('alt'), "The SproutCore Logo", "sets alt attribute"); run['default'](function() { property_set.set(view, 'content.title', "El logo de Eember"); }); equal(view.$('img').attr('alt'), "El logo de Eember", "updates alt attribute when content's title attribute changes"); run['default'](function() { property_set.set(view, 'content', EmberObject['default'].create({ url: "http://www.thegooglez.com/theydonnothing", title: "I CAN HAZ SEARCH" })); }); equal(view.$('img').attr('alt'), "I CAN HAZ SEARCH", "updates alt attribute when content object changes"); run['default'](function() { property_set.set(view, 'content', { url: "http://www.emberjs.com/assets/images/logo.png", title: "The SproutCore Logo" }); }); equal(view.$('img').attr('alt'), "The SproutCore Logo", "updates alt attribute when content object is a hash"); run['default'](function() { property_set.set(view, 'content', EmberObject['default'].createWithMixins({ url: "http://www.emberjs.com/assets/images/logo.png", title: computed.computed(function() { return "Nanananana Ember!"; }) })); }); equal(view.$('img').attr('alt'), "Nanananana Ember!", "updates alt attribute when title property is computed"); }); QUnit.test("should be able to bind to view attributes with {{bind-attr}}", function() { view = EmberView['default'].create({ value: 'Test', template: compile['default']('view.value}}') }); utils.runAppend(view); equal(view.$('img').attr('alt'), "Test", "renders initial value"); run['default'](function() { view.set('value', 'Updated'); }); equal(view.$('img').attr('alt'), "Updated", "updates value"); }); QUnit.test("should be able to bind to globals with {{bind-attr}} (DEPRECATED)", function() { TemplateTests.set('value', 'Test'); view = EmberView['default'].create({ template: compile['default']('TemplateTests.value}}') }); expectDeprecation(function() { utils.runAppend(view); }, /Global lookup of TemplateTests.value from a Handlebars template is deprecated/); equal(view.$('img').attr('alt'), "Test", "renders initial value"); }); QUnit.test("should not allow XSS injection via {{bind-attr}}", function() { view = EmberView['default'].create({ template: compile['default']('view.content.value}}'), content: { value: 'Trololol" onmouseover="alert(\'HAX!\');' } }); utils.runAppend(view); equal(view.$('img').attr('onmouseover'), undefined); // If the whole string is here, then it means we got properly escaped equal(view.$('img').attr('alt'), 'Trololol" onmouseover="alert(\'HAX!\');'); }); QUnit.test("should be able to bind use {{bind-attr}} more than once on an element", function() { var template = compile['default']('view.content.title}}'); view = EmberView['default'].create({ template: template, content: EmberObject['default'].create({ url: "http://www.emberjs.com/assets/images/logo.png", title: "The SproutCore Logo" }) }); utils.runAppend(view); equal(view.$('img').attr('src'), "http://www.emberjs.com/assets/images/logo.png", "sets src attribute"); equal(view.$('img').attr('alt'), "The SproutCore Logo", "sets alt attribute"); run['default'](function() { property_set.set(view, 'content.title', "El logo de Eember"); }); equal(view.$('img').attr('alt'), "El logo de Eember", "updates alt attribute when content's title attribute changes"); run['default'](function() { property_set.set(view, 'content', EmberObject['default'].create({ url: "http://www.thegooglez.com/theydonnothing", title: "I CAN HAZ SEARCH" })); }); equal(view.$('img').attr('alt'), "I CAN HAZ SEARCH", "updates alt attribute when content object changes"); run['default'](function() { property_set.set(view, 'content', { url: "http://www.emberjs.com/assets/images/logo.png", title: "The SproutCore Logo" }); }); equal(view.$('img').attr('alt'), "The SproutCore Logo", "updates alt attribute when content object is a hash"); run['default'](function() { property_set.set(view, 'content', EmberObject['default'].createWithMixins({ url: "http://www.emberjs.com/assets/images/logo.png", title: computed.computed(function() { return "Nanananana Ember!"; }) })); }); equal(view.$('img').attr('alt'), "Nanananana Ember!", "updates alt attribute when title property is computed"); }); QUnit.test("{{bindAttr}} is aliased to {{bind-attr}}", function() { expect(4); var originalBindAttr = helpers['default']['bind-attr']; try { helpers['default']['bind-attr'] = { helperFunction: function() { equal(arguments[0], 'foo', 'First arg match'); equal(arguments[1], 'bar', 'Second arg match'); return 'result'; } }; expectDeprecation(function() { var result; result = helpers['default'].bindAttr.helperFunction('foo', 'bar'); equal(result, 'result', 'Result match'); }, "The 'bindAttr' view helper is deprecated in favor of 'bind-attr'"); } finally { helpers['default']['bind-attr'] = originalBindAttr; } }); QUnit.test("{{bindAttr}} can be used to bind attributes [DEPRECATED]", function() { expect(3); view = EmberView['default'].create({ value: 'Test', template: compile['default']('view.value}}') }); expectDeprecation(function() { utils.runAppend(view); }, /The 'bindAttr' view helper is deprecated in favor of 'bind-attr'/); equal(view.$('img').attr('alt'), "Test", "renders initial value"); run['default'](function() { view.set('value', 'Updated'); }); equal(view.$('img').attr('alt'), "Updated", "updates value"); }); QUnit.test("should be able to bind element attributes using {{bind-attr}} inside a block", function() { var template = compile['default']('{{#with view.content as image}}image.title}}{{/with}}'); view = EmberView['default'].create({ template: template, content: EmberObject['default'].create({ url: "http://www.emberjs.com/assets/images/logo.png", title: "The SproutCore Logo" }) }); utils.runAppend(view); equal(view.$('img').attr('src'), "http://www.emberjs.com/assets/images/logo.png", "sets src attribute"); equal(view.$('img').attr('alt'), "The SproutCore Logo", "sets alt attribute"); run['default'](function() { property_set.set(view, 'content.title', "El logo de Eember"); }); equal(view.$('img').attr('alt'), "El logo de Eember", "updates alt attribute when content's title attribute changes"); }); QUnit.test("should be able to bind class attribute with {{bind-attr}}", function() { var template = compile['default'](''); view = EmberView['default'].create({ template: template, foo: 'bar' }); utils.runAppend(view); equal(view.element.firstChild.className, 'bar', 'renders class'); run['default'](function() { property_set.set(view, 'foo', 'baz'); }); equal(view.element.firstChild.className, 'baz', 'updates rendered class'); }); QUnit.test("should be able to bind unquoted class attribute with {{bind-attr}}", function() { var template = compile['default'](''); view = EmberView['default'].create({ template: template, foo: 'bar' }); utils.runAppend(view); equal(view.$('img').attr('class'), 'bar', "renders class"); run['default'](function() { property_set.set(view, 'foo', 'baz'); }); equal(view.$('img').attr('class'), 'baz', "updates class"); }); QUnit.test("should be able to bind class attribute via a truthy property with {{bind-attr}}", function() { var template = compile['default'](''); view = EmberView['default'].create({ template: template, isNumber: 5 }); utils.runAppend(view); equal(view.element.firstChild.className, 'is-truthy', 'renders class'); run['default'](function() { property_set.set(view, 'isNumber', 0); }); ok(view.element.firstChild.className !== 'is-truthy', 'removes class'); }); QUnit.test("should be able to bind class to view attribute with {{bind-attr}}", function() { var template = compile['default'](''); view = EmberView['default'].create({ template: template, foo: 'bar' }); utils.runAppend(view); equal(view.$('img').attr('class'), 'bar', "renders class"); run['default'](function() { property_set.set(view, 'foo', 'baz'); }); equal(view.$('img').attr('class'), 'baz', "updates class"); }); QUnit.test("should not allow XSS injection via {{bind-attr}} with class", function() { view = EmberView['default'].create({ template: compile['default'](''), foo: '" onmouseover="alert(\'I am in your classes hacking your app\');' }); try { utils.runAppend(view); } catch (e) { } equal(view.$('img').attr('onmouseover'), undefined); }); QUnit.test("should be able to bind class attribute using ternary operator in {{bind-attr}}", function() { var template = compile['default'](''); var content = EmberObject['default'].create({ isDisabled: true }); view = EmberView['default'].create({ template: template, content: content }); utils.runAppend(view); ok(view.$('img').hasClass('disabled'), 'disabled class is rendered'); ok(!view.$('img').hasClass('enabled'), 'enabled class is not rendered'); run['default'](function() { property_set.set(content, 'isDisabled', false); }); ok(!view.$('img').hasClass('disabled'), 'disabled class is not rendered'); ok(view.$('img').hasClass('enabled'), 'enabled class is rendered'); }); QUnit.test("should be able to add multiple classes using {{bind-attr class}}", function() { var template = compile['default']('
'); var content = EmberObject['default'].create({ isAwesomeSauce: true, isAlsoCool: true, isAmazing: true, isEnabled: true }); view = EmberView['default'].create({ template: template, content: content }); utils.runAppend(view); ok(view.$('div').hasClass('is-awesome-sauce'), "dasherizes first property and sets classname"); ok(view.$('div').hasClass('is-also-cool'), "dasherizes second property and sets classname"); ok(view.$('div').hasClass('amazing'), "uses alias for third property and sets classname"); ok(view.$('div').hasClass('is-super-duper'), "static class is present"); ok(view.$('div').hasClass('enabled'), "truthy class in ternary classname definition is rendered"); ok(!view.$('div').hasClass('disabled'), "falsy class in ternary classname definition is not rendered"); run['default'](function() { property_set.set(content, 'isAwesomeSauce', false); property_set.set(content, 'isAmazing', false); property_set.set(content, 'isEnabled', false); }); ok(!view.$('div').hasClass('is-awesome-sauce'), "removes dasherized class when property is set to false"); ok(!view.$('div').hasClass('amazing'), "removes aliased class when property is set to false"); ok(view.$('div').hasClass('is-super-duper'), "static class is still present"); ok(!view.$('div').hasClass('enabled'), "truthy class in ternary classname definition is not rendered"); ok(view.$('div').hasClass('disabled'), "falsy class in ternary classname definition is rendered"); }); QUnit.test("should be able to bind classes to globals with {{bind-attr class}} (DEPRECATED)", function() { TemplateTests.set('isOpen', true); view = EmberView['default'].create({ template: compile['default']('') }); expectDeprecation(function() { utils.runAppend(view); }, /Global lookup of TemplateTests.isOpen from a Handlebars template is deprecated/); ok(view.$('img').hasClass('is-open'), "sets classname to the dasherized value of the global property"); }); QUnit.test("should be able to bind-attr to 'this' in an {{#each}} block [DEPRECATED]", function() { expectDeprecation('Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); view = EmberView['default'].create({ template: compile['default']('{{#each view.images}}{{/each}}'), images: native_array.A(['one.png', 'two.jpg', 'three.gif']) }); utils.runAppend(view); var images = view.$('img'); ok(/one\.png$/.test(images[0].src)); ok(/two\.jpg$/.test(images[1].src)); ok(/three\.gif$/.test(images[2].src)); }); QUnit.test("should be able to bind classes to 'this' in an {{#each}} block with {{bind-attr class}} [DEPRECATED]", function() { expectDeprecation('Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); view = EmberView['default'].create({ template: compile['default']('{{#each view.items}}
  • Item
  • {{/each}}'), items: native_array.A(['a', 'b', 'c']) }); utils.runAppend(view); ok(view.$('li').eq(0).hasClass('a'), "sets classname to the value of the first item"); ok(view.$('li').eq(1).hasClass('b'), "sets classname to the value of the second item"); ok(view.$('li').eq(2).hasClass('c'), "sets classname to the value of the third item"); }); QUnit.test("should be able to bind-attr to var in {{#each var in list}} block", function() { view = EmberView['default'].create({ template: compile['default']('{{#each image in view.images}}{{/each}}'), images: native_array.A(['one.png', 'two.jpg', 'three.gif']) }); utils.runAppend(view); var images = view.$('img'); ok(/one\.png$/.test(images[0].src)); ok(/two\.jpg$/.test(images[1].src)); ok(/three\.gif$/.test(images[2].src)); run['default'](function() { var imagesArray = view.get('images'); imagesArray.removeAt(0); }); images = view.$('img'); ok(images.length === 2, ""); ok(/two\.jpg$/.test(images[0].src)); ok(/three\.gif$/.test(images[1].src)); }); QUnit.test("should teardown observers from bind-attr on rerender", function() { view = EmberView['default'].create({ template: compile['default']('wat'), foo: 'bar' }); utils.runAppend(view); equal(observer.observersFor(view, 'foo').length, 1); run['default'](function() { view.rerender(); }); equal(observer.observersFor(view, 'foo').length, 1); }); QUnit.test("should keep class in the order it appears in", function() { view = EmberView['default'].create({ template: compile['default']('') }); utils.runAppend(view); equal(view.element.firstChild.className, 'foo baz', 'classes are in expected order'); }); QUnit.test('should allow either quoted or unquoted values', function() { view = EmberView['default'].create({ value: 'Test', source: 'test.jpg', template: compile['default']('view.value') }); utils.runAppend(view); equal(view.$('img').attr('alt'), "Test", "renders initial value"); equal(view.$('img').attr('src'), "test.jpg", "renders initial value"); run['default'](function() { view.set('value', 'Updated'); view.set('source', 'test2.jpg'); }); equal(view.$('img').attr('alt'), "Updated", "updates value"); equal(view.$('img').attr('src'), "test2.jpg", "updates value"); }); QUnit.test("property before didInsertElement", function() { var matchingElement; view = EmberView['default'].create({ name: 'bob', template: compile['default']('
    '), didInsertElement: function() { matchingElement = this.$('div[alt=bob]'); } }); utils.runAppend(view); equal(matchingElement.length, 1, 'element is in the DOM when didInsertElement'); }); QUnit.test("asserts for
    ", function() { var template = compile['default']('
    '); view = EmberView['default'].create({ template: template, foo: 'bar' }); expectAssertion(function() { utils.runAppend(view); }, /You cannot set `class` manually and via `{{bind-attr}}` helper on the same element/); }); QUnit.test("asserts for
    ", function() { var template = compile['default']('
    '); view = EmberView['default'].create({ template: template, blah: 'bar' }); expectAssertion(function() { utils.runAppend(view); }, /You cannot set `data-bar` manually and via `{{bind-attr}}` helper on the same element/); }); QUnit.test("src attribute bound to undefined is not present", function() { var template = compile['default'](""); view = EmberView['default'].create({ template: template, undefinedValue: undefined }); utils.runAppend(view); ok(!view.element.hasAttribute('src'), "src attribute not present"); }); QUnit.test("src attribute bound to null is not present", function() { var template = compile['default'](""); view = EmberView['default'].create({ template: template, nullValue: null }); utils.runAppend(view); ok(!view.element.hasAttribute('src'), "src attribute not present"); }); }); enifed('ember-htmlbars/tests/helpers/bind_attr_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/bind_attr_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/helpers/bind_attr_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/helpers/bind_attr_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/bind_attr_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/helpers/bind_attr_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/helpers/collection_test', ['ember-views/views/collection_view', 'ember-runtime/system/object', 'ember-views/views/view', 'ember-runtime/system/array_proxy', 'ember-runtime/system/namespace', 'ember-runtime/system/container', 'ember-runtime/system/native_array', 'ember-metal/run_loop', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-views/system/jquery', 'ember-metal/computed', 'ember-runtime/tests/utils', 'ember-template-compiler/system/compile'], function (CollectionView, EmberObject, EmberView, ArrayProxy, Namespace, system__container, native_array, run, property_get, property_set, jQuery, computed, utils, compile) { 'use strict'; /*jshint newcap:false*/ var trim = jQuery['default'].trim; var view; var originalLookup = Ember.lookup; var TemplateTests, registry, container, lookup; function nthChild(view, nth) { return property_get.get(view, 'childViews').objectAt(nth || 0); } var firstChild = nthChild; function firstGrandchild(view) { return property_get.get(property_get.get(view, 'childViews').objectAt(0), 'childViews').objectAt(0); } QUnit.module("collection helper", { setup: function() { Ember.lookup = lookup = {}; lookup.TemplateTests = TemplateTests = Namespace['default'].create(); registry = new system__container.Registry(); container = registry.container(); registry.optionsForType('template', { instantiate: false }); // registry.register('view:default', _MetamorphView); registry.register('view:toplevel', EmberView['default'].extend()); }, teardown: function() { utils.runDestroy(container); utils.runDestroy(view); registry = container = view = null; Ember.lookup = lookup = originalLookup; TemplateTests = null; } }); QUnit.test("Collection views that specify an example view class have their children be of that class", function() { var ExampleViewCollection = CollectionView['default'].extend({ itemViewClass: EmberView['default'].extend({ isCustom: true }), content: native_array.A(['foo']) }); view = EmberView['default'].create({ exampleViewCollection: ExampleViewCollection, template: compile['default']('{{#collection view.exampleViewCollection}}OHAI{{/collection}}') }); utils.runAppend(view); ok(firstGrandchild(view).isCustom, "uses the example view class"); }); QUnit.test("itemViewClass works in the #collection helper with a global (DEPRECATED)", function() { TemplateTests.ExampleItemView = EmberView['default'].extend({ isAlsoCustom: true }); view = EmberView['default'].create({ exampleController: ArrayProxy['default'].create({ content: native_array.A(['alpha']) }), template: compile['default']('{{#collection content=view.exampleController itemViewClass=TemplateTests.ExampleItemView}}beta{{/collection}}') }); var deprecation = /Global lookup of TemplateTests.ExampleItemView from a Handlebars template is deprecated/; expectDeprecation(function() { utils.runAppend(view); }, deprecation); ok(firstGrandchild(view).isAlsoCustom, "uses the example view class specified in the #collection helper"); }); QUnit.test("itemViewClass works in the #collection helper with a property", function() { var ExampleItemView = EmberView['default'].extend({ isAlsoCustom: true }); var ExampleCollectionView = CollectionView['default']; view = EmberView['default'].create({ possibleItemView: ExampleItemView, exampleCollectionView: ExampleCollectionView, exampleController: ArrayProxy['default'].create({ content: native_array.A(['alpha']) }), template: compile['default']('{{#collection view.exampleCollectionView content=view.exampleController itemViewClass=view.possibleItemView}}beta{{/collection}}') }); utils.runAppend(view); ok(firstGrandchild(view).isAlsoCustom, "uses the example view class specified in the #collection helper"); }); QUnit.test("itemViewClass works in the #collection via container", function() { registry.register('view:example-item', EmberView['default'].extend({ isAlsoCustom: true })); view = EmberView['default'].create({ container: container, exampleCollectionView: CollectionView['default'].extend(), exampleController: ArrayProxy['default'].create({ content: native_array.A(['alpha']) }), template: compile['default']('{{#collection view.exampleCollectionView content=view.exampleController itemViewClass="example-item"}}beta{{/collection}}') }); utils.runAppend(view); ok(firstGrandchild(view).isAlsoCustom, "uses the example view class specified in the #collection helper"); }); QUnit.test("passing a block to the collection helper sets it as the template for example views", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView}} {{/collection}}') }); utils.runAppend(view); equal(view.$('label').length, 3, 'one label element is created for each content item'); }); QUnit.test("collection helper should try to use container to resolve view", function() { var registry = new system__container.Registry(); var container = registry.container(); var ACollectionView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); registry.register('view:collectionTest', ACollectionView); var controller = { container: container }; view = EmberView['default'].create({ controller: controller, template: compile['default']('{{#collection "collectionTest"}} {{/collection}}') }); utils.runAppend(view); equal(view.$('label').length, 3, 'one label element is created for each content item'); }); QUnit.test("collection helper should accept relative paths", function() { view = EmberView['default'].create({ template: compile['default']('{{#collection view.collection}} {{/collection}}'), collection: CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }) }); utils.runAppend(view); equal(view.$('label').length, 3, 'one label element is created for each content item'); }); QUnit.test("empty views should be removed when content is added to the collection (regression, ht: msofaer)", function() { var EmptyView = EmberView['default'].extend({ template : compile['default']("No Rows Yet") }); var ListView = CollectionView['default'].extend({ emptyView: EmptyView }); var listController = ArrayProxy['default'].create({ content : native_array.A() }); view = EmberView['default'].create({ listView: ListView, listController: listController, template: compile['default']('{{#collection view.listView content=view.listController tagName="table"}} {{view.content.title}} {{/collection}}') }); utils.runAppend(view); equal(view.$('tr').length, 1, 'Make sure the empty view is there (regression)'); run['default'](function() { listController.pushObject({ title : "Go Away, Placeholder Row!" }); }); equal(view.$('tr').length, 1, 'has one row'); equal(view.$('tr:nth-child(1) td').text(), 'Go Away, Placeholder Row!', 'The content is the updated data.'); }); QUnit.test("should be able to specify which class should be used for the empty view", function() { var App; run['default'](function() { lookup.App = App = Namespace['default'].create(); }); var EmptyView = EmberView['default'].extend({ template: compile['default']('This is an empty view') }); view = EmberView['default'].create({ container: { lookupFactory: function() { return EmptyView; } }, template: compile['default']('{{collection emptyViewClass="empty-view"}}') }); utils.runAppend(view); equal(view.$().text(), 'This is an empty view', "Empty view should be rendered."); utils.runDestroy(App); }); QUnit.test("if no content is passed, and no 'else' is specified, nothing is rendered", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A() }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView}} {{/collection}}') }); utils.runAppend(view); equal(view.$('li').length, 0, 'if no "else" is specified, nothing is rendered'); }); QUnit.test("if no content is passed, and 'else' is specified, the else block is rendered", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A() }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView}} {{ else }} {{/collection}}') }); utils.runAppend(view); equal(view.$('li:has(del)').length, 1, 'the else block is rendered'); }); QUnit.test("a block passed to a collection helper defaults to the content property of the context", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView}} {{/collection}}') }); utils.runAppend(view); equal(view.$('li:nth-child(1) label').length, 1); equal(view.$('li:nth-child(1) label').text(), 'foo'); equal(view.$('li:nth-child(2) label').length, 1); equal(view.$('li:nth-child(2) label').text(), 'bar'); equal(view.$('li:nth-child(3) label').length, 1); equal(view.$('li:nth-child(3) label').text(), 'baz'); }); QUnit.test("a block passed to a collection helper defaults to the view", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView}} {{/collection}}') }); utils.runAppend(view); // Preconds equal(view.$('li:nth-child(1) label').length, 1); equal(view.$('li:nth-child(1) label').text(), 'foo'); equal(view.$('li:nth-child(2) label').length, 1); equal(view.$('li:nth-child(2) label').text(), 'bar'); equal(view.$('li:nth-child(3) label').length, 1); equal(view.$('li:nth-child(3) label').text(), 'baz'); run['default'](function() { property_set.set(firstChild(view), 'content', native_array.A()); }); equal(view.$('label').length, 0, "all list item views should be removed from DOM"); }); QUnit.test("should include an id attribute if id is set in the options hash", function() { var CollectionTestView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); view = EmberView['default'].create({ collectionTestView: CollectionTestView, template: compile['default']('{{#collection view.collectionTestView id="baz"}}foo{{/collection}}') }); utils.runAppend(view); equal(view.$('ul#baz').length, 1, "adds an id attribute"); }); QUnit.test("should give its item views the class specified by itemClass", function() { var ItemClassTestCollectionView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo', 'bar', 'baz']) }); view = EmberView['default'].create({ itemClassTestCollectionView: ItemClassTestCollectionView, template: compile['default']('{{#collection view.itemClassTestCollectionView itemClass="baz"}}foo{{/collection}}') }); utils.runAppend(view); equal(view.$('ul li.baz').length, 3, "adds class attribute"); }); QUnit.test("should give its item views the classBinding specified by itemClassBinding", function() { var ItemClassBindingTestCollectionView = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A([EmberObject['default'].create({ isBaz: false }), EmberObject['default'].create({ isBaz: true }), EmberObject['default'].create({ isBaz: true })]) }); view = EmberView['default'].create({ itemClassBindingTestCollectionView: ItemClassBindingTestCollectionView, isBar: true, template: compile['default']('{{#collection view.itemClassBindingTestCollectionView itemClassBinding="view.isBar"}}foo{{/collection}}') }); utils.runAppend(view); equal(view.$('ul li.is-bar').length, 3, "adds class on initial rendering"); // NOTE: in order to bind an item's class to a property of the item itself (e.g. `isBaz` above), it will be necessary // to introduce a new keyword that could be used from within `itemClassBinding`. For instance, `itemClassBinding="item.isBaz"`. }); QUnit.test("should give its item views the property specified by itemPropertyBinding", function() { var ItemPropertyBindingTestItemView = EmberView['default'].extend({ tagName: 'li' }); // Use preserveContext=false so the itemView handlebars context is the view context // Set itemView bindings using item* view = EmberView['default'].create({ baz: "baz", content: native_array.A([EmberObject['default'].create(), EmberObject['default'].create(), EmberObject['default'].create()]), container: { lookupFactory: function() { return ItemPropertyBindingTestItemView; } }, template: compile['default']('{{#collection contentBinding="view.content" tagName="ul" itemViewClass="item-property-binding-test-item-view" itemPropertyBinding="view.baz" preserveContext=false}}{{view.property}}{{/collection}}') }); utils.runAppend(view); equal(view.$('ul li').length, 3, "adds 3 itemView"); view.$('ul li').each(function(i, li) { equal(jQuery['default'](li).text(), "baz", "creates the li with the property = baz"); }); run['default'](function() { property_set.set(view, 'baz', "yobaz"); }); equal(view.$('ul li:first').text(), "yobaz", "change property of sub view"); }); QUnit.test("should unsubscribe stream bindings", function() { view = EmberView['default'].create({ baz: "baz", content: native_array.A([EmberObject['default'].create(), EmberObject['default'].create(), EmberObject['default'].create()]), template: compile['default']('{{#collection contentBinding="view.content" itemPropertyBinding="view.baz"}}{{view.property}}{{/collection}}') }); utils.runAppend(view); var barStreamBinding = view._streamBindings['view.baz']; equal(barStreamBinding.subscribers.length, 3*2, "adds 3 subscribers"); run['default'](function() { view.get('content').popObject(); }); equal(barStreamBinding.subscribers.length, 2*2, "removes 1 subscriber"); }); QUnit.test("should work inside a bound {{#if}}", function() { var testData = native_array.A([EmberObject['default'].create({ isBaz: false }), EmberObject['default'].create({ isBaz: true }), EmberObject['default'].create({ isBaz: true })]); var IfTestCollectionView = CollectionView['default'].extend({ tagName: 'ul', content: testData }); view = EmberView['default'].create({ ifTestCollectionView: IfTestCollectionView, template: compile['default']('{{#if view.shouldDisplay}}{{#collection view.ifTestCollectionView}}{{content.isBaz}}{{/collection}}{{/if}}'), shouldDisplay: true }); utils.runAppend(view); equal(view.$('ul li').length, 3, "renders collection when conditional is true"); run['default'](function() { property_set.set(view, 'shouldDisplay', false); }); equal(view.$('ul li').length, 0, "removes collection when conditional changes to false"); run['default'](function() { property_set.set(view, 'shouldDisplay', true); }); equal(view.$('ul li').length, 3, "collection renders when conditional changes to true"); }); QUnit.test("should pass content as context when using {{#each}} helper [DEPRECATED]", function() { view = EmberView['default'].create({ template: compile['default']('{{#each view.releases}}Mac OS X {{version}}: {{name}} {{/each}}'), releases: native_array.A([ { version: '10.7', name: 'Lion' }, { version: '10.6', name: 'Snow Leopard' }, { version: '10.5', name: 'Leopard' } ]) }); expectDeprecation(function() { utils.runAppend(view); }, 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); equal(view.$().text(), "Mac OS X 10.7: Lion Mac OS X 10.6: Snow Leopard Mac OS X 10.5: Leopard ", "prints each item in sequence"); }); QUnit.test("should re-render when the content object changes", function() { var RerenderTest = CollectionView['default'].extend({ tagName: 'ul', content: native_array.A() }); view = EmberView['default'].create({ rerenderTestView: RerenderTest, template: compile['default']('{{#collection view.rerenderTestView}}{{view.content}}{{/collection}}') }); utils.runAppend(view); run['default'](function() { property_set.set(firstChild(view), 'content', native_array.A(['bing', 'bat', 'bang'])); }); run['default'](function() { property_set.set(firstChild(view), 'content', native_array.A(['ramalamadingdong'])); }); equal(view.$('li').length, 1, "rerenders with correct number of items"); equal(trim(view.$('li:eq(0)').text()), "ramalamadingdong"); }); QUnit.test("select tagName on collection helper automatically sets child tagName to option", function() { var RerenderTest = CollectionView['default'].extend({ content: native_array.A(['foo']) }); view = EmberView['default'].create({ rerenderTestView: RerenderTest, template: compile['default']('{{#collection view.rerenderTestView tagName="select"}}{{view.content}}{{/collection}}') }); utils.runAppend(view); equal(view.$('option').length, 1, "renders the correct child tag name"); }); QUnit.test("tagName works in the #collection helper", function() { var RerenderTest = CollectionView['default'].extend({ content: native_array.A(['foo', 'bar']) }); view = EmberView['default'].create({ rerenderTestView: RerenderTest, template: compile['default']('{{#collection view.rerenderTestView tagName="ol"}}{{view.content}}{{/collection}}') }); utils.runAppend(view); equal(view.$('ol').length, 1, "renders the correct tag name"); equal(view.$('li').length, 2, "rerenders with correct number of items"); run['default'](function() { property_set.set(firstChild(view), 'content', native_array.A(['bing', 'bat', 'bang'])); }); equal(view.$('li').length, 3, "rerenders with correct number of items"); equal(trim(view.$('li:eq(0)').text()), "bing"); }); QUnit.test("should render nested collections", function() { var registry = new system__container.Registry(); var container = registry.container(); registry.register('view:inner-list', CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['one','two','three']) })); registry.register('view:outer-list', CollectionView['default'].extend({ tagName: 'ul', content: native_array.A(['foo']) })); view = EmberView['default'].create({ container: container, template: compile['default']('{{#collection "outer-list" class="outer"}}{{content}}{{#collection "inner-list" class="inner"}}{{content}}{{/collection}}{{/collection}}') }); utils.runAppend(view); equal(view.$('ul.outer > li').length, 1, "renders the outer list with correct number of items"); equal(view.$('ul.inner').length, 1, "the inner list exsits"); equal(view.$('ul.inner > li').length, 3, "renders the inner list with correct number of items"); }); QUnit.test("should render multiple, bound nested collections (#68)", function() { var view; run['default'](function() { TemplateTests.contentController = ArrayProxy['default'].create({ content: native_array.A(['foo','bar']) }); var InnerList = CollectionView['default'].extend({ tagName: 'ul', contentBinding: 'parentView.innerListContent' }); var OuterListItem = EmberView['default'].extend({ innerListView: InnerList, template: compile['default']('{{#collection view.innerListView class="inner"}}{{content}}{{/collection}}{{content}}'), innerListContent: computed.computed(function() { return native_array.A([1,2,3]); }) }); var OuterList = CollectionView['default'].extend({ tagName: 'ul', contentBinding: 'TemplateTests.contentController', itemViewClass: OuterListItem }); view = EmberView['default'].create({ outerListView: OuterList, template: compile['default']('{{collection view.outerListView class="outer"}}') }); }); utils.runAppend(view); equal(view.$('ul.outer > li').length, 2, "renders the outer list with correct number of items"); equal(view.$('ul.inner').length, 2, "renders the correct number of inner lists"); equal(view.$('ul.inner:first > li').length, 3, "renders the first inner list with correct number of items"); equal(view.$('ul.inner:last > li').length, 3, "renders the second list with correct number of items"); utils.runDestroy(view); }); QUnit.test("should allow view objects to be swapped out without throwing an error (#78)", function() { var view, dataset, secondDataset; run['default'](function() { TemplateTests.datasetController = EmberObject['default'].create(); var ExampleCollectionView = CollectionView['default'].extend({ contentBinding: 'parentView.items', tagName: 'ul', template: compile['default']("{{view.content}}") }); var ReportingView = EmberView['default'].extend({ exampleCollectionView: ExampleCollectionView, datasetBinding: 'TemplateTests.datasetController.dataset', readyBinding: 'dataset.ready', itemsBinding: 'dataset.items', template: compile['default']("{{#if view.ready}}{{collection view.exampleCollectionView}}{{else}}Loading{{/if}}") }); view = ReportingView.create(); }); utils.runAppend(view); equal(view.$().text(), "Loading", "renders the loading text when the dataset is not ready"); run['default'](function() { dataset = EmberObject['default'].create({ ready: true, items: native_array.A([1,2,3]) }); TemplateTests.datasetController.set('dataset', dataset); }); equal(view.$('ul > li').length, 3, "renders the collection with the correct number of items when the dataset is ready"); run['default'](function() { secondDataset = EmberObject['default'].create({ ready: false }); TemplateTests.datasetController.set('dataset', secondDataset); }); equal(view.$().text(), "Loading", "renders the loading text when the second dataset is not ready"); utils.runDestroy(view); }); QUnit.test("context should be content", function() { var view; registry = new system__container.Registry(); container = registry.container(); var items = native_array.A([ EmberObject['default'].create({ name: 'Dave' }), EmberObject['default'].create({ name: 'Mary' }), EmberObject['default'].create({ name: 'Sara' }) ]); registry.register('view:an-item', EmberView['default'].extend({ template: compile['default']("Greetings {{name}}") })); view = EmberView['default'].create({ container: container, controller: { items: items }, template: compile['default']('{{collection contentBinding="items" itemViewClass="an-item"}}') }); utils.runAppend(view); equal(view.$().text(), "Greetings DaveGreetings MaryGreetings Sara"); utils.runDestroy(view); }); }); enifed('ember-htmlbars/tests/helpers/collection_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/collection_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/helpers/collection_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/helpers/collection_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/collection_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/helpers/collection_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/helpers/component_test', ['ember-views/component_lookup', 'container/registry', 'ember-views/views/view', 'ember-template-compiler/system/compile', 'ember-runtime/tests/utils'], function (ComponentLookup, Registry, EmberView, compile, utils) { 'use strict'; var set = Ember.set; var get = Ember.get; var view, registry, container; QUnit.module("ember-htmlbars: {{#component}} helper", { setup: function() { registry = new Registry['default'](); container = registry.container(); registry.optionsForType('template', { instantiate: false }); registry.register('component-lookup:main', ComponentLookup['default']); }, teardown: function() { utils.runDestroy(view); utils.runDestroy(container); registry = container = view = null; } }); QUnit.test("component helper with unquoted string is bound", function() { registry.register('template:components/foo-bar', compile['default']('yippie! {{location}} {{yield}}')); registry.register('template:components/baz-qux', compile['default']('yummy {{location}} {{yield}}')); view = EmberView['default'].create({ container: container, dynamicComponent: 'foo-bar', location: 'Caracas', template: compile['default']('{{#component view.dynamicComponent location=view.location}}arepas!{{/component}}') }); utils.runAppend(view); equal(view.$().text(), 'yippie! Caracas arepas!', 'component was looked up and rendered'); Ember.run(function() { set(view, "dynamicComponent", 'baz-qux'); set(view, "location", 'Loisaida'); }); equal(view.$().text(), 'yummy Loisaida arepas!', 'component was updated and re-rendered'); }); QUnit.test("component helper with actions", function() { registry.register('template:components/foo-bar', compile['default']('yippie! {{yield}}')); registry.register('component:foo-bar', Ember.Component.extend({ classNames: 'foo-bar', didInsertElement: function() { // trigger action on click in absence of app's EventDispatcher var self = this; this.$().on('click', function() { self.sendAction('fooBarred'); }); }, willDestroyElement: function() { this.$().off('click'); } })); var actionTriggered = 0; var controller = Ember.Controller.extend({ dynamicComponent: 'foo-bar', actions: { mappedAction: function() { actionTriggered++; } } }).create(); view = EmberView['default'].create({ container: container, controller: controller, template: compile['default']('{{#component dynamicComponent fooBarred="mappedAction"}}arepas!{{/component}}') }); utils.runAppend(view); Ember.run(function() { view.$('.foo-bar').trigger('click'); }); equal(actionTriggered, 1, 'action was triggered'); }); QUnit.test('component helper maintains expected logical parentView', function() { registry.register('template:components/foo-bar', compile['default']('yippie! {{yield}}')); var componentInstance; registry.register('component:foo-bar', Ember.Component.extend({ didInsertElement: function() { componentInstance = this; } })); view = EmberView['default'].create({ container: container, dynamicComponent: 'foo-bar', template: compile['default']('{{#component view.dynamicComponent}}arepas!{{/component}}') }); utils.runAppend(view); equal(get(componentInstance, 'parentView'), view, 'component\'s parentView is the view invoking the helper'); }); QUnit.test("nested component helpers", function() { registry.register('template:components/foo-bar', compile['default']('yippie! {{location}} {{yield}}')); registry.register('template:components/baz-qux', compile['default']('yummy {{location}} {{yield}}')); registry.register('template:components/corge-grault', compile['default']('delicious {{location}} {{yield}}')); view = EmberView['default'].create({ container: container, dynamicComponent1: 'foo-bar', dynamicComponent2: 'baz-qux', location: 'Caracas', template: compile['default']('{{#component view.dynamicComponent1 location=view.location}}{{#component view.dynamicComponent2 location=view.location}}arepas!{{/component}}{{/component}}') }); utils.runAppend(view); equal(view.$().text(), 'yippie! Caracas yummy Caracas arepas!', 'components were looked up and rendered'); Ember.run(function() { set(view, "dynamicComponent1", 'corge-grault'); set(view, "location", 'Loisaida'); }); equal(view.$().text(), 'delicious Loisaida yummy Loisaida arepas!', 'components were updated and re-rendered'); }); QUnit.test("component helper can be used with a quoted string (though you probably would not do this)", function() { registry.register('template:components/foo-bar', compile['default']('yippie! {{location}} {{yield}}')); view = EmberView['default'].create({ container: container, location: 'Caracas', template: compile['default']('{{#component "foo-bar" location=view.location}}arepas!{{/component}}') }); utils.runAppend(view); equal(view.$().text(), 'yippie! Caracas arepas!', 'component was looked up and rendered'); }); QUnit.test("component with unquoted param resolving to non-existent component", function() { view = EmberView['default'].create({ container: container, dynamicComponent: 'does-not-exist', location: 'Caracas', template: compile['default']('{{#component view.dynamicComponent location=view.location}}arepas!{{/component}}') }); throws(function() { utils.runAppend(view); }, /HTMLBars error: Could not find component named "does-not-exist"./); }); QUnit.test("component with quoted param for non-existent component", function() { view = EmberView['default'].create({ container: container, location: 'Caracas', template: compile['default']('{{#component "does-not-exist" location=view.location}}arepas!{{/component}}') }); throws(function() { utils.runAppend(view); }, /HTMLBars error: Could not find component named "does-not-exist"./); }); }); enifed('ember-htmlbars/tests/helpers/component_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/component_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/helpers/component_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/helpers/component_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/component_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/helpers/component_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/helpers/debug_test', ['ember-metal/core', 'ember-metal/logger', 'ember-views/views/view', 'ember-template-compiler/system/compile', 'ember-runtime/tests/utils'], function (Ember, EmberLogger, EmberView, compile, utils) { 'use strict'; var originalLookup = Ember['default'].lookup; var lookup; var originalLog, logCalls; var view; QUnit.module("Handlebars {{log}} helper", { setup: function() { Ember['default'].lookup = lookup = { Ember: Ember['default'] }; originalLog = EmberLogger['default'].log; logCalls = []; EmberLogger['default'].log = function() { logCalls.push.apply(logCalls, arguments); }; }, teardown: function() { utils.runDestroy(view); view = null; EmberLogger['default'].log = originalLog; Ember['default'].lookup = originalLookup; } }); QUnit.test("should be able to log multiple properties", function() { var context = { value: 'one', valueTwo: 'two' }; view = EmberView['default'].create({ context: context, template: compile['default']('{{log value valueTwo}}') }); utils.runAppend(view); equal(view.$().text(), "", "shouldn't render any text"); equal(logCalls[0], 'one'); equal(logCalls[1], 'two'); }); QUnit.test("should be able to log primitives", function() { var context = { value: 'one', valueTwo: 'two' }; view = EmberView['default'].create({ context: context, template: compile['default']('{{log value "foo" 0 valueTwo true}}') }); utils.runAppend(view); equal(view.$().text(), "", "shouldn't render any text"); strictEqual(logCalls[0], 'one'); strictEqual(logCalls[1], 'foo'); strictEqual(logCalls[2], 0); strictEqual(logCalls[3], 'two'); strictEqual(logCalls[4], true); }); }); enifed('ember-htmlbars/tests/helpers/debug_test.jscs-test', function () { 'use strict'; module('JSCS - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/debug_test.js should pass jscs', function() { ok(true, 'ember-htmlbars/tests/helpers/debug_test.js should pass jscs.'); }); }); enifed('ember-htmlbars/tests/helpers/debug_test.jshint', function () { 'use strict'; module('JSHint - ember-htmlbars/tests/helpers'); test('ember-htmlbars/tests/helpers/debug_test.js should pass jshint', function() { ok(true, 'ember-htmlbars/tests/helpers/debug_test.js should pass jshint.'); }); }); enifed('ember-htmlbars/tests/helpers/each_test', ['ember-metal/core', 'ember-runtime/system/object', 'ember-metal/run_loop', 'ember-views/views/view', 'ember-views/views/metamorph_view', 'ember-metal/computed', 'ember-runtime/controllers/array_controller', 'ember-runtime/system/native_array', 'ember-runtime/controllers/controller', 'ember-runtime/controllers/object_controller', 'ember-runtime/system/container', 'ember-metal/property_get', 'ember-metal/property_set', 'ember-runtime/tests/utils', 'ember-template-compiler/system/compile'], function (Ember, EmberObject, run, EmberView, _MetamorphView, computed, ArrayController, native_array, controllers__controller, ObjectController, system__container, property_get, property_set, utils, compile) { 'use strict'; /*jshint newcap:false*/ var people, view, registry, container; var template, templateMyView, MyView, MyEmptyView, templateMyEmptyView; // This function lets us write {{#EACH|people|p}} {{p}} {{/each}} // and generate: // // - {{#each p in people}} (legacy) // - {{#each people as |p|}} (legacy) function makeReplacer(useBlockParams) { return function(_, matchString) { var values = matchString.split("|"); if (values.length === 1) { return "each"; } var arr = useBlockParams ? ["each", values[1], "as", "|" + values[2] + "|"] : ["each", values[2], "in", values[1]]; var options = values[3]; if (options) { if (useBlockParams) { arr.splice(2, 0, options); } else { arr.push(options); } } return arr.join(" "); }; } var parseEachReplacerBlockParam = makeReplacer(true); var parseEachReplacerNonBlockParam = makeReplacer(false); var EACH_REGEX = /(EACH[^\}]*)/g; function parseEach(str, useBlockParams) { return str.replace(EACH_REGEX, useBlockParams ? parseEachReplacerBlockParam : parseEachReplacerNonBlockParam); } QUnit.module("parseEach test helper"); QUnit.test("block param syntax substitution", function() { equal(parseEach("{{#EACH|people|p}}p people{{/EACH}}", true), "{{#each people as |p|}}p people{{/each}}"); equal(parseEach("{{#EACH|people|p|a='b' c='d'}}p people{{/EACH}}", true), "{{#each people a='b' c='d' as |p|}}p people{{/each}}"); }); QUnit.test("non-block param syntax substitution", function() { equal(parseEach("{{#EACH|people|p}}p people{{/EACH}}", false), "{{#each p in people}}p people{{/each}}"); equal(parseEach("{{#EACH|people|p|a='b' c='d'}}p people{{/EACH}}", false), "{{#each p in people a='b' c='d'}}p people{{/each}}"); }); function templateFor(templateString, useBlockParams) { return compile['default'](parseEach(templateString, useBlockParams)); } var originalLookup = Ember['default'].lookup; var lookup; QUnit.module("the #each helper [DEPRECATED]", { setup: function() { Ember['default'].lookup = lookup = { Ember: Ember['default'] }; template = templateFor("{{#each view.people}}{{name}}{{/each}}"); people = native_array.A([{ name: "Steve Holt" }, { name: "Annabelle" }]); registry = new system__container.Registry(); container = registry.container(); registry.register('view:default', _MetamorphView['default']); registry.register('view:toplevel', EmberView['default'].extend()); view = EmberView['default'].create({ container: container, template: template, people: people }); templateMyView = templateFor("{{name}}"); lookup.MyView = MyView = EmberView['default'].extend({ template: templateMyView }); templateMyEmptyView = templateFor("I'm empty"); lookup.MyEmptyView = MyEmptyView = EmberView['default'].extend({ template: templateMyEmptyView }); expectDeprecation(function() { utils.runAppend(view); }, 'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead.'); }, teardown: function() { utils.runDestroy(container); utils.runDestroy(view); registry = container = view = null; Ember['default'].lookup = originalLookup; } }); var assertHTML = function(view, expectedHTML) { var html = view.$().html(); // IE 8 (and prior?) adds the \r\n html = html.replace(/]*><\/script>/ig, '').replace(/[\r\n]/g, ''); equal(html, expectedHTML); }; var assertText = function(view, expectedText) { equal(view.$().text(), expectedText); }; QUnit.test("it renders the template for each item in an array", function() { assertHTML(view, "Steve HoltAnnabelle"); }); QUnit.test("it updates the view if an item is added", function() { run['default'](function() { people.pushObject({ name: "Tom Dale" }); }); assertHTML(view, "Steve HoltAnnabelleTom Dale"); }); if (typeof Handlebars === "object") { QUnit.test("should be able to use standard Handlebars #each helper", function() { utils.runDestroy(view); view = EmberView['default'].create({ context: { items: ['a', 'b', 'c'] }, template: Handlebars.compile("{{#each items}}{{this}}{{/each}}") }); utils.runAppend(view); equal(view.$().html(), "abc"); }); } QUnit.test("it allows you to access the current context using {{this}}", function() { utils.runDestroy(view); view = EmberView['default'].create({ template: templateFor("{{#each view.people}}{{this}}{{/each}}"), people: native_array.A(['Black Francis', 'Joey Santiago', 'Kim Deal', 'David Lovering']) }); utils.runAppend(view); assertHTML(view, "Black FrancisJoey SantiagoKim DealDavid Lovering"); }); QUnit.test("it updates the view if an item is removed", function() { run['default'](function() { people.removeAt(0); }); assertHTML(view, "Annabelle"); }); QUnit.test("it updates the view if an item is replaced", function() { run['default'](function() { people.removeAt(0); people.insertAt(0, { name: "Kazuki" }); }); assertHTML(view, "KazukiAnnabelle"); }); QUnit.test("can add and replace in the same runloop", function() { run['default'](function() { people.pushObject({ name: "Tom Dale" }); people.removeAt(0); people.insertAt(0, { name: "Kazuki" }); }); assertHTML(view, "KazukiAnnabelleTom Dale"); }); QUnit.test("can add and replace the object before the add in the same runloop", function() { run['default'](function() { people.pushObject({ name: "Tom Dale" }); people.removeAt(1); people.insertAt(1, { name: "Kazuki" }); }); assertHTML(view, "Steve HoltKazukiTom Dale"); }); QUnit.test("can add and replace complicatedly", function() { run['default'](function() { people.pushObject({ name: "Tom Dale" }); people.removeAt(1); people.insertAt(1, { name: "Kazuki" }); people.pushObject({ name: "Firestone" }); people.pushObject({ name: "McMunch" }); people.removeAt(3); }); assertHTML(view, "Steve HoltKazukiTom DaleMcMunch"); }); QUnit.test("can add and replace complicatedly harder", function() { run['default'](function() { people.pushObject({ name: "Tom Dale" }); people.removeAt(1); people.insertAt(1, { name: "Kazuki" }); people.pushObject({ name: "Firestone" }); people.pushObject({ name: "McMunch" }); people.removeAt(2); }); assertHTML(view, "Steve HoltKazukiFirestoneMcMunch"); }); QUnit.test("it does not mark each option tag as selected", function() { var selectView = EmberView['default'].create({ template: templateFor(''), people: people }); utils.runAppend(selectView); equal(selectView.$('option').length, 3, "renders 3