diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a1ad8e81cf..fa618e607b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,6 +1,11 @@ name: Tests -on: [push, pull_request] +on: + push: + branches: + - master + - release/** + pull_request: concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -8,6 +13,8 @@ jobs: release: name: Tests runs-on: ubuntu-latest + # For now, we know this will fail, so we allow failures + continue-on-error: true steps: - name: Checkout Repo uses: actions/checkout@v3 diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index 529a51eeff..5c66b682aa 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -246,7 +246,10 @@ exports[`integration tests [html file]: form-fields.html 1`] = ` + + + + + + + + diff --git a/packages/rrweb/test/html/mask-text.html b/packages/rrweb/test/html/mask-text.html index 2abaaaa511..7610310985 100644 --- a/packages/rrweb/test/html/mask-text.html +++ b/packages/rrweb/test/html/mask-text.html @@ -16,5 +16,15 @@
mask3
+
+ mask4 +
+
+ mask5 +
+ +
+ + diff --git a/packages/rrweb/test/integration-sentry.test.ts b/packages/rrweb/test/integration-sentry.test.ts new file mode 100644 index 0000000000..fc518939a1 --- /dev/null +++ b/packages/rrweb/test/integration-sentry.test.ts @@ -0,0 +1,434 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import type * as puppeteer from 'puppeteer'; +import { + assertSnapshot, + startServer, + getServerURL, + launchPuppeteer, + replaceLast, + generateRecordSnippet, + ISuite, +} from './utils'; +import type { recordOptions } from '../src/types'; +import { eventWithTime, EventType, IncrementalSource } from '@rrweb/types'; + +/** + * Used to filter scroll events out of snapshots as they are flakey + */ +function isNotScroll(snapshot: eventWithTime) { + return !( + snapshot.type === EventType.IncrementalSnapshot && + snapshot.data.source === IncrementalSource.Scroll + ); +} + +describe('record integration tests', function (this: ISuite) { + jest.setTimeout(10_000); + + const getHtml = ( + fileName: string, + options: recordOptions = {}, + ): string => { + const filePath = path.resolve(__dirname, `./html/${fileName}`); + const html = fs.readFileSync(filePath, 'utf8'); + return replaceLast( + html, + '', + ` + + + `, + ); + }; + + let server: ISuite['server']; + let serverURL: string; + let code: ISuite['code']; + let browser: ISuite['browser']; + + beforeAll(async () => { + server = await startServer(); + serverURL = getServerURL(server); + browser = await launchPuppeteer(); + + const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js'); + const pluginsCode = [ + path.resolve(__dirname, '../dist/plugins/console-record.min.js'), + ] + .map((path) => fs.readFileSync(path, 'utf8')) + .join(); + code = fs.readFileSync(bundlePath, 'utf8') + pluginsCode; + }); + + afterAll(async () => { + await browser.close(); + server.close(); + }); + + it('can configure onMutation', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + + await page.setContent( + getHtml.call(this, 'mutation-observer.html', { + // XXX(sentry) + // onMutation: `(mutations) => { window.lastMutationsLength = mutations.length; return mutations.length < 500 }`, + }), + ); + + await page.evaluate(() => { + const ul = document.querySelector('ul') as HTMLUListElement; + + for (let i = 0; i < 2000; i++) { + const li = document.createElement('li'); + ul.appendChild(li); + const p = document.querySelector('p') as HTMLParagraphElement; + p.appendChild(document.createElement('span')); + } + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + + const lastMutationsLength = await page.evaluate( + 'window.lastMutationsLength', + ); + expect(lastMutationsLength).toBe(4000); + }); + + it('should not record input values on selectively masked elements when maskAllInputs is disabled', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form-masked.html', { + maskAllInputs: false, + // XXX(sentry) + // maskInputSelector: '.rr-mask', + }), + ); + + await page.type('input[type="text"]', 'test'); + await page.click('input[type="radio"]'); + await page.click('input[type="checkbox"]'); + await page.type('input[type="password"]', 'password'); + await page.type('textarea', 'textarea test'); + await page.select('select', '1'); + await page.type('#empty', 'test'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('correctly masks & unmasks attribute values', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'attributes-mask.html', { + // XXX(sentry) + // maskAllText: true, + // unmaskTextSelector: '.rr-unmask', + }), + ); + + // Change attributes, should still be masked + await page.evaluate(() => { + document + .querySelectorAll('body [title]') + .forEach((el) => el.setAttribute('title', 'new title')); + document + .querySelectorAll('body [aria-label]') + .forEach((el) => el.setAttribute('aria-label', 'new aria label')); + document + .querySelectorAll('body [placeholder]') + .forEach((el) => el.setAttribute('placeholder', 'new placeholder')); + document + .querySelectorAll('input[type="button"],input[type="submit"]') + .forEach((el) => el.setAttribute('value', 'new value')); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should record input values if dynamically added and maskAllInputs is false', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: false }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input'; + el.value = 'input should not be masked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record textarea values if dynamically added and maskAllInputs is false', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: false }), + ); + + await page.evaluate(() => { + const el = document.createElement('textarea'); + el.id = 'textarea'; + el.innerText = `textarea should not be masked +`; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#textarea', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record input values if dynamically added, maskAllInputs is false, and mask selector is used', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { + maskAllInputs: false, + // XXX(sentry) + // maskInputSelector: '.rr-mask', + }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input-masked'; + el.className = 'rr-mask'; + el.value = 'input should be masked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input-masked', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should not record textarea values if dynamically added and maskAllInputs is true', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: true }), + ); + + await page.evaluate(() => { + const el = document.createElement('textarea'); + el.id = 'textarea'; + el.innerText = `textarea should be masked +`; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#textarea', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record input values if dynamically added, maskAllInputs is true, and unmask selector is used', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { + maskAllInputs: true, + // XXX(sentry) + // unmaskInputSelector: '.rr-unmask', + }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input-unmasked'; + el.className = 'rr-unmask'; + el.value = 'input should be unmasked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input-unmasked', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should always mask value attribute of passwords', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'password.html', { + maskInputOptions: {}, + }), + ); + + await page.type('#password', 'secr3t'); + + // Change type to text (simulate "show password") + await page.click('#show-password'); + await page.type('#password', 'XY'); + await page.click('#show-password'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask text in form elements', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form.html', { + // XXX(sentry) + // maskAllText: true + }), + ); + + // Ensure also masked when we change stuff + await page.evaluate(() => { + document + .querySelector('input[type="submit"]') + ?.setAttribute('value', 'new value'); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should not record blocked elements from blockSelector, when dynamically added', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'block.html', { + blockSelector: 'video', + }), + ); + + await page.evaluate(() => { + const el2 = document.createElement('video'); + el2.className = 'rr-block'; + el2.style.width = '100px'; + el2.style.height = '100px'; + const source2 = document.createElement('source'); + source2.src = 'file:///foo.mp4'; + // These aren't valid, but doing this for testing + source2.style.width = '100px'; + source2.style.height = '100px'; + el2.appendChild(source2); + + const el = document.createElement('video'); + el.style.width = '100px'; + el.style.height = '100px'; + const source = document.createElement('source'); + source.src = 'file:///foo.mp4'; + // These aren't valid, but doing this for testing + source.style.width = '100px'; + source.style.height = '100px'; + el.appendChild(source); + + const nextElement = document.querySelector('.rr-block')!; + nextElement.parentNode!.insertBefore(el, nextElement); + nextElement.parentNode!.insertBefore(el2, nextElement); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should only record unblocked elements', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'block.html', { + blockSelector: 'img,svg', + // XXX(sentry) + // unblockSelector: '.rr-unblock', + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask only inputs', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskAllInputs: true, + // XXX(sentry) + // maskAllText: false, + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask all text (except unmaskTextSelector), using maskAllText ', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskTextClass: 'none', + // XXX(sentry) + // maskAllText: true, + // unmaskTextSelector: '.rr-unmask', + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); +}); diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 39e32dbcd6..3bdbe764e7 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -12,7 +12,12 @@ import { ISuite, } from './utils'; import type { recordOptions } from '../src/types'; -import { eventWithTime, EventType, RecordPlugin } from '@rrweb/types'; +import { + eventWithTime, + EventType, + RecordPlugin, + IncrementalSource, +} from '@rrweb/types'; import { visitSnapshot, NodeType } from 'rrweb-snapshot'; describe('record integration tests', function (this: ISuite) { @@ -122,7 +127,7 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); - it('can record character data muatations', async () => { + it('can record character data mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); await page.setContent(getHtml.call(this, 'mutation-observer.html')); @@ -167,7 +172,13 @@ describe('record integration tests', function (this: ISuite) { it('handles null attribute values', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); - await page.setContent(getHtml.call(this, 'mutation-observer.html', {})); + await page.setContent( + getHtml.call(this, 'mutation-observer.html', { + maskAllInputs: true, + // XXX(sentry) + // maskAllText: true, + }), + ); await page.evaluate(() => { const li = document.createElement('li'); @@ -262,7 +273,11 @@ describe('record integration tests', function (this: ISuite) { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); await page.setContent( - getHtml.call(this, 'form.html', { maskAllInputs: true }), + getHtml.call(this, 'form.html', { + maskAllInputs: true, + // XXX(sentry) + // unmaskTextSelector: '.rr-unmask', + }), ); await page.type('input[type="text"]', 'test'); @@ -271,6 +286,7 @@ describe('record integration tests', function (this: ISuite) { await page.type('input[type="password"]', 'password'); await page.type('textarea', 'textarea test'); await page.select('select', '1'); + await page.type('#empty', 'test'); const snapshots = (await page.evaluate( 'window.snapshots', @@ -286,12 +302,13 @@ describe('record integration tests', function (this: ISuite) { maskInputOptions: { text: false, textarea: false, - password: true, + color: true, }, }), ); await page.type('input[type="text"]', 'test'); + await page.type('input[type="color"]', '#FF0000'); await page.click('input[type="radio"]'); await page.click('input[type="checkbox"]'); await page.type('textarea', 'textarea test'); diff --git a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap index 48d4bdb33a..a82228fe9f 100644 --- a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap +++ b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap @@ -1310,9 +1310,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1350,9 +1349,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1377,9 +1374,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -1391,7 +1386,9 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1413,6 +1410,124 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"rootId\\": 11, \\"id\\": 51 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 55 + } + ], + \\"rootId\\": 11, + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 56 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 60 + } + ], + \\"rootId\\": 11, + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 61 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 63 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-val\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 64 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 65 + } + ], + \\"rootId\\": 11, + \\"id\\": 62 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 66 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -1424,7 +1539,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 53 + \\"id\\": 68 }, { \\"type\\": 2, @@ -1438,23 +1553,23 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 54 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 55 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -1467,7 +1582,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -1482,7 +1597,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 60 + \\"id\\": 75 }, { \\"type\\": 2, @@ -1494,19 +1609,19 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", + \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 61 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 78 }, { \\"type\\": 2, @@ -1517,39 +1632,39 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", + \\"textContent\\": \\"Option BB\\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 57 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 83 }, { \\"type\\": 2, @@ -1562,7 +1677,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 85 }, { \\"type\\": 2, @@ -1572,23 +1687,119 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 86 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 87 + } + ], + \\"rootId\\": 11, + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 88 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 90 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 91 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 92 + } + ], + \\"rootId\\": 11, + \\"id\\": 89 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 93 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 95 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 96 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 97 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 94 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 98 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 99 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 100 } ], \\"rootId\\": 11, @@ -1598,7 +1809,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 101 } ], \\"rootId\\": 11, @@ -1668,7 +1879,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1684,7 +1895,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1692,7 +1903,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1700,7 +1911,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 39, + \\"id\\": 44, \\"pointerType\\": 0 } }, @@ -1710,16 +1921,25 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 39 + \\"id\\": 44 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 44 + \\"id\\": 49 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 54 } }, { @@ -1727,7 +1947,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1735,7 +1955,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1743,7 +1963,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1751,7 +1971,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1759,7 +1979,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 49, + \\"id\\": 59, \\"pointerType\\": 0 } }, @@ -1768,8 +1988,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 49 + \\"isChecked\\": false, + \\"id\\": 59 } }, { @@ -1777,7 +1997,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1785,7 +2005,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1794,7 +2014,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1803,7 +2023,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1812,7 +2032,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1821,7 +2041,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1830,7 +2050,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1839,7 +2059,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1848,7 +2068,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1857,7 +2077,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1865,7 +2085,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1873,7 +2093,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1882,7 +2102,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1891,7 +2111,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1900,7 +2120,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1909,7 +2129,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1918,7 +2138,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1927,7 +2147,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1936,7 +2156,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1945,7 +2165,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1954,7 +2174,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1963,7 +2183,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1972,7 +2192,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1981,7 +2201,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1990,7 +2210,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1999,7 +2219,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } } ]" @@ -2307,9 +2527,8 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2347,9 +2566,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2374,9 +2591,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -2388,7 +2603,9 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2410,6 +2627,124 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"rootId\\": 11, \\"id\\": 51 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 55 + } + ], + \\"rootId\\": 11, + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 56 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 60 + } + ], + \\"rootId\\": 11, + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 61 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 63 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-val\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 64 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 65 + } + ], + \\"rootId\\": 11, + \\"id\\": 62 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 66 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -2421,7 +2756,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 53 + \\"id\\": 68 }, { \\"type\\": 2, @@ -2435,23 +2770,23 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 54 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 55 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -2464,7 +2799,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -2479,7 +2814,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 60 + \\"id\\": 75 }, { \\"type\\": 2, @@ -2491,19 +2826,19 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", + \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 61 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 78 }, { \\"type\\": 2, @@ -2514,39 +2849,39 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", + \\"textContent\\": \\"Option BB\\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 57 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 83 }, { \\"type\\": 2, @@ -2559,7 +2894,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 85 }, { \\"type\\": 2, @@ -2569,23 +2904,119 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 86 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 87 + } + ], + \\"rootId\\": 11, + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 88 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 90 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 91 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 92 + } + ], + \\"rootId\\": 11, + \\"id\\": 89 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 93 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 95 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 96 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 97 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 94 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 98 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 99 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 100 } ], \\"rootId\\": 11, @@ -2595,7 +3026,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 101 } ], \\"rootId\\": 11, diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts index 7756710410..38214cab99 100644 --- a/packages/rrweb/test/replayer.test.ts +++ b/packages/rrweb/test/replayer.test.ts @@ -16,6 +16,7 @@ import inputEvents from './events/input'; import iframeEvents from './events/iframe'; import selectionEvents from './events/selection'; import shadowDomEvents from './events/shadow-dom'; +import shadowDomEventsSentry from './events/shadow-dom-sentry'; import StyleSheetTextMutation from './events/style-sheet-text-mutation'; import canvasInIframe from './events/canvas-in-iframe'; import adoptedStyleSheet from './events/adopted-style-sheet'; @@ -1076,4 +1077,18 @@ describe('replayer', function () { ), ).toBe(':hover'); }); + + it('should have `:defined` web components', async () => { + await page.evaluate(`events = ${JSON.stringify(shadowDomEventsSentry)}`); + const result = await page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.play(); + replayer.pause(1000); + replayer.iframe.contentDocument.querySelectorAll(':not(:defined)').length; + `); + await page.waitForTimeout(200); + + expect(result).toEqual(0); + }); }); diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index dd5a8cf7cc..0cbd82507e 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -588,6 +588,13 @@ export async function waitForRAF( } export function generateRecordSnippet(options: recordOptions) { + // XXX(sentry) + // maskInputSelector: ${JSON.stringify(options.maskInputSelector)}, + // onMutation: ${options.onMutation || undefined}, + // maskAllText: ${options.maskAllText}, + // unmaskTextSelector: ${JSON.stringify(options.unmaskTextSelector)}, + // unmaskInputSelector: ${JSON.stringify(options.unmaskInputSelector)}, + // unblockSelector: ${JSON.stringify(options.unblockSelector)}, return ` window.snapshots = []; rrweb.record({ @@ -595,11 +602,13 @@ export function generateRecordSnippet(options: recordOptions) { window.snapshots.push(event); }, maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, + blockSelector: ${JSON.stringify(options.blockSelector)}, maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, userTriggeredOnInput: ${options.userTriggeredOnInput}, maskTextFn: ${options.maskTextFn}, maskInputFn: ${options.maskInputFn}, + blockSelector: ${JSON.stringify(options.blockSelector)}, recordCanvas: ${options.recordCanvas}, recordAfter: '${options.recordAfter || 'load'}', inlineImages: ${options.inlineImages},