diff --git a/packages/ember-glimmer/tests/integration/components/local-lookup-test.js b/packages/ember-glimmer/tests/integration/components/local-lookup-test.js new file mode 100644 index 00000000000..e53d1aeef45 --- /dev/null +++ b/packages/ember-glimmer/tests/integration/components/local-lookup-test.js @@ -0,0 +1,120 @@ +import { moduleFor, RenderingTest } from '../../utils/test-case'; + +// copied from ember-htmlbars/tests/integration/local-lookup-test.js +function buildResolver() { + let resolver = { + resolve() { }, + expandLocalLookup(fullName, sourceFullName) { + let [sourceType, sourceName ] = sourceFullName.split(':'); + let [type, name ] = fullName.split(':'); + + if (type !== 'template' && sourceType === 'template' && sourceName.slice(0, 11) === 'components/') { + sourceName = sourceName.slice(11); + } + + if (type === 'template' && sourceType === 'template' && name.slice(0, 11) === 'components/') { + name = name.slice(11); + } + + + let result = `${type}:${sourceName}/${name}`; + + return result; + } + }; + + return resolver; +} + +moduleFor('Components test: local lookup', class extends RenderingTest { + getOwnerOptions() { + return { + _registryOptions: { + resolver: buildResolver() + } + }; + } + + ['@htmlbars it can lookup a local template']() { + this.registerComponent('x-outer/x-inner', { template: 'Nested template says: {{yield}}' }); + this.registerComponent('x-outer', { template: '{{#x-inner}}Hi!{{/x-inner}}' }); + + this.render('{{x-outer}}'); + + this.assertText('Nested template says: Hi!', 'Initial render works'); + + this.runTask(() => this.rerender()); + + this.assertText('Nested template says: Hi!', 'Re-render works'); + } + + ['@htmlbars it can lookup a local component template']() { + this.registerTemplate('components/x-outer/x-inner', 'Nested template says: {{yield}}'); + this.registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); + + this.render('{{x-outer}}'); + + this.assertText('Nested template says: Hi!', 'Initial render works'); + + this.runTask(() => this.rerender()); + + this.assertText('Nested template says: Hi!', 'Re-render works'); + } + + ['@htmlbars it can lookup a local helper']() { + this.registerHelper('x-outer/x-helper', () => { + return 'Who dis?'; + }); + this.registerComponent('x-outer', { template: 'Who dat? {{x-helper}}' }); + + this.render('{{x-outer}}'); + + this.assertText('Who dat? Who dis?', 'Initial render works'); + + this.runTask(() => this.rerender()); + + this.assertText('Who dat? Who dis?', 'Re-render works'); + } + + ['@htmlbars it overrides global helper lookup']() { + this.registerHelper('x-outer/x-helper', () => { + return 'Who dis?'; + }); + + this.registerHelper('x-helper', () => { + return 'I dunno'; + }); + + this.registerComponent('x-outer', { template: 'Who dat? {{x-helper}}' }); + + this.render('{{x-outer}} {{x-helper}}'); + + this.assertText('Who dat? Who dis? I dunno', 'Initial render works'); + + this.runTask(() => this.rerender()); + + this.assertText('Who dat? Who dis? I dunno', 'Re-render works'); + } + + ['@htmlbars lookup without match issues standard assertion (with local helper name)']() { + this.registerComponent('x-outer', { template: '{{#x-inner}}Hi!{{/x-inner}}' }); + + expectAssertion(() => { + this.render('{{x-outer}}'); + }, /A helper named 'x-inner' could not be found/); + } + + ['@htmlbars overrides global lookup']() { + this.registerComponent('x-outer', { template: '{{#x-inner}}Hi!{{/x-inner}}' }); + this.registerComponent('x-outer/x-inner', { template: 'Nested template says (from local): {{yield}}' }); + this.registerComponent('x-inner', { template: 'Nested template says (from global): {{yield}}' }); + + this.render('{{#x-inner}}Hi!{{/x-inner}} {{x-outer}} {{#x-outer/x-inner}}Hi!{{/x-outer/x-inner}}'); + + this.assertText('Nested template says (from global): Hi! Nested template says (from local): Hi! Nested template says (from local): Hi!'); + + this.runTask(() => this.rerender()); + + this.assertText('Nested template says (from global): Hi! Nested template says (from local): Hi! Nested template says (from local): Hi!'); + } +}); diff --git a/packages/ember-glimmer/tests/utils/abstract-test-case.js b/packages/ember-glimmer/tests/utils/abstract-test-case.js index ae30f660b30..2eaea6e8d19 100644 --- a/packages/ember-glimmer/tests/utils/abstract-test-case.js +++ b/packages/ember-glimmer/tests/utils/abstract-test-case.js @@ -264,7 +264,9 @@ export class ApplicationTest extends TestCase { } registerTemplate(name, template) { - this.application.register(`template:${name}`, compile(template)); + this.application.register(`template:${name}`, compile(template, { + moduleName: name + })); } registerController(name, controller) { @@ -276,13 +278,17 @@ export class RenderingTest extends TestCase { constructor() { super(); let dom = new DOMHelper(document); - let owner = this.owner = buildOwner(); + let owner = this.owner = buildOwner(this.getOwnerOptions()); let env = this.env = new Environment({ dom, owner, [OWNER]: owner }); this.renderer = InteractiveRenderer.create({ dom, env, [OWNER]: owner }); this.element = jQuery('#qunit-fixture')[0]; this.component = null; } + getOwnerOptions() { + return {}; + } + teardown() { if (this.component) { runDestroy(this.component); @@ -297,7 +303,9 @@ export class RenderingTest extends TestCase { render(templateStr, context = {}) { let { renderer, owner } = this; - owner.register('template:-top-level', compile(templateStr)); + owner.register('template:-top-level', compile(templateStr, { + moduleName: '-top-level' + })); let attrs = assign({}, context, { tagName: '', @@ -347,7 +355,20 @@ export class RenderingTest extends TestCase { } if (typeof template === 'string') { - owner.register(`template:components/${name}`, compile(template)); + owner.register(`template:components/${name}`, compile(template, { + moduleName: `components/${name}` + })); + } + } + + registerTemplate(name, template) { + let { owner } = this; + if (typeof template === 'string') { + owner.register(`template:${name}`, compile(template, { + moduleName: name + })); + } else { + throw new Error(`Registered template "${name}" must be a string`); } } diff --git a/packages/ember-htmlbars/lib/hooks/component.js b/packages/ember-htmlbars/lib/hooks/component.js index 8e759cb93b4..e23acba5f18 100644 --- a/packages/ember-htmlbars/lib/hooks/component.js +++ b/packages/ember-htmlbars/lib/hooks/component.js @@ -53,6 +53,8 @@ export default function componentHook(renderNode, env, scope, _tagName, params, // Determine if this is an initial render or a re-render. if (state.manager) { + let templateMeta = state.manager.block.template.meta; + env.meta.moduleName = (templateMeta && templateMeta.moduleName) || (env.meta && env.meta.moduleName); state.manager.rerender(env, attrs, visitor); return; } diff --git a/packages/ember-htmlbars/tests/integration/local-lookup-test.js b/packages/ember-htmlbars/tests/integration/local-lookup-test.js deleted file mode 100644 index f4d4cffee13..00000000000 --- a/packages/ember-htmlbars/tests/integration/local-lookup-test.js +++ /dev/null @@ -1,179 +0,0 @@ -import isEnabled from 'ember-metal/features'; -import EmberView from 'ember-views/views/view'; -import compile from 'ember-template-compiler/system/compile'; -import ComponentLookup from 'ember-views/component_lookup'; -import Component from 'ember-views/components/component'; -import { helper } from 'ember-htmlbars/helper'; -import { runAppend, runDestroy } from 'ember-runtime/tests/utils'; -import buildOwner from 'container/tests/test-helpers/build-owner'; -import { OWNER } from 'container/owner'; - -var owner, view; - -function buildResolver() { - let resolver = { - resolve() { }, - expandLocalLookup(fullName, sourceFullName) { - let [sourceType, sourceName ] = sourceFullName.split(':'); - let [type, name ] = fullName.split(':'); - - if (type !== 'template' && sourceType === 'template' && sourceName.slice(0, 11) === 'components/') { - sourceName = sourceName.slice(11); - } - - if (type === 'template' && sourceType === 'template' && name.slice(0, 11) === 'components/') { - name = name.slice(11); - } - - - let result = `${type}:${sourceName}/${name}`; - - return result; - } - }; - - return resolver; -} - -function commonSetup() { - owner = buildOwner({ - _registryOptions: { - resolver: buildResolver() - } - }); - owner.registerOptionsForType('component', { singleton: false }); - owner.registerOptionsForType('view', { singleton: false }); - owner.registerOptionsForType('template', { instantiate: false }); - owner.register('component-lookup:main', ComponentLookup); -} - -function commonTeardown() { - runDestroy(view); - runDestroy(owner); - owner = view = null; -} - -function appendViewFor(template, moduleName='', hash={}) { - let view = EmberView.extend({ - template: compile(template, { moduleName }), - [OWNER]: owner - }).create(hash); - - runAppend(view); - - return view; -} - -function registerTemplate(moduleName, snippet) { - owner.register(`template:${moduleName}`, compile(snippet, { moduleName })); -} - -function registerComponent(name, factory) { - owner.register(`component:${name}`, factory); -} - -function registerHelper(name, helper) { - owner.register(`helper:${name}`, helper); -} - -if (!isEnabled('ember-glimmer')) { - // jscs:disable - -QUnit.module('component - local lookup', { - setup() { - commonSetup(); - }, - - teardown() { - commonTeardown(); - } -}); - -if (isEnabled('ember-htmlbars-local-lookup')) { - // jscs:disable validateIndentation - -QUnit.test('local component lookup with matching template', function() { - expect(1); - - registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); - registerTemplate('components/x-outer/x-inner', 'Nested template says: {{yield}}'); - - view = appendViewFor(`{{x-outer}}`, 'route-template'); - - equal(view.$().text(), 'Nested template says: Hi!'); -}); - -QUnit.test('local component lookup with matching component', function() { - expect(1); - - registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); - registerComponent('x-outer/x-inner', Component.extend({ - tagName: 'span' - })); - - view = appendViewFor(`{{x-outer}}`, 'route-template'); - - equal(view.$('span').text(), 'Hi!'); -}); - -QUnit.test('local helper lookup', function() { - expect(1); - - registerTemplate('components/x-outer', 'Who dat? {{x-helper}}'); - registerHelper('x-outer/x-helper', helper(() => { - return 'Who dis?'; - })); - - view = appendViewFor(`{{x-outer}}`, 'route-template'); - - equal(view.$().text(), 'Who dat? Who dis?'); -}); - -QUnit.test('local helper lookup overrides global lookup', function() { - expect(1); - - registerTemplate('components/x-outer', 'Who dat? {{x-helper}}'); - registerHelper('x-outer/x-helper', helper(() => 'Who dis?')); - registerHelper('x-helper', helper(() => 'I dunno')); - - view = appendViewFor(`{{x-outer}} {{x-helper}}`, 'route-template'); - - equal(view.$().text(), 'Who dat? Who dis? I dunno'); -}); - -QUnit.test('lookup without match issues standard assertion (with local helper name)', function() { - expect(1); - - registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); - - expectAssertion(function() { - appendViewFor(`{{x-outer}}`, 'route-template'); - }, /A helper named 'x-inner' could not be found/); -}); - -QUnit.test('local lookup overrides global lookup', function() { - expect(1); - - registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); - registerTemplate('components/x-outer/x-inner', 'Nested template says (from local): {{yield}}'); - registerTemplate('components/x-inner', 'Nested template says (from global): {{yield}}'); - - view = appendViewFor(`{{#x-inner}}Hi!{{/x-inner}} {{x-outer}} {{#x-outer/x-inner}}Hi!{{/x-outer/x-inner}}`, 'route-template'); - - equal(view.$().text(), 'Nested template says (from global): Hi! Nested template says (from local): Hi! Nested template says (from local): Hi!'); -}); -} else { - QUnit.test('lookup with both global and local match uses specifically invoked component', function() { - expect(1); - - registerTemplate('components/x-outer', '{{#x-inner}}Hi!{{/x-inner}}'); - registerTemplate('components/x-outer/x-inner', 'Nested template says (from local): {{yield}}'); - registerTemplate('components/x-inner', 'Nested template says (from global): {{yield}}'); - - view = appendViewFor(`{{#x-inner}}Hi!{{/x-inner}} {{x-outer}} {{#x-outer/x-inner}}Hi!{{/x-outer/x-inner}}`, 'route-template'); - - equal(view.$().text(), 'Nested template says (from global): Hi! Nested template says (from global): Hi! Nested template says (from local): Hi!'); - }); -} - -}