chrome-devtools-frontend
Version:
Chrome DevTools UI
242 lines (215 loc) • 8.9 kB
text/typescript
// Copyright 2023 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {renderElementIntoDOM} from '../../testing/DOMHelpers.js';
import * as VisualLogging from './visual_logging-testing.js';
describe('DomState', () => {
let container: HTMLElement;
beforeEach(() => {
container = document.createElement('div');
renderElementIntoDOM(container);
});
const el = (id: string, d: Document|ShadowRoot = document) => d.getElementById(id) as Element;
it('gets loggable elements and their parents', () => {
container.innerHTML = `
<div id="1">
<div jslog="TreeItem" id="11">
<div id="111">
<div jslog="TreeItem" id="1111">
<div jslog="TreeItem" id="11111"></div>
</div>
<div jslog="TreeItem" id="1112"></div>
</div>
<div id="112"><span>hello</span></div>
<div jslog="TreeItem" id="113"></div>
</div>
<div id="12">
<div jslog="TreeItem" id="121">
<div jslog="TreeItem" id="1211"></div>
</div>
</div>
<div>
<div jslog="TreeItem" id="2"></div>`;
const {loggables} = VisualLogging.DomState.getDomState([document]);
assert.sameDeepMembers(loggables, [
{element: el('2'), parent: undefined},
{element: el('121'), parent: undefined},
{element: el('1211'), parent: el('121')},
{element: el('11'), parent: undefined},
{element: el('113'), parent: el('11')},
{element: el('1112'), parent: el('11')},
{element: el('1111'), parent: el('11')},
{element: el('11111'), parent: el('1111')},
]);
});
it('returns element in a BFS order', () => {
container.innerHTML = `
<li jslog="TreeItem" id="1">
</li>
<ol>
<li jslog="TreeItem" id="11">
</li>
<li jslog="TreeItem" id="12">
</ol>
<li jslog="TreeItem" id="2">
</li>
<ol>
<li jslog="TreeItem" id="21">
</li>
<li jslog="TreeItem" id="22">
</li>
</li>
</ol>`;
const {loggables} = VisualLogging.DomState.getDomState([document]);
assert.deepEqual(loggables, [
{element: el('1'), parent: undefined},
{element: el('2'), parent: undefined},
{element: el('11'), parent: undefined},
{element: el('12'), parent: undefined},
{element: el('21'), parent: undefined},
{element: el('22'), parent: undefined},
]);
});
it('gets loggable elements across documents', () => {
container.innerHTML = `
<div jslog="TreeItem" id="1"></div>
<iframe id="iframe"></iframe>`;
const iframe = el('iframe') as HTMLIFrameElement;
const iframeDocument = iframe.contentDocument;
assert.exists(iframeDocument);
iframeDocument.body.innerHTML = `
<div jslog="TreeItem" id="2"></div>`;
const {loggables} = VisualLogging.DomState.getDomState([document, iframeDocument]);
assert.sameDeepMembers(loggables, [
{element: el('1'), parent: undefined},
{element: el('2', iframeDocument), parent: undefined},
]);
});
it('identifies parents across shadow DOM', () => {
container.innerHTML = `
<div jslog="TreeItem" id="1">
<div jslog="TreeItem" id="12"></div>
<div id="13"></div>
</div>`;
const shadow = el('13').attachShadow({mode: 'open'});
const shadowContent = document.createElement('div');
shadowContent.innerHTML = `
<div id="131">
<div jslog="TreeItem" id="1311"></div>
</div>`;
shadow.appendChild(shadowContent);
const {loggables} = VisualLogging.DomState.getDomState([document]);
assert.sameDeepMembers(loggables, [
{element: el('1'), parent: undefined},
{element: el('1311', shadow), parent: el('1')},
{element: el('12'), parent: el('1')},
]);
});
it('walks slots in the assigned order and ignores the rest of light DOM', () => {
class TestComponent extends HTMLElement {
private render() {
const shadow = this.attachShadow({mode: 'open'});
shadow.innerHTML = `
<div jslog="TreeItem" id="c1"><slot id="slot-1" name="slot-1"></slot></div>
<div jslog="TreeItem" id="c2"><slot id="slot-2" name="slot-2"></slot></div>`;
}
connectedCallback() {
this.render();
}
}
customElements.define('ve-test-component', class extends TestComponent {});
container.innerHTML = `
<div id="0" jslog="TreeItem">
<ve-test-component id="1" jslog="TreeItem">
<div jslog="TreeItem" id="11" slot="slot-1">
<div id="111" jslog="TreeItem"></div>
</div>
<div id="12" slot="slot-2" jslog="TreeItem"></div>
<div id="13" jslog="TreeItem"></div>
</ve-test-component>
</div>`;
const {loggables} = VisualLogging.DomState.getDomState([document]);
const shadow = el('1').shadowRoot as ShadowRoot;
assert.sameDeepMembers(loggables, [
{element: el('0'), parent: undefined},
{element: el('1'), parent: el('0')},
{element: el('c1', shadow), parent: el('1')},
{element: el('11'), parent: el('c1', shadow)},
{element: el('111'), parent: el('11')},
{element: el('c2', shadow), parent: el('1')},
{element: el('12'), parent: el('c2', shadow)},
]);
});
it('ignores template elements', () => {
container.innerHTML = `
<template jslog="TreeItem">
<div jslog="TreeItem" id="11" slot="slot-1">
<div id="111" jslog="TreeItem"></div>
</div>
<div id="12" slot="slot-2" jslog="TreeItem">
<div id="13" jslog="TreeItem">
</div>`;
const {loggables} = VisualLogging.DomState.getDomState([document]);
assert.isEmpty(loggables);
});
it('returns shadow roots', () => {
container.innerHTML = `
<div id="1">
<div class="shadow" id="11"></div>
</div>
<div class="shadow" id="2"></div>`;
const addedShadowRoots: ShadowRoot[] = [];
const attachShadows = (el: HTMLElement|ShadowRoot) => {
for (const target of el.querySelectorAll('.shadow')) {
const shadow = target.attachShadow({mode: 'open'});
const content = document.createElement('div');
content.innerHTML = '<div></div><div class="shadow></div>';
shadow.appendChild(content);
addedShadowRoots.push(shadow);
}
};
attachShadows(container);
for (const shadow of addedShadowRoots) {
attachShadows(shadow);
}
const {shadowRoots} = VisualLogging.DomState.getDomState([document]);
assert.sameDeepMembers(shadowRoots, addedShadowRoots);
});
it('identifies visible elements', () => {
container.innerHTML = `
<style>
.box {
position: absolute;
height: 100px;
width: 100px;
}
</style>
<div id="1" class="box" style="left: 50px; top: 0;"></div>
<div id="2" class="box" style="left: 0; top: 50px;"></div>`;
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(0, 0, 200, 200)), new DOMRect(50, 0, 100, 100));
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(0, 0, 200, 200)), new DOMRect(0, 50, 100, 100));
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(0, 0, 100, 100)), new DOMRect(50, 0, 50, 100));
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(0, 0, 100, 100)), new DOMRect(0, 50, 100, 50));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(0, 0, 50, 50)));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(0, 0, 50, 50)));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(0, 0, 50, 100)));
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(0, 0, 50, 100)), new DOMRect(0, 50, 50, 50));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(25, 25, 25, 50)));
assert.deepEqual(
VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(25, 25, 25, 50)), new DOMRect(25, 50, 25, 25));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(25, 25, 30, 30)));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(25, 25, 30, 30)));
});
it('identifies small visible elements', () => {
container.innerHTML = `
<div id="1" class="box" style="width: 100px; height: 5px;"></div>
<div id="2" class="box" style="width: 0; height: 5px;"></div>`;
assert.isNotNull(VisualLogging.DomState.visibleOverlap(el('1'), new DOMRect(0, 0, 200, 200)));
assert.isNull(VisualLogging.DomState.visibleOverlap(el('2'), new DOMRect(0, 0, 200, 200)));
});
});