UNPKG

@lion/ui

Version:

A package of extendable web components

226 lines (208 loc) 9.1 kB
import { expect, fixture } from '@open-wc/testing'; import { html } from 'lit'; import { deepContains } from '@lion/ui/overlays.js'; describe('deepContains()', () => { it('returns true if element contains a target element with a shadow boundary in between', async () => { const shadowElement = /** @type {HTMLElement} */ (await fixture('<div id="shadow"></div>')); const shadowRoot = shadowElement.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <button id="el-1">Button</button> <a id="el-2" href="#foo">Href</a> <input id="el-3"> `; const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-1')); const element = /** @type {HTMLElement} */ ( await fixture(html` <div id="light"> ${shadowElement} <button id="light-el-1">Button</button> </div> `) ); const lightChildEl = /** @type {HTMLElement} */ (element.querySelector('#light-el-1')); expect(deepContains(element, element)).to.be.true; expect(deepContains(element, shadowElement)).to.be.true; expect(deepContains(element, shadowElementChild)).to.be.true; expect(deepContains(element, lightChildEl)).to.be.true; expect(deepContains(shadowElement, shadowElement)).to.be.true; expect(deepContains(shadowElement, shadowElementChild)).to.be.true; expect(deepContains(shadowRoot, shadowElementChild)).to.be.true; // Siblings expect( deepContains( /** @type {HTMLElement} */ (element.firstElementChild), /** @type {HTMLElement} */ (element.lastElementChild), ), ).to.be.false; // Unrelated expect(deepContains(lightChildEl, shadowElementChild)).to.be.false; }); it('returns true if element contains a target element with a shadow boundary in between, for multiple shadowroots', async () => { const shadowElement = /** @type {HTMLElement} */ (await fixture('<div id="shadow"></div>')); const shadowRoot = shadowElement.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <button id="el-1">Button</button> <a id="el-2" href="#foo">Href</a> <input id="el-3"> `; const shadowElement2 = /** @type {HTMLElement} */ (await fixture('<div id="shadow2"></div>')); const shadowRoot2 = shadowElement2.attachShadow({ mode: 'open' }); shadowRoot2.innerHTML = ` <button id="el-1">Button</button> <a id="el-2" href="#foo">Href</a> <input id="el-3"> `; const shadowElementChild = /** @type {HTMLElement} */ (shadowRoot.querySelector('#el-2')); const shadowElementChild2 = /** @type {HTMLElement} */ (shadowRoot2.querySelector('#el-2')); const element = /** @type {HTMLElement} */ ( await fixture(html` <div id="light"> ${shadowElement} ${shadowElement2} <button id="light-el-1">Button</button> </div> `) ); expect(deepContains(element, shadowElementChild)).to.be.true; expect(deepContains(shadowElement, shadowElementChild)).to.be.true; expect(deepContains(shadowRoot, shadowElementChild)).to.be.true; expect(deepContains(element, shadowElementChild2)).to.be.true; expect(deepContains(shadowElement2, shadowElementChild2)).to.be.true; expect(deepContains(shadowRoot2, shadowElementChild2)).to.be.true; }); it('can detect containing elements inside multiple nested shadow roots', async () => { const shadowNestedElement = await fixture('<div id="shadow-nested"></div>'); const shadowNestedRoot = shadowNestedElement.attachShadow({ mode: 'open' }); shadowNestedRoot.innerHTML = ` <button id="nested-el-1">Button</button> <a id="nested-el-2" href="#foo">Href</a> <input id="nested-el-3"> `; const shadowElement = /** @type {HTMLElement} */ (await fixture('<div id="shadow"></div>')); const shadowRoot = shadowElement.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <button id="el-1">Button</button> <input id="el-3"> `; shadowRoot.insertBefore(shadowNestedElement, shadowRoot.lastElementChild); const element = /** @type {HTMLElement} */ ( await fixture(html` <div id="light"> ${shadowElement} <button id="light-el-1">Button</button> </div> `) ); const elementFirstChild = /** @type {HTMLElement} */ (element.firstElementChild); const elementFirstChildShadow = /** @type {ShadowRoot} */ (elementFirstChild.shadowRoot); const elementFirstChildShadowChildren = /** @type {HTMLElement[]} */ ( Array.from(elementFirstChildShadow.children) ); const elementFirstChildShadowChildShadow = /** @type {ShadowRoot} */ ( elementFirstChildShadowChildren[1].shadowRoot ); const elementFirstChildShadowChildShadowLastChild = /** @type {HTMLElement} */ ( elementFirstChildShadowChildShadow.lastElementChild ); expect(deepContains(element, elementFirstChild)).to.be.true; expect(deepContains(element, elementFirstChildShadow)).to.be.true; expect(deepContains(element, elementFirstChildShadowChildren[1])).to.be.true; expect(deepContains(element, elementFirstChildShadowChildShadow)).to.be.true; expect(deepContains(element, elementFirstChildShadowChildShadowLastChild)).to.be.true; }); it('returns true if the element, which is located in ShadowsRoot, contains a target element, located in the LightDom', async () => { const mainElement = /** @type {HTMLElement} */ (await fixture('<div id="main"></div>')); mainElement.innerHTML = ` <div slot="content" id="light-el-content"> <input type="text" id="light-el-input-1"></input> </div> <div slot="content" id="light-el-content"> <input type="text" id="light-el-input-2"></input> </div> `; const shadowRoot = mainElement.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = ` <div id="dialog-wrapper"> <div id="dialog-header"> Header </div> <div id="dialog-content"> <slot name="content" id="shadow-el-content"></slot> </div> </div> `; const inputElement = /** @type {HTMLElement} */ ( mainElement.querySelector('#light-el-input-2') ); const dialogWrapperElement = /** @type {HTMLElement} */ ( shadowRoot.querySelector('#dialog-wrapper') ); expect(deepContains(dialogWrapperElement, inputElement)).to.be.true; }); it(`returns true if the element, which is located in ShadowRoot, contains a target element, located in the ShadowRoot element of the LightDom element `, async () => { /** * The DOM for the `main` element looks as follows: * * <div id="main"> * #shadow-root * <div id="dialog-wrapper"> // dialogWrapperElement * <div id="dialog-header"> * Header * </div> * <div id="dialog-content"> * <slot name="content" id="shadow-el-content"></slot> * </div> * </div> * <div slot="content" id="light-el-content"> * <div id="conent-wrapper"> * #shadow-root * <div id="conent-wrapper-sub"> * #shadow-root * <input type="type" id="content-input"></input> //inputElement * </div> * </div> * </div> * </div> */ const mainElement = /** @type {HTMLElement} */ (await fixture('<div id="main"></div>')); mainElement.innerHTML = ` <div slot="content" id="light-el-content"> <div id="content-wrapper"></div> </div> <div slot="content" id="light-el-content"> <div id="content-wrapper"></div> </div> `; const contentWrapper = /** @type {HTMLElement} */ ( mainElement.querySelector('#content-wrapper') ); const contentWrapperShadowRoot = contentWrapper.attachShadow({ mode: 'open' }); contentWrapperShadowRoot.innerHTML = ` <div id="conent-wrapper-sub"></div> `; const contentWrapperSub = /** @type {HTMLElement} */ ( contentWrapperShadowRoot.querySelector('#conent-wrapper-sub') ); const contentWrapperSubShadowRoot = contentWrapperSub.attachShadow({ mode: 'open' }); contentWrapperSubShadowRoot.innerHTML = ` <input type="type" id="content-input"></input> `; const inputElement = /** @type {HTMLElement} */ ( contentWrapperSubShadowRoot.querySelector('#content-input') ); const mainElementShadowRoot = mainElement.attachShadow({ mode: 'open' }); mainElementShadowRoot.innerHTML = ` <div id="dialog-wrapper"> <div id="dialog-header"> Header </div> <div id="dialog-content"> <slot name="content" id="shadow-el-content"></slot> </div> </div> `; const dialogWrapperElement = /** @type {HTMLElement} */ ( mainElementShadowRoot.querySelector('#dialog-wrapper') ); expect(deepContains(dialogWrapperElement, inputElement)).to.be.true; }); });