Tests: Iframe event order (#568)

* add failing test

* assert order of events

* defer attaching of iframe till FullSnapshot is done
Fixes: https://github.com/rrweb-io/rrweb/issues/567

* correct event order in iframe integration test snapshot

* trigger build

* trigger build

* Move settimeout responsibility to snapshot
https://github.com/rrweb-io/rrweb-snapshot/pull/78

* upgrade rrweb-snapshot to 1.1.4

* DRY record tests

* cleanup

* Upgrade puppeteer to 9.1.1
for (hopefully) more consistent behaviour between CI and development

* make input bigger to prevent triggering scroll events

* page.waitFor is deprecated
more info: https://github.com/puppeteer/puppeteer/issues/6214

* Set os and distro for Travis ci

Co-authored-by: yz-yu <yanzhen@smartx.com>
This commit is contained in:
Justin Halsall
2026-04-01 12:00:00 +08:00
committed by GitHub
parent b9e1938951
commit 80e7307729
8 changed files with 588 additions and 446 deletions

View File

@@ -32,9 +32,7 @@ interface IWindow extends Window {
emit: (e: eventWithTime) => undefined;
}
describe('record', function (this: ISuite) {
this.timeout(10_000);
const setup = async function (this: ISuite, content: string) {
before(async () => {
this.browser = await launchPuppeteer();
@@ -45,13 +43,7 @@ describe('record', function (this: ISuite) {
beforeEach(async () => {
const page: puppeteer.Page = await this.browser.newPage();
await page.goto('about:blank');
await page.setContent(`
<html>
<body>
<input type="text" />
</body>
</html>
`);
await page.setContent(content);
await page.evaluate(this.code);
this.page = page;
this.events = [];
@@ -72,6 +64,21 @@ describe('record', function (this: ISuite) {
after(async () => {
await this.browser.close();
});
};
describe('record', function (this: ISuite) {
this.timeout(10_000);
setup.call(
this,
`
<html>
<body>
<input type="text" size="40" />
</body>
</html>
`,
);
it('will only have one full snapshot without checkout config', async () => {
await this.page.evaluate(() => {
@@ -84,7 +91,7 @@ describe('record', function (this: ISuite) {
while (count--) {
await this.page.type('input', 'a');
}
await this.page.waitFor(10);
await this.page.waitForTimeout(10);
expect(this.events.length).to.equal(33);
expect(
this.events.filter(
@@ -110,7 +117,7 @@ describe('record', function (this: ISuite) {
while (count--) {
await this.page.type('input', 'a');
}
await this.page.waitFor(10);
await this.page.waitForTimeout(10);
expect(this.events.length).to.equal(39);
expect(
this.events.filter(
@@ -140,11 +147,11 @@ describe('record', function (this: ISuite) {
while (count--) {
await this.page.type('input', 'a');
}
await this.page.waitFor(300);
await this.page.waitForTimeout(300);
expect(this.events.length).to.equal(33); // before first automatic snapshot
await this.page.waitFor(200); // could be 33 or 35 events by now depending on speed of test env
await this.page.waitForTimeout(200); // could be 33 or 35 events by now depending on speed of test env
await this.page.type('input', 'a');
await this.page.waitFor(10);
await this.page.waitForTimeout(10);
expect(this.events.length).to.equal(36); // additionally includes the 2 checkout events
expect(
this.events.filter(
@@ -182,7 +189,7 @@ describe('record', function (this: ISuite) {
document.body.appendChild(span);
}, 10);
});
await this.page.waitFor(100);
await this.page.waitForTimeout(100);
assertSnapshot(this.events, __filename, 'async-checkout');
});
@@ -197,7 +204,7 @@ describe('record', function (this: ISuite) {
a: 'b',
});
});
await this.page.waitFor(50);
await this.page.waitForTimeout(50);
assertSnapshot(this.events, __filename, 'custom-event');
});
@@ -226,7 +233,7 @@ describe('record', function (this: ISuite) {
styleSheet.insertRule('body { color: #ccc; }');
}, 10);
});
await this.page.waitFor(50);
await this.page.waitForTimeout(50);
const styleSheetRuleEvents = this.events.filter(
(e) =>
e.type === EventType.IncrementalSnapshot &&
@@ -244,3 +251,42 @@ describe('record', function (this: ISuite) {
assertSnapshot(this.events, __filename, 'stylesheet-rules');
});
});
describe('record iframes', function (this: ISuite) {
this.timeout(10_000);
setup.call(
this,
`
<html>
<body>
<iframe srcdoc="<button>Mysterious Button</button>" />
</body>
</html>
`,
);
it('captures iframe content in correct order', async () => {
await this.page.evaluate(() => {
const { record } = ((window as unknown) as IWindow).rrweb;
record({
emit: ((window as unknown) as IWindow).emit,
});
});
await this.page.waitForTimeout(10);
// console.log(JSON.stringify(this.events));
expect(this.events.length).to.equal(3);
const eventTypes = this.events
.filter(
(e) =>
e.type === EventType.IncrementalSnapshot ||
e.type === EventType.FullSnapshot,
)
.map((e) => e.type);
expect(eventTypes).to.have.ordered.members([
EventType.FullSnapshot,
EventType.IncrementalSnapshot,
]);
});
});