fix: wrong rootId value in special iframes (#1100)
1. When some same-origin iframes are nested in cross-origin iframes, their `rootId`s are wrong. 2. The property `rootId` is missing in serialized cross-origin iframes
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { Mirror, serializedNodeWithId } from 'rrweb-snapshot';
|
||||
import { genId } from 'rrweb-snapshot';
|
||||
import { genId, NodeType } from 'rrweb-snapshot';
|
||||
import type { CrossOriginIframeMessageEvent } from '../types';
|
||||
import CrossOriginIframeMirror from './cross-origin-iframe-mirror';
|
||||
import { EventType, IncrementalSource } from '@rrweb/types';
|
||||
@@ -14,6 +14,10 @@ export class IframeManager {
|
||||
> = new WeakMap();
|
||||
public crossOriginIframeMirror = new CrossOriginIframeMirror(genId);
|
||||
public crossOriginIframeStyleMirror: CrossOriginIframeMirror;
|
||||
public crossOriginIframeRootIdMap: WeakMap<
|
||||
HTMLIFrameElement,
|
||||
number
|
||||
> = new WeakMap();
|
||||
private mirror: Mirror;
|
||||
private mutationCb: mutationCallBack;
|
||||
private wrappedEmit: (e: eventWithTime, isCheckout?: boolean) => void;
|
||||
@@ -121,6 +125,9 @@ export class IframeManager {
|
||||
* Replaces the original id of the iframe with a new set of unique ids
|
||||
*/
|
||||
this.replaceIdOnNode(e.data.node, iframeEl);
|
||||
const rootId = e.data.node.id;
|
||||
this.crossOriginIframeRootIdMap.set(iframeEl, rootId);
|
||||
this.patchRootIdOnNode(e.data.node, rootId);
|
||||
return {
|
||||
timestamp: e.timestamp,
|
||||
type: EventType.IncrementalSnapshot,
|
||||
@@ -171,6 +178,8 @@ export class IframeManager {
|
||||
'previousId',
|
||||
]);
|
||||
this.replaceIdOnNode(n.node, iframeEl);
|
||||
const rootId = this.crossOriginIframeRootIdMap.get(iframeEl);
|
||||
rootId && this.patchRootIdOnNode(n.node, rootId);
|
||||
});
|
||||
e.data.removes.forEach((n) => {
|
||||
this.replaceIds(n, iframeEl, ['parentId', 'id']);
|
||||
@@ -273,11 +282,20 @@ export class IframeManager {
|
||||
node: serializedNodeWithId,
|
||||
iframeEl: HTMLIFrameElement,
|
||||
) {
|
||||
this.replaceIds(node, iframeEl, ['id']);
|
||||
this.replaceIds(node, iframeEl, ['id', 'rootId']);
|
||||
if ('childNodes' in node) {
|
||||
node.childNodes.forEach((child) => {
|
||||
this.replaceIdOnNode(child, iframeEl);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private patchRootIdOnNode(node: serializedNodeWithId, rootId: number) {
|
||||
if (node.type !== NodeType.Document && !node.rootId) node.rootId = rootId;
|
||||
if ('childNodes' in node) {
|
||||
node.childNodes.forEach((child) => {
|
||||
this.patchRootIdOnNode(child, rootId);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import type { Page } from 'puppeteer';
|
||||
import type { eventWithTime, recordOptions } from '../../src/types';
|
||||
import type { eventWithTime } from '@rrweb/types';
|
||||
import type { recordOptions } from '../../src/types';
|
||||
import { startServer, launchPuppeteer, ISuite, getServerURL } from '../utils';
|
||||
|
||||
const suites: Array<
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import type { eventWithTime, recordOptions } from '../../src/types';
|
||||
import type { eventWithTime } from '@rrweb/types';
|
||||
import type { recordOptions } from '../../src/types';
|
||||
import { launchPuppeteer, ISuite } from '../utils';
|
||||
|
||||
const suites: Array<{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -517,6 +517,24 @@ describe('cross origin iframes', function (this: ISuite) {
|
||||
serverBURL: string;
|
||||
};
|
||||
|
||||
it('should record same-origin iframe in cross-origin iframe', async () => {
|
||||
const frame = ctx.page.mainFrame().childFrames()[0];
|
||||
await frame.evaluate(() => {
|
||||
const iframe2 = document.createElement('iframe');
|
||||
// Append a same-origin iframe in a cross-origin iframe.
|
||||
document.body.appendChild(iframe2);
|
||||
iframe2.contentDocument!.body.appendChild(
|
||||
document.createTextNode('Same-origin iframe in cross-origin iframe'),
|
||||
);
|
||||
});
|
||||
|
||||
await waitForRAF(ctx.page);
|
||||
const snapshots = (await ctx.page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should filter out forwarded cross origin rrweb messages', async () => {
|
||||
const frame = ctx.page.mainFrame().childFrames()[0];
|
||||
const iframe2URL = `${ctx.serverBURL}/html/blank.html`;
|
||||
@@ -533,10 +551,11 @@ describe('cross origin iframes', function (this: ISuite) {
|
||||
|
||||
// Wait for iframe2 to load
|
||||
await ctx.page.waitForFrame(iframe2URL);
|
||||
const iframe2 = frame.childFrames()[0];
|
||||
// Record iframe2
|
||||
await injectRecordScript(frame.childFrames()[0]);
|
||||
await injectRecordScript(iframe2);
|
||||
|
||||
await waitForRAF(frame.childFrames()[0]);
|
||||
await waitForRAF(iframe2);
|
||||
const snapshots = (await ctx.page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
|
||||
Reference in New Issue
Block a user