refactor rebuild implementation which mount DOM onto the target document object

This commit is contained in:
Yanzhen Yu
2018-10-22 10:34:23 +08:00
parent 202a674636
commit 508bbdfc26
7 changed files with 230 additions and 117 deletions

12
index.d.ts vendored
View File

@@ -1,11 +1,19 @@
import { serializedNodeWithId, idNodeMap } from './src/types'; import { serializedNodeWithId, idNodeMap, INode } from './src/types';
export * from './src/types'; export * from './src/types';
export function snapshot(n: Document): [serializedNodeWithId | null, idNodeMap]; export function snapshot(n: Document): [serializedNodeWithId | null, idNodeMap];
export function rebuild(n: serializedNodeWithId, doc: Document): Node | null; export function rebuild(
n: serializedNodeWithId,
doc: Document,
): [Node | null, idNodeMap];
export function serializeNodeWithId( export function serializeNodeWithId(
n: Node, n: Node,
doc: Document, doc: Document,
map: idNodeMap, map: idNodeMap,
): serializedNodeWithId | null; ): serializedNodeWithId | null;
export function resetId(): void; export function resetId(): void;
export function buildNodeWithSN(
n: serializedNodeWithId,
doc: Document,
map: idNodeMap,
): INode | null;

View File

@@ -1,6 +1,6 @@
{ {
"name": "rrweb-snapshot", "name": "rrweb-snapshot",
"version": "0.4.4", "version": "0.5.1",
"description": "rrweb's component to take a snapshot of DOM, aka DOM serializer", "description": "rrweb's component to take a snapshot of DOM, aka DOM serializer",
"main": "dist/index.js", "main": "dist/index.js",
"module": "dist/module.js", "module": "dist/module.js",

View File

@@ -1,5 +1,5 @@
import snapshot, { serializeNodeWithId, resetId } from './snapshot'; import snapshot, { serializeNodeWithId, resetId } from './snapshot';
import rebuild from './rebuild'; import rebuild, { buildNodeWithSN } from './rebuild';
export * from './types'; export * from './types';
export { snapshot, serializeNodeWithId, resetId, rebuild }; export { snapshot, serializeNodeWithId, resetId, rebuild, buildNodeWithSN };

View File

@@ -1,4 +1,108 @@
import { serializedNodeWithId, NodeType, tagMap, elementNode } from './types'; import {
serializedNodeWithId,
NodeType,
tagMap,
elementNode,
idNodeMap,
INode,
} from './types';
// TODO: need a more accurate list
const svgTags = [
'altGlyph',
'altGlyphDef',
'altGlyphItem',
'animate',
'animateColor',
'animateMotion',
'animateTransform',
'animation',
'circle',
'clipPath',
'color-profile',
'cursor',
'defs',
'desc',
'discard',
'ellipse',
'feBlend',
'feColorMatrix',
'feComponentTransfer',
'feComposite',
'feConvolveMatrix',
'feDiffuseLighting',
'feDisplacementMap',
'feDistantLight',
'feDropShadow',
'feFlood',
'feFuncA',
'feFuncB',
'feFuncG',
'feFuncR',
'feGaussianBlur',
'feImage',
'feMerge',
'feMergeNode',
'feMorphology',
'feOffset',
'fePointLight',
'feSpecularLighting',
'feSpotLight',
'feTile',
'feTurbulence',
'filter',
'font',
'font-face',
'font-face-format',
'font-face-name',
'font-face-src',
'font-face-uri',
'foreignObject',
'g',
'glyph',
'glyphRef',
'handler',
'hatch',
'hatchpath',
'hkern',
'image',
'line',
'linearGradient',
'listener',
'marker',
'mask',
'mesh',
'meshgradient',
'meshpatch',
'meshrow',
'metadata',
'missing-glyph',
'mpath',
'path',
'pattern',
'polygon',
'polyline',
'prefetch',
'radialGradient',
'rect',
'set',
'solidColor',
'solidcolor',
'stop',
'svg',
'switch',
'symbol',
'tbreak',
'text',
'textArea',
'textPath',
'tref',
'tspan',
'unknown',
'use',
'view',
'vkern',
];
const tagMap: tagMap = { const tagMap: tagMap = {
script: 'noscript', script: 'noscript',
@@ -23,8 +127,12 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
); );
case NodeType.Element: case NodeType.Element:
const tagName = getTagName(n); const tagName = getTagName(n);
const node = doc.createElement(tagName); let node: Element;
const extraChildIndexes: number[] = []; if (svgTags.indexOf(tagName) < 0) {
node = doc.createElement(tagName);
} else {
node = doc.createElementNS('http://www.w3.org/2000/svg', tagName);
}
for (const name in n.attributes) { for (const name in n.attributes) {
if (n.attributes.hasOwnProperty(name)) { if (n.attributes.hasOwnProperty(name)) {
let value = n.attributes[name]; let value = n.attributes[name];
@@ -33,10 +141,7 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
const isRemoteCss = tagName === 'style' && name === '_cssText'; const isRemoteCss = tagName === 'style' && name === '_cssText';
if (isTextarea || isRemoteCss) { if (isTextarea || isRemoteCss) {
const child = doc.createTextNode(value); const child = doc.createTextNode(value);
// identify the extra child DOM we added when rebuild
extraChildIndexes.push(node.childNodes.length);
node.appendChild(child); node.appendChild(child);
continue;
} }
try { try {
node.setAttribute(name, value); node.setAttribute(name, value);
@@ -45,12 +150,6 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
} }
} }
} }
if (extraChildIndexes.length) {
node.setAttribute(
'data-extra-child-index',
JSON.stringify(extraChildIndexes),
);
}
return node; return node;
case NodeType.Text: case NodeType.Text:
return doc.createTextNode(n.textContent); return doc.createTextNode(n.textContent);
@@ -63,25 +162,42 @@ function buildNode(n: serializedNodeWithId, doc: Document): Node | null {
} }
} }
function rebuild(n: serializedNodeWithId, doc: Document): Node | null { export function buildNodeWithSN(
const root = buildNode(n, doc); n: serializedNodeWithId,
if (!root) { doc: Document,
map: idNodeMap,
): INode | null {
let node = buildNode(n, doc);
if (!node) {
return null; return null;
} }
if (n.type === NodeType.Element) { // use target document as root document
(root as HTMLElement).setAttribute('data-rrid', String(n.id)); if (n.type === NodeType.Document) {
doc.open();
node = doc;
} }
(node as INode).__sn = n;
map[n.id] = node as INode;
if (n.type === NodeType.Document || n.type === NodeType.Element) { if (n.type === NodeType.Document || n.type === NodeType.Element) {
for (const childN of n.childNodes) { for (const childN of n.childNodes) {
const childNode = rebuild(childN, doc); const childNode = buildNodeWithSN(childN, doc, map);
if (!childNode) { if (!childNode) {
console.warn('Failed to rebuild', childN); console.warn('Failed to rebuild', childN);
} else { } else {
root.appendChild(childNode); node.appendChild(childNode);
} }
} }
} }
return root; return node as INode;
}
function rebuild(
n: serializedNodeWithId,
doc: Document,
): [Node | null, idNodeMap] {
const idNodeMap: idNodeMap = {};
return [buildNodeWithSN(n, doc, idNodeMap), idNodeMap];
} }
export default rebuild; export default rebuild;

