Skip to content

Commit

Permalink
[PER-2252] Blob assets not being serialized by Percy (#1299)
Browse files Browse the repository at this point in the history
  • Loading branch information
shantanuk-browserstack authored Jul 7, 2023
1 parent 14191aa commit 9cdbed7
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 4 deletions.
27 changes: 24 additions & 3 deletions packages/dom/src/serialize-cssom.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,13 @@ function styleSheetsMatch(sheetA, sheetB) {
return true;
}

function createStyleResource(styleSheet) {
const styles = Array.from(styleSheet.cssRules)
.map(cssRule => cssRule.cssText).join('\n');
let resource = resourceFromText(uid(), 'text/css', styles);
return resource;
}

export function serializeCSSOM({ dom, clone, resources, cache }) {
// in-memory CSSOM into their respective DOM nodes.
for (let styleSheet of dom.styleSheets) {
Expand All @@ -35,6 +42,22 @@ export function serializeCSSOM({ dom, clone, resources, cache }) {

cloneOwnerNode.parentNode.insertBefore(style, cloneOwnerNode.nextSibling);
cloneOwnerNode.remove();
} else if (styleSheet.href?.startsWith('blob:')) {
const styleLink = document.createElement('link');
styleLink.setAttribute('rel', 'stylesheet');
let resource = createStyleResource(styleSheet);
resources.add(resource);

styleLink.setAttribute('data-percy-blob-stylesheets-serialized', 'true');
styleLink.setAttribute('data-percy-serialized-attribute-href', resource.url);

/* istanbul ignore next: tested, but coverage is stripped */
if (clone.constructor.name === 'HTMLDocument' || clone.constructor.name === 'DocumentFragment') {
// handle document and iframe
clone.body.prepend(styleLink);
} else if (clone.constructor.name === 'ShadowRoot') {
clone.prepend(styleLink);
}
}
}

Expand All @@ -45,9 +68,7 @@ export function serializeCSSOM({ dom, clone, resources, cache }) {
styleLink.setAttribute('rel', 'stylesheet');

if (!cache.has(sheet)) {
const styles = Array.from(sheet.cssRules)
.map(cssRule => cssRule.cssText).join('\n');
let resource = resourceFromText(uid(), 'text/css', styles);
let resource = createStyleResource(sheet);
resources.add(resource);
cache.set(sheet, resource.url);
}
Expand Down
54 changes: 53 additions & 1 deletion packages/dom/test/serialize-css.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { withExample, withCSSOM, parseDOM, platforms, platformDOM, createShadowEl } from './helpers';
import { when } from 'interactor.js';
import { assert, withExample, withCSSOM, parseDOM, platforms, platformDOM, createShadowEl } from './helpers';
import serializeDOM from '@percy/dom';

describe('serializeCSSOM', () => {
Expand Down Expand Up @@ -158,5 +159,56 @@ describe('serializeCSSOM', () => {
shadowEl.shadowRoot.adoptedStyleSheets = [];
shadowElChild.shadowRoot.adoptedStyleSheets = [];
});

it('captures blob styleSheets', async () => {
if (platform !== 'plain') {
return;
}
withExample('<div>BlobStyle</div>', { withShadow: false });

function generateBlobUrl(cssStyle) {
const blob = new window.Blob([cssStyle], { type: 'text/css' });
return window.URL.createObjectURL(blob);
}

function createStyleLinkElement(blobURL) {
const linkElement = dom.createElement('link');
linkElement.rel = 'stylesheet';
linkElement.type = 'text/css';
linkElement.href = blobURL;
return linkElement;
}

const cssStyle1 = '.box { height: 500px; }';
const cssStyle2 = '.box { height: 1000px; }';

const blobUrl1 = generateBlobUrl(cssStyle1);
const blobUrl2 = generateBlobUrl(cssStyle2);

const linkElement1 = createStyleLinkElement(blobUrl1);
const linkElement2 = createStyleLinkElement(blobUrl1);
const linkElement3 = createStyleLinkElement(blobUrl2);

dom.head.appendChild(linkElement1);
dom.head.appendChild(linkElement2);
dom.head.appendChild(linkElement3);

await when(() => {
assert(dom.styleSheets.length === 3);
}, 5000);
const capture = serializeDOM();
let $ = parseDOM(capture, 'plain');
expect($('body')[0].innerHTML).toMatch(
`<link rel="stylesheet" data-percy-blob-stylesheets-serialized="true" href="${capture.resources[2].url}">` +
`<link rel="stylesheet" data-percy-blob-stylesheets-serialized="true" href="${capture.resources[1].url}">` +
`<link rel="stylesheet" data-percy-blob-stylesheets-serialized="true" href="${capture.resources[0].url}">`
);

dom.head.removeChild(linkElement1);
dom.head.removeChild(linkElement2);
dom.head.removeChild(linkElement3);
URL.revokeObjectURL(blobUrl1);
URL.revokeObjectURL(blobUrl2);
});
});
});

0 comments on commit 9cdbed7

Please sign in to comment.