Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ In addition to adding integration tests and unit tests, rrweb also provides a RE
</tr>
</table>

## Who's using rrweb
## Who's using rrweb?

<table>
<tr>
Expand Down
2 changes: 1 addition & 1 deletion packages/rrdom/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@typescript-eslint/parser": "^5.23.0",
"eslint": "^8.15.0",
"jest": "^27.5.1",
"puppeteer": "^9.1.1",
"puppeteer": "^17.1.3",
"rollup": "^2.56.3",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.31.2",
Expand Down
2 changes: 1 addition & 1 deletion packages/rrweb-snapshot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"jest": "^27.2.4",
"jest-snapshot": "^23.6.0",
"jsdom": "^16.4.0",
"puppeteer": "^1.15.0",
"puppeteer": "^17.1.3",
"rollup": "^2.45.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-typescript2": "^0.31.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ exports[`integration tests [html file]: block-element.html 1`] = `
`;

exports[`integration tests [html file]: compat-mode.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><!-- no doctype! --><html><head>
"<!-- no doctype! --><html><head>
<title>Compat Mode; image resizing</title>
</head>
<body>
Expand Down Expand Up @@ -287,12 +287,12 @@ exports[`integration tests [html file]: iframe.html 1`] = `
`;

exports[`integration tests [html file]: iframe-inner.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><html><head></head><body><button>inner iframe button</button>
"<html><head></head><body><button>inner iframe button</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These Transitional DOCTYPE here were added deliberately in #697

Copy link
Member Author

@Juice10 Juice10 Jan 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Newer versions of Chrome strip them out if they aren’t in standards mode I think

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a moment to dig into what is going on. Newer versions of chrome don't add a transitional doctype if you never specified one to begin with. Chrome just leaves it empty.

iframe-inner.html:
image

what chrome renders:
image

I went through each of the changes in this PR and compared them to their source document and this does seem correct.

Example of the compat-mode.html file:
image

How chrome renders it:
image
(consistent with the snapshot)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not understanding!
The transitional doctypes are there in the source test files in order to test that the resultant replay also replays with compatMode=true
Maybe ye guys are one step ahead of me?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay got it now!
Only problem I can think of is if future versions of Chrome decide that lack of a doctype should imply HTML5 ... but happy to defer worrying about that to the future.

</body></html>"
`;

exports[`integration tests [html file]: invalid-attribute.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD HTML 4.0 Transitional//EN\\"><html foo=\\"bar\\"><head></head><body>
"<html foo=\\"bar\\"><head></head><body>
</body></html>"
`;

Expand Down Expand Up @@ -335,7 +335,7 @@ exports[`integration tests [html file]: mask-text.html 1`] = `
`;

exports[`integration tests [html file]: picture.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\"><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
<picture>
<source type=\\"image/webp\\" srcset=\\"http://localhost:3030/assets/img/characters/robot.webp\\" />
<img src=\\"http://localhost:3030/assets/img/characters/robot.png\\" />
Expand All @@ -345,20 +345,20 @@ exports[`integration tests [html file]: picture.html 1`] = `
`;

exports[`integration tests [html file]: picture-blob.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\"><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
<img src=\\"\\" alt=\\"This is a robot\\" />
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
<img src=\\"blob:http://localhost:xxxx/...\\" alt=\\"This is a robot\\" />

<noscript>SCRIPT_PLACEHOLDER</noscript></body></html>"
`;

exports[`integration tests [html file]: picture-blob-in-frame.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\"><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
<iframe></iframe>
</body></html>"
`;

exports[`integration tests [html file]: picture-in-frame.html 1`] = `
"<!DOCTYPE html PUBLIC \\"-//W3C//DTD XHTML 1.0 Transitional//EN\\"><html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
"<html xmlns=\\"http://www.w3.org/1999/xhtml\\"><head></head><body>
<iframe></iframe>
</body></html>"
`;
Expand Down Expand Up @@ -750,7 +750,7 @@ exports[`shadow DOM integration tests snapshot shadow DOM 1`] = `
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\":host { display: inline-block; width: 650px; font-family: \\\\\\"Roboto Slab\\\\\\"; contain: content; }:host([background]) { background: var(--background-color, #9E9E9E); border-radius: 10px; padding: 10px; }#panels { box-shadow: rgba(0, 0, 0, 0.3) 0px 2px 2px; background: white; border-radius: 3px; padding: 16px; height: 250px; overflow: auto; }#tabs { display: inline-flex; user-select: none; }#tabs slot { display: inline-flex; }#tabs ::slotted(*) { font: 400 16px/22px Roboto; padding: 16px 8px; margin: 0px; text-align: center; width: 100px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; cursor: pointer; border-top-left-radius: 3px; border-top-right-radius: 3px; background: linear-gradient(rgb(250, 250, 250), rgb(238, 238, 238)); border: none; }#tabs ::slotted([aria-selected=\\\\\\"true\\\\\\"]) { font-weight: 600; background: white; box-shadow: none; }#tabs ::slotted(:focus) { z-index: 1; }#panels ::slotted([aria-hidden=\\\\\\"true\\\\\\"]) { display: none; }\\",
\\"textContent\\": \\":host { display: inline-block; width: 650px; font-family: \\\\\\"Roboto Slab\\\\\\"; contain: content; }:host([background]) { background: var(--background-color, #9E9E9E); border-radius: 10px; padding: 10px; }#panels { box-shadow: rgba(0, 0, 0, 0.3) 0px 2px 2px; background: white; border-radius: 3px; padding: 16px; height: 250px; overflow: auto; }#tabs { display: inline-flex; user-select: none; }#tabs slot { display: inline-flex; }#tabs ::slotted(*) { font: 400 16px / 22px Roboto; padding: 16px 8px; margin: 0px; text-align: center; width: 100px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; cursor: pointer; border-top-left-radius: 3px; border-top-right-radius: 3px; background: linear-gradient(rgb(250, 250, 250), rgb(238, 238, 238)); border: none; }#tabs ::slotted([aria-selected=\\\\\\"true\\\\\\"]) { font-weight: 600; background: white; box-shadow: none; }#tabs ::slotted(:focus) { z-index: 1; }#panels ::slotted([aria-hidden=\\\\\\"true\\\\\\"]) { display: none; }\\",
\\"isStyle\\": true,
\\"id\\": 38
}
Expand Down
2 changes: 1 addition & 1 deletion packages/rrweb-snapshot/test/html/picture-blob.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
const robotBlobUrl = URL.createObjectURL(robotBlob);
const images = document.querySelectorAll('img');
images.forEach((img) => {
img.src = robotBlobUrl;
img.setAttribute('src', robotBlobUrl);
});
}, 0);
</script>
Expand Down
42 changes: 25 additions & 17 deletions packages/rrweb-snapshot/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ describe('integration tests', function (this: ISuite) {
waitUntil: 'load',
});
}
const rebuildHtml = (
await page.evaluate(`${code}
await waitForRAF(page);
const rebuildHtml = ((await page.evaluate(`${code}
const x = new XMLSerializer();
const snap = rrweb.snapshot(document);
let out = x.serializeToString(rrweb.rebuild(snap, { doc: document }));
Expand All @@ -138,8 +138,12 @@ describe('integration tests', function (this: ISuite) {
out = out.replace(' xmlns=\"http://www.w3.org/1999/xhtml\"', '');
}
out; // return
`)
).replace(/\n\n/g, '');
`)) as string)
.replace(/\n\n/g, '')
.replace(
/blob:http:\/\/localhost:\d+\/[0-9a-z\-]+/,
'blob:http://localhost:xxxx/...',
);
expect(rebuildHtml).toMatchSnapshot();
});
}
Expand All @@ -158,9 +162,9 @@ describe('integration tests', function (this: ISuite) {
compatMode +
' for compat-mode.html should be BackCompat as DOCTYPE is deliberately omitted',
);
const renderedHeight = await page.evaluate(
const renderedHeight = (await page.evaluate(
'document.querySelector("center").clientHeight',
);
)) as number;
// can remove following assertion if dimensions of page change
assert(
renderedHeight < 400,
Expand Down Expand Up @@ -203,8 +207,10 @@ iframe.contentDocument.querySelector('center').clientHeight
inlineImages: true,
inlineStylesheet: false
})`);
await page.waitFor(100);
const snapshot = await page.evaluate('JSON.stringify(snapshot, null, 2);');
await waitForRAF(page);
const snapshot = (await page.evaluate(
'JSON.stringify(snapshot, null, 2);',
)) as string;
assert(snapshot.includes('"rr_dataURL"'));
assert(snapshot.includes('data:image/webp;base64,'));
});
Expand All @@ -221,8 +227,10 @@ iframe.contentDocument.querySelector('center').clientHeight
inlineImages: true,
inlineStylesheet: false
})`);
await page.waitFor(100);
const snapshot = await page.evaluate('JSON.stringify(snapshot, null, 2);');
await waitForRAF(page);
const snapshot = (await page.evaluate(
'JSON.stringify(snapshot, null, 2);',
)) as string;
assert(snapshot.includes('"rr_dataURL"'));
assert(snapshot.includes('data:image/webp;base64,'));
});
Expand All @@ -244,10 +252,10 @@ iframe.contentDocument.querySelector('center').clientHeight
window.snapshot = sn;
}
})`);
await page.waitFor(100);
const snapshot = await page.evaluate(
await waitForRAF(page);
const snapshot = (await page.evaluate(
'JSON.stringify(window.snapshot, null, 2);',
);
)) as string;
assert(snapshot.includes('"rr_dataURL"'));
assert(snapshot.includes('data:image/webp;base64,'));
});
Expand All @@ -269,10 +277,10 @@ iframe.contentDocument.querySelector('center').clientHeight
window.snapshot = sn;
}
})`);
await page.waitFor(100);
const snapshot = await page.evaluate(
await waitForRAF(page);
const snapshot = (await page.evaluate(
'JSON.stringify(window.snapshot, null, 2);',
);
)) as string;
assert(snapshot.includes('"rr_dataURL"'));
assert(snapshot.includes('data:image/webp;base64,'));
});
Expand All @@ -287,7 +295,7 @@ iframe.contentDocument.querySelector('center').clientHeight
window.snapshot = rrweb.snapshot(document, {
inlineStylesheet: true,
})`);
await page.waitFor(100);
await waitForRAF(page);
const snapshot = (await page.evaluate(
'JSON.stringify(window.snapshot, null, 2);',
)) as string;
Expand Down
4 changes: 1 addition & 3 deletions packages/rrweb/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ export {
ReplayerEvents,
} from '@rrweb/types';

export type {
recordOptions,
} from './types';
export type { recordOptions } from './types';

const { addCustomEvent } = record;
const { freezePage } = record;
Expand Down
2 changes: 1 addition & 1 deletion packages/rrweb/test/html/frame2.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
iframe5.id = 'five';
setTimeout(() => {
document.body.appendChild(iframe5);
}, 10);
}, 100);
</script>
</html>
2 changes: 1 addition & 1 deletion packages/rrweb/test/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ describe('record integration tests', function (this: ISuite) {
await page.goto('about:blank');
await page.setContent(getHtml.call(this, 'frame2.html'));

await page.waitForTimeout(10); // wait till frame was added to dom
await page.waitForSelector('iframe'); // wait for iframe to get added
await waitForRAF(page); // wait till browser loaded contents of frame

await page.evaluate(() => {
Expand Down
29 changes: 22 additions & 7 deletions packages/rrweb/test/replayer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -798,8 +798,23 @@ describe('replayer', function () {
events = ${JSON.stringify(adoptedStyleSheetModification)};
const { Replayer } = rrweb;
var replayer = new Replayer(events,{showDebug:true});
replayer.play();
`);
replayer.pause(0);

