diff --git a/packages/@lwc/synthetic-shadow/src/env/element.ts b/packages/@lwc/synthetic-shadow/src/env/element.ts index dcd5054834..1449d30418 100644 --- a/packages/@lwc/synthetic-shadow/src/env/element.ts +++ b/packages/@lwc/synthetic-shadow/src/env/element.ts @@ -110,6 +110,13 @@ const shadowRootGetter: (this: Element) => ShadowRoot | null = hasOwnProperty.ca ? getOwnPropertyDescriptor(Element.prototype, 'shadowRoot')!.get! : () => null; +const assignedSlotGetter: (this: Element) => HTMLSlotElement | null = hasOwnProperty.call( + Element.prototype, + 'assignedSlot' +) + ? getOwnPropertyDescriptor(Element.prototype, 'assignedSlot')!.get! + : () => null; + export { attachShadow, childrenGetter, @@ -139,4 +146,5 @@ export { tagNameGetter, tabIndexGetter, tabIndexSetter, + assignedSlotGetter, }; diff --git a/packages/@lwc/synthetic-shadow/src/env/text.ts b/packages/@lwc/synthetic-shadow/src/env/text.ts new file mode 100644 index 0000000000..1419d31a9e --- /dev/null +++ b/packages/@lwc/synthetic-shadow/src/env/text.ts @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021, salesforce.com, inc. + * All rights reserved. + * SPDX-License-Identifier: MIT + * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT + */ + +import { hasOwnProperty, getOwnPropertyDescriptor } from '@lwc/shared'; + +export const assignedSlotGetter: (this: Text) => HTMLSlotElement | null = hasOwnProperty.call( + Text.prototype, + 'assignedSlot' +) + ? getOwnPropertyDescriptor(Text.prototype, 'assignedSlot')!.get! + : () => null; diff --git a/packages/@lwc/synthetic-shadow/src/faux-shadow/node.ts b/packages/@lwc/synthetic-shadow/src/faux-shadow/node.ts index 88f0ae8933..2bff0e6853 100644 --- a/packages/@lwc/synthetic-shadow/src/faux-shadow/node.ts +++ b/packages/@lwc/synthetic-shadow/src/faux-shadow/node.ts @@ -130,7 +130,9 @@ function parentElementGetterPatched(this: Node): Element | null { } function compareDocumentPositionPatched(this: Node, otherNode: Node) { - if (this.getRootNode() === otherNode) { + if (this === otherNode) { + return 0; + } else if (this.getRootNode() === otherNode) { // "this" is in a shadow tree where the shadow root is the "otherNode". return 10; // Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING } else if (getNodeOwnerKey(this) !== getNodeOwnerKey(otherNode)) { diff --git a/packages/@lwc/synthetic-shadow/src/faux-shadow/slot.ts b/packages/@lwc/synthetic-shadow/src/faux-shadow/slot.ts index 4e74287426..f70d4af7b6 100644 --- a/packages/@lwc/synthetic-shadow/src/faux-shadow/slot.ts +++ b/packages/@lwc/synthetic-shadow/src/faux-shadow/slot.ts @@ -17,7 +17,13 @@ import { isTrue, isUndefined, } from '@lwc/shared'; -import { getAttribute, setAttribute } from '../env/element'; +import { + getAttribute, + setAttribute, + assignedSlotGetter as originalElementAssignedSlotGetter, + shadowRootGetter, +} from '../env/element'; +import { assignedSlotGetter as originalTextAssignedSlotGetter } from '../env/text'; import { dispatchEvent } from '../env/event-target'; import { MutationObserverObserve, MutationObserver } from '../env/mutation-observer'; import { childNodesGetter, parentNodeGetter } from '../env/node'; @@ -25,6 +31,7 @@ import { assignedNodes as originalAssignedNodes, assignedElements as originalAssignedElements, } from '../env/slot'; +import { isInstanceOfNativeShadowRoot } from '../env/shadow-root'; import { isSlotElement, getNodeOwner, @@ -83,12 +90,23 @@ function getFilteredSlotFlattenNodes(slot: HTMLElement): Node[] { ); } -export function assignedSlotGetterPatched(this: Element): HTMLSlotElement | null { +export function assignedSlotGetterPatched(this: Element | Text): HTMLSlotElement | null { const parentNode = parentNodeGetter.call(this); + // use original assignedSlot if parent has a native shdow root + if (parentNode instanceof Element) { + const sr = shadowRootGetter.call(parentNode); + if (isInstanceOfNativeShadowRoot(sr)) { + if (this instanceof Text) { + return originalTextAssignedSlotGetter.call(this); + } + return originalElementAssignedSlotGetter.call(this); + } + } + /** * The node is assigned to a slot if: - * - it has a parent and it parent its parent is a slot element + * - it has a parent and its parent is a slot element * - and if the slot owner key is different than the node owner key. * * When the slot and the slotted node are 2 different shadow trees, the owner keys will be diff --git a/packages/integration-karma/test/light-dom/slotting/index.spec.js b/packages/integration-karma/test/light-dom/slotting/index.spec.js index 88b399ed6e..5e5c71c788 100644 --- a/packages/integration-karma/test/light-dom/slotting/index.spec.js +++ b/packages/integration-karma/test/light-dom/slotting/index.spec.js @@ -52,6 +52,13 @@ describe('Slotting', () => { ]); }); + it('should return null for assignedSlot of default slotted content', () => { + const nodes = createTestElement('x-dynamic-children', DynamicChildren); + + expect(nodes['container-upper-slot-default'].assignedSlot).toBeNull(); + expect(nodes['container-lower-slot-default'].assignedSlot).toBeNull(); + }); + it('shadow container, light consumer', () => { const nodes = createTestElement('x-light-consumer', LightConsumer); diff --git a/packages/integration-karma/test/light-dom/synthetic-shadow/index.spec.js b/packages/integration-karma/test/light-dom/synthetic-shadow/index.spec.js index 634c252c47..b4cb345abd 100644 --- a/packages/integration-karma/test/light-dom/synthetic-shadow/index.spec.js +++ b/packages/integration-karma/test/light-dom/synthetic-shadow/index.spec.js @@ -22,11 +22,9 @@ describe('Light DOM + Synthetic Shadow DOM', () => { expect(nodes.slot.assignedElements()).toEqual([nodes.p]); }); - if (!process.env.MIXED_SHADOW) { - it('assignedSlot', () => { - expect(nodes.p.assignedSlot).toEqual(nodes.slot); - }); - } + it('assignedSlot', () => { + expect(nodes.p.assignedSlot).toEqual(nodes.slot); + }); it('childNodes', () => { expect(Array.from(nodes.slot.childNodes)).toEqual([]); @@ -97,13 +95,9 @@ describe('Light DOM + Synthetic Shadow DOM', () => { it('assignedElements', () => { expect(nodes.slot.assignedElements()).toEqual([nodes.p]); }); - - if (!process.env.MIXED_SHADOW) { - it('assignedSlot', () => { - expect(nodes.p.assignedSlot).toEqual(nodes.slot); - }); - } - + it('assignedSlot', () => { + expect(nodes.p.assignedSlot).toEqual(nodes.slot); + }); it('childNodes', () => { expect(Array.from(nodes.slot.childNodes)).toEqual([]); }); diff --git a/packages/integration-karma/test/rendering/elements-are-not-recycled/index.spec.js b/packages/integration-karma/test/rendering/elements-are-not-recycled/index.spec.js index d3fbcd9dbf..bfb1b9059f 100644 --- a/packages/integration-karma/test/rendering/elements-are-not-recycled/index.spec.js +++ b/packages/integration-karma/test/rendering/elements-are-not-recycled/index.spec.js @@ -7,35 +7,33 @@ import Container from 'x/container'; // In the synthetic shadow however, slot content will be not be present in the DOM when not rendered. describe('custom elements', () => { - if (!process.env.MIXED_SHADOW) { - it('should not be reused when slotted', function () { - const elm = createElement('x-container', { is: Container }); - elm.isCustomElement = true; - document.body.appendChild(elm); + it('should not be reused when slotted', function () { + const elm = createElement('x-container', { is: Container }); + elm.isCustomElement = true; + document.body.appendChild(elm); - const child = elm.shadowRoot.querySelector('x-child'); - let firstRenderCustomElement; + const child = elm.shadowRoot.querySelector('x-child'); + let firstRenderCustomElement; - return Promise.resolve() - .then(() => (child.open = true)) - .then(() => { - firstRenderCustomElement = elm.shadowRoot.querySelector('x-simple'); - child.open = false; - }) - .then(() => (child.open = true)) - .then(() => { - const xSimple = elm.shadowRoot.querySelector('x-simple'); + return Promise.resolve() + .then(() => (child.open = true)) + .then(() => { + firstRenderCustomElement = elm.shadowRoot.querySelector('x-simple'); + child.open = false; + }) + .then(() => (child.open = true)) + .then(() => { + const xSimple = elm.shadowRoot.querySelector('x-simple'); - expect(xSimple).not.toBeNull(); - expect(xSimple.assignedSlot).not.toBeNull(); - expect(elm.shadowRoot.querySelector('.mark')).not.toBeNull(); + expect(xSimple).not.toBeNull(); + expect(xSimple.assignedSlot).not.toBeNull(); + expect(elm.shadowRoot.querySelector('.mark')).not.toBeNull(); - if (!process.env.NATIVE_SHADOW) { - expect(xSimple).not.toBe(firstRenderCustomElement); - } - }); - }); - } + if (!process.env.NATIVE_SHADOW) { + expect(xSimple).not.toBe(firstRenderCustomElement); + } + }); + }); }); describe('elements', () => { diff --git a/packages/integration-karma/test/shadow-dom/Element-properties/Element.assignedSlot.spec.js b/packages/integration-karma/test/shadow-dom/Element-properties/Element.assignedSlot.spec.js index 4807a999eb..6c4ed4575a 100644 --- a/packages/integration-karma/test/shadow-dom/Element-properties/Element.assignedSlot.spec.js +++ b/packages/integration-karma/test/shadow-dom/Element-properties/Element.assignedSlot.spec.js @@ -23,51 +23,45 @@ describe('assignedSlot', () => { expect(child.assignedSlot).toBe(null); }); - if (!process.env.MIXED_SHADOW) { - it('should return the correct slot when native element is slotted', () => { - const elm = createElement('x-native-slotted-component', { is: SlottedParent }); - document.body.appendChild(elm); - const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); - const child = elm.shadowRoot.querySelector('div'); - expect(child.assignedSlot).toBe(slot); - }); + it('should return the correct slot when native element is slotted', () => { + const elm = createElement('x-native-slotted-component', { is: SlottedParent }); + document.body.appendChild(elm); + const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); + const child = elm.shadowRoot.querySelector('div'); + expect(child.assignedSlot).toBe(slot); + }); - it('should return the correct slot when custom element is slotted', () => { - const elm = createElement('x-custom-slotted-component', { is: SlottedCustomElement }); - document.body.appendChild(elm); - const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); - const child = elm.shadowRoot.querySelector('x-child'); - expect(child.assignedSlot).toBe(slot); - }); + it('should return the correct slot when custom element is slotted', () => { + const elm = createElement('x-custom-slotted-component', { is: SlottedCustomElement }); + document.body.appendChild(elm); + const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); + const child = elm.shadowRoot.querySelector('x-child'); + expect(child.assignedSlot).toBe(slot); + }); - it('should return the correct named slot when native element is slotted', () => { - const elm = createElement('x-native-slotted-component', { is: SlottedParent }); - document.body.appendChild(elm); - const slot = elm.shadowRoot - .querySelector('x-named-slot') - .shadowRoot.querySelector('slot'); - const child = elm.shadowRoot.querySelector('div.named'); - expect(child.assignedSlot).toBe(slot); - }); + it('should return the correct named slot when native element is slotted', () => { + const elm = createElement('x-native-slotted-component', { is: SlottedParent }); + document.body.appendChild(elm); + const slot = elm.shadowRoot.querySelector('x-named-slot').shadowRoot.querySelector('slot'); + const child = elm.shadowRoot.querySelector('div.named'); + expect(child.assignedSlot).toBe(slot); + }); - it('should return the correct named slot when custom element is slotted', () => { - const elm = createElement('x-custom-slotted-component', { is: SlottedCustomElement }); - document.body.appendChild(elm); - const slot = elm.shadowRoot - .querySelector('x-named-slot') - .shadowRoot.querySelector('slot'); - const child = elm.shadowRoot.querySelector('x-child.named'); - expect(child.assignedSlot).toBe(slot); - }); + it('should return the correct named slot when custom element is slotted', () => { + const elm = createElement('x-custom-slotted-component', { is: SlottedCustomElement }); + document.body.appendChild(elm); + const slot = elm.shadowRoot.querySelector('x-named-slot').shadowRoot.querySelector('slot'); + const child = elm.shadowRoot.querySelector('x-child.named'); + expect(child.assignedSlot).toBe(slot); + }); - it('should return the correct slot when text is slotted', () => { - const elm = createElement('x-native-slotted-component', { is: TextSlotted }); - document.body.appendChild(elm); - const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); - const text = getHostChildNodes(elm.shadowRoot.querySelector('x-slot'))[0]; - expect(text.assignedSlot).toBe(slot); - }); - } + it('should return the correct slot when text is slotted', () => { + const elm = createElement('x-native-slotted-component', { is: TextSlotted }); + document.body.appendChild(elm); + const slot = elm.shadowRoot.querySelector('x-slot').shadowRoot.querySelector('slot'); + const text = getHostChildNodes(elm.shadowRoot.querySelector('x-slot'))[0]; + expect(text.assignedSlot).toBe(slot); + }); it('should return null when native element default slot content', () => { const elm = createElement('x-assigned-slot', { is: SlotReceiver }); diff --git a/packages/integration-karma/test/shadow-dom/Node-properties/Node.compareDocumentPosition.spec.js b/packages/integration-karma/test/shadow-dom/Node-properties/Node.compareDocumentPosition.spec.js index c0767d8d8d..94be871c80 100644 --- a/packages/integration-karma/test/shadow-dom/Node-properties/Node.compareDocumentPosition.spec.js +++ b/packages/integration-karma/test/shadow-dom/Node-properties/Node.compareDocumentPosition.spec.js @@ -31,80 +31,74 @@ describe('Node.compareDocumentPosition', () => { ).not.toBe(0); }); - if (!process.env.MIXED_SHADOW) { - it('should return the right value for nodes in the same shadow tree', () => { - const elm = createElement('x-slotted', { is: ComplexSlotted }); - document.body.appendChild(elm); + it('should return the right value for nodes in the same shadow tree', () => { + const elm = createElement('x-slotted', { is: ComplexSlotted }); + document.body.appendChild(elm); - const { shadowRoot } = elm; + const { shadowRoot } = elm; - const before = shadowRoot.querySelector('.before'); - const after = shadowRoot.querySelector('.after'); - const outer = shadowRoot.querySelector('.outer'); - const xContainer = shadowRoot.querySelector('x-container'); - const slotted = shadowRoot.querySelector('.slotted'); + const before = shadowRoot.querySelector('.before'); + const after = shadowRoot.querySelector('.after'); + const outer = shadowRoot.querySelector('.outer'); + const xContainer = shadowRoot.querySelector('x-container'); + const slotted = shadowRoot.querySelector('.slotted'); - expect(shadowRoot.compareDocumentPosition(before)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(shadowRoot.compareDocumentPosition(shadowRoot)).toBe(0); - expect(shadowRoot.compareDocumentPosition(outer)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(shadowRoot.compareDocumentPosition(xContainer)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(shadowRoot.compareDocumentPosition(slotted)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(shadowRoot.compareDocumentPosition(after)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); + expect(shadowRoot.compareDocumentPosition(before)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(shadowRoot.compareDocumentPosition(shadowRoot)).toBe(0); + expect(shadowRoot.compareDocumentPosition(outer)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(shadowRoot.compareDocumentPosition(xContainer)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(shadowRoot.compareDocumentPosition(slotted)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(shadowRoot.compareDocumentPosition(after)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); - expect(outer.compareDocumentPosition(before)).toBe(Node.DOCUMENT_POSITION_PRECEDING); - expect(outer.compareDocumentPosition(shadowRoot)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(outer.compareDocumentPosition(outer)).toBe(0); - expect(outer.compareDocumentPosition(xContainer)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(outer.compareDocumentPosition(slotted)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(outer.compareDocumentPosition(after)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); + expect(outer.compareDocumentPosition(before)).toBe(Node.DOCUMENT_POSITION_PRECEDING); + expect(outer.compareDocumentPosition(shadowRoot)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(outer.compareDocumentPosition(outer)).toBe(0); + expect(outer.compareDocumentPosition(xContainer)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(outer.compareDocumentPosition(slotted)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(outer.compareDocumentPosition(after)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); - expect(xContainer.compareDocumentPosition(before)).toBe( - Node.DOCUMENT_POSITION_PRECEDING - ); - expect(xContainer.compareDocumentPosition(shadowRoot)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(xContainer.compareDocumentPosition(outer)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(xContainer.compareDocumentPosition(xContainer)).toBe(0); - expect(xContainer.compareDocumentPosition(slotted)).toBe( - Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING - ); - expect(xContainer.compareDocumentPosition(after)).toBe( - Node.DOCUMENT_POSITION_FOLLOWING - ); + expect(xContainer.compareDocumentPosition(before)).toBe(Node.DOCUMENT_POSITION_PRECEDING); + expect(xContainer.compareDocumentPosition(shadowRoot)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(xContainer.compareDocumentPosition(outer)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(xContainer.compareDocumentPosition(xContainer)).toBe(0); + expect(xContainer.compareDocumentPosition(slotted)).toBe( + Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING + ); + expect(xContainer.compareDocumentPosition(after)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); - expect(slotted.compareDocumentPosition(before)).toBe(Node.DOCUMENT_POSITION_PRECEDING); - expect(slotted.compareDocumentPosition(shadowRoot)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(slotted.compareDocumentPosition(outer)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(slotted.compareDocumentPosition(xContainer)).toBe( - Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING - ); - expect(slotted.compareDocumentPosition(slotted)).toBe(0); - expect(slotted.compareDocumentPosition(after)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); - }); - } + expect(slotted.compareDocumentPosition(before)).toBe(Node.DOCUMENT_POSITION_PRECEDING); + expect(slotted.compareDocumentPosition(shadowRoot)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(slotted.compareDocumentPosition(outer)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(slotted.compareDocumentPosition(xContainer)).toBe( + Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING + ); + expect(slotted.compareDocumentPosition(slotted)).toBe(0); + expect(slotted.compareDocumentPosition(after)).toBe(Node.DOCUMENT_POSITION_FOLLOWING); + }); it('should return the right value for slotted node', () => { const elm = createElement('x-slotted', { is: ComplexSlotted }); diff --git a/packages/integration-karma/test/shadow-dom/event-in-shadow-tree/propagation.spec.js b/packages/integration-karma/test/shadow-dom/event-in-shadow-tree/propagation.spec.js index 7e4fe0b5fa..e9bb97db33 100644 --- a/packages/integration-karma/test/shadow-dom/event-in-shadow-tree/propagation.spec.js +++ b/packages/integration-karma/test/shadow-dom/event-in-shadow-tree/propagation.spec.js @@ -41,97 +41,95 @@ function createDisconnectedTestElement() { describe('event propagation', () => { describe('dispatched on native element', () => { - if (!process.env.MIXED_SHADOW) { - it('{bubbles: true, composed: true}', () => { - const nodes = createTestElement(); - const event = new CustomEvent('test', { bubbles: true, composed: true }); - const actualLogs = dispatchEventWithLog(nodes.button, nodes, event); + it('{bubbles: true, composed: true}', () => { + const nodes = createTestElement(); + const event = new CustomEvent('test', { bubbles: true, composed: true }); + const actualLogs = dispatchEventWithLog(nodes.button, nodes, event); - const composedPath = [ - nodes.button, - nodes.button_div, - nodes['x-button'].shadowRoot, - nodes['x-button'], - nodes.button_group_slot, - nodes.button_group_internal_slot, - nodes['x-button-group-internal'].shadowRoot, - nodes['x-button-group-internal'], - nodes.button_group_div, - nodes['x-button-group'].shadowRoot, - nodes['x-button-group'], - nodes.container_div, - nodes['x-container'].shadowRoot, - nodes['x-container'], - document.body, - document.documentElement, - document, - window, - ]; - const expectedLogs = [ - [nodes.button, nodes.button, composedPath], - [nodes.button_div, nodes.button, composedPath], - [nodes['x-button'].shadowRoot, nodes.button, composedPath], - [nodes['x-button'], nodes['x-button'], composedPath], - [nodes.button_group_slot, nodes['x-button'], composedPath], - [nodes.button_group_internal_slot, nodes['x-button'], composedPath], - [nodes['x-button-group-internal'].shadowRoot, nodes['x-button'], composedPath], - [nodes['x-button-group-internal'], nodes['x-button'], composedPath], - [nodes.button_group_div, nodes['x-button'], composedPath], - [nodes['x-button-group'].shadowRoot, nodes['x-button'], composedPath], - [nodes['x-button-group'], nodes['x-button'], composedPath], - [nodes.container_div, nodes['x-button'], composedPath], - [nodes['x-container'].shadowRoot, nodes['x-button'], composedPath], - [nodes['x-container'], nodes['x-container'], composedPath], - [document.body, nodes['x-container'], composedPath], - [document.documentElement, nodes['x-container'], composedPath], - [document, nodes['x-container'], composedPath], - [window, nodes['x-container'], composedPath], - ]; + const composedPath = [ + nodes.button, + nodes.button_div, + nodes['x-button'].shadowRoot, + nodes['x-button'], + nodes.button_group_slot, + nodes.button_group_internal_slot, + nodes['x-button-group-internal'].shadowRoot, + nodes['x-button-group-internal'], + nodes.button_group_div, + nodes['x-button-group'].shadowRoot, + nodes['x-button-group'], + nodes.container_div, + nodes['x-container'].shadowRoot, + nodes['x-container'], + document.body, + document.documentElement, + document, + window, + ]; + const expectedLogs = [ + [nodes.button, nodes.button, composedPath], + [nodes.button_div, nodes.button, composedPath], + [nodes['x-button'].shadowRoot, nodes.button, composedPath], + [nodes['x-button'], nodes['x-button'], composedPath], + [nodes.button_group_slot, nodes['x-button'], composedPath], + [nodes.button_group_internal_slot, nodes['x-button'], composedPath], + [nodes['x-button-group-internal'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-button-group-internal'], nodes['x-button'], composedPath], + [nodes.button_group_div, nodes['x-button'], composedPath], + [nodes['x-button-group'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-button-group'], nodes['x-button'], composedPath], + [nodes.container_div, nodes['x-button'], composedPath], + [nodes['x-container'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-container'], nodes['x-container'], composedPath], + [document.body, nodes['x-container'], composedPath], + [document.documentElement, nodes['x-container'], composedPath], + [document, nodes['x-container'], composedPath], + [window, nodes['x-container'], composedPath], + ]; - expect(actualLogs).toEqual(expectedLogs); - }); + expect(actualLogs).toEqual(expectedLogs); + }); - it('{bubbles: false, composed: true}', () => { - const nodes = createTestElement(); - const event = new CustomEvent('test', { bubbles: false, composed: true }); - const actualLogs = dispatchEventWithLog(nodes.button, nodes, event); + it('{bubbles: false, composed: true}', () => { + const nodes = createTestElement(); + const event = new CustomEvent('test', { bubbles: false, composed: true }); + const actualLogs = dispatchEventWithLog(nodes.button, nodes, event); - const composedPath = [ - nodes.button, - nodes.button_div, - nodes['x-button'].shadowRoot, - nodes['x-button'], - nodes.button_group_slot, - nodes.button_group_internal_slot, - nodes['x-button-group-internal'].shadowRoot, - nodes['x-button-group-internal'], - nodes.button_group_div, - nodes['x-button-group'].shadowRoot, - nodes['x-button-group'], - nodes.container_div, - nodes['x-container'].shadowRoot, - nodes['x-container'], - document.body, - document.documentElement, - document, - window, - ]; + const composedPath = [ + nodes.button, + nodes.button_div, + nodes['x-button'].shadowRoot, + nodes['x-button'], + nodes.button_group_slot, + nodes.button_group_internal_slot, + nodes['x-button-group-internal'].shadowRoot, + nodes['x-button-group-internal'], + nodes.button_group_div, + nodes['x-button-group'].shadowRoot, + nodes['x-button-group'], + nodes.container_div, + nodes['x-container'].shadowRoot, + nodes['x-container'], + document.body, + document.documentElement, + document, + window, + ]; - let expectedLogs; - if (process.env.NATIVE_SHADOW) { - expectedLogs = [ - [nodes.button, nodes.button, composedPath], - [nodes['x-button'], nodes['x-button'], composedPath], - [nodes['x-container'], nodes['x-container'], composedPath], - ]; - } else { - // TODO [#1138]: {bubbles: false, composed: true} events should invoke event listeners on ancestor hosts - expectedLogs = [[nodes.button, nodes.button, composedPath]]; - } + let expectedLogs; + if (process.env.NATIVE_SHADOW) { + expectedLogs = [ + [nodes.button, nodes.button, composedPath], + [nodes['x-button'], nodes['x-button'], composedPath], + [nodes['x-container'], nodes['x-container'], composedPath], + ]; + } else { + // TODO [#1138]: {bubbles: false, composed: true} events should invoke event listeners on ancestor hosts + expectedLogs = [[nodes.button, nodes.button, composedPath]]; + } - expect(actualLogs).toEqual(expectedLogs); - }); - } + expect(actualLogs).toEqual(expectedLogs); + }); it('{bubbles: true, composed: false}', () => { const nodes = createTestElement(); @@ -299,93 +297,91 @@ describe('event propagation', () => { }); describe('dispatched on shadow root', () => { - if (!process.env.MIXED_SHADOW) { - it('{bubbles: true, composed: true}', () => { - const nodes = createTestElement(); - const event = new CustomEvent('test', { bubbles: true, composed: true }); - const actualLogs = dispatchEventWithLog(nodes['x-button'].shadowRoot, nodes, event); + it('{bubbles: true, composed: true}', () => { + const nodes = createTestElement(); + const event = new CustomEvent('test', { bubbles: true, composed: true }); + const actualLogs = dispatchEventWithLog(nodes['x-button'].shadowRoot, nodes, event); - const composedPath = [ - nodes['x-button'].shadowRoot, - nodes['x-button'], - nodes.button_group_slot, - nodes.button_group_internal_slot, - nodes['x-button-group-internal'].shadowRoot, - nodes['x-button-group-internal'], - nodes.button_group_div, - nodes['x-button-group'].shadowRoot, - nodes['x-button-group'], - nodes.container_div, - nodes['x-container'].shadowRoot, - nodes['x-container'], - document.body, - document.documentElement, - document, - window, - ]; - const expectedLogs = [ + const composedPath = [ + nodes['x-button'].shadowRoot, + nodes['x-button'], + nodes.button_group_slot, + nodes.button_group_internal_slot, + nodes['x-button-group-internal'].shadowRoot, + nodes['x-button-group-internal'], + nodes.button_group_div, + nodes['x-button-group'].shadowRoot, + nodes['x-button-group'], + nodes.container_div, + nodes['x-container'].shadowRoot, + nodes['x-container'], + document.body, + document.documentElement, + document, + window, + ]; + const expectedLogs = [ + [nodes['x-button'].shadowRoot, nodes['x-button'].shadowRoot, composedPath], + [nodes['x-button'], nodes['x-button'], composedPath], + [nodes.button_group_slot, nodes['x-button'], composedPath], + [nodes.button_group_internal_slot, nodes['x-button'], composedPath], + [nodes['x-button-group-internal'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-button-group-internal'], nodes['x-button'], composedPath], + [nodes.button_group_div, nodes['x-button'], composedPath], + [nodes['x-button-group'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-button-group'], nodes['x-button'], composedPath], + [nodes.container_div, nodes['x-button'], composedPath], + [nodes['x-container'].shadowRoot, nodes['x-button'], composedPath], + [nodes['x-container'], nodes['x-container'], composedPath], + [document.body, nodes['x-container'], composedPath], + [document.documentElement, nodes['x-container'], composedPath], + [document, nodes['x-container'], composedPath], + [window, nodes['x-container'], composedPath], + ]; + + expect(actualLogs).toEqual(expectedLogs); + }); + + it('{bubbles: false, composed: true}', () => { + const nodes = createTestElement(); + const event = new CustomEvent('test', { bubbles: false, composed: true }); + const actualLogs = dispatchEventWithLog(nodes['x-button'].shadowRoot, nodes, event); + + const composedPath = [ + nodes['x-button'].shadowRoot, + nodes['x-button'], + nodes.button_group_slot, + nodes.button_group_internal_slot, + nodes['x-button-group-internal'].shadowRoot, + nodes['x-button-group-internal'], + nodes.button_group_div, + nodes['x-button-group'].shadowRoot, + nodes['x-button-group'], + nodes.container_div, + nodes['x-container'].shadowRoot, + nodes['x-container'], + document.body, + document.documentElement, + document, + window, + ]; + + let expectedLogs; + if (process.env.NATIVE_SHADOW) { + expectedLogs = [ [nodes['x-button'].shadowRoot, nodes['x-button'].shadowRoot, composedPath], [nodes['x-button'], nodes['x-button'], composedPath], - [nodes.button_group_slot, nodes['x-button'], composedPath], - [nodes.button_group_internal_slot, nodes['x-button'], composedPath], - [nodes['x-button-group-internal'].shadowRoot, nodes['x-button'], composedPath], - [nodes['x-button-group-internal'], nodes['x-button'], composedPath], - [nodes.button_group_div, nodes['x-button'], composedPath], - [nodes['x-button-group'].shadowRoot, nodes['x-button'], composedPath], - [nodes['x-button-group'], nodes['x-button'], composedPath], - [nodes.container_div, nodes['x-button'], composedPath], - [nodes['x-container'].shadowRoot, nodes['x-button'], composedPath], [nodes['x-container'], nodes['x-container'], composedPath], - [document.body, nodes['x-container'], composedPath], - [document.documentElement, nodes['x-container'], composedPath], - [document, nodes['x-container'], composedPath], - [window, nodes['x-container'], composedPath], ]; - - expect(actualLogs).toEqual(expectedLogs); - }); - - it('{bubbles: false, composed: true}', () => { - const nodes = createTestElement(); - const event = new CustomEvent('test', { bubbles: false, composed: true }); - const actualLogs = dispatchEventWithLog(nodes['x-button'].shadowRoot, nodes, event); - - const composedPath = [ - nodes['x-button'].shadowRoot, - nodes['x-button'], - nodes.button_group_slot, - nodes.button_group_internal_slot, - nodes['x-button-group-internal'].shadowRoot, - nodes['x-button-group-internal'], - nodes.button_group_div, - nodes['x-button-group'].shadowRoot, - nodes['x-button-group'], - nodes.container_div, - nodes['x-container'].shadowRoot, - nodes['x-container'], - document.body, - document.documentElement, - document, - window, + } else { + expectedLogs = [ + [nodes['x-button'].shadowRoot, nodes['x-button'].shadowRoot, composedPath], + [nodes['x-button'], nodes['x-button'], composedPath], ]; + } - let expectedLogs; - if (process.env.NATIVE_SHADOW) { - expectedLogs = [ - [nodes['x-button'].shadowRoot, nodes['x-button'].shadowRoot, composedPath], - [nodes['x-button'], nodes['x-button'], composedPath], - [nodes['x-container'], nodes['x-container'], composedPath], - ]; - } else { - expectedLogs = [ - [nodes['x-button'].shadowRoot, nodes['x-button'].shadowRoot, composedPath], - [nodes['x-button'], nodes['x-button'], composedPath], - ]; - } - - expect(actualLogs).toEqual(expectedLogs); - }); - } + expect(actualLogs).toEqual(expectedLogs); + }); it('{bubbles: true, composed: false}', () => { const nodes = createTestElement(); diff --git a/packages/integration-karma/test/synthetic-shadow/element-api/element-api.spec.js b/packages/integration-karma/test/synthetic-shadow/element-api/element-api.spec.js index 67c6b1d20f..6ed0a10603 100644 --- a/packages/integration-karma/test/synthetic-shadow/element-api/element-api.spec.js +++ b/packages/integration-karma/test/synthetic-shadow/element-api/element-api.spec.js @@ -403,3 +403,25 @@ if (!process.env.NATIVE_SHADOW) { }); }); } + +if (!process.env.COMPAT) { + describe('synthetic shadow for mixed mode', () => { + describe('Element.prototype API', () => { + it('should preseve assignedSlot behavior', () => { + const div = document.createElement('div'); + document.body.appendChild(div); + + div.attachShadow({ mode: 'open' }).innerHTML = ` + + `; + + const slotted = document.createElement('div'); + slotted.textContent = 'slotted'; + div.appendChild(slotted); + + const assignedSlot = div.shadowRoot.querySelector('slot'); + expect(slotted.assignedSlot).toBe(assignedSlot); + }); + }); + }); +}