diff --git a/app/components/render-tree-toolbar.hbs b/app/components/render-tree-toolbar.hbs
index 145aa0b60f..d05db12c24 100644
--- a/app/components/render-tree-toolbar.hbs
+++ b/app/components/render-tree-toolbar.hbs
@@ -17,4 +17,17 @@
@value={{@searchValue}}
class="js-render-profiles-search"
/>
+ {{#if @isHighlightEnabled}}
+
+
+
+ {{/if}}
diff --git a/app/controllers/render-tree.js b/app/controllers/render-tree.js
index 2f62ff2953..2b4c639b48 100644
--- a/app/controllers/render-tree.js
+++ b/app/controllers/render-tree.js
@@ -7,9 +7,12 @@ import debounceComputed from 'ember-inspector/computed/debounce';
import { and, equal } from '@ember/object/computed';
export default Controller.extend({
+ port: service(),
+
initialEmpty: false,
- modelEmpty: equal('model.length', 0),
+ modelEmpty: equal('model.profiles.length', 0),
showEmpty: and('initialEmpty', 'modelEmpty'),
+ shouldHighlightRender: false,
/**
* Storage is needed for remembering if the user closed the warning
@@ -56,16 +59,20 @@ export default Controller.extend({
return escapeRegExp(this.search.toLowerCase());
}),
+ isHighlightEnabled: computed('model.isHighlightSupported', function () {
+ return get(this.model, 'isHighlightSupported');
+ }),
+
filtered: computed(
'escapedSearch',
- 'model.@each.name',
+ 'model.profiles.@each.name',
'search',
function () {
if (isEmpty(this.escapedSearch)) {
- return this.model;
+ return get(this.model, 'profiles');
}
- return this.model.filter((item) => {
+ return get(this.model, 'profiles').filter((item) => {
const regExp = new RegExp(this.escapedSearch);
return recursiveMatch(item, regExp);
});
@@ -75,6 +82,14 @@ export default Controller.extend({
closeWarning: action(function () {
this.set('isWarningClosed', true);
}),
+
+ updateShouldHighlightRender: action(function () {
+ const value = !this.shouldHighlightRender;
+ this.set('shouldHighlightRender', value);
+ this.port.send('render:updateShouldHighlightRender', {
+ shouldHighlightRender: value,
+ });
+ }),
});
function recursiveMatch(item, regExp) {
diff --git a/app/routes/render-tree.js b/app/routes/render-tree.js
index 14fd85d691..fe0fdaf4a0 100644
--- a/app/routes/render-tree.js
+++ b/app/routes/render-tree.js
@@ -1,4 +1,4 @@
-import { action, get, set } from '@ember/object';
+import EmberObject, { action, get, set } from '@ember/object';
import { inject as service } from '@ember/service';
import { Promise } from 'rsvp';
import TabRoute from 'ember-inspector/routes/tab';
@@ -9,9 +9,12 @@ export default class RenderTreeRoute extends TabRoute {
model() {
const port = this.port;
return new Promise(function (resolve) {
- port.one('render:profilesAdded', function (message) {
- resolve(message.profiles);
- });
+ port.one(
+ 'render:profilesAdded',
+ function ({ profiles, isHighlightSupported }) {
+ resolve(EmberObject.create({ profiles, isHighlightSupported }));
+ }
+ );
port.send('render:watchProfiles');
});
}
@@ -19,7 +22,7 @@ export default class RenderTreeRoute extends TabRoute {
setupController(controller, model) {
super.setupController(...arguments);
- if (model.length === 0) {
+ if (get(model, 'profiles.length') === 0) {
controller.set('initialEmpty', true);
}
const port = this.port;
@@ -37,16 +40,27 @@ export default class RenderTreeRoute extends TabRoute {
}
profilesUpdated(message) {
- set(this, 'controller.model', message.profiles);
+ set(this, 'controller.model.profiles', message.profiles);
}
profilesAdded(message) {
- const model = get(this, 'controller.model');
+ const currentProfiles = get(this, 'controller.model.profiles');
const profiles = message.profiles;
+ if (
+ message.isHighlightSupported !== undefined &&
+ message.isHighlightSupported !==
+ get(this, 'controller.model.isHighlightSupported')
+ ) {
+ set(
+ this,
+ 'controller.model.isHighlightSupported',
+ message.isHighlightSupported
+ );
+ }
- model.pushObjects(profiles);
- if (model.length > 100) {
- set(this, 'controller.model', model.slice(0, 100));
+ currentProfiles.pushObjects(profiles);
+ if (currentProfiles.length > 100) {
+ set(this, 'controller.model.profiles', currentProfiles.slice(0, 100));
}
}
diff --git a/app/templates/render-tree.hbs b/app/templates/render-tree.hbs
index 57b7c971db..62a0223e11 100644
--- a/app/templates/render-tree.hbs
+++ b/app/templates/render-tree.hbs
@@ -5,6 +5,9 @@
@refreshPage={{action send "refreshPage"}}
@searchValue={{this.searchValue}}
@showEmpty={{this.showEmpty}}
+ @shouldHighlightRender={{this.shouldHighlightRender}}
+ @updateShouldHighlightRender={{this.updateShouldHighlightRender}}
+ @isHighlightEnabled={{this.isHighlightEnabled}}
/>
{{/in-element}}
{{/if}}
diff --git a/ember_debug/models/profile-manager.js b/ember_debug/models/profile-manager.js
index a1debe00a7..7b76e39ab9 100644
--- a/ember_debug/models/profile-manager.js
+++ b/ember_debug/models/profile-manager.js
@@ -1,6 +1,65 @@
import ProfileNode from './profile-node';
+import Ember from '../utils/ember';
+import { compareVersion } from 'ember-debug/utils/version';
-import { later, scheduleOnce } from '../utils/ember/runloop';
+import { later, scheduleOnce, cancel } from '../utils/ember/runloop';
+
+function getEdges(first, last, closest) {
+ let start = null;
+ let end = null;
+ for (let i = 0; i < closest.length; i++) {
+ if (closest.item(i) === first.node) start = i;
+ else if (closest.item(i) === last.node) end = i;
+ }
+ return [start, end];
+}
+
+function getUnfilteredRoots(first, last, closest) {
+ if (first.node === last.node) return [first.node];
+
+ const roots = [];
+
+ const [start, end] = getEdges(first, last, closest);
+
+ if (start === null || end === null) return [];
+
+ for (let i = start; i <= end; i++) roots.push(closest.item(i));
+
+ return roots;
+}
+
+function findRoots({ first, last, parent }) {
+ const closest = parent.childNodes;
+
+ const roots = getUnfilteredRoots(first, last, closest);
+
+ return roots.filter((el) => el?.nodeType === 1);
+}
+
+function makeHighlight() {
+ const node = document.createElement('div');
+ node.setAttribute('role', 'presentation');
+ node.setAttribute('class', 'ember-inspector-render-highlight');
+ return node;
+}
+function insertHTML(node) {
+ document.body.appendChild(node);
+}
+
+function insertStylesheet() {
+ const content = `
+ .ember-inspector-render-highlight {
+ border: 2px solid rgba(255,0,0,0.2);
+ box-shadow: 0px 0px 1px rgba(255,0,0,0.2);
+ z-index: 1000000;
+ pointer-events: none;
+ }
+ `;
+ const style = document.createElement('style');
+ style.appendChild(document.createTextNode(content));
+ document.head.appendChild(style);
+ return style;
+}
/**
* A class for keeping track of active rendering profiles as a list.
@@ -12,11 +71,20 @@ export default class ProfileManager {
this.currentSet = [];
this._profilesAddedCallbacks = [];
this.queue = [];
+ this.shouldHighlightRender = false;
+ this.stylesheet = insertStylesheet();
+ // keep track of all the active highlights
+ this.highlights = [];
+ this.isHighlightEnabled = compareVersion(Ember?.VERSION, '3.20.0') !== -1;
}
began(timestamp, payload, now) {
return this.wrapForErrors(this, function () {
this.current = new ProfileNode(timestamp, payload, this.current, now);
+ if (this.shouldHighlightRender && payload.view) {
+ this._highLightView(payload.view);
+ }
+ this.current.isHighlightEnabled = this.isHighlightEnabled;
return this.current;
});
}
@@ -42,6 +110,18 @@ export default class ProfileManager {
return callback.call(context);
}
+ _highLightView(view) {
+ const symbols = Object.getOwnPropertySymbols(view);
+ const bounds = view[symbols.find((sym) => sym.description === 'BOUNDS')];
+ if (!bounds) return;
+
+ const elements = findRoots(bounds);
+
+ elements.forEach((node) => {
+ this._renderHighlight(node);
+ });
+ }
+
/**
* Push a new profile into the queue
* @param info
@@ -77,6 +157,61 @@ export default class ProfileManager {
}
}
+ teardown() {
+ this.stylesheet?.remove();
+ // remove all the active highlighted components
+ this._removeAllHighlights();
+ }
+
+ _removeAllHighlights() {
+ const els = this.highlights.slice(0);
+ els.forEach((el) => {
+ this._removeHighlight(el);
+ });
+ }
+
+ _removeHighlight(highlight) {
+ this.highlights = this.highlights.filter((item) => item !== highlight);
+ cancel(highlight.timeout);
+ highlight.el.remove();
+ }
+
+ _addHighlight(highlight) {
+ insertHTML(highlight.el);
+ this.highlights.push(highlight);
+
+ highlight.timeout = later(() => {
+ this._removeHighlight(highlight);
+ }, 500);
+ }
+
+ _constructHighlight(renderedNode) {
+ const rect = renderedNode.getBoundingClientRect();
+ const highlight = makeHighlight();
+
+ const { top, left, width, height } = rect;
+ const { scrollX, scrollY } = window;
+ const { style } = highlight;
+ if (style) {
+ style.position = 'absolute';
+ style.top = `${top + scrollY}px`;
+ style.left = `${left + scrollX}px`;
+ style.width = `${width}px`;
+ style.height = `${height}px`;
+ }
+ return highlight;
+ }
+
+ _renderHighlight(renderedNode) {
+ if (!renderedNode?.getBoundingClientRect) {
+ return;
+ }
+
+ const highlight = this._constructHighlight(renderedNode);
+
+ this._addHighlight({ el: highlight });
+ }
+
_flush() {
let entry, i;
for (i = 0; i < this.queue.length; i++) {
diff --git a/ember_debug/render-debug.js b/ember_debug/render-debug.js
index 9a1162255e..f32753a9e8 100644
--- a/ember_debug/render-debug.js
+++ b/ember_debug/render-debug.js
@@ -32,10 +32,14 @@ export default EmberObject.extend(PortMixin, {
this.profileManager.offProfilesAdded(this, this.sendAdded);
this.profileManager.offProfilesAdded(this, this._updateComponentTree);
+ this.profileManager.teardown();
},
sendAdded(profiles) {
- this.sendMessage('profilesAdded', { profiles });
+ this.sendMessage('profilesAdded', {
+ profiles,
+ isHighlightSupported: this.profileManager.isHighlightEnabled,
+ });
},
/**
@@ -62,6 +66,10 @@ export default EmberObject.extend(PortMixin, {
});
this.profileManager.onProfilesAdded(this, this.sendAdded);
},
+
+ updateShouldHighlightRender({ shouldHighlightRender }) {
+ this.profileManager.shouldHighlightRender = shouldHighlightRender;
+ },
},
});
@@ -79,7 +87,6 @@ function _subscribeToRenderEvents() {
payload,
now: Date.now(),
};
-
return profileManager.addToQueue(info);
},
diff --git a/tests/ember_debug/profile-manager-test.js b/tests/ember_debug/profile-manager-test.js
index 44eadeaa12..4f64d7192d 100644
--- a/tests/ember_debug/profile-manager-test.js
+++ b/tests/ember_debug/profile-manager-test.js
@@ -1,8 +1,565 @@
-import { test } from 'qunit';
-import ProfileManager from 'ember-debug/models/profile-manager';
+import { find, visit, waitUntil, getSettledState } from '@ember/test-helpers';
+import EmberComponent from '@ember/component';
+import GlimmerComponent from '@glimmer/component';
+import EmberRoute from '@ember/routing/route';
+import Controller from '@ember/controller';
+import { module, test } from 'qunit';
+import { hbs } from 'ember-cli-htmlbars';
+import EmberDebug from 'ember-debug/main';
+import setupEmberDebugTest from '../helpers/setup-ember-debug-test';
+import { run } from '@ember/runloop';
+import Ember from 'ember-debug/utils/ember';
+import { compareVersion } from 'ember-debug/utils/version';
-test('Ember Debug - Construction', function (assert) {
- let manager = new ProfileManager();
- assert.ok(!!manager, 'it was created');
- assert.equal(manager.profiles.length, 0, 'it has no profiles');
+const { VERSION } = Ember;
+
+const isComponentHighlightSupported = compareVersion(VERSION, '3.20.0') !== -1;
+
+const getRounded = (value) => {
+ let data = value;
+ if (typeof data === 'string') {
+ // remove unit px
+ if (data.indexOf('px') !== -1) {
+ data.replace('px', '');
+ }
+ data = parseFloat(data);
+ }
+ return Math.floor(data);
+};
+class OneRootGlimmer extends GlimmerComponent {
+ classNames = 'simple-component';
+}
+
+const mockedComponents = {
+ text: {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs('text only', {
+ moduleName: 'my-app/templates/components/text.hbs',
+ }),
+ },
+ 'text-glimmer': {
+ component: GlimmerComponent,
+ template: hbs('text only', {
+ moduleName: 'my-app/templates/components/text-glimmer.hbs',
+ }),
+ },
+ comment: {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs('', {
+ moduleName: 'my-app/templates/components/comment.hbs',
+ }),
+ },
+ 'comment-glimmer': {
+ component: GlimmerComponent,
+ template: hbs('', {
+ moduleName: 'my-app/templates/components/comment-glimmer.hbs',
+ }),
+ },
+ 'one-root': {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs('one root
', {
+ moduleName: 'my-app/templates/components/one-root.hbs',
+ }),
+ },
+ 'one-root-glimmer': {
+ component: OneRootGlimmer,
+ template: hbs('one root
', {
+ moduleName: 'my-app/templates/components/one-root-glimmer.hbs',
+ }),
+ },
+ 'two-root': {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs(
+ 'one
two
',
+ { moduleName: 'my-app/templates/components/two-root.hbs' }
+ ),
+ },
+ 'two-root-glimmer': {
+ component: GlimmerComponent,
+ template: hbs(
+ 'one
two
',
+ { moduleName: 'my-app/templates/components/two-root-glimmer.hbs' }
+ ),
+ },
+ 'root-comment-root': {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs(
+ 'one
two
',
+ { moduleName: 'my-app/templates/components/root-comment-root.hbs' }
+ ),
+ },
+ 'root-comment-root-glimmer': {
+ component: GlimmerComponent,
+ template: hbs(
+ 'one
two
',
+ {
+ moduleName: 'my-app/templates/components/root-comment-root-glimmer.hbs',
+ }
+ ),
+ },
+ 'comment-root-comment': {
+ component: EmberComponent.extend({
+ tagName: '',
+ }),
+ template: hbs(
+ 'one
',
+ { moduleName: 'my-app/templates/components/comment-root-comment.hbs' }
+ ),
+ },
+ 'comment-root-comment-glimmer': {
+ component: GlimmerComponent,
+ template: hbs(
+ 'one
',
+ { moduleName: 'my-app/templates/components/comment-root-comment.hbs' }
+ ),
+ },
+ 'div-tag': {
+ component: EmberComponent.extend({
+ classNames: ['simple-component'],
+ }),
+ template: hbs('text in div', {
+ moduleName: 'my-app/templates/components/div-tag.hbs',
+ }),
+ },
+ 'div-roots': {
+ component: EmberComponent.extend({
+ classNames: ['simple-component'],
+ }),
+ template: hbs('one
two
', {
+ moduleName: 'my-app/templates/components/div-roots.hbs',
+ }),
+ },
+};
+
+const mockedRoutes = {
+ 'text-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/text-route.hbs',
+ }),
+ expectedRender: [],
+ },
+ 'text-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/text-glimmer-route.hbs',
+ }),
+ expectedRender: [],
+ },
+ 'comment-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/comment-route.hbs',
+ }),
+ expectedRender: [],
+ },
+ 'comment-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/comment-glimmer-route.hbs',
+ }),
+ expectedRender: [],
+ },
+ 'one-root-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/one-root-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+ 'one-root-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/one-root-glimmer-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+ 'two-root-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/two-root-route.hbs',
+ }),
+ expectedRender: ['.simple-component', '.another-component'],
+ },
+ 'two-root-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/two-root-glimmer-route.hbs',
+ }),
+ expectedRender: ['.simple-component', '.another-component'],
+ },
+ 'root-comment-root-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/root-comment-root-route.hbs',
+ }),
+ expectedRender: ['.simple-component', '.another-component'],
+ },
+ 'root-comment-root-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/root-comment-root-glimmer-route.hbs',
+ }),
+ expectedRender: ['.simple-component', '.another-component'],
+ },
+ 'comment-root-comment-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/comment-root-comment-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+ 'comment-root-comment-glimmer-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/comment-root-comment-glimmer-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+ 'div-tag-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/div-tag-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+ 'div-roots-route': {
+ template: hbs('', {
+ moduleName: 'my-app/templates/div-roots-route.hbs',
+ }),
+ expectedRender: ['.simple-component'],
+ },
+};
+
+const constructBase = (owner) => {
+ owner.register('route:application', EmberRoute);
+
+ owner.register('controller:application', Controller);
+
+ owner.register(
+ 'template:application',
+ hbs(
+ '{{outlet}}
',
+ { moduleName: 'my-app/templates/application.hbs' }
+ )
+ );
+
+ owner.register('route:home', EmberRoute);
+
+ owner.register(
+ 'template:home',
+ hbs('Home', { moduleName: 'my-app/templates/home.hbs' })
+ );
+};
+
+const constructComponents = (owner, componentsMap) => {
+ for (const componentKey in componentsMap) {
+ if (componentsMap[componentKey].component) {
+ owner.register(
+ `component:${componentKey}`,
+ componentsMap[componentKey].component
+ );
+ }
+ if (componentsMap[componentKey].template) {
+ owner.register(
+ `template:components/${componentKey}`,
+ componentsMap[componentKey].template
+ );
+ }
+ }
+};
+
+const constructRoutes = (owner, routes) => {
+ routes.forEach((routeKey) => {
+ if (mockedRoutes[routeKey].route) {
+ owner.register(`route:${routeKey}`, mockedRoutes[routeKey].route);
+ }
+ if (mockedRoutes[routeKey].controller) {
+ owner.register(
+ `controller:${routeKey}`,
+ mockedRoutes[routeKey].controller
+ );
+ }
+ if (mockedRoutes[routeKey].template) {
+ owner.register(`template:${routeKey}`, mockedRoutes[routeKey].template);
+ }
+ });
+};
+
+const assertNodeSizes = (assert, synthetic, real) => {
+ const style = synthetic.style;
+ const box = real.getBoundingClientRect();
+ const dimensions = [
+ ['left', 'x'],
+ ['top', 'y'],
+ ['width', 'width'],
+ ['height', 'height'],
+ ];
+ for (const [styleKey, boxKey] of dimensions) {
+ assert.equal(
+ getRounded(style[styleKey]),
+ getRounded(box[boxKey]),
+ `same ${boxKey} as component`
+ );
+ }
+};
+
+const matchHighlights = (
+ assert,
+ testedRoute,
+ newHighlights,
+ isGlimmerComponent
+) => {
+ const renderedComponents = mockedRoutes[testedRoute].expectedRender.map(
+ (selector) => {
+ const component = find(selector);
+ assert.ok(
+ component,
+ isComponentHighlightSupported
+ ? 'expected component is rendered'
+ : 'expected component is rendered but the component highlight is not supported'
+ );
+ return component;
+ }
+ );
+
+ if (isComponentHighlightSupported && !isGlimmerComponent) {
+ renderedComponents.forEach((renderedComponent, index) => {
+ assertNodeSizes(assert, newHighlights[index], renderedComponent);
+ });
+ } else {
+ assert.notOk(
+ newHighlights.length,
+ 'Should not have any highlight if highlight is not supported'
+ );
+ }
+};
+
+const enableHighlight = () => {
+ run(() =>
+ EmberDebug.port.trigger('render:updateShouldHighlightRender', {
+ shouldHighlightRender: true,
+ })
+ );
+};
+
+async function highlightsPromise(testedRoute, isGlimmerComponent) {
+ await visit('/home');
+ enableHighlight();
+ // Glimmer component does support highlight. so there should not be any highlights
+ const numberOfHighlights = isGlimmerComponent
+ ? 0
+ : mockedRoutes[testedRoute].expectedRender.length;
+ const observedHighlights = [];
+ if (!isComponentHighlightSupported) {
+ await visit('/' + testedRoute);
+ return observedHighlights;
+ }
+ const observer = new MutationObserver(function (records) {
+ records.forEach((record) => {
+ record.addedNodes.forEach((node) => {
+ if (node.className === 'ember-inspector-render-highlight') {
+ observedHighlights.push(node);
+ }
+ });
+ });
+ });
+ observer.observe(document.body, { childList: true });
+ await visit('/' + testedRoute);
+ if (numberOfHighlights > 0) {
+ await waitUntil(() => observedHighlights.length === numberOfHighlights, {
+ timeout: 2000,
+ });
+ } else {
+ await waitUntil(() => {
+ // Check for the settled state minus hasPendingTimers
+ let { hasRunLoop, hasPendingRequests, hasPendingWaiters } =
+ getSettledState();
+ if (hasRunLoop || hasPendingRequests || hasPendingWaiters) {
+ return false;
+ }
+ return true;
+ });
+ }
+ observer.disconnect();
+ return observedHighlights;
+}
+
+module('Ember Debug - profile manager component highlight', function (hooks) {
+ setupEmberDebugTest(hooks, {
+ routes() {
+ this.route('home');
+ Object.keys(mockedRoutes).forEach((route) => {
+ this.route(route);
+ });
+ },
+ });
+
+ hooks.beforeEach(async function () {
+ EmberDebug.IGNORE_DEPRECATIONS = true;
+ constructBase(this.owner);
+ constructComponents(this.owner, mockedComponents);
+ });
+
+ hooks.afterEach(function (assert) {
+ const highlights = document.getElementsByClassName(
+ 'ember-inspector-render-highlight'
+ );
+
+ assert.notOk(
+ highlights?.length,
+ 'highlights should be destroyed after execution'
+ );
+ });
+
+ test('Should not show highlights for text component - Ember component', async function (assert) {
+ assert.expect(2);
+
+ const testedRoute = 'text-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ assert.notOk(newHighlights.length, 'should not render highlight');
+ });
+
+ test('Should not show highlights for text component - Glimmer component', async function (assert) {
+ assert.expect(2);
+
+ const testedRoute = 'text-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ assert.notOk(newHighlights.length, 'should not render highlight');
+ });
+
+ test('Should not show highlights for comment component - Ember component', async function (assert) {
+ assert.expect(2);
+
+ const testedRoute = 'comment-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ assert.notOk(newHighlights.length, 'should not render highlight');
+ });
+
+ test('Should not show highlights for comment component - Glimmer component', async function (assert) {
+ assert.expect(2);
+
+ const testedRoute = 'comment-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ assert.notOk(newHighlights.length, 'should not render highlight');
+ });
+
+ test('Should highlight one rootNode Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 6 : 3);
+
+ const testedRoute = 'one-root-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
+
+ test('Highlight is not supported, should not highlight one rootNode Glimmer component', async function (assert) {
+ assert.expect(3);
+
+ const testedRoute = 'one-root-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ matchHighlights(assert, testedRoute, newHighlights, true);
+ });
+
+ test('Should highlight two rootNode ([rootNode, rootNode] and no tagName) Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 11 : 4);
+
+ const testedRoute = 'two-root-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
+
+ test('Highlight is not supported, should not highlight two rootNode ([rootNode, rootNode] and no tagName) Glimmer component', async function (assert) {
+ assert.expect(4);
+
+ const testedRoute = 'two-root-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ matchHighlights(assert, testedRoute, newHighlights, true);
+ });
+
+ test('Should highlight two rootNode with one comment ([rootNode, commentNode, rootNode] and no tagName) Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 11 : 4);
+
+ const testedRoute = 'root-comment-root-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
+
+ test('Highlight is not supported, should not highlight two rootNode with one comment ([rootNode, commentNode, rootNode] and no tagName) Glimmer component', async function (assert) {
+ assert.expect(4);
+
+ const testedRoute = 'root-comment-root-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ matchHighlights(assert, testedRoute, newHighlights, true);
+ });
+
+ test('Should highlight one rootNode with two comment ([commentNode, rootNode, commentNode] and no tagName) Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 6 : 3);
+
+ const testedRoute = 'comment-root-comment-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
+
+ test('Highlight is not supported, should not highlight one rootNode with two comment ([commentNode, rootNode, commentNode] and no tagName) Glimmer component', async function (assert) {
+ assert.expect(3);
+
+ const testedRoute = 'comment-root-comment-glimmer-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute, true);
+
+ matchHighlights(assert, testedRoute, newHighlights, true);
+ });
+
+ test('Should highlight tagName div Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 6 : 3);
+
+ const testedRoute = 'div-tag-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
+
+ test('Should highlight two rootNode ([rootNode, rootNode] and tagName div) Ember component', async function (assert) {
+ assert.expect(isComponentHighlightSupported ? 6 : 3);
+
+ const testedRoute = 'div-roots-route';
+ constructRoutes(this.owner, [testedRoute]);
+
+ const newHighlights = await highlightsPromise(testedRoute);
+
+ matchHighlights(assert, testedRoute, newHighlights);
+ });
});