Keep blocked root elements as placeholders (#696)
* Keep blocked root elements as placeholders `serializeNode` turns blocked elements into placeholder nodes so we need to make sure we don't remove these elements from the mutations when they get added. We do however need to keep removing any children of these blocked elements from getting added or mutated. * Update packages/rrweb/src/record/mutation.ts
This commit is contained in:
@@ -262,9 +262,6 @@ export default class MutationBuffer {
|
||||
ns = ns && ns.nextSibling;
|
||||
nextId = ns && this.mirror.getId((ns as unknown) as INode);
|
||||
}
|
||||
if (nextId === -1 && isBlocked(n.nextSibling, this.blockClass)) {
|
||||
nextId = null;
|
||||
}
|
||||
return nextId;
|
||||
};
|
||||
const pushAdd = (n: Node) => {
|
||||
@@ -534,11 +531,7 @@ export default class MutationBuffer {
|
||||
const parentId = isShadowRoot(m.target)
|
||||
? this.mirror.getId((m.target.host as unknown) as INode)
|
||||
: this.mirror.getId(m.target as INode);
|
||||
if (
|
||||
isBlocked(n, this.blockClass) ||
|
||||
isBlocked(m.target, this.blockClass) ||
|
||||
isIgnored(n)
|
||||
) {
|
||||
if (isBlocked(m.target, this.blockClass) || isIgnored(n)) {
|
||||
return;
|
||||
}
|
||||
// removed node has not been serialized yet, just remove it from the Set
|
||||
@@ -582,9 +575,7 @@ export default class MutationBuffer {
|
||||
};
|
||||
|
||||
private genAdds = (n: Node | INode, target?: Node | INode) => {
|
||||
if (isBlocked(n, this.blockClass)) {
|
||||
return;
|
||||
}
|
||||
// parent was blocked, so we can ignore this node
|
||||
if (target && isBlocked(target, this.blockClass)) {
|
||||
return;
|
||||
}
|
||||
@@ -604,7 +595,11 @@ export default class MutationBuffer {
|
||||
this.addedSet.add(n);
|
||||
this.droppedSet.delete(n);
|
||||
}
|
||||
n.childNodes.forEach((childN) => this.genAdds(childN));
|
||||
|
||||
// if this node is blocked `serializeNode` will turn it into a placeholder element
|
||||
// but we have to remove it's children otherwise they will be added as placeholders too
|
||||
if (!isBlocked(n, this.blockClass))
|
||||
n.childNodes.forEach((childN) => this.genAdds(childN));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +332,212 @@ exports[`block 1`] = `
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`block 2 1`] = `
|
||||
"[
|
||||
{
|
||||
\\"type\\": 0,
|
||||
\\"data\\": {}
|
||||
},
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"data\\": {}
|
||||
},
|
||||
{
|
||||
\\"type\\": 4,
|
||||
\\"data\\": {
|
||||
\\"href\\": \\"about:blank\\",
|
||||
\\"width\\": 1920,
|
||||
\\"height\\": 1080
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"data\\": {
|
||||
\\"node\\": {
|
||||
\\"type\\": 0,
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 1,
|
||||
\\"name\\": \\"html\\",
|
||||
\\"publicId\\": \\"\\",
|
||||
\\"systemId\\": \\"\\",
|
||||
\\"id\\": 2
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"html\\",
|
||||
\\"attributes\\": {
|
||||
\\"lang\\": \\"en\\"
|
||||
},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"head\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 5
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"meta\\",
|
||||
\\"attributes\\": {
|
||||
\\"charset\\": \\"UTF-8\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 6
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 7
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"meta\\",
|
||||
\\"attributes\\": {
|
||||
\\"name\\": \\"viewport\\",
|
||||
\\"content\\": \\"width=device-width, initial-scale=1.0\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 8
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 9
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"meta\\",
|
||||
\\"attributes\\": {
|
||||
\\"http-equiv\\": \\"X-UA-Compatible\\",
|
||||
\\"content\\": \\"ie=edge\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 10
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 11
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"title\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"Block record\\",
|
||||
\\"id\\": 13
|
||||
}
|
||||
],
|
||||
\\"id\\": 12
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 14
|
||||
}
|
||||
],
|
||||
\\"id\\": 4
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 15
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"body\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\",
|
||||
\\"id\\": 17
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"div\\",
|
||||
\\"attributes\\": {
|
||||
\\"class\\": \\"rr-block\\",
|
||||
\\"rr_width\\": \\"50px\\",
|
||||
\\"rr_height\\": \\"50px\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 18
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\",
|
||||
\\"id\\": 19
|
||||
},
|
||||
{
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"script\\",
|
||||
\\"attributes\\": {},
|
||||
\\"childNodes\\": [
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
|
||||
\\"id\\": 21
|
||||
}
|
||||
],
|
||||
\\"id\\": 20
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\",
|
||||
\\"id\\": 22
|
||||
}
|
||||
],
|
||||
\\"id\\": 16
|
||||
}
|
||||
],
|
||||
\\"id\\": 3
|
||||
}
|
||||
],
|
||||
\\"id\\": 1
|
||||
},
|
||||
\\"initialOffset\\": {
|
||||
\\"left\\": 0,
|
||||
\\"top\\": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
\\"type\\": 3,
|
||||
\\"data\\": {
|
||||
\\"source\\": 0,
|
||||
\\"texts\\": [],
|
||||
\\"attributes\\": [],
|
||||
\\"removes\\": [],
|
||||
\\"adds\\": [
|
||||
{
|
||||
\\"parentId\\": 16,
|
||||
\\"nextId\\": 18,
|
||||
\\"node\\": {
|
||||
\\"type\\": 2,
|
||||
\\"tagName\\": \\"button\\",
|
||||
\\"attributes\\": {
|
||||
\\"class\\": \\"rr-block\\",
|
||||
\\"rr_width\\": \\"100px\\",
|
||||
\\"rr_height\\": \\"100px\\"
|
||||
},
|
||||
\\"childNodes\\": [],
|
||||
\\"id\\": 23
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]"
|
||||
`;
|
||||
|
||||
exports[`canvas 1`] = `
|
||||
"[
|
||||
{
|
||||
|
||||
@@ -185,7 +185,9 @@ describe('record integration tests', function (this: ISuite) {
|
||||
// toggle the select box
|
||||
await page.click('.select2-container', { clickCount: 2, delay: 100 });
|
||||
// test storage of !important style
|
||||
await page.evaluate('document.getElementById("select2-drop").setAttribute("style", document.getElementById("select2-drop").style.cssText + "color:black !important")');
|
||||
await page.evaluate(
|
||||
'document.getElementById("select2-drop").setAttribute("style", document.getElementById("select2-drop").style.cssText + "color:black !important")',
|
||||
);
|
||||
const snapshots = await page.evaluate('window.snapshots');
|
||||
assertSnapshot(snapshots, __filename, 'select2');
|
||||
});
|
||||
@@ -317,6 +319,26 @@ describe('record integration tests', function (this: ISuite) {
|
||||
assertSnapshot(snapshots, __filename, 'block');
|
||||
});
|
||||
|
||||
it('should not record blocked elements dynamically added', async () => {
|
||||
const page: puppeteer.Page = await this.browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(getHtml.call(this, 'block.html'));
|
||||
|
||||
await page.evaluate(() => {
|
||||
const el = document.createElement('button');
|
||||
el.className = 'rr-block';
|
||||
el.style.width = '100px';
|
||||
el.style.height = '100px';
|
||||
el.innerText = 'Should not be recorded';
|
||||
|
||||
const nextElement = document.querySelector('.rr-block')!;
|
||||
nextElement.parentNode!.insertBefore(el, nextElement);
|
||||
});
|
||||
|
||||
const snapshots = await page.evaluate('window.snapshots');
|
||||
assertSnapshot(snapshots, __filename, 'block 2');
|
||||
});
|
||||
|
||||
it('should record DOM node movement 1', async () => {
|
||||
const page: puppeteer.Page = await this.browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
|
||||
Reference in New Issue
Block a user