async function playTill(offsetTime) {
replayer.play();
return new Promise((resolve) => {
const checkTime = () => {
if (replayer.getCurrentTime() >= offsetTime) {
replayer.pause();
resolve(undefined);
} else {
requestAnimationFrame(checkTime);
}
};
checkTime();
});
}`);

const iframe = await page.$('iframe');
const contentDocument = await iframe!.contentFrame()!;

Expand Down Expand Up @@ -916,19 +931,19 @@ describe('replayer', function () {
).toBeTruthy();
};

await page.waitForTimeout(235);
await page.evaluate(`playTill(250)`);
await check250ms();

await page.waitForTimeout(50);
await page.evaluate(`playTill(300)`);
await check300ms();

await page.waitForTimeout(100);
await page.evaluate(`playTill(400)`);
await check400ms();

await page.waitForTimeout(100);
await page.evaluate(`playTill(500)`);
await check500ms();

await page.waitForTimeout(100);
await page.evaluate(`playTill(600)`);
await check600ms();

// To test the correctness of replaying adopted stylesheet mutation events in the fast-forward mode.
Expand Down
8 changes: 8 additions & 0 deletions packages/rrweb/test/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,14 @@ function stringifySnapshots(snapshots: eventWithTime[]): string {
}
}
});
} else if (
s.type === EventType.IncrementalSnapshot &&
s.data.source === IncrementalSource.MediaInteraction
) {
// round the currentTime to 1 decimal place
if (s.data.currentTime) {
s.data.currentTime = Math.round(s.data.currentTime * 10) / 10;
}
}
delete (s as Optional<eventWithTime, 'timestamp'>).timestamp;
return s as event;
Expand Down
Loading