diff --git a/packages/ember-glimmer/tests/utils/abstract-test-case.js b/packages/ember-glimmer/tests/utils/abstract-test-case.js index 382b1cbecd3..8371e161ff7 100644 --- a/packages/ember-glimmer/tests/utils/abstract-test-case.js +++ b/packages/ember-glimmer/tests/utils/abstract-test-case.js @@ -129,8 +129,12 @@ export class TestCase { return snapshot; } - assertText(text) { - this.assert.strictEqual(this.textValue(), text, '#qunit-fixture content'); + assertText(expected, message) { + this.assert.strictEqual(this.textValue(), expected, message || '#qunit-fixture content'); + } + + assertTextForSelector(selector, expected, message) { + this.assert.strictEqual(this.$(selector).text(), expected, message || `$(${selector}) content`); } assertHTML(html) { @@ -252,10 +256,10 @@ export class RenderingTest extends TestCase { return this.component; } - render(templateStr, context = {}) { + render(templateStr, context = {}, { templateOptions = {} } = {}) { let { renderer, owner } = this; - owner.register('template:-top-level', compile(templateStr)); + owner.register('template:-top-level', compile(templateStr, templateOptions)); let attrs = assign({}, context, { tagName: '', @@ -289,7 +293,7 @@ export class RenderingTest extends TestCase { } } - registerComponent(name, { ComponentClass = null, template = null }) { + registerComponent(name, { ComponentClass = null, template = null, templateOptions = {} }) { let { owner } = this; if (ComponentClass) { @@ -297,7 +301,7 @@ export class RenderingTest extends TestCase { } if (typeof template === 'string') { - owner.register(`template:components/${name}`, compile(template)); + owner.register(`template:components/${name}`, compile(template, templateOptions)); } } diff --git a/packages/ember-htmlbars/tests/integration/component_invocation_test.js b/packages/ember-htmlbars/tests/integration/component_invocation_test.js index 4151b1fb555..4c12c2a00e0 100644 --- a/packages/ember-htmlbars/tests/integration/component_invocation_test.js +++ b/packages/ember-htmlbars/tests/integration/component_invocation_test.js @@ -1,955 +1,830 @@ import Ember from 'ember-metal/core'; -import EmberView from 'ember-views/views/view'; -import jQuery from 'ember-views/system/jquery'; -import compile from 'ember-template-compiler/system/compile'; -import ComponentLookup from 'ember-views/component_lookup'; import Component from 'ember-views/components/component'; import GlimmerComponent from 'ember-htmlbars/glimmer-component'; -import { runAppend, runDestroy } from 'ember-runtime/tests/utils'; -import { set } from 'ember-metal/property_set'; import run from 'ember-metal/run_loop'; import { A as emberA } from 'ember-runtime/system/native_array'; -import buildOwner from 'container/tests/test-helpers/build-owner'; -import { OWNER } from 'container/owner'; - -var owner, view; - -function commonSetup() { - owner = buildOwner(); - owner.registerOptionsForType('component', { singleton: false }); - owner.registerOptionsForType('view', { singleton: false }); - owner.registerOptionsForType('template', { instantiate: false }); - owner.register('component-lookup:main', ComponentLookup); -} - -function commonTeardown() { - runDestroy(owner); - runDestroy(view); - owner = view = null; -} - -function appendViewFor(template, hash={}) { - let view = EmberView.extend({ - [OWNER]: owner, - template: compile(template) - }).create(hash); +import compile from 'ember-template-compiler/system/compile'; +import { RenderingTest, moduleFor } from 'ember-htmlbars/tests/utils/test-case'; - runAppend(view); +moduleFor('component - invocation', class extends RenderingTest { + ['@test non-block without properties']() { + expect(1); - return view; -} + this.registerComponent('non-block', { + template: 'In layout' + }); -QUnit.module('component - invocation', { - setup() { - commonSetup(); - }, + this.render('{{non-block}}'); - teardown() { - commonTeardown(); + this.assertText('In layout'); } -}); - -QUnit.test('non-block without properties', function() { - expect(1); - - owner.register('template:components/non-block', compile('In layout')); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block}}') - }).create(); + ['@test GlimmerComponent cannot be invoked with curly braces']() { + this.registerComponent('non-block', { + ComponentClass: GlimmerComponent.extend(), + template: 'In layout' + }); - runAppend(view); - - equal(jQuery('#qunit-fixture').text(), 'In layout'); -}); - -QUnit.test('GlimmerComponent cannot be invoked with curly braces', function() { - owner.register('template:components/non-block', compile('In layout')); - owner.register('component:non-block', GlimmerComponent.extend()); - - expectAssertion(function() { - view = appendViewFor('{{non-block}}'); - }, /cannot invoke the 'non-block' component with curly braces/); -}); - -QUnit.test('block without properties', function() { - expect(1); - - owner.register('template:components/with-block', compile('In layout - {{yield}}')); + expectAssertion(() => { + this.render('{{non-block}}'); + }, /cannot invoke the 'non-block' component with curly braces/); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block}}In template{{/with-block}}') - }).create(); + ['@test block without properties']() { + expect(1); - runAppend(view); + this.registerComponent('with-block', { + template: 'In layout - {{yield}}' + }); - equal(jQuery('#qunit-fixture').text(), 'In layout - In template'); -}); + this.render('{{#with-block}}In template{{/with-block}}'); -QUnit.test('non-block with properties on attrs', function() { - expect(1); + this.assertText('In layout - In template'); + } - owner.register('template:components/non-block', compile('In layout - someProp: {{attrs.someProp}}')); + ['@test non-block with properties on attrs']() { + expect(1); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block someProp="something here"}}') - }).create(); + this.registerComponent('non-block', { + template: 'In layout - someProp: {{attrs.someProp}}' + }); - runAppend(view); + this.render('{{non-block someProp="something here"}}'); - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: something here'); -}); + this.assertText('In layout - someProp: something here'); + } -QUnit.test('non-block with properties on attrs and component class', function() { - owner.register('component:non-block', Component.extend()); - owner.register('template:components/non-block', compile('In layout - someProp: {{attrs.someProp}}')); + ['@test non-block with properties on attrs and component class']() { + this.registerComponent('non-block', { + ComponentClass: Component.extend(), + template: 'In layout - someProp: {{attrs.someProp}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block someProp="something here"}}') - }).create(); + this.render('{{non-block someProp="something here"}}'); - runAppend(view); + this.assertText('In layout - someProp: something here'); + } - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: something here'); -}); -QUnit.test('non-block with properties on overridden in init', function() { - owner.register('component:non-block', Component.extend({ - someProp: null, + ['@test non-block with properties on overridden in init']() { + this.registerComponent('non-block', { + ComponentClass: Component.extend({ + someProp: null, - init() { - this._super(...arguments); - this.someProp = 'value set in init'; - } - })); - owner.register('template:components/non-block', compile('In layout - someProp: {{someProp}}')); + init() { + this._super(...arguments); + this.someProp = 'value set in init'; + } + }), - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block someProp="something passed when invoked"}}') - }).create(); + template: 'In layout - someProp: {{someProp}}' + }); - runAppend(view); + this.render('{{non-block someProp="something passed when invoked"}}'); - equal(view.$().text(), 'In layout - someProp: value set in init'); -}); + this.assertText('In layout - someProp: value set in init'); + } -QUnit.test('lookup of component takes priority over property', function() { - expect(1); + ['@test lookup of component takes priority over property']() { + expect(1); - owner.register('template:components/some-component', compile('some-component')); + this.registerComponent('some-component', { + template: 'some-component' + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{some-prop}} {{some-component}}'), - context: { + this.render('{{some-prop}} {{some-component}}', { 'some-component': 'not-some-component', 'some-prop': 'some-prop' - } - }).create(); - - runAppend(view); + }); - equal(jQuery('#qunit-fixture').text(), 'some-prop some-component'); -}); + this.assertText('some-prop some-component'); + } -QUnit.test('component without dash is not looked up', function() { - expect(1); + ['@test component without dash is not looked up']() { + expect(1); - owner.register('template:components/somecomponent', compile('somecomponent')); + this.registerComponent('somecomponent', { + template: 'somecomponent' + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{somecomponent}}'), - context: { + this.render('{{somecomponent}}', { 'somecomponent': 'notsomecomponent' - } - }).create(); - - runAppend(view); - - equal(jQuery('#qunit-fixture').text(), 'notsomecomponent'); -}); - -QUnit.test('rerendering component with attrs from parent', function() { - var willUpdate = 0; - var didReceiveAttrs = 0; - - owner.register('component:non-block', Component.extend({ - didReceiveAttrs() { - didReceiveAttrs++; - }, - - willUpdate() { - willUpdate++; - } - })); - owner.register('template:components/non-block', compile('In layout - someProp: {{attrs.someProp}}')); + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block someProp=view.someProp}}'), - someProp: 'wycats' - }).create(); - - runAppend(view); + this.assertText('notsomecomponent'); + } - equal(didReceiveAttrs, 1, 'The didReceiveAttrs hook fired'); + ['@test rerendering component with attrs from parent']() { + let willUpdate = 0; + let didReceiveAttrs = 0; - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: wycats'); + this.registerComponent('non-block', { + ComponentClass: Component.extend({ + didReceiveAttrs() { + didReceiveAttrs++; + }, - run(function() { - view.set('someProp', 'tomdale'); - }); + willUpdate() { + willUpdate++; + } + }), - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: tomdale'); - equal(didReceiveAttrs, 2, 'The didReceiveAttrs hook fired again'); - equal(willUpdate, 1, 'The willUpdate hook fired once'); + template: 'In layout - someProp: {{attrs.someProp}}' + }); - run(view, 'rerender'); + this.render('{{non-block someProp=view.someProp}}', { + someProp: 'wycats' + }); - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: tomdale'); - equal(didReceiveAttrs, 3, 'The didReceiveAttrs hook fired again'); - equal(willUpdate, 2, 'The willUpdate hook fired again'); -}); + equal(didReceiveAttrs, 1, 'The didReceiveAttrs hook fired'); + this.assertText('In layout - someProp: wycats'); -QUnit.test('[DEPRECATED] non-block with properties on self', function() { - // TODO: attrs - // expectDeprecation("You accessed the `someProp` attribute directly. Please use `attrs.someProp` instead."); + run(() => { + this.component.set('someProp', 'tomdale'); + }); - owner.register('template:components/non-block', compile('In layout - someProp: {{someProp}}')); + this.assertText('In layout - someProp: tomdale'); + equal(didReceiveAttrs, 2, 'The didReceiveAttrs hook fired again'); + equal(willUpdate, 1, 'The willUpdate hook fired once'); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block someProp="something here"}}') - }).create(); + run(() => { + this.rerender(); + }); - runAppend(view); + this.assertText('In layout - someProp: tomdale'); + equal(didReceiveAttrs, 3, 'The didReceiveAttrs hook fired again'); + equal(willUpdate, 2, 'The willUpdate hook fired again'); + } - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: something here'); -}); + ['@test [DEPRECATED] non-block with properties on self']() { + // TODO: attrs + // expectDeprecation("You accessed the `someProp` attribute directly. Please use `attrs.someProp` instead."); -QUnit.test('block with properties on attrs', function() { - expect(1); + this.registerComponent('non-block', { + template: 'In layout - someProp: {{someProp}}' + }); - owner.register('template:components/with-block', compile('In layout - someProp: {{attrs.someProp}} - {{yield}}')); + this.render('{{non-block someProp="something here"}}'); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block someProp="something here"}}In template{{/with-block}}') - }).create(); + this.assertText('In layout - someProp: something here'); + } - runAppend(view); + ['@test block with properties on attrs']() { + expect(1); - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: something here - In template'); -}); + this.registerComponent('with-block', { + template: 'In layout - someProp: {{attrs.someProp}} - {{yield}}' + }); -QUnit.test('[DEPRECATED] block with properties on self', function() { - // TODO: attrs - // expectDeprecation("You accessed the `someProp` attribute directly. Please use `attrs.someProp` instead."); + this.render('{{#with-block someProp="something here"}}In template{{/with-block}}'); - owner.register('template:components/with-block', compile('In layout - someProp: {{someProp}} - {{yield}}')); + this.assertText('In layout - someProp: something here - In template'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block someProp="something here"}}In template{{/with-block}}') - }).create(); + ['@test [DEPRECATED] block with properties on self']() { + // TODO: attrs + // expectDeprecation("You accessed the `someProp` attribute directly. Please use `attrs.someProp` instead."); - runAppend(view); + this.registerComponent('with-block', { + template: 'In layout - someProp: {{someProp}} - {{yield}}' + }); - equal(jQuery('#qunit-fixture').text(), 'In layout - someProp: something here - In template'); -}); + this.render('{{#with-block someProp="something here"}}In template{{/with-block}}'); -QUnit.test('with ariaRole specified', function() { - expect(1); - - owner.register('template:components/aria-test', compile('Here!')); + this.assertText('In layout - someProp: something here - In template'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{aria-test id="aria-test" ariaRole="main"}}') - }).create(); + ['@test with ariaRole specified']() { + expect(1); - runAppend(view); + this.registerComponent('aria-test', { + template: 'Here!' + }); - equal(view.$('#aria-test').attr('role'), 'main', 'role attribute is applied'); -}); + this.render('{{aria-test id="aria-test" ariaRole="main"}}'); -QUnit.test('`template` specified in a component is overridden by block', function() { - expect(1); + equal(this.$('#aria-test').attr('role'), 'main', 'role attribute is applied'); + } - owner.register('component:with-block', Component.extend({ - layout: compile('{{yield}}'), - template: compile('Oh, noes!') - })); + ['@test `template` specified in a component is overridden by block']() { + expect(1); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block}}Whoop, whoop!{{/with-block}}') - }).create(); + this.registerComponent('with-block', { + ComponentClass: Component.extend({ + layout: compile('{{yield}}'), + template: compile('Oh, noes!') + }) + }); - runAppend(view); + this.render('{{#with-block}}Whoop, whoop!{{/with-block}}'); - equal(view.$().text(), 'Whoop, whoop!', 'block provided always overrides template property'); -}); + this.assertText('Whoop, whoop!', 'block provided always overrides template property'); + } -QUnit.test('hasBlock is true when block supplied', function() { - expect(1); + ['@test hasBlock is true when block supplied']() { + expect(1); - owner.register('template:components/with-block', compile('{{#if hasBlock}}{{yield}}{{else}}No Block!{{/if}}')); + this.registerComponent('with-block', { + template: '{{#if hasBlock}}{{yield}}{{else}}No Block!{{/if}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block}}In template{{/with-block}}') - }).create(); + this.render('{{#with-block}}In template{{/with-block}}'); - runAppend(view); + this.assertText('In template'); + } - equal(jQuery('#qunit-fixture').text(), 'In template'); -}); + ['@test hasBlock is false when no block supplied']() { + expect(1); -QUnit.test('hasBlock is false when no block supplied', function() { - expect(1); + this.registerComponent('with-block', { + template: '{{#if hasBlock}}{{yield}}{{else}}No Block!{{/if}}' + }); - owner.register('template:components/with-block', compile('{{#if hasBlock}}{{yield}}{{else}}No Block!{{/if}}')); + this.render('{{with-block}}'); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{with-block}}') - }).create(); + this.assertText('No Block!'); + } - runAppend(view); + ['@test hasBlock is false when no block supplied']() { + expect(1); - equal(jQuery('#qunit-fixture').text(), 'No Block!'); -}); + this.registerComponent('with-block', { + template: '{{#if hasBlock}}{{yield}}{{else}}No Block!{{/if}}' + }); -QUnit.test('hasBlockParams is true when block param supplied', function() { - expect(1); + this.render('{{with-block}}'); - owner.register('template:components/with-block', compile('{{#if hasBlockParams}}{{yield this}} - In Component{{else}}{{yield}} No Block!{{/if}}')); + this.assertText('No Block!'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block as |something|}}In template{{/with-block}}') - }).create(); + ['@test hasBlockParams is true when block param supplied']() { + expect(1); - runAppend(view); + this.registerComponent('with-block', { + template: '{{#if hasBlockParams}}{{yield this}} - In Component{{else}}{{yield}} No Block!{{/if}}' + }); - equal(jQuery('#qunit-fixture').text(), 'In template - In Component'); -}); + this.render('{{#with-block as |something|}}In template{{/with-block}}'); -QUnit.test('hasBlockParams is false when no block param supplied', function() { - expect(1); + this.assertText('In template - In Component'); + } - owner.register('template:components/with-block', compile('{{#if hasBlockParams}}{{yield this}}{{else}}{{yield}} No Block Param!{{/if}}')); + ['@test hasBlockParams is false when no block param supplied']() { + expect(1); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#with-block}}In block{{/with-block}}') - }).create(); + this.registerComponent('with-block', { + template: '{{#if hasBlockParams}}{{yield this}}{{else}}{{yield}} No Block Param!{{/if}}' + }); - runAppend(view); + this.render('{{#with-block}}In block{{/with-block}}'); - equal(jQuery('#qunit-fixture').text(), 'In block No Block Param!'); -}); + this.assertText('In block No Block Param!'); + } -QUnit.test('static named positional parameters', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: ['name', 'age'] - }); - owner.register('template:components/sample-component', compile('{{attrs.name}}{{attrs.age}}')); - owner.register('component:sample-component', SampleComponent); + ['@test static named positional parameters']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: ['name', 'age'] + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component "Quint" 4}}') - }).create(); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{attrs.name}}{{attrs.age}}' + }); - runAppend(view); + this.render('{{sample-component "Quint" 4}}'); - equal(jQuery('#qunit-fixture').text(), 'Quint4'); -}); + this.assertText('Quint4'); + } -QUnit.test('dynamic named positional parameters', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: ['name', 'age'] - }); + ['@test dynamic named positional parameters']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: ['name', 'age'] + }); - owner.register('template:components/sample-component', compile('{{attrs.name}}{{attrs.age}}')); - owner.register('component:sample-component', SampleComponent); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{attrs.name}}{{attrs.age}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component myName myAge}}'), - context: { + this.render('{{sample-component myName myAge}}', { myName: 'Quint', myAge: 4 - } - }).create(); - - runAppend(view); - - equal(jQuery('#qunit-fixture').text(), 'Quint4'); - run(function() { - set(view.context, 'myName', 'Edward'); - set(view.context, 'myAge', '5'); - }); - - equal(jQuery('#qunit-fixture').text(), 'Edward5'); -}); - -QUnit.test('if a value is passed as a non-positional parameter, it takes precedence over the named one', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: ['name'] - }); + }); - owner.register('template:components/sample-component', compile('{{attrs.name}}')); - owner.register('component:sample-component', SampleComponent); + this.assertText('Quint4'); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component notMyName name=myName}}'), - context: { - myName: 'Quint', - notMyName: 'Sergio' - } - }).create(); + run(() => { + this.component.set('myName', 'Edward'); + this.component.set('myAge', '5'); + }); - expectAssertion(function() { - runAppend(view); - }, `You cannot specify both a positional param (at position 0) and the hash argument \`name\`.`); -}); + this.assertText('Edward5'); + } -QUnit.test('static arbitrary number of positional parameters', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: 'names' - }); + ['@test if a value is passed as a non-positional parameter, it takes precedence over the named one']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: ['name'] + }); + + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{attrs.name}}' + }); + + expectAssertion(() => { + this.render('{{sample-component notMyName name=myName}}', { + myName: 'Quint', + notMyName: 'Sergio' + }); + }, `You cannot specify both a positional param (at position 0) and the hash argument \`name\`.`); + } - owner.register('template:components/sample-component', compile('{{#each attrs.names as |name|}}{{name}}{{/each}}')); - owner.register('component:sample-component', SampleComponent); + ['@test static arbitrary number of positional parameters']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: 'names' + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component "Foo" 4 "Bar" id="args-3"}}{{sample-component "Foo" 4 "Bar" 5 "Baz" id="args-5"}}{{component "sample-component" "Foo" 4 "Bar" 5 "Baz" id="helper"}}') - }).create(); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{#each attrs.names as |name|}}{{name}}{{/each}}' + }); - runAppend(view); + this.render('{{sample-component "Foo" 4 "Bar" id="args-3"}}{{sample-component "Foo" 4 "Bar" 5 "Baz" id="args-5"}}{{component "sample-component" "Foo" 4 "Bar" 5 "Baz" id="helper"}}'); - equal(view.$('#args-3').text(), 'Foo4Bar'); - equal(view.$('#args-5').text(), 'Foo4Bar5Baz'); - equal(view.$('#helper').text(), 'Foo4Bar5Baz'); -}); + this.assertTextForSelector('#args-3', 'Foo4Bar'); + this.assertTextForSelector('#args-5', 'Foo4Bar5Baz'); + this.assertTextForSelector('#helper', 'Foo4Bar5Baz'); + } -QUnit.test('arbitrary positional parameter conflict with hash parameter is reported', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: 'names' - }); - - owner.register('template:components/sample-component', compile('{{#each attrs.names as |name|}}{{name}}{{/each}}')); - owner.register('component:sample-component', SampleComponent); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component "Foo" 4 "Bar" names=numbers id="args-3"}}'), - context: { - numbers: [1, 2, 3] - } - }).create(); - - expectAssertion(function() { - runAppend(view); - }, `You cannot specify positional parameters and the hash argument \`names\`.`); -}); + ['@test arbitrary positional parameter conflict with hash parameter is reported']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: 'names' + }); + + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{#each attrs.names as |name|}}{{name}}{{/each}}' + }); + + expectAssertion(() => { + this.render('{{sample-component "Foo" 4 "Bar" names=numbers id="args-3"}}', { + numbers: [1, 2, 3] + }); + }, `You cannot specify positional parameters and the hash argument \`names\`.`); + } -QUnit.test('can use hash parameter instead of arbitrary positional param [GH #12444]', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: 'names' - }); + ['@test can use hash parameter instead of arbitrary positional param [GH #12444]']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: 'names' + }); - owner.register('template:components/sample-component', compile('{{#each attrs.names as |name|}}{{name}}{{/each}}')); - owner.register('component:sample-component', SampleComponent); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{#each attrs.names as |name|}}{{name}}{{/each}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component names=things id="args-3"}}'), - context: { + this.render('{{sample-component names=things id="args-3"}}', { things: ['Foo', 4, 'Bar'] - } - }).create(); - - runAppend(view); + }); - equal(view.$('#args-3').text(), 'Foo4Bar'); -}); + this.assertTextForSelector('#args-3', 'Foo4Bar'); + } -QUnit.test('can use hash parameter instead of positional param', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: ['first', 'second'] - }); + ['@test can use hash parameter instead of positional param']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: ['first', 'second'] + }); - owner.register('template:components/sample-component', compile('{{attrs.first}} - {{attrs.second}}')); - owner.register('component:sample-component', SampleComponent); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{attrs.first}} - {{attrs.second}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile(` + this.render(` {{sample-component "one" "two" id="two-positional"}} {{sample-component "one" second="two" id="one-positional"}} {{sample-component first="one" second="two" id="no-positional"}} - - `), - context: { + `, { things: ['Foo', 4, 'Bar'] - } - }).create(); - - runAppend(view); + }); - equal(view.$('#two-positional').text(), 'one - two'); - equal(view.$('#one-positional').text(), 'one - two'); - equal(view.$('#no-positional').text(), 'one - two'); -}); + this.assertTextForSelector('#two-positional', 'one - two'); + this.assertTextForSelector('#one-positional', 'one - two'); + this.assertTextForSelector('#no-positional', 'one - two'); + } -QUnit.test('dynamic arbitrary number of positional parameters', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: 'n' - }); - owner.register('template:components/sample-component', compile('{{#each attrs.n as |name|}}{{name}}{{/each}}')); - owner.register('component:sample-component', SampleComponent); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component user1 user2 id="direct"}}{{component "sample-component" user1 user2 id="helper"}}'), - context: { + ['@test dynamic arbitrary number of positional parameters']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: 'n' + }); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{#each attrs.n as |name|}}{{name}}{{/each}}' + }); + + this.render('{{sample-component user1 user2 id="direct"}}{{component "sample-component" user1 user2 id="helper"}}', { user1: 'Foo', user2: 4 - } - }).create(); + }); - runAppend(view); + this.assertTextForSelector('#direct', 'Foo4'); + this.assertTextForSelector('#helper', 'Foo4'); - equal(view.$('#direct').text(), 'Foo4'); - equal(view.$('#helper').text(), 'Foo4'); - run(function() { - set(view.context, 'user1', 'Bar'); - set(view.context, 'user2', '5'); - }); + run(() => { + this.component.set('user1', 'Bar'); + this.component.set('user2', '5'); + }); - equal(view.$('#direct').text(), 'Bar5'); - equal(view.$('#helper').text(), 'Bar5'); + this.assertTextForSelector('#direct', 'Bar5'); + this.assertTextForSelector('#helper', 'Bar5'); - run(function() { - set(view.context, 'user2', '6'); - }); + run(() => { + this.component.set('user2', '6'); + }); - equal(view.$('#direct').text(), 'Bar6'); - equal(view.$('#helper').text(), 'Bar6'); -}); + this.assertTextForSelector('#direct', 'Bar6'); + this.assertTextForSelector('#helper', 'Bar6'); + } -QUnit.test('moduleName is available on _renderNode when a layout is present', function() { - expect(1); - - var layoutModuleName = 'my-app-name/templates/components/sample-component'; - var sampleComponentLayout = compile('Sample Component - {{yield}}', { - moduleName: layoutModuleName - }); - owner.register('template:components/sample-component', sampleComponentLayout); - owner.register('component:sample-component', Component.extend({ - didInsertElement: function() { - equal(this._renderNode.lastResult.template.meta.moduleName, layoutModuleName); - } - })); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{sample-component}}') - }).create(); - - runAppend(view); -}); + ['@test moduleName is available on _renderNode when a layout is present']() { + expect(1); -QUnit.test('moduleName is available on _renderNode when no layout is present', function() { - expect(1); + let layoutModuleName = 'my-app-name/templates/components/sample-component'; + let sampleComponentLayout = compile('Sample Component - {{yield}}', { + moduleName: layoutModuleName + }); - var templateModuleName = 'my-app-name/templates/application'; - owner.register('component:sample-component', Component.extend({ - didInsertElement: function() { - equal(this._renderNode.lastResult.template.meta.moduleName, templateModuleName); - } - })); + this.owner.register('template:components/sample-component', sampleComponentLayout); + this.owner.register('component:sample-component', Component.extend({ + didInsertElement: function() { + equal(this._renderNode.lastResult.template.meta.moduleName, layoutModuleName); + } + })); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{#sample-component}}Derp{{/sample-component}}', { - moduleName: templateModuleName - }) - }).create(); + this.render('{{sample-component}}'); + } - runAppend(view); -}); + ['@test moduleName is available on _renderNode when no layout is present']() { + expect(1); + + let templateModuleName = 'my-app-name/templates/application'; + this.registerComponent('sample-component', { + ComponentClass: Component.extend({ + didInsertElement: function() { + equal(this._renderNode.lastResult.template.meta.moduleName, templateModuleName); + } + }) + }); + + this.render('{{#sample-component}}Derp{{/sample-component}}', {}, { + templateOptions: { moduleName: templateModuleName } + }); + } -QUnit.test('{{component}} helper works with positional params', function() { - var SampleComponent = Component.extend(); - SampleComponent.reopenClass({ - positionalParams: ['name', 'age'] - }); + ['@test {{component}} helper works with positional params']() { + let SampleComponent = Component.extend(); + SampleComponent.reopenClass({ + positionalParams: ['name', 'age'] + }); - owner.register('template:components/sample-component', compile('{{attrs.name}}{{attrs.age}}')); - owner.register('component:sample-component', SampleComponent); + this.registerComponent('sample-component', { + ComponentClass: SampleComponent, + template: '{{attrs.name}}{{attrs.age}}' + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{component "sample-component" myName myAge}}'), - context: { + this.render('{{component "sample-component" myName myAge}}', { myName: 'Quint', myAge: 4 - } - }).create(); - - runAppend(view); - equal(jQuery('#qunit-fixture').text(), 'Quint4'); - run(function() { - set(view.context, 'myName', 'Edward'); - set(view.context, 'myAge', '5'); - }); - - equal(jQuery('#qunit-fixture').text(), 'Edward5'); -}); - -QUnit.test('yield to inverse', function() { - owner.register('template:components/my-if', compile('{{#if predicate}}Yes:{{yield someValue}}{{else}}No:{{yield to="inverse"}}{{/if}}')); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{#my-if predicate=activated someValue=42 as |result|}}Hello{{result}}{{else}}Goodbye{{/my-if}}'), - context: { - activated: true - } - }).create(); - - runAppend(view); - equal(jQuery('#qunit-fixture').text(), 'Yes:Hello42'); - run(function() { - set(view.context, 'activated', false); - }); - - equal(jQuery('#qunit-fixture').text(), 'No:Goodbye'); -}); - -QUnit.test('parameterized hasBlock inverse', function() { - owner.register('template:components/check-inverse', compile('{{#if (hasBlock "inverse")}}Yes{{else}}No{{/if}}')); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{#check-inverse id="expect-no"}}{{/check-inverse}} {{#check-inverse id="expect-yes"}}{{else}}{{/check-inverse}}') - }).create(); - - runAppend(view); - equal(jQuery('#qunit-fixture #expect-no').text(), 'No'); - equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes'); -}); - -QUnit.test('parameterized hasBlock default', function() { - owner.register('template:components/check-block', compile('{{#if (hasBlock)}}Yes{{else}}No{{/if}}')); + }); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}') - }).create(); + this.assertText('Quint4'); - runAppend(view); - equal(jQuery('#qunit-fixture #expect-no').text(), 'No'); - equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes'); -}); - -QUnit.test('non-expression hasBlock ', function() { - owner.register('template:components/check-block', compile('{{#if hasBlock}}Yes{{else}}No{{/if}}')); - - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}') - }).create(); - - runAppend(view); - equal(jQuery('#qunit-fixture #expect-no').text(), 'No'); - equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes'); -}); + run(() => { + this.component.set('myName', 'Edward'); + this.component.set('myAge', '5'); + }); -QUnit.test('parameterized hasBlockParams', function() { - owner.register('template:components/check-params', compile('{{#if (hasBlockParams)}}Yes{{else}}No{{/if}}')); + this.assertText('Edward5'); + } - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}') - }).create(); + ['@test yield to inverse']() { + this.registerComponent('my-if', { + template: '{{#if predicate}}Yes:{{yield someValue}}{{else}}No:{{yield to="inverse"}}{{/if}}' + }); - runAppend(view); - equal(jQuery('#qunit-fixture #expect-no').text(), 'No'); - equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes'); -}); + this.render('{{#my-if predicate=activated someValue=42 as |result|}}Hello{{result}}{{else}}Goodbye{{/my-if}}', { + activated: true + }); -QUnit.test('non-expression hasBlockParams', function() { - owner.register('template:components/check-params', compile('{{#if hasBlockParams}}Yes{{else}}No{{/if}}')); + this.assertText('Yes:Hello42'); - view = EmberView.extend({ - [OWNER]: owner, - layout: compile('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}') - }).create(); + run(() => { + this.component.set('activated', false); + }); - runAppend(view); - equal(jQuery('#qunit-fixture #expect-no').text(), 'No'); - equal(jQuery('#qunit-fixture #expect-yes').text(), 'Yes'); -}); - -QUnit.test('components in template of a yielding component should have the proper parentView', function() { - var outer, innerTemplate, innerLayout; - - owner.register('component:x-outer', Component.extend({ - init() { - this._super(...arguments); - outer = this; - } - })); - - owner.register('component:x-inner-in-template', Component.extend({ - init() { - this._super(...arguments); - innerTemplate = this; - } - })); - - owner.register('component:x-inner-in-layout', Component.extend({ - init() { - this._super(...arguments); - innerLayout = this; - } - })); - - owner.register('template:components/x-outer', compile('{{x-inner-in-layout}}{{yield}}')); - - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#x-outer}}{{x-inner-in-template}}{{/x-outer}}') - }).create(); - - runAppend(view); - - equal(innerTemplate.parentView, outer, 'receives the wrapping component as its parentView in template blocks'); - equal(innerLayout.parentView, outer, 'receives the wrapping component as its parentView in layout'); - equal(outer.parentView, view, 'x-outer receives the ambient scope as its parentView'); -}); + this.assertText('No:Goodbye'); + } -QUnit.test('newly-added sub-components get correct parentView', function() { - var outer, inner; + ['@test parameterized hasBlock inverse']() { + this.registerComponent('check-inverse', { + template: '{{#if (hasBlock "inverse")}}Yes{{else}}No{{/if}}' + }); - owner.register('component:x-outer', Component.extend({ - init() { - this._super(...arguments); - outer = this; - } - })); + this.render('{{#check-inverse id="expect-no"}}{{/check-inverse}} {{#check-inverse id="expect-yes"}}{{else}}{{/check-inverse}}'); - owner.register('component:x-inner', Component.extend({ - init() { - this._super(...arguments); - inner = this; - } - })); + this.assertTextForSelector('#expect-no', 'No'); + this.assertTextForSelector('#expect-yes', 'Yes'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#x-outer}}{{#if view.showInner}}{{x-inner}}{{/if}}{{/x-outer}}'), - showInner: false - }).create(); + ['@test parameterized hasBlock default']() { + this.registerComponent('check-block', { + template: '{{#if (hasBlock)}}Yes{{else}}No{{/if}}' + }); - runAppend(view); + this.render('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}'); - run(() => { view.set('showInner', true); }); + this.assertTextForSelector('#expect-no', 'No'); + this.assertTextForSelector('#expect-yes', 'Yes'); + } - equal(inner.parentView, outer, 'receives the wrapping component as its parentView in template blocks'); - equal(outer.parentView, view, 'x-outer receives the ambient scope as its parentView'); -}); + ['@test non-expression hasBlock ']() { + this.registerComponent('check-block', { + template: '{{#if hasBlock}}Yes{{else}}No{{/if}}' + }); -QUnit.test('components should receive the viewRegistry from the parent view', function() { - var outer, innerTemplate, innerLayout; - - var viewRegistry = {}; - - owner.register('component:x-outer', Component.extend({ - init() { - this._super(...arguments); - outer = this; - } - })); - - owner.register('component:x-inner-in-template', Component.extend({ - init() { - this._super(...arguments); - innerTemplate = this; - } - })); - - owner.register('component:x-inner-in-layout', Component.extend({ - init() { - this._super(...arguments); - innerLayout = this; - } - })); - - owner.register('template:components/x-outer', compile('{{x-inner-in-layout}}{{yield}}')); - - view = EmberView.extend({ - [OWNER]: owner, - _viewRegistry: viewRegistry, - template: compile('{{#x-outer}}{{x-inner-in-template}}{{/x-outer}}') - }).create(); - - runAppend(view); - - equal(innerTemplate._viewRegistry, viewRegistry); - equal(innerLayout._viewRegistry, viewRegistry); - equal(outer._viewRegistry, viewRegistry); -}); + this.render('{{check-block id="expect-no"}} {{#check-block id="expect-yes"}}{{/check-block}}'); -QUnit.test('comopnent should rerender when a property is changed during children\'s rendering', function() { - expectDeprecation(/modified value twice in a single render/); + this.assertTextForSelector('#expect-no', 'No'); + this.assertTextForSelector('#expect-yes', 'Yes'); + } - var outer, middle; + ['@test parameterized hasBlockParams']() { + this.registerComponent('check-params', { + template: '{{#if (hasBlockParams)}}Yes{{else}}No{{/if}}' + }); - owner.register('component:x-outer', Component.extend({ - value: 1, - grabReference: Ember.on('init', function() { - outer = this; - }) - })); + this.render('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}'); - owner.register('component:x-middle', Component.extend({ - value: null, - grabReference: Ember.on('init', function() { - middle = this; - }) - })); + this.assertTextForSelector('#expect-no', 'No'); + this.assertTextForSelector('#expect-yes', 'Yes'); + } - owner.register('component:x-inner', Component.extend({ - value: null, - pushDataUp: Ember.observer('value', function() { - middle.set('value', this.get('value')); - }) - })); + ['@test non-expression hasBlockParams']() { + this.registerComponent('check-params', { + template: '{{#if hasBlockParams}}Yes{{else}}No{{/if}}' + }); - owner.register('template:components/x-outer', compile('{{#x-middle}}{{x-inner value=value}}{{/x-middle}}')); - owner.register('template:components/x-middle', compile('
{{value}}
{{yield}}')); - owner.register('template:components/x-inner', compile('
{{value}}
')); + this.render('{{#check-params id="expect-no"}}{{/check-params}} {{#check-params id="expect-yes" as |foo|}}{{/check-params}}'); + this.assertTextForSelector('#expect-no', 'No'); + this.assertTextForSelector('#expect-yes', 'Yes'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{x-outer}}') - }).create(); + ['@test components in template of a yielding component should have the proper parentView']() { + let outer, innerTemplate, innerLayout; + + this.registerComponent('x-outer', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + outer = this; + } + }), + template: '{{x-inner-in-layout}}{{yield}}' + }); + + this.registerComponent('x-inner-in-template', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + innerTemplate = this; + } + }) + }); + + this.registerComponent('x-inner-in-layout', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + innerLayout = this; + } + }) + }); + + this.render('{{#x-outer}}{{x-inner-in-template}}{{/x-outer}}'); + + equal(innerTemplate.parentView, outer, 'receives the wrapping component as its parentView in template blocks'); + equal(innerLayout.parentView, outer, 'receives the wrapping component as its parentView in layout'); + equal(outer.parentView, this.component, 'x-outer receives the ambient scope as its parentView'); + } - runAppend(view); + ['@test newly-added sub-components get correct parentView']() { + let outer, inner; + + this.registerComponent('x-outer', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + outer = this; + } + }) + }); + + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + inner = this; + } + }) + }); + + this.render('{{#x-outer}}{{#if view.showInner}}{{x-inner}}{{/if}}{{/x-outer}}', { + showInner: false + }); + + run(() => { this.component.set('showInner', true); }); + + equal(inner.parentView, outer, 'receives the wrapping component as its parentView in template blocks'); + equal(outer.parentView, this.component, 'x-outer receives the ambient scope as its parentView'); + } - equal(view.$('#inner-value').text(), '1', 'initial render of inner'); - equal(view.$('#middle-value').text(), '', 'initial render of middle (observers do not run during init)'); + ['@test components should receive the viewRegistry from the parent view']() { + let outer, innerTemplate, innerLayout; + + let viewRegistry = {}; + + this.registerComponent('x-outer', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + outer = this; + } + }), + template: '{{x-inner-in-layout}}{{yield}}' + }); + + this.registerComponent('x-inner-in-template', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + innerTemplate = this; + } + }) + }); + + this.registerComponent('x-inner-in-layout', { + ComponentClass: Component.extend({ + init() { + this._super(...arguments); + innerLayout = this; + } + }) + }); + + this.render('{{#x-outer}}{{x-inner-in-template}}{{/x-outer}}', { + _viewRegistry: viewRegistry + }); + + equal(innerTemplate._viewRegistry, viewRegistry); + equal(innerLayout._viewRegistry, viewRegistry); + equal(outer._viewRegistry, viewRegistry); + } - run(() => outer.set('value', 2)); + ['@test comopnent should rerender when a property is changed during children\'s rendering']() { + expectDeprecation(/modified value twice in a single render/); + + let outer, middle; + + this.registerComponent('x-outer', { + ComponentClass: Component.extend({ + value: 1, + init() { + this._super(...arguments); + outer = this; + } + }), + template: '{{#x-middle}}{{x-inner value=value}}{{/x-middle}}' + }); + + this.registerComponent('x-middle', { + ComponentClass: Component.extend({ + value: null, + init() { + this._super(...arguments); + middle = this; + } + }), + template: '
{{value}}
{{yield}}' + }); + + this.registerComponent('x-inner', { + ComponentClass: Component.extend({ + value: null, + pushDataUp: Ember.observer('value', function() { + middle.set('value', this.get('value')); + }) + }), + template: '
{{value}}
' + }); + + + this.render('{{x-outer}}'); + + this.assertTextForSelector('#inner-value', '1', 'initial render of inner'); + this.assertTextForSelector('#middle-value', '', 'initial render of middle (observers do not run during init)'); + + run(() => outer.set('value', 2)); + + this.assertTextForSelector('#inner-value', '2', 'second render of inner'); + this.assertTextForSelector('#middle-value', '2', 'second render of middle'); + + run(() => outer.set('value', 3)); + + this.assertTextForSelector('#inner-value', '3', 'third render of inner'); + this.assertTextForSelector('#middle-value', '3', 'third render of middle'); + } - equal(view.$('#inner-value').text(), '2', 'second render of inner'); - equal(view.$('#middle-value').text(), '2', 'second render of middle'); + ['@test non-block with each rendering child components']() { + expect(2); - run(() => outer.set('value', 3)); + this.registerComponent('non-block', { + template: 'In layout. {{#each attrs.items as |item|}}[{{child-non-block item=item}}]{{/each}}' + }); + this.registerComponent('child-non-block', { + template: 'Child: {{attrs.item}}.' + }); - equal(view.$('#inner-value').text(), '3', 'third render of inner'); - equal(view.$('#middle-value').text(), '3', 'third render of middle'); -}); + let items = emberA(['Tom', 'Dick', 'Harry']); -QUnit.test('non-block with each rendering child components', function() { - expect(2); + this.render('{{non-block items=view.items}}', { + items: items + }); - owner.register('template:components/non-block', compile('In layout. {{#each attrs.items as |item|}}[{{child-non-block item=item}}]{{/each}}')); - owner.register('template:components/child-non-block', compile('Child: {{attrs.item}}.')); + this.assertText('In layout. [Child: Tom.][Child: Dick.][Child: Harry.]'); - var items = emberA(['Tom', 'Dick', 'Harry']); + run(() => { + items.pushObject('James'); + }); - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{non-block items=view.items}}'), - items: items - }).create(); + this.assertText('In layout. [Child: Tom.][Child: Dick.][Child: Harry.][Child: James.]'); + } - runAppend(view); + ['@test specifying classNames results in correct class'](assert) { + expect(3); - equal(jQuery('#qunit-fixture').text(), 'In layout. [Child: Tom.][Child: Dick.][Child: Harry.]'); + let clickyThing; + this.registerComponent('some-clicky-thing', { + ComponentClass: Component.extend({ + tagName: 'button', + classNames: ['foo', 'bar'], + init() { + this._super(...arguments); + clickyThing = this; + } + }) + }); - run(function() { - items.pushObject('James'); - }); + this.render('{{#some-clicky-thing classNames="baz"}}Click Me{{/some-clicky-thing}}'); - equal(jQuery('#qunit-fixture').text(), 'In layout. [Child: Tom.][Child: Dick.][Child: Harry.][Child: James.]'); -}); + let button = this.$('button'); + assert.ok(button.is('.foo.bar.baz.ember-view'), 'the element has the correct classes: ' + button.attr('class')); -QUnit.test('specifying classNames results in correct class', function(assert) { - expect(3); + let expectedClassNames = ['ember-view', 'foo', 'bar', 'baz']; + assert.deepEqual(clickyThing.get('classNames'), expectedClassNames, 'classNames are properly combined'); - let clickyThing; - owner.register('component:some-clicky-thing', Component.extend({ - tagName: 'button', - classNames: ['foo', 'bar'], - init() { - this._super(...arguments); - clickyThing = this; - } - })); + let buttonClassNames = button.attr('class'); + assert.deepEqual(buttonClassNames.split(' '), expectedClassNames, 'all classes are set 1:1 in DOM'); + } - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#some-clicky-thing classNames="baz"}}Click Me{{/some-clicky-thing}}') - }).create(); + ['@test specifying custom concatenatedProperties avoids clobbering'](assert) { + expect(1); - runAppend(view); + let clickyThing; + this.registerComponent('some-clicky-thing', { + ComponentClass: Component.extend({ + concatenatedProperties: ['blahzz'], + blahzz: ['blark', 'pory'], + init() { + this._super(...arguments); + clickyThing = this; + } + }) + }); - let button = view.$('button'); - ok(button.is('.foo.bar.baz.ember-view'), 'the element has the correct classes: ' + button.attr('class')); + this.render('{{#some-clicky-thing blahzz="baz"}}Click Me{{/some-clicky-thing}}'); - let expectedClassNames = ['ember-view', 'foo', 'bar', 'baz']; - assert.deepEqual(clickyThing.get('classNames'), expectedClassNames, 'classNames are properly combined'); + assert.deepEqual(clickyThing.get('blahzz'), ['blark', 'pory', 'baz'], 'property is properly combined'); + } - let buttonClassNames = button.attr('class'); - assert.deepEqual(buttonClassNames.split(' '), expectedClassNames, 'all classes are set 1:1 in DOM'); }); -QUnit.test('specifying custom concatenatedProperties avoids clobbering', function(assert) { - expect(1); - - let clickyThing; - owner.register('component:some-clicky-thing', Component.extend({ - concatenatedProperties: ['blahzz'], - blahzz: ['blark', 'pory'], - init() { - this._super(...arguments); - clickyThing = this; - } - })); - - view = EmberView.extend({ - [OWNER]: owner, - template: compile('{{#some-clicky-thing blahzz="baz"}}Click Me{{/some-clicky-thing}}') - }).create(); - - runAppend(view); - - assert.deepEqual(clickyThing.get('blahzz'), ['blark', 'pory', 'baz'], 'property is properly combined'); -}); diff --git a/packages/ember-runtime/tests/utils.js b/packages/ember-runtime/tests/utils.js index 2e8fa7a9b08..dd273565a22 100644 --- a/packages/ember-runtime/tests/utils.js +++ b/packages/ember-runtime/tests/utils.js @@ -1,4 +1,12 @@ +import { OWNER } from 'container/owner'; +import Component from 'ember-views/components/component'; +import ComponentLookup from 'ember-views/component_lookup'; +import buildOwner from 'container/tests/test-helpers/build-owner'; import run from 'ember-metal/run_loop'; +import symbol from 'ember-metal/symbol'; + +export const TEST_OWNER = symbol('TEST_OWNER'); +export const TEST_MAIN_COMPONENT = symbol('TEST_MAIN_COMPONENT'); function runAppend(view) { run(view, 'appendTo', '#qunit-fixture'); @@ -10,7 +18,77 @@ function runDestroy(destroyed) { } } +function moduleForApp(moduleName, options={}) { + let setup = function() { + this[TEST_OWNER] = buildOwner(); + this[TEST_OWNER].registerOptionsForType('component', { singleton: false }); + this[TEST_OWNER].registerOptionsForType('template', { instantiate: false }); + this[TEST_OWNER].register('component-lookup:main', ComponentLookup); + + this.getOwner = () => this[TEST_OWNER]; + this.register = register; + this.render = render; + this.rerender = rerender; + this.$ = customSelector; + + if (typeof options.setup === 'function') { + options.setup.apply(this, arguments); + } + }; + + let teardown = function() { + if (typeof options.teardown === 'function') { + options.teardown.apply(this, arguments); + } + + if (this[TEST_MAIN_COMPONENT]) { + runDestroy(this[TEST_MAIN_COMPONENT]); + } + + runDestroy(this[TEST_OWNER]); + + this[TEST_MAIN_COMPONENT] = this[TEST_OWNER] = null; + }; + + QUnit.module(moduleName, { + setup, + teardown + }); +} + +function register(fullName, factory, options) { + this.getOwner().register(fullName, factory, options); + return factory; +} + +function render(template, hash={}) { + if (this[TEST_MAIN_COMPONENT]) { + ok(false, 'you cannot render twice in the same test'); + return; + } + + this[TEST_MAIN_COMPONENT] = Component.extend({ + template, + [OWNER]: this.getOwner() + }).create(hash); + + runAppend(this[TEST_MAIN_COMPONENT]); + + return this[TEST_MAIN_COMPONENT]; +} + +function rerender() { + if (this[TEST_MAIN_COMPONENT]) { + run(this[TEST_MAIN_COMPONENT], 'rerender'); + } +} + +function customSelector() { + return this[TEST_MAIN_COMPONENT].$(...arguments); +} + export { + moduleForApp, runAppend, runDestroy };