Skip to content

Commit

Permalink
Bug fix and regression test for rrweb-io#112
Browse files Browse the repository at this point in the history
 - this is to fix up 'historical' recordings, as duplicate textarea content should no longer be being created at record time (see previous commit in this PR)
 - new test shows what the snapshot generated by previous versions of rrweb used to look like, hence 'bad'
 - original 0efe23f fix either didn't work or no longer works due to childNodes being appended subsequent to this part of the code
  • Loading branch information
eoghanmurray committed Nov 9, 2023
1 parent 4f4b00a commit 96cc446
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
9 changes: 2 additions & 7 deletions packages/rrweb-snapshot/src/rebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,9 @@ function buildNode(
value = addHoverClass(value, cache);
}
if ((isTextarea || isRemoteOrDynamicCss) && typeof value === 'string') {
const child = doc.createTextNode(value);
node.appendChild(doc.createTextNode(value));
// https://github.com/rrweb-io/rrweb/issues/112
for (const c of Array.from(node.childNodes)) {
if (c.nodeType === node.TEXT_NODE) {
node.removeChild(c);
}
}
node.appendChild(child);
n.childNodes = []; // value overrides childNodes
continue;
}

Expand Down
80 changes: 80 additions & 0 deletions packages/rrweb/test/events/bad-textarea.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { EventType, IncrementalSource } from '@rrweb/types';
import type { eventWithTime } from '@rrweb/types';

const now = Date.now();
const events: eventWithTime[] = [
{
type: EventType.DomContentLoaded,
data: {},
timestamp: now,
},
{
type: EventType.Load,
data: {},
timestamp: now + 50,
},
{
type: EventType.Meta,
data: {
href: 'http://localhost',
width: 1000,
height: 800,
},
timestamp: now + 50,
},
// full snapshot:
{
data: {
node: {
id: 1,
type: 0,
childNodes: [
{ id: 2, name: 'html', type: 1, publicId: '', systemId: '' },
{
id: 3,
type: 2,
tagName: 'html',
attributes: { lang: 'en' },
childNodes: [
{
id: 4,
type: 2,
tagName: 'head',
attributes: {},
childNodes: [],
},
{
id: 5,
type: 2,
tagName: 'body',
attributes: {},
childNodes: [
{
id: 6,
type: 2,
tagName: 'textarea',
attributes: {
value: 'dupe',
},
childNodes: [
{
type: 3,
textContent: 'dupe should ignore',
id: 7,
},
],
},
],
},
],
},
],
},
initialOffset: { top: 0, left: 0 },
},
type: EventType.FullSnapshot,
timestamp: now + 50,
},
];

export default events;
16 changes: 16 additions & 0 deletions packages/rrweb/test/replayer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import inputEvents from './events/input';
import iframeEvents from './events/iframe';
import selectionEvents from './events/selection';
import shadowDomEvents from './events/shadow-dom';
import textareaEvents from './events/bad-textarea';
import StyleSheetTextMutation from './events/style-sheet-text-mutation';
import canvasInIframe from './events/canvas-in-iframe';
import adoptedStyleSheet from './events/adopted-style-sheet';
Expand Down Expand Up @@ -1092,4 +1093,19 @@ describe('replayer', function () {
// If the custom element is defined, the display value will be 'block'.
expect(displayValue).toEqual('block');
});

it('can deal with legacy duplicate/conflicting values on textareas', async () => {
await page.evaluate(`events = ${JSON.stringify(textareaEvents)}`);

const displayValue = await page.evaluate(`
const { Replayer } = rrweb;
const replayer = new Replayer(events);
replayer.pause(100);
const textarea = replayer.iframe.contentDocument.querySelector('textarea');
textarea.value;
`);
// If the custom element is not defined, the display value will be 'none'.
// If the custom element is defined, the display value will be 'block'.
expect(displayValue).toEqual('dupe');
});
});

0 comments on commit 96cc446

Please sign in to comment.