View File

@@ -187,24 +187,12 @@ export function serializeNodeWithId(
}); });
(n as INode).__sn = serializedNode; (n as INode).__sn = serializedNode;
map[serializedNode.id] = n as INode; map[serializedNode.id] = n as INode;
return serializedNode;
}
function _snapshot(
n: Node,
doc: Document,
map: idNodeMap,
): serializedNodeWithId | null {
const serializedNode = serializeNodeWithId(n, doc, map);
if (!serializedNode) {
return null;
}
if ( if (
serializedNode.type === NodeType.Document || serializedNode.type === NodeType.Document ||
serializedNode.type === NodeType.Element serializedNode.type === NodeType.Element
) { ) {
for (const childN of Array.from(n.childNodes)) { for (const childN of Array.from(n.childNodes)) {
const serializedChildNode = _snapshot(childN, doc, map); const serializedChildNode = serializeNodeWithId(childN, doc, map);
if (serializedChildNode) { if (serializedChildNode) {
serializedNode.childNodes.push(serializedChildNode); serializedNode.childNodes.push(serializedChildNode);
} }
@@ -216,7 +204,7 @@ function _snapshot(
function snapshot(n: Document): [serializedNodeWithId | null, idNodeMap] { function snapshot(n: Document): [serializedNodeWithId | null, idNodeMap] {
resetId(); resetId();
const idNodeMap: idNodeMap = {}; const idNodeMap: idNodeMap = {};
return [_snapshot(n, n, idNodeMap), idNodeMap]; return [serializeNodeWithId(n, n, idNodeMap), idNodeMap];
} }
export default snapshot; export default snapshot;

View File

@@ -1,9 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`[html file]: about-mozilla.html 1`] = ` exports[`[html file]: about-mozilla.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head>
<title data-rrid=\\"6\\">The Book of Mozilla, 11:9</title> <title>The Book of Mozilla, 11:9</title>
<style type=\\"text/css\\" data-rrid=\\"9\\"> <style type=\\"text/css\\">
html { html {
background: maroon; background: maroon;
color: white; color: white;
@@ -26,120 +26,120 @@ exports[`[html file]: about-mozilla.html 1`] = `
color: white; color: white;
} }
</style> </style>
</head><body data-rrid=\\"13\\"> <p id=\\"moztext\\" data-rrid=\\"15\\"> </head><body> <p id=\\"moztext\\">
Mammon slept. And the <em data-rrid=\\"17\\">beast reborn</em> spread over the earth and its numbers Mammon slept. And the <em>beast reborn</em> spread over the earth and its numbers
grew legion. And they proclaimed the times and <em data-rrid=\\"20\\">sacrificed</em> crops unto the grew legion. And they proclaimed the times and <em>sacrificed</em> crops unto the
fire, with the <em data-rrid=\\"23\\">cunning of foxes</em>. And they built a new world in their own fire, with the <em>cunning of foxes</em>. And they built a new world in their own
image as promised by the <em data-rrid=\\"26\\"><a href=\\"http://www.mozilla.org/about/mozilla-manifesto.html\\" data-rrid=\\"27\\"> image as promised by the <em><a href=\\"http://www.mozilla.org/about/mozilla-manifesto.html\\">
sacred words</a></em>, and <em data-rrid=\\"30\\"><a href=\\"http://wiki.mozilla.org/About:mozilla\\" data-rrid=\\"31\\">spoke sacred words</a></em>, and <em><a href=\\"http://wiki.mozilla.org/About:mozilla\\">spoke
</a></em> of the beast with their children. Mammon awoke, and lo! it was </a></em> of the beast with their children. Mammon awoke, and lo! it was
<em data-rrid=\\"34\\">naught</em> but a follower. <em>naught</em> but a follower.
</p> <p id=\\"from\\" data-rrid=\\"38\\"> </p> <p id=\\"from\\">
from <strong data-rrid=\\"40\\">The Book of Mozilla,</strong> 11:9<br data-rrid=\\"43\\" /><small data-rrid=\\"44\\">(10th Edition)</small> from <strong>The Book of Mozilla,</strong> 11:9<br /><small>(10th Edition)</small>
</p></body></html>" </p></body></html>"
`; `;
exports[`[html file]: basic.html 1`] = ` exports[`[html file]: basic.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">Document</title> <title>Document</title>
</head><body data-rrid=\\"16\\"></body></html>" </head><body></body></html>"
`; `;
exports[`[html file]: cors-style-sheet.html 1`] = ` exports[`[html file]: cors-style-sheet.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">with style sheet</title> <title>with style sheet</title>
<link rel=\\"stylesheet\\" href=\\"https://cdn.jsdelivr.net/npm/pure@2.85.0/index.css\\" data-rrid=\\"15\\" /> <link rel=\\"stylesheet\\" href=\\"https://cdn.jsdelivr.net/npm/pure@2.85.0/index.css\\" />
</head><body data-rrid=\\"18\\"></body></html>" </head><body></body></html>"
`; `;
exports[`[html file]: form-fields.html 1`] = ` exports[`[html file]: form-fields.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">form fields</title> <title>form fields</title>
</head><body data-rrid=\\"16\\"> </head><body>
<form data-rrid=\\"18\\"> <form>
<label for=\\"text\\" data-rrid=\\"20\\"> <label for=\\"text\\">
<input type=\\"text\\" value=\\"1\\" data-rrid=\\"22\\" /> <input type=\\"text\\" value=\\"1\\" />
</label> </label>
<label for=\\"radio\\" data-rrid=\\"25\\"> <label for=\\"radio\\">
<input type=\\"radio\\" checked=\\"\\" data-rrid=\\"27\\" /> <input type=\\"radio\\" checked=\\"\\" />
</label> </label>
<label for=\\"checkbox\\" data-rrid=\\"30\\"> <label for=\\"checkbox\\">
<input type=\\"checkbox\\" checked=\\"\\" data-rrid=\\"32\\" /> <input type=\\"checkbox\\" checked=\\"\\" />
</label> </label>
<label for=\\"textarea\\" data-rrid=\\"35\\"> <label for=\\"textarea\\">
<textarea name=\\"\\" id=\\"\\" cols=\\"30\\" rows=\\"10\\" data-extra-child-index=\\"[0]\\" data-rrid=\\"37\\">1234</textarea> <textarea name=\\"\\" id=\\"\\" cols=\\"30\\" rows=\\"10\\" value=\\"1234\\">1234</textarea>
</label> </label>
<label for=\\"select\\" data-rrid=\\"40\\"> <label for=\\"select\\">
<select name=\\"\\" id=\\"\\" value=\\"2\\" data-rrid=\\"42\\"> <select name=\\"\\" id=\\"\\" value=\\"2\\">
<option value=\\"1\\" data-rrid=\\"44\\">1</option> <option value=\\"1\\">1</option>
<option value=\\"2\\" selected=\\"\\" data-rrid=\\"47\\">2</option> <option value=\\"2\\" selected=\\"\\">2</option>
</select> </select>
</label> </label>
</form><noscript data-rrid=\\"53\\">SCRIPT_PLACEHOLDER</noscript> </form><noscript>SCRIPT_PLACEHOLDER</noscript>
</body></html>" </body></html>"
`; `;
exports[`[html file]: iframe.html 1`] = ` exports[`[html file]: iframe.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">iframe</title> <title>iframe</title>
</head> </head>
<body data-rrid=\\"16\\"> <body>
<iframe src=\\"http://localhost:3030/html/iframe-inner.html\\" width=\\"100\\" height=\\"50\\" data-rrid=\\"18\\"></iframe> <iframe src=\\"http://localhost:3030/html/iframe-inner.html\\" width=\\"100\\" height=\\"50\\"></iframe>
</body></html>" </body></html>"
`; `;
exports[`[html file]: iframe-inner.html 1`] = ` exports[`[html file]: iframe-inner.html 1`] = `
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\" data-rrid=\\"2\\"><head data-rrid=\\"3\\"></head><body data-rrid=\\"4\\"><button data-rrid=\\"5\\">inner iframe button</button> "<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body><button>inner iframe button</button>
</body></html>" </body></html>"
`; `;
exports[`[html file]: invalid-attribute.html 1`] = ` exports[`[html file]: invalid-attribute.html 1`] = `
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\" foo=\\"bar\\" data-rrid=\\"2\\"><head data-rrid=\\"3\\"></head><body data-rrid=\\"4\\"> "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" foo=\\"bar\\"><head></head><body>
</body></html>" </body></html>"
`; `;
exports[`[html file]: with-relative-res.html 1`] = ` exports[`[html file]: with-relative-res.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">Document</title> <title>Document</title>
</head> </head>
<body data-rrid=\\"16\\"> <body>
<a href=\\"http://localhost:3030/basic.html\\" data-rrid=\\"18\\"></a> <a href=\\"http://localhost:3030/basic.html\\"></a>
<img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"\\" data-rrid=\\"20\\" /></body></html>" <img src=\\"http://localhost:3030/a.jpg\\" alt=\\"\\" srcset=\\"\\" /></body></html>"
`; `;
exports[`[html file]: with-script.html 1`] = ` exports[`[html file]: with-script.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">with script</title> <title>with script</title>
</head><body data-rrid=\\"16\\"> </head><body>
<noscript src=\\"http://localhost:3030/js/a.js\\" data-rrid=\\"18\\"></noscript> <noscript src=\\"http://localhost:3030/js/a.js\\"></noscript>
<noscript data-rrid=\\"20\\">SCRIPT_PLACEHOLDER</noscript></body></html>" <noscript>SCRIPT_PLACEHOLDER</noscript></body></html>"
`; `;
exports[`[html file]: with-style-sheet.html 1`] = ` exports[`[html file]: with-style-sheet.html 1`] = `
"<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\" data-rrid=\\"3\\"><head data-rrid=\\"4\\"> "<!DOCTYPE html><html xmlns=\\"http://www.w3.org/1999/xhtml\\" lang=\\"en\\"><head>
<meta charset=\\"UTF-8\\" data-rrid=\\"6\\" /> <meta charset=\\"UTF-8\\" />
<meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" data-rrid=\\"8\\" /> <meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1.0\\" />
<meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" data-rrid=\\"10\\" /> <meta http-equiv=\\"X-UA-Compatible\\" content=\\"ie=edge\\" />
<title data-rrid=\\"12\\">with style sheet</title> <title>with style sheet</title>
<style data-extra-child-index=\\"[0]\\" data-rrid=\\"15\\">body { margin: 0px; background: url('http://localhost:3030/a.jpg'); }p { color: red; background: url('http://localhost:3030/css/b.jpg'); }body &gt; p { color: yellow; }</style> <style _csstext=\\"body { margin: 0px; background: url('http://localhost:3030/a.jpg'); }p { color: red; background: url('http://localhost:3030/css/b.jpg'); }body &gt; p { color: yellow; }\\">body { margin: 0px; background: url('http://localhost:3030/a.jpg'); }p { color: red; background: url('http://localhost:3030/css/b.jpg'); }body &gt; p { color: yellow; }</style>
</head><body data-rrid=\\"18\\"> </head><body>
</body></html>" </body></html>"
`; `;

View File

@@ -70,6 +70,7 @@ describe('integration tests', () => {
before(async () => { before(async () => {
this.server = await server(); this.server = await server();
this.browser = await puppeteer.launch({ this.browser = await puppeteer.launch({
executablePath: '/home/yanzhen/Desktop/chrome-linux/chrome',
// headless: false, // headless: false,
}); });
@@ -101,7 +102,7 @@ describe('integration tests', () => {
const rebuildHtml = (await page.evaluate(`${this.code} const rebuildHtml = (await page.evaluate(`${this.code}
const x = new XMLSerializer(); const x = new XMLSerializer();
const [snap] = rrweb.snapshot(document); const [snap] = rrweb.snapshot(document);
x.serializeToString(rrweb.rebuild(snap, document)); x.serializeToString(rrweb.rebuild(snap, document)[0]);
`)).replace(/\n\n/g, ''); `)).replace(/\n\n/g, '');
const result = matchSnapshot(rebuildHtml, __filename, title); const result = matchSnapshot(rebuildHtml, __filename, title);
assert(result.pass, result.pass ? '' : result.report()); assert(result.pass, result.pass ? '' : result.report());