Fix: shadow dom bugs (#1049)
* Add test cases for bugs * Fix shadow dom recording When moving an element containing shadow dom When adding an element to shadow dom before its attached to the dom * Apply formatting changes * Refactor in dom checking code * Nodes don't get processed in more than one mutation buffer * Constrain node mutations to one mutation buffer per request animation frame * Make tests less flaky under heavy load * Apply suggestions from code review * Update packages/rrweb-snapshot/test/rebuild.test.ts * Remove unused nodeSet Co-authored-by: Yun Feng <yun.feng0817@gmail.com>
This commit is contained in:
@@ -667,6 +667,119 @@ describe('record integration tests', function (this: ISuite) {
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should record shadow DOM 2', async () => {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(getHtml.call(this, 'blank.html'));
|
||||
await page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
const el = document.createElement('div') as HTMLDivElement;
|
||||
el.attachShadow({ mode: 'open' });
|
||||
(el.shadowRoot as ShadowRoot).appendChild(
|
||||
document.createElement('input'),
|
||||
);
|
||||
setTimeout(() => {
|
||||
document.body.append(el);
|
||||
resolve(null);
|
||||
}, 10);
|
||||
});
|
||||
});
|
||||
await waitForRAF(page);
|
||||
|
||||
const snapshots = (await page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should record shadow DOM 3', async () => {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(getHtml.call(this, 'blank.html'));
|
||||
|
||||
await page.evaluate(() => {
|
||||
const el = document.createElement('div') as HTMLDivElement;
|
||||
el.attachShadow({ mode: 'open' });
|
||||
(el.shadowRoot as ShadowRoot).appendChild(
|
||||
document.createElement('input'),
|
||||
);
|
||||
document.body.append(el);
|
||||
});
|
||||
await waitForRAF(page);
|
||||
|
||||
const snapshots = (await page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should record moved shadow DOM', async () => {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(getHtml.call(this, 'blank.html'));
|
||||
|
||||
await page.evaluate(() => {
|
||||
return new Promise((resolve) => {
|
||||
const el = document.createElement('div') as HTMLDivElement;
|
||||
el.attachShadow({ mode: 'open' });
|
||||
(el.shadowRoot as ShadowRoot).appendChild(
|
||||
document.createElement('input'),
|
||||
);
|
||||
document.body.append(el);
|
||||
setTimeout(() => {
|
||||
const newEl = document.createElement('div') as HTMLDivElement;
|
||||
document.body.append(newEl);
|
||||
newEl.append(el);
|
||||
resolve(null);
|
||||
}, 50);
|
||||
});
|
||||
});
|
||||
await waitForRAF(page);
|
||||
|
||||
const snapshots = (await page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should record moved shadow DOM 2', async () => {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(getHtml.call(this, 'blank.html'));
|
||||
|
||||
await page.evaluate(() => {
|
||||
const el = document.createElement('div') as HTMLDivElement;
|
||||
el.id = 'el';
|
||||
el.attachShadow({ mode: 'open' });
|
||||
(el.shadowRoot as ShadowRoot).appendChild(
|
||||
document.createElement('input'),
|
||||
);
|
||||
document.body.append(el);
|
||||
(el.shadowRoot as ShadowRoot).appendChild(document.createElement('span'));
|
||||
(el.shadowRoot as ShadowRoot).appendChild(document.createElement('p'));
|
||||
const newEl = document.createElement('div') as HTMLDivElement;
|
||||
newEl.id = 'newEl';
|
||||
document.body.append(newEl);
|
||||
newEl.append(el);
|
||||
const input = el.shadowRoot?.children[0] as HTMLInputElement;
|
||||
const span = el.shadowRoot?.children[1] as HTMLSpanElement;
|
||||
const p = el.shadowRoot?.children[2] as HTMLParagraphElement;
|
||||
input.remove();
|
||||
span.append(input);
|
||||
p.append(input);
|
||||
span.append(input);
|
||||
setTimeout(() => {
|
||||
p.append(input);
|
||||
}, 0);
|
||||
});
|
||||
await waitForRAF(page);
|
||||
|
||||
const snapshots = (await page.evaluate(
|
||||
'window.snapshots',
|
||||
)) as eventWithTime[];
|
||||
assertSnapshot(snapshots);
|
||||
});
|
||||
|
||||
it('should record nested iframes and shadow doms', async () => {
|
||||
const page: puppeteer.Page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
|
||||
Reference in New Issue
Block a user