Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion packages/dom/src/serialize-frames.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
import serializeDOM from './serialize-dom';

let policy = null;

export function resetPolicy() {
policy = null;
}

function getPolicy() {
if (typeof window !== 'undefined' && window.trustedTypes && window.trustedTypes.createPolicy) {
if (policy && policy.createHTML) return policy;

try {
policy = window.trustedTypes.createPolicy('percy-dom', {
// codeql[js/dom-text-reinterpreted-as-html]
createHTML: html => html
});
} catch (e) {
// ignore
}
/* istanbul ignore next */
return policy || {};
}
}

// Adds a `<base>` element to the serialized iframe's `<head>`. This is necessary when
// embedded documents are serialized and their contents become root-relative.
function setBaseURI(dom) {
Expand Down Expand Up @@ -46,7 +69,11 @@ export function serializeFrames({ dom, clone, warnings, resources, enableJavaScr
for (let r of serialized.resources) resources.add(r);

// assign serialized html to srcdoc and remove src
cloneEl.setAttribute('srcdoc', serialized.html);
let p = getPolicy() || {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also was checking if site has specific CSP even though you add this it will have no impact and will still break.
Instead can we have catch block for TrustedHTML issue to continue with serialization even though we are not able to serialize iframe?, this will not cause failures for Website Scanner in that case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, it fixes it but we see that few resources are missing in that case. It might happen that some iframe or asset do not load in that case. added a try catch to catch this.

try {
cloneEl.setAttribute('srcdoc', p.createHTML ? p.createHTML(serialized.html) : serialized.html);
} catch {}

cloneEl.removeAttribute('src');

// delete inaccessible frames built with js when js is disabled because they
Expand Down
31 changes: 30 additions & 1 deletion packages/dom/test/serialize-frames.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { when } from 'interactor.js';
import { assert, withExample, parseDOM, platforms, platformDOM, getTestBrowser, chromeBrowser, firefoxBrowser } from './helpers';
import serializeDOM from '@percy/dom';
import serializeDOM from '../src/serialize-dom';
import { resetPolicy } from '../src/serialize-frames';

describe('serializeFrames', () => {
let serialized, cache = { shadow: {}, plain: {} };
Expand Down Expand Up @@ -159,5 +160,33 @@ describe('serializeFrames', () => {
it(`${platform}: removes inaccessible JS frames`, () => {
expect($('#frame-inject')).toHaveSize(0);
});

if (platform === 'plain') {
it('uses Trusted Types policy to create srcdoc when available', () => {
let createHTML = jasmine.createSpy('createHTML').and.callFake(html => html);
let createPolicy = jasmine.createSpy('createPolicy').and.returnValue({ createHTML });
let trustedTypesDescriptor = Object.getOwnPropertyDescriptor(window, 'trustedTypes');

// Reset policy to ensure we don't use a cached version from a previous test/environment
resetPolicy();

Object.defineProperty(window, 'trustedTypes', {
value: { createPolicy },
configurable: true
});

try {
serializeDOM();
expect(createPolicy).toHaveBeenCalledWith('percy-dom', jasmine.objectContaining({ createHTML: jasmine.any(Function) }));
expect(createHTML).toHaveBeenCalled();
} finally {
if (trustedTypesDescriptor) {
Object.defineProperty(window, 'trustedTypes', trustedTypesDescriptor);
} else {
delete window.trustedTypes;
}
}
});
}
});
});
Loading