Skip to content

Commit

Permalink
Shadowroot support using getHTML (#1795)
Browse files Browse the repository at this point in the history
* Shadowroot support using getHTML

* Removing backward compatability for getInnerHTML

* Removing checks for innerHTML

* Adding back the backward compatability for tests

* Fixing Test Coverage
  • Loading branch information
Amit3200 authored Nov 26, 2024
1 parent 160670d commit 58cbca4
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 13 deletions.
19 changes: 15 additions & 4 deletions packages/dom/src/clone-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ export function cloneNodeAndShadow(ctx) {
clone.shadowRoot.innerHTML = '';
} else {
clone.attachShadow({
mode: 'open'
mode: 'open',
serializable: true
});
}
// clone dom elements
Expand Down Expand Up @@ -84,10 +85,20 @@ export function cloneNodeAndShadow(ctx) {
* Use `getInnerHTML()` to serialize shadow dom as <template> tags. `innerHTML` and `outerHTML` don't do this. Buzzword: "declarative shadow dom"
*/
export function getOuterHTML(docElement) {
// firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
if (!docElement.getInnerHTML) { return docElement.outerHTML; }
// All major browsers in latest versions supports getHTML API to get serialized DOM
// https://developer.mozilla.org/en-US/docs/Web/API/Element/getHTML
// old firefox doesn't serialize shadow DOM, we're awaiting API's by firefox to become ready and are not polyfilling it.
// new firefox from 128 onwards serializes it using getHTML
/* istanbul ignore if: Only triggered in firefox <= 128 and tests runs on latest */
if (!docElement.getHTML) { return docElement.outerHTML; }
// chromium gives us declarative shadow DOM serialization API
let innerHTML = docElement.getInnerHTML({ includeShadowRoots: true });
let innerHTML = '';
/* istanbul ignore else if: Only triggered in chrome <= 128 and tests runs on latest */
if (docElement.getHTML) {
innerHTML = docElement.getHTML({ serializableShadowRoots: true });
} else if (docElement.getInnerHTML) {
innerHTML = docElement.getInnerHTML({ includeShadowRoots: true });
}
docElement.textContent = '';
// Note: Here we are specifically passing replacer function to avoid any replacements due to
// special characters in client's dom like $&
Expand Down
6 changes: 3 additions & 3 deletions packages/dom/test/serialize-css.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('serializeCSSOM', () => {
}]));

expect(resultShadowEl.innerHTML).toEqual([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-0</p>',
'</template>'
Expand Down Expand Up @@ -157,14 +157,14 @@ describe('serializeCSSOM', () => {
const resultShadowElChild = $('#Percy-1')[0];

expect(resultShadowEl.innerHTML).toMatch([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-0</p>',
'</template>'
].join(''));

expect(resultShadowElChild.innerHTML).toMatch([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[1].url}">`,
`<link rel="stylesheet" data-percy-adopted-stylesheets-serialized="true" href="${capture.resources[0].url}">`,
'<p>Percy-1</p>',
Expand Down
12 changes: 6 additions & 6 deletions packages/dom/test/serialize-dom.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe('serializeDOM', () => {
shadow.appendChild(paragraphEl);

const html = serializeDOM().html;
expect(html).toMatch('<template shadowrootmode="open">');
expect(html).toMatch('<template shadowrootmode="open" shadowrootserializable="">');
expect(html).toMatch('Hey Percy!');
});

Expand Down Expand Up @@ -162,10 +162,10 @@ describe('serializeDOM', () => {
const html = serializeDOM().html;

expect(html).toMatch(new RegExp([
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
'<p>Percy-1</p>',
'<div id="Percy-2" .*>',
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
'<p>Percy-2</p>',
'</template>'
].join('')));
Expand Down Expand Up @@ -193,7 +193,7 @@ describe('serializeDOM', () => {
el = newEl;
matchRegex += [
`<div id="Percy-${j}" .*>`,
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<p>Percy-${j}</p>`
].join('');
}
Expand All @@ -218,7 +218,7 @@ describe('serializeDOM', () => {
baseContent.appendChild(newEl);
matchRegex += [
`<div id="Percy-${j}" .*>`,
'<template shadowrootmode="open">',
'<template shadowrootmode="open" shadowrootserializable="">',
`<p>Percy-${j}</p>`,
'</template>',
'</div>'
Expand Down Expand Up @@ -251,7 +251,7 @@ describe('serializeDOM', () => {
constructor() {
super();
// Create a shadow root
const shadow = this.shadowRoot || this.attachShadow({ mode: 'open' });
const shadow = this.shadowRoot || this.attachShadow({ mode: 'open', serializable: true });
const wrapper = document.createElement('h2');
wrapper.innerText = 'Test';
shadow.appendChild(wrapper);
Expand Down

0 comments on commit 58cbca4

Please sign in to comment.