test("it supports itemController when using a custom keyword", function() { var Controller = EmberController.extend({ controllerName: computed(function() { return "controller:"+this.get('content.name'); }) }); var container = new Container(); container.register('controller:array', ArrayController.extend()); run(function() { view.destroy(); }); // destroy existing view view = EmberView.create({ container: container, template: templateFor('{{#each person in view.people itemController="person"}}{{person.controllerName}}{{/each}}'), people: people, controller: { container: container } }); container.register('controller:person', Controller); append(view); equal(view.$().text(), "controller:Steve Holtcontroller:Annabelle"); run(function() { view.rerender(); }); equal(view.$().text(), "controller:Steve Holtcontroller:Annabelle"); });
test("itemController specified in ArrayController with name binding does not change context", function() { people = A([{ name: "Steve Holt" }, { name: "Annabelle" }]); var PersonController = ObjectController.extend({ controllerName: computed(function() { return "controller:" + get(this, 'content.name') + ' of ' + get(this, 'parentController.company'); }) }), PeopleController = ArrayController.extend({ content: people, itemController: 'person', company: 'Yapp', controllerName: 'controller:people' }), container = new Container(); container.register('controller:people', PeopleController); container.register('controller:person', PersonController); view = EmberView.create({ container: container, template: templateFor('{{#each person in this}}{{controllerName}} - {{person.controllerName}} - {{/each}}'), controller: container.lookup('controller:people') }); append(view); equal(view.$().text(), "controller:people - controller:Steve Holt of Yapp - controller:people - controller:Annabelle of Yapp - "); });
test("should render nested collections", function() { var container = new Container(); container.register('view:inner-list', CollectionView.extend({ tagName: 'ul', content: A(['one','two','three']) })); container.register('view:outer-list', CollectionView.extend({ tagName: 'ul', content: A(['foo']) })); view = EmberView.create({ container: container, template: compile('{{#collection "outer-list" class="outer"}}{{content}}{{#collection "inner-list" class="inner"}}{{content}}{{/collection}}{{/collection}}') }); run(function() { view.appendTo('#qunit-fixture'); }); 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"); });
test("itemController specified in template gets a parentController property", function() { // using an ObjectController for this test to verify that parentController does accidentally get set // on the proxied model. var Controller = ObjectController.extend({ controllerName: computed(function() { return "controller:" + get(this, 'content.name') + ' of ' + get(this, 'parentController.company'); }) }), container = new Container(), parentController = { container: container, company: 'Yapp' }; container.register('controller:array', ArrayController.extend()); run(function() { view.destroy(); }); // destroy existing view view = EmberView.create({ container: container, template: templateFor('{{#each view.people itemController="person"}}{{controllerName}}{{/each}}'), people: people, controller: parentController }); container.register('controller:person', Controller); append(view); equal(view.$().text(), "controller:Steve Holt of Yappcontroller:Annabelle of Yapp"); });
test("itemController's parentController property, when the ArrayController has a parentController", function() { var PersonController = ObjectController.extend({ controllerName: computed(function() { return "controller:" + get(this, 'content.name') + ' of ' + get(this, 'parentController.company'); }) }), PeopleController = ArrayController.extend({ content: people, itemController: 'person', parentController: computed(function(){ return this.container.lookup('controller:company'); }), company: 'Yapp' }), CompanyController = EmberController.extend(), container = new Container(); container.register('controller:company', CompanyController); container.register('controller:people', PeopleController); container.register('controller:person', PersonController); run(function() { view.destroy(); }); // destroy existing view view = EmberView.create({ container: container, template: templateFor('{{#each}}{{controllerName}}{{/each}}'), controller: container.lookup('controller:people') }); append(view); equal(view.$().text(), "controller:Steve Holt of Yappcontroller:Annabelle of Yapp"); });
setup: function() { Ember.lookup = lookup = { Ember: Ember }; template = templateFor("{{#each view.people}}{{name}}{{/each}}"); people = A([{ name: "Steve Holt" }, { name: "Annabelle" }]); container = new Container(); container.register('view:default', _MetamorphView); container.register('view:toplevel', EmberView.extend()); view = EmberView.create({ container: container, template: template, people: people }); templateMyView = templateFor("{{name}}"); lookup.MyView = MyView = EmberView.extend({ template: templateMyView }); expectDeprecation(function() { append(view); },'Using the context switching form of {{each}} is deprecated. Please use the keyword form (`{{#each foo in bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); },
setup: function() { Ember.lookup = lookup = {}; lookup.TemplateTests = TemplateTests = Namespace.create(); container = new Container(); container.optionsForType('template', { instantiate: false }); container.register('view:default', _MetamorphView); container.register('view:toplevel', EmberView.extend()); },
test("raises if a dependency with a period is requested", function() { var container = new Container(); container.register('controller:big.bird', Controller.extend()); container.register('controller:foo', Controller.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'); });
test("it supports itemController", function() { var Controller = EmberController.extend({ controllerName: computed(function() { return "controller:"+this.get('content.name'); }) }); var container = new Container(); run(function() { view.destroy(); }); // destroy existing view var parentController = { container: container }; container.register('controller:array', ArrayController.extend()); view = EmberView.create({ container: container, template: templateFor('{{#each view.people itemController="person"}}{{controllerName}}{{/each}}'), people: people, controller: parentController }); container.register('controller:person', Controller); append(view); equal(view.$().text(), "controller:Steve Holtcontroller:Annabelle"); run(function() { view.rerender(); }); assertText(view, "controller:Steve Holtcontroller:Annabelle"); run(function() { people.pushObject({ name: "Yehuda Katz" }); }); assertText(view, "controller:Steve Holtcontroller:Annabellecontroller:Yehuda Katz"); run(function() { set(view, 'people', A([{ name: "Trek Glowacki" }, { name: "Geoffrey Grosenbach" }])); }); assertText(view, "controller:Trek Glowackicontroller:Geoffrey Grosenbach"); var controller = view.get('_childViews')[0].get('controller'); strictEqual(view.get('_childViews')[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly"); });
test("controllers can be injected into controllers", function() { var container = new Container(); container.register('controller:post', Controller.extend({ postsController: inject.controller('posts') })); container.register('controller:posts', Controller.extend()); var postController = container.lookup('controller:post'), postsController = container.lookup('controller:posts'); equal(postsController, postController.get('postsController'), "controller.posts is injected"); });
test("If a controller specifies a dependency, it is accessible", function() { var container = new Container(); container.register('controller:post', Controller.extend({ needs: 'posts' })); container.register('controller:posts', Controller.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"); });
test("services can be injected into controllers", function() { var container = new Container(); container.register('controller:application', Controller.extend({ authService: inject.service('auth') })); container.register('service:auth', Service.extend()); var appController = container.lookup('controller:application'), authService = container.lookup('service:auth'); equal(authService, appController.get('authService'), "service.auth is injected"); });
test("services can be injected into components", function() { var container = new Container(); container.register('component:application', Component.extend({ profilerService: inject.service('profiler') })); container.register('service:profiler', Service.extend()); var appComponent = container.lookup('component:application'), profilerService = container.lookup('service:profiler'); equal(profilerService, appComponent.get('profilerService'), "service.profiler is injected"); });
test("should target the with-controller inside an {{#with controller='person'}} [DEPRECATED]", function() { var registeredTarget; ActionHelper.registerAction = function(actionName, options) { registeredTarget = options.target.value(); }; var PersonController = EmberObjectController.extend(); var container = new Container(); var parentController = EmberObject.create({ container: container }); view = EmberView.create({ container: container, template: compile('{{#with view.person controller="person"}}<div {{action "editTodo"}}></div>{{/with}}'), person: EmberObject.create(), controller: parentController }); container.register('controller:person', PersonController); expectDeprecation(function() { runAppend(view); }, 'Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); ok(registeredTarget instanceof PersonController, "the with-controller is the target of action"); });
test("it should still have access to original parentController within an {{#each}}", function() { var Controller = ObjectController.extend({ controllerName: computed(function() { return "controller:"+this.get('model.name') + ' and ' + this.get('parentController.name'); }) }); var people = A([{ name: "Steve Holt" }, { name: "Carl Weathers" }]); var container = new Container(); var parentController = EmberObject.create({ container: container, name: 'Bob Loblaw', people: people }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#each person in people}}{{#with person controller="person"}}{{controllerName}}{{/with}}{{/each}}'), controller: parentController }); container.register('controller:person', Controller); appendView(view); equal(view.$().text(), "controller:Steve Holt and Bob Loblawcontroller:Carl Weathers and Bob Loblaw"); run(function() { view.destroy(); }); // destroy existing view });
test("should target the with-controller inside an {{each}} in a {{#with controller='person'}}", function() { var eventsCalled = []; var PeopleController = EmberArrayController.extend({ actions: { robert: function() { eventsCalled.push('robert'); }, brian: function() { eventsCalled.push('brian'); } } }); var container = new Container(); var parentController = EmberObject.create({ container: container, people: Ember.A([ {name: 'robert'}, {name: 'brian'} ]) }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#with people controller="people"}}{{#each}}<a href="#" {{action name}}>{{name}}</a>{{/each}}{{/with}}'), controller: parentController }); container.register('controller:people', PeopleController); appendView(); view.$('a').trigger('click'); deepEqual(eventsCalled, ['robert', 'brian'], 'the events are fired properly'); });
test("should target the with-controller inside an {{#with controller='person'}}", function() { var registeredTarget; ActionHelper.registerAction = function(actionName, options) { registeredTarget = options.target; }; var PersonController = EmberObjectController.extend(); var container = new Container(); var parentController = EmberObject.create({ container: container }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#with view.person controller="person"}}{{action "editTodo"}}{{/with}}'), person: EmberObject.create(), controller: parentController }); container.register('controller:person', PersonController); appendView(); ok(registeredTarget.root instanceof PersonController, "the with-controller is the target of action"); ActionHelper.registerAction = originalRegisterAction; });
test("context should be content", function() { var view; var container = new Container(); var items = A([ EmberObject.create({name: 'Dave'}), EmberObject.create({name: 'Mary'}), EmberObject.create({name: 'Sara'}) ]); container.register('view:an-item', EmberView.extend({ template: compile("Greetings {{name}}") })); view = EmberView.create({ container: container, controller: { items: items }, template: compile('{{collection contentBinding="items" itemViewClass="an-item"}}') }); run(function() { view.appendTo('#qunit-fixture'); }); equal(view.$().text(), "Greetings DaveGreetings MaryGreetings Sara"); run(view, 'destroy'); });
test("destroys the controller generated with {{with foo controller='blah'}} [DEPRECATED]", function() { var destroyed = false; var Controller = ObjectController.extend({ willDestroy: function() { this._super(); destroyed = true; } }); var person = EmberObject.create({name: 'Steve Holt'}); var container = new Container(); var parentController = EmberObject.create({ container: container, person: person, name: 'Bob Loblaw' }); view = EmberView.create({ container: container, template: compile('{{#with person controller="person"}}{{controllerName}}{{/with}}'), controller: parentController }); container.register('controller:person', Controller); expectDeprecation(function(){ runAppend(view); }, 'Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); runDestroy(view); ok(destroyed, 'controller was destroyed properly'); });
test("destroys the controller generated with {{with foo as bar controller='blah'}}", function() { var destroyed = false; var Controller = ObjectController.extend({ willDestroy: function() { this._super(); destroyed = true; } }); var person = EmberObject.create({name: 'Steve Holt'}); var container = new Container(); var parentController = EmberObject.create({ container: container, person: person, name: 'Bob Loblaw' }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#with person as steve controller="person"}}{{controllerName}}{{/with}}'), controller: parentController }); container.register('controller:person', Controller); appendView(view); run(view, 'destroy'); // destroy existing view ok(destroyed, 'controller was destroyed properly'); });
test("itemController specified in template with name binding does not change context", function() { var Controller = EmberController.extend({ controllerName: computed(function() { return "controller:"+this.get('content.name'); }) }); var container = new Container(); people = A([{ name: "Steve Holt" }, { name: "Annabelle" }]); var parentController = { container: container, people: people, controllerName: 'controller:parentController' }; container.register('controller:array', ArrayController.extend()); view = EmberView.create({ container: container, template: templateFor('{{#each person in people itemController="person"}}{{controllerName}} - {{person.controllerName}} - {{/each}}'), controller: parentController }); container.register('controller:person', Controller); append(view); equal(view.$().text(), "controller:parentController - controller:Steve Holt - controller:parentController - controller:Annabelle - "); run(function() { people.pushObject({ name: "Yehuda Katz" }); }); assertText(view, "controller:parentController - controller:Steve Holt - controller:parentController - controller:Annabelle - controller:parentController - controller:Yehuda Katz - "); run(function() { set(parentController, 'people', A([{ name: "Trek Glowacki" }, { name: "Geoffrey Grosenbach" }])); }); assertText(view, "controller:parentController - controller:Trek Glowacki - controller:parentController - controller:Geoffrey Grosenbach - "); var controller = view.get('_childViews')[0].get('controller'); strictEqual(view.get('_childViews')[0].get('_arrayController.target'), parentController, "the target property of the child controllers are set correctly"); });
test("If a controller specifies an unavailable dependency, it raises", function() { var container = new Container(); container.register('controller:post', Controller.extend({ needs: ['comments'] })); throws(function() { container.lookup('controller:post'); }, /controller:comments/); container.register('controller:blog', Controller.extend({ needs: ['posts', 'comments'] })); throws(function() { container.lookup('controller:blog'); }, /controller:posts, controller:comments/); });
expectAssertion(function() { var container = new Container(); var AnObject = Object.extend({ container: container, foo: inject.controller('bar') }); container.register('foo:main', AnObject); container.lookupFactory('foo:main'); }, /Defining an injected controller property on a non-controller is not allowed./);
test("Mixin sets up controllers if there is needs before calling super", function() { var container = new Container(); container.register('controller:other', ArrayController.extend({ needs: 'posts', model: computed.alias('controllers.posts') })); container.register('controller:another', ArrayController.extend({ needs: 'posts', modelBinding: 'controllers.posts' })); container.register('controller:posts', ArrayController.extend()); container.lookup('controller:posts').set('model', A(['a','b','c'])); deepEqual(['a','b','c'], container.lookup('controller:other').toArray()); deepEqual(['a','b','c'], container.lookup('controller:another').toArray()); });
test("it should wrap context with object controller [DEPRECATED]", function() { var Controller = ObjectController.extend({ controllerName: computed(function() { return "controller:"+this.get('model.name') + ' and ' + this.get('parentController.name'); }) }); var person = EmberObject.create({name: 'Steve Holt'}); var container = new Container(); var parentController = EmberObject.create({ container: container, name: 'Bob Loblaw' }); view = EmberView.create({ container: container, template: compile('{{#with view.person controller="person"}}{{controllerName}}{{/with}}'), person: person, controller: parentController }); container.register('controller:person', Controller); expectDeprecation(function(){ runAppend(view); }, 'Using the context switching form of `{{with}}` is deprecated. Please use the keyword form (`{{with foo as bar}}`) instead. See http://emberjs.com/guides/deprecations/#toc_more-consistent-handlebars-scope for more details.'); equal(view.$().text(), "controller:Steve Holt and Bob Loblaw"); run(function() { view.rerender(); }); equal(view.$().text(), "controller:Steve Holt and Bob Loblaw"); run(function() { parentController.set('name', 'Carl Weathers'); view.rerender(); }); equal(view.$().text(), "controller:Steve Holt and Carl Weathers"); run(function() { person.set('name', 'Gob'); view.rerender(); }); equal(view.$().text(), "controller:Gob and Carl Weathers"); strictEqual(view.get('_childViews')[0].get('controller.target'), parentController, "the target property of the child controllers are set correctly"); runDestroy(view); });
test ("setting the value of a controller dependency should not be possible", function(){ var container = new Container(); container.register('controller:post', Controller.extend({ needs: 'posts' })); container.register('controller:posts', Controller.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"); });
test("it should wrap context with object controller", function() { var Controller = ObjectController.extend({ controllerName: computed(function() { return "controller:"+this.get('model.name') + ' and ' + this.get('parentController.name'); }) }); var person = EmberObject.create({name: 'Steve Holt'}); var container = new Container(); var parentController = EmberObject.create({ container: container, name: 'Bob Loblaw' }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#with view.person controller="person"}}{{controllerName}}{{/with}}'), person: person, controller: parentController }); container.register('controller:person', Controller); appendView(view); equal(view.$().text(), "controller:Steve Holt and Bob Loblaw"); run(function() { view.rerender(); }); equal(view.$().text(), "controller:Steve Holt and Bob Loblaw"); run(function() { parentController.set('name', 'Carl Weathers'); view.rerender(); }); equal(view.$().text(), "controller:Steve Holt and Carl Weathers"); run(function() { person.set('name', 'Gob'); view.rerender(); }); equal(view.$().text(), "controller:Gob and Carl Weathers"); strictEqual(view.get('_childViews')[0].get('controller.target'), parentController, "the target property of the child controllers are set correctly"); run(function() { view.destroy(); }); // destroy existing view });
test("attempting to inject a nonexistent container key should error", function() { var container = new Container(); var AnObject = Object.extend({ container: container, foo: new InjectedProperty('bar', 'baz') }); container.register('foo:main', AnObject); throws(function() { container.lookup('foo:main'); }, /Attempting to inject an unknown injection: `bar:baz`/); });
test("it should wrap keyword with object controller", function() { var PersonController = ObjectController.extend({ name: computed('model.name', function() { return get(this, 'model.name').toUpperCase(); }) }); var person = EmberObject.create({name: 'Steve Holt'}); var container = new Container(); var parentController = EmberObject.create({ container: container, person: person, name: 'Bob Loblaw' }); view = EmberView.create({ container: container, template: EmberHandlebars.compile('{{#with person as steve controller="person"}}{{name}} - {{steve.name}}{{/with}}'), controller: parentController }); container.register('controller:person', PersonController); appendView(view); equal(view.$().text(), "Bob Loblaw - STEVE HOLT"); run(function() { view.rerender(); }); equal(view.$().text(), "Bob Loblaw - STEVE HOLT"); run(function() { parentController.set('name', 'Carl Weathers'); view.rerender(); }); equal(view.$().text(), "Carl Weathers - STEVE HOLT"); run(function() { person.set('name', 'Gob'); view.rerender(); }); equal(view.$().text(), "Carl Weathers - GOB"); run(function() { view.destroy(); }); // destroy existing view });
setup: function() { Ember.lookup = lookup = { Ember: Ember }; template = templateFor("{{#each view.people}}{{name}}{{/each}}"); people = A([{ name: "Steve Holt" }, { name: "Annabelle" }]); container = new Container(); container.register('view:default', _MetamorphView); container.register('view:toplevel', EmberView.extend()); view = EmberView.create({ container: container, template: template, people: people }); templateMyView = templateFor("{{name}}"); lookup.MyView = MyView = EmberView.extend({ template: templateMyView }); append(view); },