Record when a doc is in compatMode and trigger this mode upon replay (#697)
* Hygiene: clean up the xhtml namespace attribute; this is an artefact of the `serializeToString` method which we are using (I think) to be consistent with whitespace and to clean up invalid attributes. I'm removing as was confused as am adding tests related to doctypes * Record when a document is in `compatMode` and trigger this mode on the iframe upon replay https://developer.mozilla.org/en-US/docs/Web/API/Document/compatMode the included DOCTYPE was picked up from https://stackoverflow.com/questions/18976213/ - there may be better ways of triggering compatMode * Don't write an extra DOCTYPE if there's one already present in the snapshot. Rely instead on whatever doctype is there to trigger the BackCompat mode * Modify to write the correct doctype if we can sniff xhtml - don't have any evidence that this will make a difference * Dev convenience: Ignore files generated by editors * Typo fix * Was getting a 2000ms timeout on the 'before' hook I believe * Change certain tests to go directly to their localhost page instead of loading the html content programmatically in order to avoid triggering an incorrect BackCompat mode (incorrect in that the html content has a correct doctype) * Add test based on motivating site that had images lined up in a square which were all different sizes; very old style percentage width/height attributes were doing the right thing in quirksmode, which is what we are testing for here * Fixup rrweb test html to include a valid doctype and avoid BackCompat to ensure we're not accidentally testing against quirks modes. I didn't find an elegant way of avoiding the `BackCompat` when adding a minimal iframe, so some BackCompat has slipped in here, I don't think there's much harm
This commit is contained in:
@@ -321,6 +321,20 @@ export function buildNodeWithSN(
|
||||
// close before open to make sure document was closed
|
||||
doc.close();
|
||||
doc.open();
|
||||
if (n.compatMode === 'BackCompat' &&
|
||||
(n.childNodes && n.childNodes[0].type !== NodeType.DocumentType) // there isn't one already defined
|
||||
) {
|
||||
// Trigger compatMode in the iframe
|
||||
// this is needed as document.createElement('iframe') otherwise inherits a CSS1Compat mode from the parent replayer environment
|
||||
if (n.childNodes[0].type === NodeType.Element &&
|
||||
'xmlns' in n.childNodes[0].attributes &&
|
||||
n.childNodes[0].attributes.xmlns === 'http://www.w3.org/1999/xhtml') {
|
||||
// might as well use an xhtml doctype if we've got an xhtml namespace
|
||||
doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">');
|
||||
} else {
|
||||
doc.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "">');
|
||||
}
|
||||
}
|
||||
node = doc;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
MaskTextFn,
|
||||
MaskInputFn,
|
||||
KeepIframeSrcFn,
|
||||
documentNode,
|
||||
} from './types';
|
||||
import { isElement, isShadowRoot, maskInputValue } from './utils';
|
||||
|
||||
@@ -379,11 +380,20 @@ function serializeNode(
|
||||
}
|
||||
switch (n.nodeType) {
|
||||
case n.DOCUMENT_NODE:
|
||||
return {
|
||||
type: NodeType.Document,
|
||||
childNodes: [],
|
||||
rootId,
|
||||
};
|
||||
if ((n as HTMLDocument).compatMode !== 'CSS1Compat') {
|
||||
return {
|
||||
type: NodeType.Document,
|
||||
childNodes: [],
|
||||
compatMode: (n as HTMLDocument).compatMode, // probably "BackCompat"
|
||||
rootId,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: NodeType.Document,
|
||||
childNodes: [],
|
||||
rootId,
|
||||
}
|
||||
}
|
||||
case n.DOCUMENT_TYPE_NODE:
|
||||
return {
|
||||
type: NodeType.DocumentType,
|
||||
|
||||
@@ -10,6 +10,7 @@ export enum NodeType {
|
||||
export type documentNode = {
|
||||
type: NodeType.Document;
|
||||
childNodes: serializedNodeWithId[];
|
||||
compatMode?: string;
|
||||
};
|
||||
|
||||
export type documentTypeNode = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`[html file]: about-mozilla.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head>
|
||||
"<!DOCTYPE html><html><head>
|
||||
<title>The Book of Mozilla, 11:9</title>
|
||||
<style type=\\"text/css\\">
|
||||
html {
|
||||
@@ -40,7 +40,7 @@ exports[`[html file]: about-mozilla.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: basic.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -50,7 +50,7 @@ exports[`[html file]: basic.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: block-element.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -74,8 +74,22 @@ exports[`[html file]: block-element.html 1`] = `
|
||||
</body></html>"
|
||||
`;
|
||||
|
||||
exports[`[html file]: compat-mode.html 1`] = `
|
||||
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><!-- no doctype! --><html><head>
|
||||
<title>Compat Mode; image resizing</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<a href=\\"http://localhost:3030/html#\\" class=\\"should-be-square-shaped\\">
|
||||
<img width=\\"40%\\" height=\\"35%\\" src=\\"http://localhost:3030/images/compat-top-left.png\\" />
|
||||
<img width=\\"40%\\" height=\\"35%\\" src=\\"http://localhost:3030/images/compat-top-right.png\\" />
|
||||
<br /><img width=\\"80%\\" height=\\"20%\\" src=\\"http://localhost:3030/images/compat-bottom.png\\" /></a>
|
||||
</center>
|
||||
</body></html>"
|
||||
`;
|
||||
|
||||
exports[`[html file]: cors-style-sheet.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -87,7 +101,7 @@ exports[`[html file]: cors-style-sheet.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: dynamic-stylesheet.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -101,7 +115,7 @@ exports[`[html file]: dynamic-stylesheet.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: form-fields.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -135,7 +149,7 @@ exports[`[html file]: form-fields.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: hover.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -158,7 +172,7 @@ exports[`[html file]: hover.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: iframe.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -170,17 +184,17 @@ exports[`[html file]: iframe.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: iframe-inner.html 1`] = `
|
||||
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body><button>inner iframe button</button>
|
||||
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><html><head></head><body><button>inner iframe button</button>
|
||||
</body></html>"
|
||||
`;
|
||||
|
||||
exports[`[html file]: invalid-attribute.html 1`] = `
|
||||
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\" foo=\\"bar\\"><head></head><body>
|
||||
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><html foo=\\"bar\\"><head></head><body>
|
||||
</body></html>"
|
||||
`;
|
||||
|
||||
exports[`[html file]: invalid-doctype.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<title>Invalid Doctype</title>
|
||||
@@ -189,7 +203,7 @@ exports[`[html file]: invalid-doctype.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: invalid-tagname.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -203,7 +217,7 @@ exports[`[html file]: invalid-tagname.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: mask-text.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -218,7 +232,7 @@ exports[`[html file]: mask-text.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: picture.html 1`] = `
|
||||
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
|
||||
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\"><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
|
||||
<picture>
|
||||
<source type=\\"image/webp\\" srcset=\\"http://localhost:3030/assets/img/characters/robot.webp\\" />
|
||||
<img src=\\"http://localhost:3030/assets/img/characters/robot.png\\" />
|
||||
@@ -227,7 +241,7 @@ exports[`[html file]: picture.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: preload.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<title>Document</title>
|
||||
@@ -238,7 +252,7 @@ exports[`[html file]: preload.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: shadow-dom.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<title>shadow DOM</title>
|
||||
@@ -257,7 +271,7 @@ exports[`[html file]: shadow-dom.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: video.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -272,7 +286,7 @@ exports[`[html file]: video.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: with-relative-res.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -292,7 +306,7 @@ exports[`[html file]: with-relative-res.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: with-script.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -303,7 +317,7 @@ exports[`[html file]: with-script.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: with-style-sheet.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -314,7 +328,7 @@ exports[`[html file]: with-style-sheet.html 1`] = `
|
||||
`;
|
||||
|
||||
exports[`[html file]: with-style-sheet-with-import.html 1`] = `
|
||||
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
|
||||
"<!DOCTYPE html><html lang=\\"en\\"><head>
|
||||
<meta charset=\\"UTF-8\\" />
|
||||
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
|
||||
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
|
||||
@@ -456,7 +470,7 @@ exports[`iframe integration tests 1`] = `
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`shadown DOM integration tests 1`] = `
|
||||
exports[`shadow DOM integration tests 1`] = `
|
||||
"{
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
|
||||
14
packages/rrweb-snapshot/test/html/compat-mode.html
Normal file
14
packages/rrweb-snapshot/test/html/compat-mode.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!-- no doctype! -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Compat Mode; image resizing</title>
|
||||
</head>
|
||||
<body>
|
||||
<center>
|
||||
<a href="#" class="should-be-square-shaped">
|
||||
<img width="40%" height="35%" src="/images/compat-top-left.png">
|
||||
<img width="40%" height="35%" src="/images/compat-top-right.png">
|
||||
<br><img width="80%" height="20%" src="/images/compat-bottom.png"></a>
|
||||
</center>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,4 @@
|
||||
<html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body>
|
||||
<picture>
|
||||
<source type="image/webp" srcset="assets/img/characters/robot.webp" />
|
||||
|
||||
BIN
packages/rrweb-snapshot/test/images/compat-bottom.png
Normal file
BIN
packages/rrweb-snapshot/test/images/compat-bottom.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
packages/rrweb-snapshot/test/images/compat-top-left.png
Normal file
BIN
packages/rrweb-snapshot/test/images/compat-top-left.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
BIN
packages/rrweb-snapshot/test/images/compat-top-right.png
Normal file
BIN
packages/rrweb-snapshot/test/images/compat-top-right.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
@@ -74,6 +74,8 @@ interface ISuite extends Suite {
|
||||
}
|
||||
|
||||
describe('integration tests', function (this: ISuite) {
|
||||
this.timeout(10_000);
|
||||
|
||||
before(async () => {
|
||||
this.server = await server();
|
||||
this.browser = await puppeteer.launch({
|
||||
@@ -97,32 +99,84 @@ describe('integration tests', function (this: ISuite) {
|
||||
});
|
||||
|
||||
for (const html of htmls) {
|
||||
if (html.filePath.substring(html.filePath.length - 1) === '~') {
|
||||
continue;
|
||||
}
|
||||
const title = '[html file]: ' + html.filePath;
|
||||
it(title, async () => {
|
||||
const page: puppeteer.Page = await this.browser.newPage();
|
||||
// console for debug
|
||||
// tslint:disable-next-line: no-console
|
||||
page.on('console', (msg) => console.log(msg.text()));
|
||||
await page.goto(`http://localhost:3030/html`);
|
||||
await page.setContent(html.src, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
if (html.filePath === 'iframe.html') {
|
||||
// loading directly is needed to ensure we don't trigger compatMode='BackCompat'
|
||||
// which happens before setContent can be called
|
||||
await page.goto(`http://localhost:3030/html/${html.filePath}`, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
const outerCompatMode = await page.evaluate('document.compatMode');
|
||||
const innerCompatMode = await page.evaluate('document.querySelector("iframe").contentDocument.compatMode');
|
||||
assert(outerCompatMode === 'CSS1Compat', outerCompatMode + ' for outer iframe.html should be CSS1Compat as it has "<!DOCTYPE html>"');
|
||||
// inner omits a doctype so gets rendered in backwards compat mode
|
||||
// although this was originally accidental, we'll add a synthetic doctype to the rebuild to recreate this
|
||||
assert(innerCompatMode === 'BackCompat', innerCompatMode + ' for iframe-inner.html should be BackCompat as it lacks "<!DOCTYPE html>"');
|
||||
} else {
|
||||
// loading indirectly is improtant for relative path testing
|
||||
await page.goto(`http://localhost:3030/html`);
|
||||
await page.setContent(html.src, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
}
|
||||
const rebuildHtml = (
|
||||
await page.evaluate(`${this.code}
|
||||
const x = new XMLSerializer();
|
||||
const [snap] = rrweb.snapshot(document);
|
||||
x.serializeToString(rrweb.rebuild(snap, { doc: document })[0]);
|
||||
let out = x.serializeToString(rrweb.rebuild(snap, { doc: document })[0]);
|
||||
if (document.querySelector('html').getAttribute('xmlns') !== 'http://www.w3.org/1999/xhtml') {
|
||||
// this is just an artefact of serializeToString
|
||||
out = out.replace(' xmlns=\"http://www.w3.org/1999/xhtml\"', '');
|
||||
}
|
||||
out; // return
|
||||
`)
|
||||
).replace(/\n\n/g, '');
|
||||
const result = matchSnapshot(rebuildHtml, __filename, title);
|
||||
assert(result.pass, result.pass ? '' : result.report());
|
||||
}).timeout(5000);
|
||||
}
|
||||
|
||||
it('correctly triggers backCompat mode and rendering', async () => {
|
||||
const page: puppeteer.Page = await this.browser.newPage();
|
||||
// console for debug
|
||||
// tslint:disable-next-line: no-console
|
||||
page.on('console', (msg) => console.log(msg.text()));
|
||||
|
||||
await page.goto('http://localhost:3030/html/compat-mode.html', {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
const compatMode = await page.evaluate('document.compatMode');
|
||||
assert(compatMode === 'BackCompat', compatMode + ' for compat-mode.html should be BackCompat as DOCTYPE is deliberately omitted');
|
||||
const renderedHeight = await page.evaluate('document.querySelector("center").clientHeight');
|
||||
// can remove following assertion if dimensions of page change
|
||||
assert(renderedHeight < 400, `pre-check: images will be rendered ~326px high in BackCompat mode, and ~588px in CSS1Compat mode; getting: ${renderedHeight}px`)
|
||||
const rebuildRenderedHeight = await page.evaluate(`${this.code}
|
||||
const [snap] = rrweb.snapshot(document);
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.setAttribute('width', document.body.clientWidth)
|
||||
iframe.setAttribute('height', document.body.clientHeight)
|
||||
iframe.style.transform = 'scale(0.3)'; // mini-me
|
||||
document.body.appendChild(iframe);
|
||||
// magic here! rebuild in a new iframe
|
||||
const rebuildNode = rrweb.rebuild(snap, { doc: iframe.contentDocument })[0];
|
||||
iframe.contentDocument.querySelector('center').clientHeight
|
||||
`);
|
||||
const rebuildCompatMode = await page.evaluate('document.querySelector("iframe").contentDocument.compatMode');
|
||||
assert(rebuildCompatMode === 'BackCompat', 'rebuilt compatMode should match source compatMode, but doesn\'t: ' + rebuildCompatMode);
|
||||
assert(rebuildRenderedHeight === renderedHeight, 'rebuilt height (${rebuildRenderedHeight}) should equal original height (${renderedHeight})')
|
||||
}).timeout(5000);
|
||||
|
||||
});
|
||||
|
||||
describe('iframe integration tests', function (this: ISuite) {
|
||||
const iframeHtml = path.join(__dirname, 'iframe-html/main.html');
|
||||
const raw = fs.readFileSync(iframeHtml, 'utf-8');
|
||||
|
||||
before(async () => {
|
||||
this.server = await server();
|
||||
@@ -151,8 +205,7 @@ describe('iframe integration tests', function (this: ISuite) {
|
||||
// console for debug
|
||||
// tslint:disable-next-line: no-console
|
||||
page.on('console', (msg) => console.log(msg.text()));
|
||||
await page.goto(`http://localhost:3030/html`);
|
||||
await page.setContent(raw, {
|
||||
await page.goto(`http://localhost:3030/iframe-html/main.html`, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
const snapshotResult = JSON.stringify(
|
||||
@@ -167,9 +220,7 @@ describe('iframe integration tests', function (this: ISuite) {
|
||||
}).timeout(5000);
|
||||
});
|
||||
|
||||
describe('shadown DOM integration tests', function (this: ISuite) {
|
||||
const shadowDomHtml = path.join(__dirname, 'html/shadow-dom.html');
|
||||
const raw = fs.readFileSync(shadowDomHtml, 'utf-8');
|
||||
describe('shadow DOM integration tests', function (this: ISuite) {
|
||||
|
||||
before(async () => {
|
||||
this.server = await server();
|
||||
@@ -198,8 +249,7 @@ describe('shadown DOM integration tests', function (this: ISuite) {
|
||||
// console for debug
|
||||
// tslint:disable-next-line: no-console
|
||||
page.on('console', (msg) => console.log(msg.text()));
|
||||
await page.goto(`http://localhost:3030/html`);
|
||||
await page.setContent(raw, {
|
||||
await page.goto(`http://localhost:3030/html/shadow-dom.html`, {
|
||||
waitUntil: 'load',
|
||||
});
|
||||
const snapshotResult = JSON.stringify(
|
||||
|
||||
1
packages/rrweb-snapshot/typings/types.d.ts
vendored
1
packages/rrweb-snapshot/typings/types.d.ts
vendored
@@ -9,6 +9,7 @@ export declare enum NodeType {
|
||||
export declare type documentNode = {
|
||||
type: NodeType.Document;
|
||||
childNodes: serializedNodeWithId[];
|
||||
compatMode?: string;
|
||||
};
|
||||
export declare type documentTypeNode = {
|
||||
type: NodeType.DocumentType;
|
||||
|
||||
Reference in New Issue
Block a user