-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
The Error
The current master version of rrweb triggers a "Cannot read property 'implementation' of null" error in some situations.
The Bug
I did some digging and it turns out iframes inside of a DocumentFragment don't have a iframe.contentDocument.
Lines 625 to 631 in 2b96a68
| private attachDocumentToIframe( | |
| mutation: addedNodeMutation, | |
| iframeEl: HTMLIFrameElement, | |
| ) { | |
| const collected: AppendedIframe[] = []; | |
| buildNodeWithSN(mutation.node, { | |
| doc: iframeEl.contentDocument!, |
Whenever applyMutation gets called with useVirtualParent: true and a mutation containing an iframe, rrweb ends up calling buildNodeWithSN with an empty doc property which ends up triggering the error in buildNode on: Source
return doc.implementation.createDocument(null, '', null);
// ^--- nullFixing this line and most other lines in buildNode should be quite easy, just replacing doc with document should do the trick.
For buildNodeWithSN however we need a different approach: Source
if (n.type === NodeType.Document) {
// close before open to make sure document was closed
doc.close();
// ^--- null
doc.open();
node = doc;
// ^-- node is extensively used throughout buildNodeWithSN
}I wasn't really able to go beyond this unfortunately.
The Test (to reproduce the bug)
Add to test/replayer.test.ts:
import iframeEvents from './events/iframe-events'; it('can fast forward past iframe changes on virtual elements', async () => {
await this.page.evaluate(`events = ${JSON.stringify(iframeEvents)}`);
const actionLength = await this.page.evaluate(`
const { Replayer } = rrweb;
const replayer = new Replayer(events);
replayer.play(3000);
replayer['timer']['actions'].length;
`);
expect(actionLength).to.equal(
iframeEvents.filter(
(e) => e.timestamp - iframeEvents[0].timestamp >= 3000,
).length,
);
});Contents of test/events/iframe-events.ts: iframe-events.ts.zip
The Version
I'm using rrweb's master branch