From 8a9212fed451502485749485d9c38ebcee969708 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 17 Jun 2021 15:02:42 +0200 Subject: [PATCH] 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 --- .travis.yml | 4 + package.json | 4 +- src/record/index.ts | 2 +- test/__snapshots__/integration.test.ts.snap | 562 ++++++++++---------- test/__snapshots__/record.test.ts.snap | 9 +- test/integration.test.ts | 6 +- test/record.test.ts | 82 ++- yarn.lock | 365 ++++++++----- 8 files changed, 588 insertions(+), 446 deletions(-) diff --git a/.travis.yml b/.travis.yml index 52d6bad9..ff245c5f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ language: node_js +os: linux + +dist: focal + node_js: - 12 diff --git a/package.json b/package.json index 4084e8b7..f1f6cf8e 100644 --- a/package.json +++ b/package.json @@ -41,14 +41,14 @@ "@types/inquirer": "0.0.43", "@types/mocha": "^5.2.5", "@types/node": "^10.11.7", - "@types/puppeteer": "^1.11.1", + "@types/puppeteer": "^5.4.3", "chai": "^4.2.0", "cross-env": "^5.2.0", "inquirer": "^6.2.1", "jest-snapshot": "^23.6.0", "mocha": "^5.2.0", "prettier": "2.2.1", - "puppeteer": "^1.11.0", + "puppeteer": "^9.1.1", "rollup": "^2.3.3", "rollup-plugin-commonjs": "^9.2.0", "rollup-plugin-node-resolve": "^3.4.0", diff --git a/src/record/index.ts b/src/record/index.ts index 1331d02a..4738a144 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -167,7 +167,7 @@ function record( lastFullSnapshotEvent = e; incrementalSnapshotCount = 0; } else if (e.type === EventType.IncrementalSnapshot) { - // attch iframe should be considered as full snapshot + // attach iframe should be considered as full snapshot if ( e.data.source === IncrementalSource.Mutation && e.data.isAttachIframe diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index 7326b4eb..e2f17250 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -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 - } - } - ] - } } ]" `; diff --git a/test/__snapshots__/record.test.ts.snap b/test/__snapshots__/record.test.ts.snap index 70c7ec05..f2278ded 100644 --- a/test/__snapshots__/record.test.ts.snap +++ b/test/__snapshots__/record.test.ts.snap @@ -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 diff --git a/test/integration.test.ts b/test/integration.test.ts index e14d40fe..6d5234e7 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -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'); diff --git a/test/record.test.ts b/test/record.test.ts index 025675a0..fd78052e 100644 --- a/test/record.test.ts +++ b/test/record.test.ts @@ -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(` - - - - - - `); + 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, + ` + + + + + + `, + ); 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, + ` + + +