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
2021-06-17 15:02:42 +02:00
committed by GitHub
parent 069397c2c7
commit 8a9212fed4
8 changed files with 588 additions and 446 deletions

View File

@@ -1745,53 +1745,6 @@ exports[`iframe 1`] = `
\\"height\\": 1080
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 19,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 20,
\\"id\\": 22
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 20,
\\"id\\": 23
}
],
\\"rootId\\": 20,
\\"id\\": 21
}
],
\\"id\\": 20
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 2,
\\"data\\": {
@@ -1918,7 +1871,7 @@ exports[`iframe 1`] = `
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\\\n \\",
\\"id\\": 24
\\"id\\": 20
},
{
\\"type\\": 2,
@@ -1928,15 +1881,15 @@ exports[`iframe 1`] = `
{
\\"type\\": 3,
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
\\"id\\": 26
\\"id\\": 22
}
],
\\"id\\": 25
\\"id\\": 21
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\\\n \\\\n \\",
\\"id\\": 27
\\"id\\": 23
},
{
\\"type\\": 2,
@@ -1946,15 +1899,15 @@ exports[`iframe 1`] = `
{
\\"type\\": 3,
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
\\"id\\": 29
\\"id\\": 25
}
],
\\"id\\": 28
\\"id\\": 24
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n\\\\n\\",
\\"id\\": 30
\\"id\\": 26
}
],
\\"id\\": 17
@@ -1971,6 +1924,53 @@ exports[`iframe 1`] = `
}
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 19,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 27,
\\"id\\": 29
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 27,
\\"id\\": 30
}
],
\\"rootId\\": 27,
\\"id\\": 28
}
],
\\"id\\": 27
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
@@ -1995,205 +1995,6 @@ exports[`iframe 1`] = `
]
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 47,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 48,
\\"id\\": 50
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 48,
\\"id\\": 51
}
],
\\"rootId\\": 48,
\\"id\\": 49
}
],
\\"id\\": 48
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 53,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 1,
\\"name\\": \\"html\\",
\\"publicId\\": \\"\\",
\\"systemId\\": \\"\\",
\\"rootId\\": 54,
\\"id\\": 55
},
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {
\\"lang\\": \\"en\\"
},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 54,
\\"id\\": 58
},
{
\\"type\\": 2,
\\"tagName\\": \\"meta\\",
\\"attributes\\": {
\\"charset\\": \\"UTF-8\\"
},
\\"childNodes\\": [],
\\"rootId\\": 54,
\\"id\\": 59
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 54,
\\"id\\": 60
},
{
\\"type\\": 2,
\\"tagName\\": \\"meta\\",
\\"attributes\\": {
\\"name\\": \\"viewport\\",
\\"content\\": \\"width=device-width, initial-scale=1.0\\"
},
\\"childNodes\\": [],
\\"rootId\\": 54,
\\"id\\": 61
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 54,
\\"id\\": 62
},
{
\\"type\\": 2,
\\"tagName\\": \\"title\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"Frame 2\\",
\\"rootId\\": 54,
\\"id\\": 64
}
],
\\"rootId\\": 54,
\\"id\\": 63
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 54,
\\"id\\": 65
}
],
\\"rootId\\": 54,
\\"id\\": 57
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 54,
\\"id\\": 66
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n frame 2\\\\n \\\\n \\",
\\"rootId\\": 54,
\\"id\\": 68
},
{
\\"type\\": 2,
\\"tagName\\": \\"script\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
\\"rootId\\": 54,
\\"id\\": 70
}
],
\\"rootId\\": 54,
\\"id\\": 69
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n\\\\n\\",
\\"rootId\\": 54,
\\"id\\": 71
}
],
\\"rootId\\": 54,
\\"id\\": 67
}
],
\\"rootId\\": 54,
\\"id\\": 56
}
],
\\"id\\": 54
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
@@ -2321,7 +2122,7 @@ exports[`iframe 1`] = `
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 32,
\\"id\\": 52
\\"id\\": 48
},
{
\\"type\\": 2,
@@ -2332,13 +2133,13 @@ exports[`iframe 1`] = `
},
\\"childNodes\\": [],
\\"rootId\\": 32,
\\"id\\": 53
\\"id\\": 49
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\\\n\\\\n\\",
\\"rootId\\": 32,
\\"id\\": 72
\\"id\\": 50
}
],
\\"rootId\\": 32,
@@ -2359,6 +2160,230 @@ exports[`iframe 1`] = `
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 47,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 51,
\\"id\\": 53
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [],
\\"rootId\\": 51,
\\"id\\": 54
}
],
\\"rootId\\": 51,
\\"id\\": 52
}
],
\\"id\\": 51
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"adds\\": [
{
\\"parentId\\": 49,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 0,
\\"childNodes\\": [
{
\\"type\\": 1,
\\"name\\": \\"html\\",
\\"publicId\\": \\"\\",
\\"systemId\\": \\"\\",
\\"rootId\\": 55,
\\"id\\": 56
},
{
\\"type\\": 2,
\\"tagName\\": \\"html\\",
\\"attributes\\": {
\\"lang\\": \\"en\\"
},
\\"childNodes\\": [
{
\\"type\\": 2,
\\"tagName\\": \\"head\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 55,
\\"id\\": 59
},
{
\\"type\\": 2,
\\"tagName\\": \\"meta\\",
\\"attributes\\": {
\\"charset\\": \\"UTF-8\\"
},
\\"childNodes\\": [],
\\"rootId\\": 55,
\\"id\\": 60
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 55,
\\"id\\": 61
},
{
\\"type\\": 2,
\\"tagName\\": \\"meta\\",
\\"attributes\\": {
\\"name\\": \\"viewport\\",
\\"content\\": \\"width=device-width, initial-scale=1.0\\"
},
\\"childNodes\\": [],
\\"rootId\\": 55,
\\"id\\": 62
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 55,
\\"id\\": 63
},
{
\\"type\\": 2,
\\"tagName\\": \\"title\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"Frame 2\\",
\\"rootId\\": 55,
\\"id\\": 65
}
],
\\"rootId\\": 55,
\\"id\\": 64
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 55,
\\"id\\": 66
}
],
\\"rootId\\": 55,
\\"id\\": 58
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n \\",
\\"rootId\\": 55,
\\"id\\": 67
},
{
\\"type\\": 2,
\\"tagName\\": \\"body\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n frame 2\\\\n \\\\n \\",
\\"rootId\\": 55,
\\"id\\": 69
},
{
\\"type\\": 2,
\\"tagName\\": \\"script\\",
\\"attributes\\": {},
\\"childNodes\\": [
{
\\"type\\": 3,
\\"textContent\\": \\"SCRIPT_PLACEHOLDER\\",
\\"rootId\\": 55,
\\"id\\": 71
}
],
\\"rootId\\": 55,
\\"id\\": 70
},
{
\\"type\\": 3,
\\"textContent\\": \\"\\\\n\\\\n\\",
\\"rootId\\": 55,
\\"id\\": 72
}
],
\\"rootId\\": 55,
\\"id\\": 68
}
],
\\"rootId\\": 55,
\\"id\\": 57
}
],
\\"id\\": 55
}
}
],
\\"removes\\": [],
\\"texts\\": [],
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"texts\\": [],
\\"attributes\\": [],
\\"removes\\": [],
\\"adds\\": [
{
\\"parentId\\": 68,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 2,
\\"tagName\\": \\"iframe\\",
\\"attributes\\": {
\\"id\\": \\"five\\"
},
\\"childNodes\\": [],
\\"rootId\\": 55,
\\"id\\": 73
}
}
]
}
},
{
\\"type\\": 3,
\\"data\\": {
@@ -2405,31 +2430,6 @@ exports[`iframe 1`] = `
\\"attributes\\": [],
\\"isAttachIframe\\": true
}
},
{
\\"type\\": 3,
\\"data\\": {
\\"source\\": 0,
\\"texts\\": [],
\\"attributes\\": [],
\\"removes\\": [],
\\"adds\\": [
{
\\"parentId\\": 67,
\\"nextId\\": null,
\\"node\\": {
\\"type\\": 2,
\\"tagName\\": \\"iframe\\",
\\"attributes\\": {
\\"id\\": \\"five\\"
},
\\"childNodes\\": [],
\\"rootId\\": 54,
\\"id\\": 73
}
}
]
}
}
]"
`;

View File

@@ -42,7 +42,8 @@ exports[`async-checkout 1`] = `
\\"type\\": 2,
\\"tagName\\": \\"input\\",
\\"attributes\\": {
\\"type\\": \\"text\\"
\\"type\\": \\"text\\",
\\"size\\": \\"40\\"
},
\\"childNodes\\": [],
\\"id\\": 6
@@ -283,7 +284,8 @@ exports[`custom-event 1`] = `
\\"type\\": 2,
\\"tagName\\": \\"input\\",
\\"attributes\\": {
\\"type\\": \\"text\\"
\\"type\\": \\"text\\",
\\"size\\": \\"40\\"
},
\\"childNodes\\": [],
\\"id\\": 6
@@ -369,7 +371,8 @@ exports[`stylesheet-rules 1`] = `
\\"type\\": 2,
\\"tagName\\": \\"input\\",
\\"attributes\\": {
\\"type\\": \\"text\\"
\\"type\\": \\"text\\",
\\"size\\": \\"40\\"
},
\\"childNodes\\": [],
\\"id\\": 6

View File

@@ -324,7 +324,7 @@ describe('record integration tests', function (this: ISuite) {
recordCanvas: true,
}),
);
await page.waitFor(50);
await page.waitForTimeout(50);
const snapshots = await page.evaluate('window.snapshots');
for (const event of snapshots) {
if (event.type === EventType.FullSnapshot) {
@@ -417,7 +417,7 @@ describe('record integration tests', function (this: ISuite) {
await page.goto(`http://localhost:3030/html`);
await page.setContent(getHtml.call(this, 'main.html'));
await page.waitFor(500);
await page.waitForTimeout(500);
const snapshots = await page.evaluate('window.snapshots');
assertSnapshot(snapshots, __filename, 'iframe');
});
@@ -453,7 +453,7 @@ describe('record integration tests', function (this: ISuite) {
'123';
});
});
await page.waitFor(50);
await page.waitForTimeout(50);
const snapshots = await page.evaluate('window.snapshots');
assertSnapshot(snapshots, __filename, 'shadow-dom');

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,
]);
});
});