refactor rebuild implementation which mount DOM onto the target document object
This commit is contained in:
12
index.d.ts
vendored
12
index.d.ts
vendored
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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 };
|
||||||
|
|||||||
156
src/rebuild.ts
156
src/rebuild.ts
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 > 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 > 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 > p { color: yellow; }</style>
|
||||||
</head><body data-rrid=\\"18\\">
|
</head><body>
|
||||||
</body></html>"
|
</body></html>"
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
Reference in New Issue
Block a user