diff --git a/packages/ember-glimmer/lib/environment.js b/packages/ember-glimmer/lib/environment.js index 97047a7998f..0abca7bbc2a 100644 --- a/packages/ember-glimmer/lib/environment.js +++ b/packages/ember-glimmer/lib/environment.js @@ -1,5 +1,5 @@ import { guidFor, OWNER } from 'ember-utils'; -import { Cache } from 'ember-metal'; +import { Cache, _instrumentStart } from 'ember-metal'; import { assert, warn } from 'ember-debug'; import { DEBUG } from 'ember-env-flags'; import { EMBER_NO_DOUBLE_EXTEND } from 'ember/features'; @@ -56,6 +56,10 @@ import { FACTORY_FOR } from 'container'; import { default as ActionModifierManager } from './modifiers/action'; +function instrumentationPayload(name) { + return { object: `component:${name}` }; +} + export default class Environment extends GlimmerEnvironment { static create(options) { return new Environment(options); @@ -147,11 +151,13 @@ export default class Environment extends GlimmerEnvironment { getComponentDefinition(path, symbolTable) { let name = path[0]; + let finalizer = _instrumentStart('render.getComponentDefinition', instrumentationPayload, name); let blockMeta = symbolTable.getMeta(); let owner = blockMeta.owner; let source = blockMeta.moduleName && `template:${blockMeta.moduleName}`; - - return this._definitionCache.get({ name, source, owner }); + let definition = this._definitionCache.get({ name, source, owner }); + finalizer(); + return definition; } // normally templates should be exported at the proper module name diff --git a/packages/ember-glimmer/tests/integration/components/instrumentation-compile-test.js b/packages/ember-glimmer/tests/integration/components/instrumentation-compile-test.js new file mode 100644 index 00000000000..48835d37b6a --- /dev/null +++ b/packages/ember-glimmer/tests/integration/components/instrumentation-compile-test.js @@ -0,0 +1,97 @@ +import { moduleFor, RenderingTest } from '../../utils/test-case'; +import { Component } from '../../utils/helpers'; +import { + instrumentationSubscribe, + instrumentationReset, + set +} from 'ember-metal'; + +moduleFor('Components compile instrumentation', class extends RenderingTest { + constructor() { + super(); + + this.resetEvents(); + + instrumentationSubscribe('render.getComponentDefinition', { + before: (name, timestamp, payload) => { + if (payload.view !== this.component) { + this.actual.before.push(payload); + } + }, + after: (name, timestamp, payload) => { + if (payload.view !== this.component) { + this.actual.after.push(payload); + } + } + }); + } + + resetEvents() { + this.expected = { + before: [], + after: [] + }; + + this.actual = { + before: [], + after: [] + }; + } + + teardown() { + this.assert.deepEqual(this.actual.before, [], 'No unexpected events (before)'); + this.assert.deepEqual(this.actual.after, [], 'No unexpected events (after)'); + super.teardown(); + instrumentationReset(); + } + + ['@test it should only receive an instrumentation event for initial render'](assert) { + let testCase = this; + + let BaseClass = Component.extend({ + tagName: '', + + willRender() { + testCase.expected.before.push(this); + testCase.expected.after.unshift(this); + } + }); + + this.registerComponent('x-bar', { + template: '[x-bar: {{bar}}]', + ComponentClass: BaseClass.extend() + }); + + this.render(`[-top-level: {{foo}}] {{x-bar bar=bar}}`, { + foo: 'foo', bar: 'bar' + }); + + this.assertText('[-top-level: foo] [x-bar: bar]'); + + this.assertEvents('after initial render'); + + this.runTask(() => this.rerender()); + + this.assertEvents('after no-op rerender'); + } + + assertEvents(label) { + let { actual, expected } = this; + this.assert.strictEqual(actual.before.length, actual.after.length, `${label}: before and after callbacks should be balanced`); + + this._assertEvents(`${label} (before):`, actual.before, expected.before); + this._assertEvents(`${label} (after):`, actual.before, expected.before); + + this.resetEvents(); + } + + _assertEvents(label, actual, expected) { + this.assert.equal(actual.length, expected.length, `${label}: expected ${expected.length} and got ${actual.length}`); + + actual.forEach((payload, i) => this.assertPayload(payload, expected[i])); + } + + assertPayload(payload, component) { + this.assert.equal(payload.object, component._debugContainerKey, 'payload.object'); + } +});