From 894051fac8e58196f9680cd1f889f753ed2ea197 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 6 Jan 2023 14:14:11 -0500 Subject: [PATCH 01/60] support for mask all and unmask by selector and class #1096 --- guide.md | 4 + packages/rrweb-snapshot/src/snapshot.ts | 159 +++++++- .../__snapshots__/integration.test.ts.snap | 6 + packages/rrweb-snapshot/test/snapshot.test.ts | 226 +++++++++++ packages/rrweb/src/record/index.ts | 12 + packages/rrweb/src/record/mutation.ts | 12 + packages/rrweb/src/types.ts | 10 + .../__snapshots__/integration.test.ts.snap | 352 ++++++++++++++++++ .../test/__snapshots__/record.test.ts.snap | 59 +-- packages/rrweb/test/html/unmask-text.html | 23 ++ packages/rrweb/test/integration.test.ts | 25 ++ packages/rrweb/test/utils.ts | 2 + packages/types/src/index.ts | 1 + yarn.lock | 7 +- 14 files changed, 832 insertions(+), 66 deletions(-) create mode 100644 packages/rrweb/test/html/unmask-text.html diff --git a/guide.md b/guide.md index d7807bf00d..036af9aa61 100644 --- a/guide.md +++ b/guide.md @@ -145,8 +145,11 @@ The parameter of `rrweb.record` accepts the following options. | ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements should be ignored, refer to the [privacy](#privacy) chapter | | ignoreSelector | null | Use a string to configure which selector should be ignored, refer to the [privacy](#privacy) chapter | | ignoreCSSAttributes | null | array of CSS attributes that should be ignored | +| maskAllText | false | mask all text content as \* | | maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter | +| unmaskTextClass | 'rr-unmask' | Use a string or RegExp to configure which elements should be unmasked, refer to the [privacy](#privacy) chapter | | maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter | +| unmaskTextSelector | null | Use a string to configure which selector should be unmasked, refer to the [privacy](#privacy) chapter | | maskAllInputs | false | mask all input content as \* | | maskInputOptions | { password: true } | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb/blob/588164aa12f1d94576f89ae0210b98f6e971c895/packages/rrweb-snapshot/src/types.ts#L77-L95) | | maskInputFn | - | customize mask input content recording logic | @@ -173,6 +176,7 @@ You may find some contents on the webpage which are not willing to be recorded, - An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension. - An element with the class name `.rr-ignore` will not record its input events. - All text of elements with the class name `.rr-mask` and their children will be masked. +- All text of elements with the class name `.rr-unmask` and their children will be unmasked, unless any child is marked with `.rr-mask`. - `input[type="password"]` will be masked by default. - Mask options to mask the content in input elements. diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 02619296c8..3ccb868393 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -290,26 +290,89 @@ export function classMatchesRegex( regex: RegExp, checkAncestors: boolean, ): boolean { - if (!node) return false; + return distanceToClassRegexMatch(node, regex, checkAncestors) >= 0; +} + +function distanceToClassRegexMatch( + node: Node | null, + regex: RegExp, + checkAncestors: boolean, + distance = 0, +): number { + if (!node) return -1; if (node.nodeType !== node.ELEMENT_NODE) { - if (!checkAncestors) return false; - return classMatchesRegex(node.parentNode, regex, checkAncestors); + if (!checkAncestors) return -1; + return distanceToClassRegexMatch(node.parentNode, regex, checkAncestors); } for (let eIndex = (node as HTMLElement).classList.length; eIndex--; ) { const className = (node as HTMLElement).classList[eIndex]; if (regex.test(className)) { - return true; + return distance; } } - if (!checkAncestors) return false; - return classMatchesRegex(node.parentNode, regex, checkAncestors); + if (!checkAncestors) return -1; + return distanceToClassRegexMatch( + node.parentNode, + regex, + checkAncestors, + distance + 1, + ); +} + +function distanceToSelectorMatch(el: HTMLElement, selector: string): number { + if (!el) return -1; + if (el.matches(selector)) return 0; + const closestParent = el.closest(selector); + if (closestParent) { + let current = el; + let distance = 0; + while (current && current !== closestParent) { + current = current.parentNode as HTMLElement; + if (!current) { + return -1; + } + distance++; + } + return distance; + } + return -1; +} + +function distanceToMatch( + el: HTMLElement, + className: string | RegExp, + selector: string | null, +): number { + let classDistance = -1; + let selectorDistance = -1; + + if (typeof className === 'string') { + classDistance = distanceToSelectorMatch(el, `.${className}`); + } else { + classDistance = distanceToClassRegexMatch(el, className, true); + } + + if (selector) { + selectorDistance = distanceToSelectorMatch(el, selector); + } + + return selectorDistance >= 0 + ? classDistance >= 0 + ? Math.min(classDistance, selectorDistance) + : selectorDistance + : classDistance >= 0 + ? classDistance + : -1; } export function needMaskingText( node: Node, maskTextClass: string | RegExp, maskTextSelector: string | null, + unmaskTextClass: string | RegExp, + unmaskTextSelector: string | null, + maskAllText: boolean, ): boolean { try { const el: HTMLElement | null = @@ -318,21 +381,25 @@ export function needMaskingText( : node.parentElement; if (el === null) return false; - if (typeof maskTextClass === 'string') { - if (el.classList.contains(maskTextClass)) return true; - if (el.closest(`.${maskTextClass}`)) return true; - } else { - if (classMatchesRegex(el, maskTextClass, true)) return true; - } + const maskDistance = distanceToMatch(el, maskTextClass, maskTextSelector); + const unmaskDistance = distanceToMatch( + el, + unmaskTextClass, + unmaskTextSelector, + ); - if (maskTextSelector) { - if (el.matches(maskTextSelector)) return true; - if (el.closest(maskTextSelector)) return true; - } + return maskDistance >= 0 + ? unmaskDistance >= 0 + ? maskDistance <= unmaskDistance + : true + : unmaskDistance >= 0 + ? false + : !!maskAllText; } catch (e) { // } - return false; + + return !!maskAllText; } // https://stackoverflow.com/a/36155560 @@ -426,8 +493,11 @@ function serializeNode( mirror: Mirror; blockClass: string | RegExp; blockSelector: string | null; + maskAllText: boolean; maskTextClass: string | RegExp; + unmaskTextClass: string | RegExp; maskTextSelector: string | null; + unmaskTextSelector: string | null; inlineStylesheet: boolean; maskInputOptions: MaskInputOptions; maskTextFn: MaskTextFn | undefined; @@ -447,8 +517,11 @@ function serializeNode( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions = {}, maskTextFn, @@ -500,8 +573,11 @@ function serializeNode( }); case n.TEXT_NODE: return serializeTextNode(n as Text, { + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, maskTextFn, rootId, }); @@ -531,13 +607,24 @@ function getRootId(doc: Document, mirror: Mirror): number | undefined { function serializeTextNode( n: Text, options: { + maskAllText: boolean; maskTextClass: string | RegExp; + unmaskTextClass: string | RegExp; maskTextSelector: string | null; + unmaskTextSelector: string | null; maskTextFn: MaskTextFn | undefined; rootId: number | undefined; }, ): serializedNode { - const { maskTextClass, maskTextSelector, maskTextFn, rootId } = options; + const { + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, + maskTextFn, + rootId, + } = options; // The parent node may not be a html element which has a tagName attribute. // So just let it be undefined which is ok in this use case. const parentTagName = n.parentNode && (n.parentNode as HTMLElement).tagName; @@ -572,7 +659,14 @@ function serializeTextNode( !isStyle && !isScript && textContent && - needMaskingText(n, maskTextClass, maskTextSelector) + needMaskingText( + n, + maskTextClass, + maskTextSelector, + unmaskTextClass, + unmaskTextSelector, + maskAllText, + ) ) { textContent = maskTextFn ? maskTextFn(textContent) @@ -922,11 +1016,14 @@ export function serializeNodeWithId( blockClass: string | RegExp; blockSelector: string | null; maskTextClass: string | RegExp; + unmaskTextClass: string | RegExp; maskTextSelector: string | null; + unmaskTextSelector: string | null; skipChild: boolean; inlineStylesheet: boolean; newlyAddedElement?: boolean; maskInputOptions?: MaskInputOptions; + maskAllText: boolean; maskTextFn: MaskTextFn | undefined; maskInputFn: MaskInputFn | undefined; slimDOMOptions: SlimDOMOptions; @@ -953,8 +1050,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputOptions = {}, @@ -978,8 +1078,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions, maskTextFn, @@ -1050,8 +1153,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild, inlineStylesheet, maskInputOptions, @@ -1110,8 +1216,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, @@ -1157,8 +1266,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, @@ -1198,8 +1310,11 @@ function snapshot( mirror?: Mirror; blockClass?: string | RegExp; blockSelector?: string | null; + maskAllText?: boolean; maskTextClass?: string | RegExp; + unmaskTextClass?: string | RegExp; maskTextSelector?: string | null; + unmaskTextSelector?: string | null; inlineStylesheet?: boolean; maskAllInputs?: boolean | MaskInputOptions; maskTextFn?: MaskTextFn; @@ -1227,8 +1342,11 @@ function snapshot( mirror = new Mirror(), blockClass = 'rr-block', blockSelector = null, + maskAllText = false, maskTextClass = 'rr-mask', + unmaskTextClass = 'rr-unmask', maskTextSelector = null, + unmaskTextSelector = null, inlineStylesheet = true, inlineImages = false, recordCanvas = false, @@ -1293,8 +1411,11 @@ function snapshot( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index a50f27cebe..1728e7efab 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -363,6 +363,12 @@ exports[`integration tests [html file]: picture-in-frame.html 1`] = ` " `; +exports[`integration tests [html file]: picture-with-inline-onload.html 1`] = ` +" + \\"This + " +`; + exports[`integration tests [html file]: preload.html 1`] = ` " diff --git a/packages/rrweb-snapshot/test/snapshot.test.ts b/packages/rrweb-snapshot/test/snapshot.test.ts index 75d635e0c0..7785b5bb06 100644 --- a/packages/rrweb-snapshot/test/snapshot.test.ts +++ b/packages/rrweb-snapshot/test/snapshot.test.ts @@ -6,6 +6,7 @@ import { absoluteToStylesheet, serializeNodeWithId, _isBlockedElement, + needMaskingText, } from '../src/snapshot'; import { serializedNodeWithId } from '../src/types'; import { Mirror } from '../src/utils'; @@ -143,8 +144,11 @@ describe('style elements', () => { mirror: new Mirror(), blockClass: 'blockblock', blockSelector: null, + maskAllText: false, maskTextClass: 'maskmask', + unmaskTextClass: 'unmaskmask', maskTextSelector: null, + unmaskTextSelector: null, skipChild: false, inlineStylesheet: true, maskTextFn: undefined, @@ -188,8 +192,11 @@ describe('scrollTop/scrollLeft', () => { mirror: new Mirror(), blockClass: 'blockblock', blockSelector: null, + maskAllText: false, maskTextClass: 'maskmask', + unmaskTextClass: 'unmaskmask', maskTextSelector: null, + unmaskTextSelector: null, skipChild: false, inlineStylesheet: true, maskTextFn: undefined, @@ -218,3 +225,222 @@ describe('scrollTop/scrollLeft', () => { }); }); }); + +describe('needMaskingText', () => { + const render = (html: string): HTMLDivElement => { + document.write(html); + return document.querySelector('div')!; + }; + + it('should not mask by default', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', null, 'unmaskmask', null, false), + ).toEqual(false); + }); + + it('should mask if the masking class is matched', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', null, 'unmaskmask', null, false), + ).toEqual(true); + expect( + needMaskingText(el, /^maskmask$/, null, /^unmaskmask$/, null, false), + ).toEqual(true); + }); + + it('should mask if the masking class is matched on an ancestor', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0], + 'maskmask', + null, + 'unmaskmask', + null, + false, + ), + ).toEqual(true); + expect( + needMaskingText( + el.children[0], + /^maskmask$/, + null, + /^unmaskmask$/, + null, + false, + ), + ).toEqual(true); + }); + + it('should mask if the masking selector is matched', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', '.foo', 'unmaskmask', null, false), + ).toEqual(true); + }); + + it('should mask if the masking selector is matched on an ancestor', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText( + el.children[0], + 'maskmask', + '.foo', + 'unmaskmask', + null, + false, + ), + ).toEqual(true); + }); + + it('should mask by default', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', null, 'unmaskmask', null, true), + ).toEqual(true); + }); + + it('should not mask if the un-masking class is matched', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', null, 'unmaskmask', null, true), + ).toEqual(false); + expect( + needMaskingText(el, /^maskmask$/, null, /^unmaskmask$/, null, true), + ).toEqual(false); + }); + + it('should not mask if the un-masking class is matched on an ancestor', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0], + 'maskmask', + null, + 'unmaskmask', + null, + true, + ), + ).toEqual(false); + expect( + needMaskingText( + el.children[0], + /^maskmask$/, + null, + /^unmaskmask$/, + null, + true, + ), + ).toEqual(false); + }); + + it('should mask if the masking class is more specific than the unmasking class', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0].children[0], + 'maskmask', + null, + 'unmaskmask', + null, + false, + ), + ).toEqual(true); + expect( + needMaskingText( + el.children[0].children[0], + /^maskmask$/, + null, + /^unmaskmask$/, + null, + false, + ), + ).toEqual(true); + }); + + it('should not mask if the unmasking class is more specific than the masking class', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0].children[0], + 'maskmask', + null, + 'unmaskmask', + null, + false, + ), + ).toEqual(false); + expect( + needMaskingText( + el.children[0].children[0], + /^maskmask$/, + null, + /^unmaskmask$/, + null, + false, + ), + ).toEqual(false); + }); + + it('should not mask if the unmasking selector is matched', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText(el, 'maskmask', null, 'unmaskmask', '.foo', true), + ).toEqual(false); + }); + + it('should not mask if the unmasking selector is matched on an ancestor', () => { + const el = render(`
Lorem ipsum
`); + expect( + needMaskingText( + el.children[0], + 'maskmask', + null, + 'unmaskmask', + '.foo', + true, + ), + ).toEqual(false); + }); + + it('should mask if the masking selector is more specific than the unmasking selector', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0].children[0], + 'maskmask', + '.bar', + 'unmaskmask', + '.foo', + false, + ), + ).toEqual(true); + }); + + it('should not mask if the unmasking selector is more specific than the masking selector', () => { + const el = render( + `
Lorem ipsum
`, + ); + expect( + needMaskingText( + el.children[0].children[0], + 'maskmask', + '.bar', + 'unmaskmask', + '.foo', + false, + ), + ).toEqual(false); + }); +}); diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 1c2141bfef..2dee0d6a4c 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -65,8 +65,11 @@ function record( blockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, + maskAllText = false, maskTextClass = 'rr-mask', + unmaskTextClass = 'rr-unmask', maskTextSelector = null, + unmaskTextSelector = null, inlineStylesheet = true, maskAllInputs, maskInputOptions: _maskInputOptions, @@ -324,8 +327,11 @@ function record( bypassOptions: { blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions, dataURLOptions, @@ -367,8 +373,11 @@ function record( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskAllInputs: maskInputOptions, maskTextFn, @@ -524,8 +533,11 @@ function record( blockClass, ignoreClass, ignoreSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, maskInputOptions, inlineStylesheet, sampling, diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 097d1a8fd5..a6db71d35f 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -170,8 +170,11 @@ export default class MutationBuffer { private mutationCb: observerParam['mutationCb']; private blockClass: observerParam['blockClass']; private blockSelector: observerParam['blockSelector']; + private maskAllText: observerParam['maskAllText']; private maskTextClass: observerParam['maskTextClass']; + private unmaskTextClass: observerParam['unmaskTextClass']; private maskTextSelector: observerParam['maskTextSelector']; + private unmaskTextSelector: observerParam['unmaskTextSelector']; private inlineStylesheet: observerParam['inlineStylesheet']; private maskInputOptions: observerParam['maskInputOptions']; private maskTextFn: observerParam['maskTextFn']; @@ -195,8 +198,11 @@ export default class MutationBuffer { 'mutationCb', 'blockClass', 'blockSelector', + 'maskAllText', 'maskTextClass', + 'unmaskTextClass', 'maskTextSelector', + 'unmaskTextSelector', 'inlineStylesheet', 'maskInputOptions', 'maskTextFn', @@ -297,8 +303,11 @@ export default class MutationBuffer { mirror: this.mirror, blockClass: this.blockClass, blockSelector: this.blockSelector, + maskAllText: this.maskAllText, maskTextClass: this.maskTextClass, + unmaskTextClass: this.unmaskTextClass, maskTextSelector: this.maskTextSelector, + unmaskTextSelector: this.unmaskTextSelector, skipChild: true, newlyAddedElement: true, inlineStylesheet: this.inlineStylesheet, @@ -518,6 +527,9 @@ export default class MutationBuffer { m.target, this.maskTextClass, this.maskTextSelector, + this.unmaskTextClass, + this.unmaskTextSelector, + this.maskAllText, ) && value ? this.maskTextFn ? this.maskTextFn(value) diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 17ed750e68..dd988708e0 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -25,6 +25,7 @@ import type { KeepIframeSrcFn, listenerHandler, maskTextClass, + unmaskTextClass, mediaInteractionCallback, mouseInteractionCallBack, mousemoveCallBack, @@ -47,8 +48,11 @@ export type recordOptions = { blockSelector?: string; ignoreClass?: string; ignoreSelector?: string; + maskAllText?: boolean; maskTextClass?: maskTextClass; + unmaskTextClass?: unmaskTextClass; maskTextSelector?: string; + unmaskTextSelector?: string; maskAllInputs?: boolean; maskInputOptions?: MaskInputOptions; maskInputFn?: MaskInputFn; @@ -86,8 +90,11 @@ export type observerParam = { blockSelector: string | null; ignoreClass: string; ignoreSelector: string | null; + maskAllText: boolean; maskTextClass: maskTextClass; + unmaskTextClass: unmaskTextClass; maskTextSelector: string | null; + unmaskTextSelector: string | null; maskInputOptions: MaskInputOptions; maskInputFn?: MaskInputFn; maskTextFn?: MaskTextFn; @@ -128,8 +135,11 @@ export type MutationBufferParam = Pick< | 'mutationCb' | 'blockClass' | 'blockSelector' + | 'maskAllText' | 'maskTextClass' + | 'unmaskTextClass' | 'maskTextSelector' + | 'unmaskTextSelector' | 'inlineStylesheet' | 'maskInputOptions' | 'maskTextFn' diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index c95ec53a5f..72f7f9b067 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -3574,6 +3574,349 @@ exports[`record integration tests can record style changes compactly and preserv ]" `; +exports[`record integration tests can selectively unmask parts of the page 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"http-equiv\\": \\"X-UA-Compatible\\", + \\"content\\": \\"ie=edge\\" + }, + \\"childNodes\\": [], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 11 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Unmask text\\", + \\"id\\": 13 + } + ], + \\"id\\": 12 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 14 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"unmask1\\\\n \\", + \\"id\\": 19 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"class\\": \\"rr-mask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 21 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"span\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"*****\\", + \\"id\\": 23 + } + ], + \\"id\\": 22 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 24 + } + ], + \\"id\\": 20 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 25 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 26 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"data-masking\\": \\"false\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 28 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 30 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"data-masking\\": \\"true\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"*****\\", + \\"id\\": 32 + } + ], + \\"id\\": 31 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 33 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"unmask2\\", + \\"id\\": 35 + } + ], + \\"id\\": 34 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 36 + } + ], + \\"id\\": 29 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 37 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"ul\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 38 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 39 + } + ], + \\"id\\": 27 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 40 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 42 + } + ], + \\"id\\": 41 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 43 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 38, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"li\\", + \\"attributes\\": { + \\"class\\": \\"rr-mask\\" + }, + \\"childNodes\\": [], + \\"id\\": 44 + } + }, + { + \\"parentId\\": 44, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"*** **** ****\\", + \\"id\\": 45 + } + } + ] + } + } +]" +`; + exports[`record integration tests can use maskInputOptions to configure which type of inputs should be masked 1`] = ` "[ { @@ -9193,6 +9536,15 @@ exports[`record integration tests should not record input values if dynamically \\"id\\": 21 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 3, + \\"id\\": 21, + \\"x\\": 12.5, + \\"y\\": 0 + } + }, { \\"type\\": 3, \\"data\\": { diff --git a/packages/rrweb/test/__snapshots__/record.test.ts.snap b/packages/rrweb/test/__snapshots__/record.test.ts.snap index cb40f3328d..27bcc46b5e 100644 --- a/packages/rrweb/test/__snapshots__/record.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/record.test.ts.snap @@ -3168,6 +3168,16 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 19, \\"id\\": 32 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"link\\", + \\"attributes\\": { + \\"_cssText\\": \\"body { color: pink; }\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 19, + \\"id\\": 33 } ], \\"rootId\\": 19, @@ -3177,7 +3187,7 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 19, - \\"id\\": 33 + \\"id\\": 34 }, { \\"type\\": 2, @@ -3188,11 +3198,11 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"type\\": 3, \\"textContent\\": \\"\\\\n Hello world!\\\\n \\\\n\\\\n\\", \\"rootId\\": 19, - \\"id\\": 35 + \\"id\\": 36 } ], \\"rootId\\": 19, - \\"id\\": 34 + \\"id\\": 35 } ], \\"rootId\\": 19, @@ -3208,49 +3218,6 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"attributes\\": [], \\"isAttachIframe\\": true } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 0, - \\"texts\\": [], - \\"attributes\\": [], - \\"removes\\": [], - \\"adds\\": [ - { - \\"parentId\\": 22, - \\"nextId\\": null, - \\"node\\": { - \\"type\\": 2, - \\"tagName\\": \\"link\\", - \\"attributes\\": { - \\"rel\\": \\"stylesheet\\", - \\"href\\": \\"http://localhost:3030/html/assets/style.css\\" - }, - \\"childNodes\\": [], - \\"rootId\\": 19, - \\"id\\": 36 - } - } - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 0, - \\"adds\\": [], - \\"removes\\": [], - \\"texts\\": [], - \\"attributes\\": [ - { - \\"id\\": 36, - \\"attributes\\": { - \\"_cssText\\": \\"body { color: pink; }\\" - } - } - ] - } } ]" `; diff --git a/packages/rrweb/test/html/unmask-text.html b/packages/rrweb/test/html/unmask-text.html new file mode 100644 index 0000000000..a71dc04205 --- /dev/null +++ b/packages/rrweb/test/html/unmask-text.html @@ -0,0 +1,23 @@ + + + + + + + Unmask text + + +
unmask1 +
+ mask1 +
+
+
+
+
mask2
+
unmask2
+
+
    +
    + + diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index edfc8a97af..3f718d8570 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -1193,6 +1193,31 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); + it('can selectively unmask parts of the page', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'unmask-text.html', { + maskAllText: true, + maskTextSelector: '[data-masking="true"]', + unmaskTextSelector: '[data-masking="false"]', + }), + ); + + await page.evaluate(() => { + const li = document.createElement('li'); + const ul = document.querySelector('ul') as HTMLUListElement; + li.className = 'rr-mask'; + ul.appendChild(li); + li.innerText = 'new list item'; + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + it('should record after DOMContentLoaded event', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index 5a90f62031..a32932c308 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -690,7 +690,9 @@ export function generateRecordSnippet(options: recordOptions) { }, ignoreSelector: ${JSON.stringify(options.ignoreSelector)}, maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, + unmaskTextSelector: ${JSON.stringify(options.unmaskTextSelector)}, maskAllInputs: ${options.maskAllInputs}, + maskAllText: ${options.maskAllText}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, userTriggeredOnInput: ${options.userTriggeredOnInput}, maskTextFn: ${options.maskTextFn}, diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index e6f6f15cd3..eb9b9b618a 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -179,6 +179,7 @@ export type canvasEventWithTime = eventWithTime & { export type blockClass = string | RegExp; export type maskTextClass = string | RegExp; +export type unmaskTextClass = string | RegExp; export type SamplingStrategy = Partial<{ /** diff --git a/yarn.lock b/yarn.lock index 34c29fb6fe..784f857d42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5522,10 +5522,15 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.4, cssom@^0.5.0, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": +cssom@^0.4.4, "cssom@https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz": version "0.6.0" resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" From 5309566a8a0e3c88491fe98bc14181f7a63ec813 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Thu, 12 Jan 2023 12:54:17 -0500 Subject: [PATCH 02/60] apply text mask settings to inputs #1096 --- packages/rrweb-snapshot/src/snapshot.ts | 39 ++++++++++++++++++++++++- packages/rrweb-snapshot/src/utils.ts | 5 +++- packages/rrweb/src/record/index.ts | 1 + packages/rrweb/src/record/mutation.ts | 10 +++++++ packages/rrweb/src/record/observer.ts | 19 +++++++++++- packages/rrweb/test/integration.test.ts | 23 +++++++++++++++ packages/rrweb/test/utils.ts | 1 + 7 files changed, 95 insertions(+), 3 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 3ccb868393..44449c077e 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -570,6 +570,11 @@ function serializeNode( keepIframeSrcFn, newlyAddedElement, rootId, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, }); case n.TEXT_NODE: return serializeTextNode(n as Text, { @@ -579,6 +584,8 @@ function serializeNode( maskTextSelector, unmaskTextSelector, maskTextFn, + maskInputOptions, + maskInputFn, rootId, }); case n.CDATA_SECTION_NODE: @@ -613,6 +620,8 @@ function serializeTextNode( maskTextSelector: string | null; unmaskTextSelector: string | null; maskTextFn: MaskTextFn | undefined; + maskInputOptions: MaskInputOptions; + maskInputFn: MaskInputFn | undefined; rootId: number | undefined; }, ): serializedNode { @@ -623,6 +632,8 @@ function serializeTextNode( maskTextSelector, unmaskTextSelector, maskTextFn, + maskInputOptions, + maskInputFn, rootId, } = options; // The parent node may not be a html element which has a tagName attribute. @@ -631,6 +642,7 @@ function serializeTextNode( let textContent = n.textContent; const isStyle = parentTagName === 'STYLE' ? true : undefined; const isScript = parentTagName === 'SCRIPT' ? true : undefined; + const isTextarea = parentTagName === 'TEXTAREA' ? true : undefined; if (isStyle && textContent) { try { // try to read style sheet @@ -672,6 +684,11 @@ function serializeTextNode( ? maskTextFn(textContent) : textContent.replace(/[\S]/g, '*'); } + if (isTextarea && textContent && maskInputOptions.textarea) { + textContent = maskInputFn + ? maskInputFn(textContent, n.parentNode as HTMLElement) + : textContent.replace(/[\S]/g, '*'); + } return { type: NodeType.Text, @@ -699,6 +716,11 @@ function serializeElementNode( */ newlyAddedElement?: boolean; rootId: number | undefined; + maskAllText: boolean; + maskTextClass: string | RegExp; + unmaskTextClass: string | RegExp; + maskTextSelector: string | null; + unmaskTextSelector: string | null; }, ): serializedNode | false { const { @@ -714,6 +736,11 @@ function serializeElementNode( keepIframeSrcFn, newlyAddedElement = false, rootId, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, } = options; const needBlock = _isBlockedElement(n, blockClass, blockSelector); const tagName = getValidTagName(n); @@ -771,6 +798,15 @@ function serializeElementNode( value ) { const type = getInputType(n); + const forceMask = needMaskingText( + n, + maskTextClass, + maskTextSelector, + unmaskTextClass, + unmaskTextSelector, + maskAllText, + ); + attributes.value = maskInputValue({ element: n, type, @@ -778,6 +814,7 @@ function serializeElementNode( value, maskInputOptions, maskInputFn, + forceMask, }); } else if (checked) { attributes.checked = checked; @@ -1318,7 +1355,7 @@ function snapshot( inlineStylesheet?: boolean; maskAllInputs?: boolean | MaskInputOptions; maskTextFn?: MaskTextFn; - maskInputFn?: MaskTextFn; + maskInputFn?: MaskInputFn; slimDOM?: 'all' | boolean | SlimDOMOptions; dataURLOptions?: DataURLOptions; inlineImages?: boolean; diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 95444c18b3..702d1c7b7e 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -219,6 +219,7 @@ export function maskInputValue({ type, value, maskInputFn, + forceMask, }: { element: HTMLElement; maskInputOptions: MaskInputOptions; @@ -226,13 +227,15 @@ export function maskInputValue({ type: string | null; value: string | null; maskInputFn?: MaskInputFn; + forceMask?: boolean; }): string { let text = value || ''; const actualType = type && toLowerCase(type); if ( maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] || - (actualType && maskInputOptions[actualType as keyof MaskInputOptions]) + (actualType && maskInputOptions[actualType as keyof MaskInputOptions]) || + forceMask ) { if (maskInputFn) { text = maskInputFn(text, element); diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 2dee0d6a4c..2689f33b5c 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -380,6 +380,7 @@ function record( unmaskTextSelector, inlineStylesheet, maskAllInputs: maskInputOptions, + maskInputFn, maskTextFn, slimDOM: slimDOMOptions, dataURLOptions, diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index a6db71d35f..3cbceab75a 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -548,6 +548,15 @@ export default class MutationBuffer { if (attributeName === 'value') { const type = getInputType(target); + const forceMask = needMaskingText( + m.target, + this.maskTextClass, + this.maskTextSelector, + this.unmaskTextClass, + this.unmaskTextSelector, + this.maskAllText, + ); + value = maskInputValue({ element: target, maskInputOptions: this.maskInputOptions, @@ -555,6 +564,7 @@ export default class MutationBuffer { type, value, maskInputFn: this.maskInputFn, + forceMask, }); } if ( diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 428cce1a4e..61c9087ff6 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -4,6 +4,7 @@ import { Mirror, getInputType, toLowerCase, + needMaskingText, } from 'rrweb-snapshot'; import type { FontFaceSet } from 'css-font-loading-module'; import { @@ -428,6 +429,11 @@ function initInputObserver({ maskInputFn, sampling, userTriggeredOnInput, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, }: observerParam): listenerHandler { function eventHandler(event: Event) { let target = getEventTarget(event) as HTMLElement | null; @@ -460,11 +466,21 @@ function initInputObserver({ let isChecked = false; const type: Lowercase = getInputType(target) || ''; + const forceMask = needMaskingText( + target as Node, + maskTextClass, + maskTextSelector, + unmaskTextClass, + unmaskTextSelector, + maskAllText, + ); + if (type === 'radio' || type === 'checkbox') { isChecked = (target as HTMLInputElement).checked; } else if ( maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] || - maskInputOptions[type as keyof MaskInputOptions] + maskInputOptions[type as keyof MaskInputOptions] || + forceMask ) { text = maskInputValue({ element: target, @@ -473,6 +489,7 @@ function initInputObserver({ type, value: text, maskInputFn, + forceMask, }); } cbWithDedup( diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 3f718d8570..7434ac6948 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -362,6 +362,29 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); + it('can use maskTextSelector to configure which inputs should be masked', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form.html', { + maskTextSelector: 'input[type="text"],textarea', + maskInputFn: () => '*'.repeat(10), + }), + ); + + await page.type('input[type="text"]', 'test'); + await page.click('input[type="radio"]'); + await page.click('input[type="checkbox"]'); + await page.type('textarea', 'textarea test'); + await page.type('input[type="password"]', 'password'); + await page.select('select', '1'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + it('should mask password value attribute with maskInputOptions', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index a32932c308..a3284daddd 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -694,6 +694,7 @@ export function generateRecordSnippet(options: recordOptions) { maskAllInputs: ${options.maskAllInputs}, maskAllText: ${options.maskAllText}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, + maskInputFn: ${options.maskInputFn}, userTriggeredOnInput: ${options.userTriggeredOnInput}, maskTextFn: ${options.maskTextFn}, maskInputFn: ${options.maskInputFn}, From 70dbf1ef2cffa842c76199e1ce34d29d0030713c Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 10 Feb 2023 12:48:53 -0500 Subject: [PATCH 03/60] remove default for unmaskTextClass #1096 --- guide.md | 4 ++-- packages/rrweb-snapshot/src/snapshot.ts | 26 +++++++++++++------------ packages/rrweb/src/record/index.ts | 2 +- packages/types/src/index.ts | 2 +- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/guide.md b/guide.md index 036af9aa61..fde2afb3cb 100644 --- a/guide.md +++ b/guide.md @@ -147,7 +147,7 @@ The parameter of `rrweb.record` accepts the following options. | ignoreCSSAttributes | null | array of CSS attributes that should be ignored | | maskAllText | false | mask all text content as \* | | maskTextClass | 'rr-mask' | Use a string or RegExp to configure which elements should be masked, refer to the [privacy](#privacy) chapter | -| unmaskTextClass | 'rr-unmask' | Use a string or RegExp to configure which elements should be unmasked, refer to the [privacy](#privacy) chapter | +| unmaskTextClass | null | Use a string or RegExp to configure which elements should be unmasked, refer to the [privacy](#privacy) chapter | | maskTextSelector | null | Use a string to configure which selector should be masked, refer to the [privacy](#privacy) chapter | | unmaskTextSelector | null | Use a string to configure which selector should be unmasked, refer to the [privacy](#privacy) chapter | | maskAllInputs | false | mask all input content as \* | @@ -176,7 +176,7 @@ You may find some contents on the webpage which are not willing to be recorded, - An element with the class name `.rr-block` will not be recorded. Instead, it will replay as a placeholder with the same dimension. - An element with the class name `.rr-ignore` will not record its input events. - All text of elements with the class name `.rr-mask` and their children will be masked. -- All text of elements with the class name `.rr-unmask` and their children will be unmasked, unless any child is marked with `.rr-mask`. +- All text of elements with the optional unmasking class name `unmaskTextClass` and their children will be unmasked, unless any child is marked with `.rr-mask`. - `input[type="password"]` will be masked by default. - Mask options to mask the content in input elements. diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 44449c077e..98c2caee27 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -341,16 +341,18 @@ function distanceToSelectorMatch(el: HTMLElement, selector: string): number { function distanceToMatch( el: HTMLElement, - className: string | RegExp, + className: string | RegExp | null, selector: string | null, ): number { let classDistance = -1; let selectorDistance = -1; - if (typeof className === 'string') { - classDistance = distanceToSelectorMatch(el, `.${className}`); - } else { - classDistance = distanceToClassRegexMatch(el, className, true); + if (className) { + if (typeof className === 'string') { + classDistance = distanceToSelectorMatch(el, `.${className}`); + } else { + classDistance = distanceToClassRegexMatch(el, className, true); + } } if (selector) { @@ -370,7 +372,7 @@ export function needMaskingText( node: Node, maskTextClass: string | RegExp, maskTextSelector: string | null, - unmaskTextClass: string | RegExp, + unmaskTextClass: string | RegExp | null, unmaskTextSelector: string | null, maskAllText: boolean, ): boolean { @@ -495,7 +497,7 @@ function serializeNode( blockSelector: string | null; maskAllText: boolean; maskTextClass: string | RegExp; - unmaskTextClass: string | RegExp; + unmaskTextClass: string | RegExp | null; maskTextSelector: string | null; unmaskTextSelector: string | null; inlineStylesheet: boolean; @@ -616,7 +618,7 @@ function serializeTextNode( options: { maskAllText: boolean; maskTextClass: string | RegExp; - unmaskTextClass: string | RegExp; + unmaskTextClass: string | RegExp | null; maskTextSelector: string | null; unmaskTextSelector: string | null; maskTextFn: MaskTextFn | undefined; @@ -718,7 +720,7 @@ function serializeElementNode( rootId: number | undefined; maskAllText: boolean; maskTextClass: string | RegExp; - unmaskTextClass: string | RegExp; + unmaskTextClass: string | RegExp | null; maskTextSelector: string | null; unmaskTextSelector: string | null; }, @@ -1053,7 +1055,7 @@ export function serializeNodeWithId( blockClass: string | RegExp; blockSelector: string | null; maskTextClass: string | RegExp; - unmaskTextClass: string | RegExp; + unmaskTextClass: string | RegExp | null; maskTextSelector: string | null; unmaskTextSelector: string | null; skipChild: boolean; @@ -1349,7 +1351,7 @@ function snapshot( blockSelector?: string | null; maskAllText?: boolean; maskTextClass?: string | RegExp; - unmaskTextClass?: string | RegExp; + unmaskTextClass?: string | RegExp | null; maskTextSelector?: string | null; unmaskTextSelector?: string | null; inlineStylesheet?: boolean; @@ -1381,7 +1383,7 @@ function snapshot( blockSelector = null, maskAllText = false, maskTextClass = 'rr-mask', - unmaskTextClass = 'rr-unmask', + unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 2689f33b5c..0e84f89fe3 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -67,7 +67,7 @@ function record( ignoreSelector = null, maskAllText = false, maskTextClass = 'rr-mask', - unmaskTextClass = 'rr-unmask', + unmaskTextClass = null, maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index eb9b9b618a..f63c35a1f3 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -179,7 +179,7 @@ export type canvasEventWithTime = eventWithTime & { export type blockClass = string | RegExp; export type maskTextClass = string | RegExp; -export type unmaskTextClass = string | RegExp; +export type unmaskTextClass = string | RegExp | null; export type SamplingStrategy = Partial<{ /** From f9807adb03a711ecf1e09e88cf32ea10ad0fc8f9 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 10 Feb 2023 13:04:31 -0500 Subject: [PATCH 04/60] skip mask distance if unmask is not found and maskAllText is true #1096 --- packages/rrweb-snapshot/src/snapshot.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 98c2caee27..847ed10a4f 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -383,12 +383,18 @@ export function needMaskingText( : node.parentElement; if (el === null) return false; - const maskDistance = distanceToMatch(el, maskTextClass, maskTextSelector); const unmaskDistance = distanceToMatch( el, unmaskTextClass, unmaskTextSelector, ); + + let maskDistance = -1; + if (maskAllText && unmaskDistance < 0) { + return true; + } + + maskDistance = distanceToMatch(el, maskTextClass, maskTextSelector); return maskDistance >= 0 ? unmaskDistance >= 0 From ec3767e4088d4307cdee617e43ebce50e3049cbc Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Mon, 13 Feb 2023 13:48:16 -0500 Subject: [PATCH 05/60] optimize mask/unmask rule matching #1096 --- packages/rrweb-snapshot/src/snapshot.ts | 115 ++++++++++-------------- 1 file changed, 49 insertions(+), 66 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 847ed10a4f..c06806aad4 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -285,87 +285,67 @@ export function _isBlockedElement( return false; } +function elementClassMatchesRegex(el: HTMLElement, regex: RegExp): boolean { + for (let eIndex = el.classList.length; eIndex--; ) { + const className = el.classList[eIndex]; + if (regex.test(className)) { + return true; + } + } + return false; +} + export function classMatchesRegex( node: Node | null, regex: RegExp, checkAncestors: boolean, ): boolean { - return distanceToClassRegexMatch(node, regex, checkAncestors) >= 0; + if (!node) return false; + if (checkAncestors) { + return ( + distanceToMatch(node, (node) => + elementClassMatchesRegex(node as HTMLElement, regex), + ) >= 0 + ); + } else if (node.nodeType === node.ELEMENT_NODE) { + return elementClassMatchesRegex(node as HTMLElement, regex); + } + return false; } -function distanceToClassRegexMatch( +function distanceToMatch( node: Node | null, - regex: RegExp, - checkAncestors: boolean, + matchPredicate: (node: Node) => boolean, + limit = Infinity, distance = 0, ): number { if (!node) return -1; - if (node.nodeType !== node.ELEMENT_NODE) { - if (!checkAncestors) return -1; - return distanceToClassRegexMatch(node.parentNode, regex, checkAncestors); - } - - for (let eIndex = (node as HTMLElement).classList.length; eIndex--; ) { - const className = (node as HTMLElement).classList[eIndex]; - if (regex.test(className)) { - return distance; - } - } - if (!checkAncestors) return -1; - return distanceToClassRegexMatch( - node.parentNode, - regex, - checkAncestors, - distance + 1, - ); + if (node.nodeType !== node.ELEMENT_NODE) return -1; + if (distance > limit) return -1; + if (matchPredicate(node)) return distance; + return distanceToMatch(node.parentNode, matchPredicate, limit, distance + 1); } -function distanceToSelectorMatch(el: HTMLElement, selector: string): number { - if (!el) return -1; - if (el.matches(selector)) return 0; - const closestParent = el.closest(selector); - if (closestParent) { - let current = el; - let distance = 0; - while (current && current !== closestParent) { - current = current.parentNode as HTMLElement; - if (!current) { - return -1; - } - distance++; - } - return distance; - } - return -1; -} - -function distanceToMatch( - el: HTMLElement, +function createMatchPredicate( className: string | RegExp | null, selector: string | null, -): number { - let classDistance = -1; - let selectorDistance = -1; +): (node: Node) => boolean { + return (node: Node) => { + const el = node as HTMLElement; + if (el === null) return false; - if (className) { - if (typeof className === 'string') { - classDistance = distanceToSelectorMatch(el, `.${className}`); - } else { - classDistance = distanceToClassRegexMatch(el, className, true); + if (className) { + if (typeof className === 'string') { + if (el.matches(`.${className}`)) return true; + } else if (elementClassMatchesRegex(el, className)) { + return true; + } } - } - if (selector) { - selectorDistance = distanceToSelectorMatch(el, selector); - } + if (selector && el.matches(selector)) return true; - return selectorDistance >= 0 - ? classDistance >= 0 - ? Math.min(classDistance, selectorDistance) - : selectorDistance - : classDistance >= 0 - ? classDistance - : -1; + return false; + }; } export function needMaskingText( @@ -385,16 +365,19 @@ export function needMaskingText( const unmaskDistance = distanceToMatch( el, - unmaskTextClass, - unmaskTextSelector, + createMatchPredicate(unmaskTextClass, unmaskTextSelector), ); - + let maskDistance = -1; if (maskAllText && unmaskDistance < 0) { return true; } - maskDistance = distanceToMatch(el, maskTextClass, maskTextSelector); + maskDistance = distanceToMatch( + el, + createMatchPredicate(maskTextClass, maskTextSelector), + unmaskDistance >= 0 ? unmaskDistance : Infinity, + ); return maskDistance >= 0 ? unmaskDistance >= 0 From 3b1a8598704766bd73a48408f78574703be3e2d4 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Thu, 6 Apr 2023 13:25:37 -0400 Subject: [PATCH 06/60] optimization for when maskAllText is false #1096 --- packages/rrweb-snapshot/src/snapshot.ts | 45 ++++++++++++++++++------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index c06806aad4..f2053d2245 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -363,21 +363,40 @@ export function needMaskingText( : node.parentElement; if (el === null) return false; - const unmaskDistance = distanceToMatch( - el, - createMatchPredicate(unmaskTextClass, unmaskTextSelector), - ); - let maskDistance = -1; - if (maskAllText && unmaskDistance < 0) { - return true; - } + let unmaskDistance = -1; - maskDistance = distanceToMatch( - el, - createMatchPredicate(maskTextClass, maskTextSelector), - unmaskDistance >= 0 ? unmaskDistance : Infinity, - ); + if (maskAllText) { + unmaskDistance = distanceToMatch( + el, + createMatchPredicate(unmaskTextClass, unmaskTextSelector), + ); + + if (unmaskDistance < 0) { + return true; + } + + maskDistance = distanceToMatch( + el, + createMatchPredicate(maskTextClass, maskTextSelector), + unmaskDistance >= 0 ? unmaskDistance : Infinity, + ); + } else { + maskDistance = distanceToMatch( + el, + createMatchPredicate(maskTextClass, maskTextSelector), + ); + + if (maskDistance < 0) { + return false; + } + + unmaskDistance = distanceToMatch( + el, + createMatchPredicate(unmaskTextClass, unmaskTextSelector), + maskDistance >= 0 ? maskDistance : Infinity, + ); + } return maskDistance >= 0 ? unmaskDistance >= 0 From 8239b535dd3100a4af2319e9f23d8ab44ca8aa0d Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Mon, 10 Apr 2023 12:28:56 -0400 Subject: [PATCH 07/60] add benchmarks for text masking #1096 --- .../rrweb/test/benchmark/dom-mutation.test.ts | 84 ++++++++++++------- .../test/html/benchmark-text-masking.html | 30 +++++++ 2 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 packages/rrweb/test/html/benchmark-text-masking.html diff --git a/packages/rrweb/test/benchmark/dom-mutation.test.ts b/packages/rrweb/test/benchmark/dom-mutation.test.ts index 3da794db45..50d6ba6104 100644 --- a/packages/rrweb/test/benchmark/dom-mutation.test.ts +++ b/packages/rrweb/test/benchmark/dom-mutation.test.ts @@ -10,6 +10,10 @@ const suites: Array< title: string; eval: string; times?: number; // defaults to 5 + recordOptions?: { + maskTextClass?: string; + unmaskTextClass?: string; + }; } & ({ html: string } | { url: string }) > = [ // { @@ -42,6 +46,25 @@ const suites: Array< eval: 'window.workload()', times: 5, }, + { + title: 'mask 1000x10 DOM nodes', + html: 'benchmark-text-masking.html', + eval: 'window.workload()', + times: 10, + recordOptions: { + maskTextClass: 'rr-mask', + }, + }, + { + title: 'unmask 1000x10 DOM nodes', + html: 'benchmark-text-masking.html', + eval: 'window.workload()', + times: 10, + recordOptions: { + maskTextClass: 'rr-mask', + unmaskTextClass: 'rr-unmask', + }, + }, ]; function avg(v: number[]): number { @@ -106,35 +129,40 @@ describe('benchmark: mutation observer', () => { }; const getDuration = async (): Promise => { - return (await page.evaluate((triggerWorkloadScript) => { - return new Promise((resolve, reject) => { - let start = 0; - let lastEvent: eventWithTime | null; - const options: recordOptions = { - emit: (event) => { - // console.log(event.type, event.timestamp); - if (event.type !== 5 || event.data.tag !== 'FTAG') { - lastEvent = event; - return; - } - if (!lastEvent) { - reject('no events recorded'); - return; - } - resolve(lastEvent.timestamp - start); - }, - }; - const record = (window as any).rrweb.record; - record(options); - - start = Date.now(); - eval(triggerWorkloadScript); - - requestAnimationFrame(() => { - record.addCustomEvent('FTAG', {}); + return (await page.evaluate( + (triggerWorkloadScript, recordOptions) => { + return new Promise((resolve, reject) => { + let start = 0; + let lastEvent: eventWithTime | null; + const options: recordOptions = { + ...recordOptions, + emit: (event) => { + // console.log(event.type, event.timestamp); + if (event.type !== 5 || event.data.tag !== 'FTAG') { + lastEvent = event; + return; + } + if (!lastEvent) { + reject('no events recorded'); + return; + } + resolve(lastEvent.timestamp - start); + }, + }; + const record = (window as any).rrweb.record; + record(options); + + start = Date.now(); + eval(triggerWorkloadScript); + + requestAnimationFrame(() => { + record.addCustomEvent('FTAG', {}); + }); }); - }); - }, suite.eval)) as number; + }, + suite.eval, + suite.recordOptions || {} + )) as number; }; // generate profile.json file diff --git a/packages/rrweb/test/html/benchmark-text-masking.html b/packages/rrweb/test/html/benchmark-text-masking.html new file mode 100644 index 0000000000..3c7d730fc3 --- /dev/null +++ b/packages/rrweb/test/html/benchmark-text-masking.html @@ -0,0 +1,30 @@ + + + + From 0ce76f2cd7ee4da3504470545462c9d521001547 Mon Sep 17 00:00:00 2001 From: mdellanoce Date: Mon, 10 Apr 2023 16:51:08 +0000 Subject: [PATCH 08/60] Apply formatting changes --- packages/rrweb/test/benchmark/dom-mutation.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rrweb/test/benchmark/dom-mutation.test.ts b/packages/rrweb/test/benchmark/dom-mutation.test.ts index 50d6ba6104..aca474e2ad 100644 --- a/packages/rrweb/test/benchmark/dom-mutation.test.ts +++ b/packages/rrweb/test/benchmark/dom-mutation.test.ts @@ -161,7 +161,7 @@ describe('benchmark: mutation observer', () => { }); }, suite.eval, - suite.recordOptions || {} + suite.recordOptions || {}, )) as number; }; From 7385536255df6f5e2f7687acb11a25a0c275ba55 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Wed, 12 Jul 2023 21:28:56 -0400 Subject: [PATCH 09/60] add tests for different maskAllInput configurations on dynamically added inputs (mutation vs snapshot) --- .../__snapshots__/integration.test.ts.snap | 2587 ++++++++++++++--- .../test/__snapshots__/record.test.ts.snap | 59 +- ...ecord-and-replay-a-webgl-square-1-snap.png | Bin 10650 -> 10629 bytes packages/rrweb/test/integration.test.ts | 147 +- 4 files changed, 2407 insertions(+), 386 deletions(-) diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index 72f7f9b067..c0778127d4 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -3673,7 +3673,7 @@ exports[`record integration tests can selectively unmask parts of the page 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"Unmask text\\", + \\"textContent\\": \\"****** ****\\", \\"id\\": 13 } ], @@ -3711,7 +3711,7 @@ exports[`record integration tests can selectively unmask parts of the page 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"unmask1\\\\n \\", + \\"textContent\\": \\"*******\\\\n \\", \\"id\\": 19 }, { @@ -4774,7 +4774,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty ]" `; -exports[`record integration tests handles null attribute values 1`] = ` +exports[`record integration tests can use maskTextSelector to configure which inputs should be masked 1`] = ` "[ { \\"type\\": 0, @@ -4808,201 +4808,63 @@ exports[`record integration tests handles null attribute values 1`] = ` { \\"type\\": 2, \\"tagName\\": \\"html\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, \\"childNodes\\": [ { \\"type\\": 2, \\"tagName\\": \\"head\\", \\"attributes\\": {}, - \\"childNodes\\": [], - \\"id\\": 4 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"body\\", - \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 6 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"p\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"mutation observer\\", - \\"id\\": 8 - } - ], - \\"id\\": 7 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 9 + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 }, { \\"type\\": 2, - \\"tagName\\": \\"ul\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 11 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"li\\", - \\"attributes\\": {}, - \\"childNodes\\": [], - \\"id\\": 12 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 13 - } - ], - \\"id\\": 10 + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 14 + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 }, { \\"type\\": 2, - \\"tagName\\": \\"canvas\\", - \\"attributes\\": {}, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, \\"childNodes\\": [], - \\"id\\": 15 + \\"id\\": 8 }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 16 + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 18 - } - ], - \\"id\\": 17 + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"http-equiv\\": \\"X-UA-Compatible\\", + \\"content\\": \\"ie=edge\\" + }, + \\"childNodes\\": [], + \\"id\\": 10 }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\", - \\"id\\": 19 - } - ], - \\"id\\": 5 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 0, - \\"texts\\": [], - \\"attributes\\": [], - \\"removes\\": [], - \\"adds\\": [ - { - \\"parentId\\": 10, - \\"nextId\\": null, - \\"node\\": { - \\"type\\": 2, - \\"tagName\\": \\"li\\", - \\"attributes\\": { - \\"aria-label\\": \\"label\\", - \\"id\\": \\"test-li\\" - }, - \\"childNodes\\": [], - \\"id\\": 20 - } - } - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 0, - \\"texts\\": [], - \\"attributes\\": [ - { - \\"id\\": 20, - \\"attributes\\": { - \\"aria-label\\": null - } - } - ], - \\"removes\\": [], - \\"adds\\": [] - } - } -]" -`; - -exports[`record integration tests mutations should work when blocked class is unblocked 1`] = ` -"[ - { - \\"type\\": 0, - \\"data\\": {} - }, - { - \\"type\\": 1, - \\"data\\": {} - }, - { - \\"type\\": 4, - \\"data\\": { - \\"href\\": \\"about:blank\\", - \\"width\\": 1920, - \\"height\\": 1080 - } - }, - { - \\"type\\": 2, - \\"data\\": { - \\"node\\": { - \\"type\\": 0, - \\"childNodes\\": [ - { - \\"type\\": 2, - \\"tagName\\": \\"html\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 2, - \\"tagName\\": \\"head\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 4 + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 11 }, { \\"type\\": 2, @@ -5011,43 +4873,24 @@ exports[`record integration tests mutations should work when blocked class is un \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"Uber Application for Codegen Testing\\", - \\"id\\": 6 + \\"textContent\\": \\"form fields\\", + \\"id\\": 13 } ], - \\"id\\": 5 + \\"id\\": 12 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 7 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"style\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"#b-class, #b-class-2 { height: 33px; width: 200px; }\\", - \\"isStyle\\": true, - \\"id\\": 9 - } - ], - \\"id\\": 8 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\", - \\"id\\": 10 + \\"id\\": 14 } ], - \\"id\\": 3 + \\"id\\": 4 }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n\\", - \\"id\\": 11 + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 15 }, { \\"type\\": 2, @@ -5056,34 +4899,850 @@ exports[`record integration tests mutations should work when blocked class is un \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 13 + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 17 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", + \\"tagName\\": \\"form\\", \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 15 - } - ], - \\"id\\": 14 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 16 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"br\\", - \\"attributes\\": {}, - \\"childNodes\\": [], - \\"id\\": 17 - }, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 19 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"text\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 21 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\" + }, + \\"childNodes\\": [], + \\"id\\": 22 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 23 + } + ], + \\"id\\": 20 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 24 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 26 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"on\\" + }, + \\"childNodes\\": [], + \\"id\\": 27 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 28 + } + ], + \\"id\\": 25 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 29 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 31 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 32 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 33 + } + ], + \\"id\\": 30 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 34 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 36 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\" + }, + \\"childNodes\\": [], + \\"id\\": 37 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 38 + } + ], + \\"id\\": 35 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 39 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"textarea\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"textarea\\", + \\"attributes\\": { + \\"name\\": \\"\\", + \\"id\\": \\"\\", + \\"cols\\": \\"30\\", + \\"rows\\": \\"10\\", + \\"data-unmask-example\\": \\"true\\" + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"select\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"select\\", + \\"attributes\\": { + \\"name\\": \\"\\", + \\"id\\": \\"\\", + \\"value\\": \\"1\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"option\\", + \\"attributes\\": { + \\"value\\": \\"1\\", + \\"selected\\": true + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"1\\", + \\"id\\": 50 + } + ], + \\"id\\": 49 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"option\\", + \\"attributes\\": { + \\"value\\": \\"2\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"2\\", + \\"id\\": 53 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + } + ], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 60 + } + ], + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 61 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 62 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 64 + } + ], + \\"id\\": 63 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 65 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**********\\", + \\"isChecked\\": false, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 0, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 27, + \\"pointerType\\": 0 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"off\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 0, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 37, + \\"pointerType\\": 0 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**********\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**********\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"1\\", + \\"isChecked\\": false, + \\"id\\": 47 + } + } +]" +`; + +exports[`record integration tests handles null attribute values 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 4 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 6 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"p\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mutation observer\\", + \\"id\\": 8 + } + ], + \\"id\\": 7 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"ul\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 11 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"li\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 12 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 14 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"canvas\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 15 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 16 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 18 + } + ], + \\"id\\": 17 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\", + \\"id\\": 19 + } + ], + \\"id\\": 5 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 10, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"li\\", + \\"attributes\\": { + \\"aria-label\\": \\"label\\", + \\"id\\": \\"test-li\\" + }, + \\"childNodes\\": [], + \\"id\\": 20 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 20, + \\"attributes\\": { + \\"aria-label\\": null + } + } + ], + \\"removes\\": [], + \\"adds\\": [] + } + } +]" +`; + +exports[`record integration tests mutations should work when blocked class is unblocked 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 4 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Uber Application for Codegen Testing\\", + \\"id\\": 6 + } + ], + \\"id\\": 5 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"style\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"#b-class, #b-class-2 { height: 33px; width: 200px; }\\", + \\"isStyle\\": true, + \\"id\\": 9 + } + ], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\", + \\"id\\": 10 + } + ], + \\"id\\": 3 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n\\", + \\"id\\": 11 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 15 + } + ], + \\"id\\": 14 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 16 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"br\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 17 + }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", @@ -9262,70 +9921,311 @@ exports[`record integration tests should not record input events on ignored elem { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"not \\", - \\"isChecked\\": false, - \\"id\\": 32 + \\"source\\": 5, + \\"text\\": \\"not \\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not s\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not se\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not sec\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secr\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secre\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"not secret\\", + \\"isChecked\\": false, + \\"id\\": 32 + } + } +]" +`; + +exports[`record integration tests should not record input values if dynamically added and maskAllInputs is true 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Empty\\", + \\"id\\": 11 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 12 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"one\\" + }, + \\"childNodes\\": [], + \\"id\\": 16 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 14 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 14, + \\"nextId\\": 16, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"input\\", + \\"value\\": \\"**********************\\" + }, + \\"childNodes\\": [], + \\"id\\": 21 + } + } + ] } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"not s\\", + \\"text\\": \\"**********************\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"not se\\", - \\"isChecked\\": false, - \\"id\\": 32 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"not sec\\", + \\"text\\": \\"***********************\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"not secr\\", + \\"text\\": \\"************************\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"not secre\\", + \\"text\\": \\"*************************\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"not secret\\", - \\"isChecked\\": false, - \\"id\\": 32 + \\"source\\": 3, + \\"id\\": 21, + \\"x\\": 27.5, + \\"y\\": 0 } } ]" `; -exports[`record integration tests should not record input values if dynamically added and maskAllInputs is true 1`] = ` +exports[`record integration tests should not record input values if dynamically added, maskAllInputs is false, and mask selector is used 1`] = ` "[ { \\"type\\": 0, @@ -9500,7 +10400,8 @@ exports[`record integration tests should not record input values if dynamically \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"id\\": \\"input\\", + \\"id\\": \\"input-masked\\", + \\"class\\": \\"rr-mask\\", \\"value\\": \\"**********************\\" }, \\"childNodes\\": [], @@ -9536,15 +10437,6 @@ exports[`record integration tests should not record input values if dynamically \\"id\\": 21 } }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 3, - \\"id\\": 21, - \\"x\\": 12.5, - \\"y\\": 0 - } - }, { \\"type\\": 3, \\"data\\": { @@ -10377,46 +11269,289 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"**********\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 5, + \\"text\\": \\"**********\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***********\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"************\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*************\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 47 + } + } +]" +`; + +exports[`record integration tests should not record textarea values if dynamically added and maskAllInputs is true 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Empty\\", + \\"id\\": 11 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 12 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"one\\" + }, + \\"childNodes\\": [], + \\"id\\": 16 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 14 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 14, + \\"nextId\\": 16, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"textarea\\", + \\"attributes\\": { + \\"id\\": \\"textarea\\", + \\"value\\": \\"*************************\\" + }, + \\"childNodes\\": [], + \\"id\\": 21 + } + }, + { + \\"parentId\\": 21, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"br\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 22 + } + }, + { + \\"parentId\\": 21, + \\"nextId\\": 22, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"******** ****** ** ******\\", + \\"id\\": 23 + } + } + ] } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"***********\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"************\\", + \\"text\\": \\"**************************\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*************\\", + \\"text\\": \\"***************************\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*\\", + \\"text\\": \\"****************************\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 21 } } ]" @@ -13838,28 +14973,167 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"on\\", - \\"isChecked\\": true, + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"userTriggered\\": true, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"off\\", + \\"isChecked\\": false, + \\"userTriggered\\": false, + \\"id\\": 32 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 27 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 0, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 37, + \\"pointerType\\": 0 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"userTriggered\\": true, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 27 + \\"id\\": 59 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"userTriggered\\": false, - \\"id\\": 32 + \\"userTriggered\\": true, + \\"id\\": 59 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 1, - \\"id\\": 37 + \\"source\\": 5, + \\"text\\": \\"********\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 59 } }, { @@ -13867,7 +15141,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 59 } }, { @@ -13875,286 +15149,612 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 0, - \\"id\\": 37 + \\"source\\": 5, + \\"text\\": \\"t\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 2, - \\"id\\": 37, - \\"pointerType\\": 0 + \\"source\\": 5, + \\"text\\": \\"te\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"on\\", - \\"isChecked\\": true, + \\"text\\": \\"tex\\", + \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 37 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 6, - \\"id\\": 37 + \\"source\\": 5, + \\"text\\": \\"text\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 59 + \\"source\\": 5, + \\"text\\": \\"texta\\", + \\"isChecked\\": false, + \\"userTriggered\\": true, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*\\", + \\"text\\": \\"textar\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"**\\", + \\"text\\": \\"textare\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"***\\", + \\"text\\": \\"textarea\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"****\\", + \\"text\\": \\"textarea \\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*****\\", + \\"text\\": \\"textarea t\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"******\\", + \\"text\\": \\"textarea te\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*******\\", + \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"********\\", + \\"text\\": \\"textarea test\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 6, - \\"id\\": 59 + \\"source\\": 5, + \\"text\\": \\"1\\", + \\"isChecked\\": false, + \\"userTriggered\\": false, + \\"id\\": 47 + } + } +]" +`; + +exports[`record integration tests should record input values if dynamically added and maskAllInputs is false 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Empty\\", + \\"id\\": 11 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 12 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"one\\" + }, + \\"childNodes\\": [], + \\"id\\": 16 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 14 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 42 + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 14, + \\"nextId\\": 16, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"input\\", + \\"value\\": \\"input should not be masked\\" + }, + \\"childNodes\\": [], + \\"id\\": 21 + } + } + ] } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"t\\", + \\"text\\": \\"input should not be masked\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"te\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"tex\\", + \\"text\\": \\"input should not be maskedm\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"text\\", + \\"text\\": \\"input should not be maskedmo\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"texta\\", + \\"text\\": \\"input should not be maskedmoo\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } + } +]" +`; + +exports[`record integration tests should record input values if dynamically added, maskAllInputs is true, and unmask selector is used 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textar\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 - } + \\"type\\": 1, + \\"data\\": {} }, { - \\"type\\": 3, + \\"type\\": 4, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textare\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 } }, { - \\"type\\": 3, + \\"type\\": 2, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Empty\\", + \\"id\\": 11 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 12 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"one\\" + }, + \\"childNodes\\": [], + \\"id\\": 16 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 14 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea \\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 14, + \\"nextId\\": 16, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"input-unmasked\\", + \\"class\\": \\"rr-unmask\\", + \\"value\\": \\"************************\\" + }, + \\"childNodes\\": [], + \\"id\\": 21 + } + } + ] } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea t\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"text\\": \\"************************\\", + \\"isChecked\\": false, + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea te\\", - \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea tes\\", + \\"text\\": \\"*************************\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea test\\", + \\"text\\": \\"**************************\\", \\"isChecked\\": false, - \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 21 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"1\\", + \\"text\\": \\"***************************\\", \\"isChecked\\": false, - \\"userTriggered\\": false, - \\"id\\": 47 + \\"id\\": 21 } } ]" @@ -16374,6 +17974,249 @@ exports[`record integration tests should record shadow doms polyfilled by synthe ]" `; +exports[`record integration tests should record textarea values if dynamically added and maskAllInputs is false 1`] = ` +"[ + { + \\"type\\": 0, + \\"data\\": {} + }, + { + \\"type\\": 1, + \\"data\\": {} + }, + { + \\"type\\": 4, + \\"data\\": { + \\"href\\": \\"about:blank\\", + \\"width\\": 1920, + \\"height\\": 1080 + } + }, + { + \\"type\\": 2, + \\"data\\": { + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"id\\": 2 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 5 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"id\\": 6 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 7 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"id\\": 8 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 9 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Empty\\", + \\"id\\": 11 + } + ], + \\"id\\": 10 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 12 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 13 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"id\\": \\"one\\" + }, + \\"childNodes\\": [], + \\"id\\": 16 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 19 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 20 + } + ], + \\"id\\": 14 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 14, + \\"nextId\\": 16, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"textarea\\", + \\"attributes\\": { + \\"id\\": \\"textarea\\", + \\"value\\": \\"textarea should not be masked\\" + }, + \\"childNodes\\": [], + \\"id\\": 21 + } + }, + { + \\"parentId\\": 21, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"br\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"id\\": 22 + } + }, + { + \\"parentId\\": 21, + \\"nextId\\": 22, + \\"node\\": { + \\"type\\": 3, + \\"textContent\\": \\"textarea should not be masked\\", + \\"id\\": 23 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 21 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"mtextarea should not be masked\\", + \\"isChecked\\": false, + \\"id\\": 21 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"motextarea should not be masked\\", + \\"isChecked\\": false, + \\"id\\": 21 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"mootextarea should not be masked\\", + \\"isChecked\\": false, + \\"id\\": 21 + } + } +]" +`; + exports[`record integration tests should record webgl canvas mutations 1`] = ` "[ { diff --git a/packages/rrweb/test/__snapshots__/record.test.ts.snap b/packages/rrweb/test/__snapshots__/record.test.ts.snap index 27bcc46b5e..cb40f3328d 100644 --- a/packages/rrweb/test/__snapshots__/record.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/record.test.ts.snap @@ -3168,16 +3168,6 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 19, \\"id\\": 32 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"link\\", - \\"attributes\\": { - \\"_cssText\\": \\"body { color: pink; }\\" - }, - \\"childNodes\\": [], - \\"rootId\\": 19, - \\"id\\": 33 } ], \\"rootId\\": 19, @@ -3187,7 +3177,7 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 19, - \\"id\\": 34 + \\"id\\": 33 }, { \\"type\\": 2, @@ -3198,11 +3188,11 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"type\\": 3, \\"textContent\\": \\"\\\\n Hello world!\\\\n \\\\n\\\\n\\", \\"rootId\\": 19, - \\"id\\": 36 + \\"id\\": 35 } ], \\"rootId\\": 19, - \\"id\\": 35 + \\"id\\": 34 } ], \\"rootId\\": 19, @@ -3218,6 +3208,49 @@ exports[`record loading stylesheets captures stylesheets in iframes that are sti \\"attributes\\": [], \\"isAttachIframe\\": true } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 22, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"link\\", + \\"attributes\\": { + \\"rel\\": \\"stylesheet\\", + \\"href\\": \\"http://localhost:3030/html/assets/style.css\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 19, + \\"id\\": 36 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"adds\\": [], + \\"removes\\": [], + \\"texts\\": [], + \\"attributes\\": [ + { + \\"id\\": 36, + \\"attributes\\": { + \\"_cssText\\": \\"body { color: pink; }\\" + } + } + ] + } } ]" `; diff --git a/packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-square-1-snap.png b/packages/rrweb/test/e2e/__image_snapshots__/webgl-test-ts-e-2-e-webgl-will-record-and-replay-a-webgl-square-1-snap.png index 7c9c7951db31df46a146ec1f831cbdd8a77c5695..f3d21580ad3ba2e3afb494371fa7ec8d4ee51330 100644 GIT binary patch literal 10629 zcmeHNO(;ZB6#kwWJkyLuC_htvv&L9ViDt%#DM?}>7H?(Af`x^}i&?N!Hp0%r3Rz4n zFhki$6vale5;aB2&qDF;J2O`HLw#@a&b#lt+wHsO`_8$iH{aLW<#AQG0C=L^k$xcG z1e^gq&l-8SJnXP;+C+a>7@KFlN1z(fNN8YcHFeWecog(HLsc(diM>zMmAl6Vk1Km_ z*N6T7O6wza?Yw`yiUqWHKuu{~b6!&utJZ0VVd`3$Sk>WQ+}_q^<5#7vcUPnL*Tv#@ z7r^++Ztm7pz08$NJmp&0=Ymg;9uv3^S4w`H8hQd#B1BZg)aMPgfkt-9^H^3vp`F?BO7Znjn4*W zx(S(#W!jxf-lX`WI49i;$+UKyd_^PypsltMXv2!ScYW8M9Cx46V8k zfdaq!7l3j^IZ`JV$`Ma1Dh{$BN0cB+5G6<3 z#WAE}&YL@iek_Ipu8z`gdv_>^Kk@PPIizyB=TC@e`3GTl|4;K~Mgnz$fXw^HFBu_B zhCS^JJP@XUA_Fso<-&0QDl5oj0AV?_U{SVb9pATm4mpFML~7^3ch6~p?i*M9wa zE?WMxu8LuQjh*cSU#<5LgBu?IWRilYQ*dGcc?SqO1R9`jQDR8|i!d~BFiJpJqsqYH zFd86`sK=;azi;h`x-`bH^XQ-Hd?R) ztLM?04pb_PR$-8`akL5phr>WuVWUk=P&ACj0yr^_7SZ5f7%if~!N4$DM1#X&v~U1Gc<5ALdQA{6k&soYAnzZ&I2v55y=?> z2OzP|Aj||EhfHvSjg9(nBtRrb4P#&!4KoIY(WJq^Fq)kh7)DDC28PkXk%3{fLSY!K zH-U|g(YD5D^8naVq*wDGx4Xrjfq~Nlv=(5rLIyR_M=Rvf3K^6RMl0me3K^ITMl0me o{yL~QpjU-FS_y+fd#F~zEXw85S>n%6HiJCj>FVdQ&MBb@0L-pQcmMzZ diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 7434ac6948..a05348c116 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -13,9 +13,24 @@ 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'; +/** + * 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); @@ -590,6 +605,83 @@ describe('record integration tests', function (this: ISuite) { 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 not 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, + maskTextSelector: '.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 input values if dynamically added and maskAllInputs is true', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); @@ -611,6 +703,59 @@ describe('record integration tests', function (this: ISuite) { await assertSnapshot(page); }); + 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, + unmaskTextSelector: '.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 record webgl canvas mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); From 8e85d45b06ff04217a6f60bb27d9e4c133ec8481 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Mon, 27 Feb 2023 14:30:48 +1100 Subject: [PATCH 10/60] Feat: Add support for replaying :defined pseudo-class of custom elements --- .changeset/fluffy-planes-retire.md | 5 ++ packages/rrweb-snapshot/src/rebuild.ts | 11 +++ packages/rrweb-snapshot/tsconfig.json | 1 + .../events/custom-element-define-class.ts | 88 +++++++++++++++++++ packages/rrweb/test/replayer.test.ts | 16 ++++ 5 files changed, 121 insertions(+) create mode 100644 .changeset/fluffy-planes-retire.md create mode 100644 packages/rrweb/test/events/custom-element-define-class.ts diff --git a/.changeset/fluffy-planes-retire.md b/.changeset/fluffy-planes-retire.md new file mode 100644 index 0000000000..41e9601704 --- /dev/null +++ b/.changeset/fluffy-planes-retire.md @@ -0,0 +1,5 @@ +--- +'rrweb': patch +--- + +Feat: Add support for replaying :defined pseudo-class of custom elements diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index 5cf52ebd38..d80242e2e1 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -142,6 +142,17 @@ function buildNode( if (n.isSVG) { node = doc.createElementNS('http://www.w3.org/2000/svg', tagName); } else { + if ( + // If the tag name is a custom element name + n.tagName.includes('-') && + doc.defaultView && + // If the custom element hasn't been defined yet + !doc.defaultView.customElements.get(n.tagName) + ) + doc.defaultView.customElements.define( + n.tagName, + class extends doc.defaultView.HTMLElement {}, + ); node = doc.createElement(tagName); } /** diff --git a/packages/rrweb-snapshot/tsconfig.json b/packages/rrweb-snapshot/tsconfig.json index 879f459ae4..58577aa6a9 100644 --- a/packages/rrweb-snapshot/tsconfig.json +++ b/packages/rrweb-snapshot/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "composite": true, "module": "ESNext", + "target": "ES6", "moduleResolution": "Node", "noImplicitAny": true, "strictNullChecks": true, diff --git a/packages/rrweb/test/events/custom-element-define-class.ts b/packages/rrweb/test/events/custom-element-define-class.ts new file mode 100644 index 0000000000..f7763cad57 --- /dev/null +++ b/packages/rrweb/test/events/custom-element-define-class.ts @@ -0,0 +1,88 @@ +import { EventType } from '@rrweb/types'; +import type { eventWithTime } from '@rrweb/types'; + +const now = Date.now(); +const events: eventWithTime[] = [ + { + type: EventType.DomContentLoaded, + data: {}, + timestamp: now, + }, + { + type: EventType.Load, + data: {}, + timestamp: now + 100, + }, + { + type: EventType.Meta, + data: { + href: 'http://localhost', + width: 1000, + height: 800, + }, + timestamp: now + 100, + }, + // full snapshot: + { + data: { + node: { + id: 1, + type: 0, + childNodes: [ + { id: 2, name: 'html', type: 1, publicId: '', systemId: '' }, + { + id: 3, + type: 2, + tagName: 'html', + attributes: { lang: 'en' }, + childNodes: [ + { + id: 4, + type: 2, + tagName: 'head', + attributes: {}, + childNodes: [ + { + id: 5, + type: 2, + tagName: 'style', + childNodes: [ + { + id: 6, + type: 3, + isStyle: true, + // Set style of defined custom element to display: block + // Set undefined custom element to display: none + textContent: + 'custom-element:not(:defined) { display: none;} \n custom-element:defined { display: block; }', + }, + ], + }, + ], + }, + { + id: 7, + type: 2, + tagName: 'body', + attributes: {}, + childNodes: [ + { + id: 8, + type: 2, + tagName: 'custom-element', + childNodes: [], + }, + ], + }, + ], + }, + ], + }, + initialOffset: { top: 0, left: 0 }, + }, + type: EventType.FullSnapshot, + timestamp: now + 100, + }, +]; + +export default events; diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts index 7756710410..183d2417fb 100644 --- a/packages/rrweb/test/replayer.test.ts +++ b/packages/rrweb/test/replayer.test.ts @@ -22,6 +22,7 @@ import adoptedStyleSheet from './events/adopted-style-sheet'; import adoptedStyleSheetModification from './events/adopted-style-sheet-modification'; import documentReplacementEvents from './events/document-replacement'; import hoverInIframeShadowDom from './events/iframe-shadowdom-hover'; +import customElementDefineClass from './events/custom-element-define-class'; import { ReplayerEvents } from '@rrweb/types'; interface ISuite { @@ -1076,4 +1077,19 @@ describe('replayer', function () { ), ).toBe(':hover'); }); + + it('should replay styles with :define pseudo-class', async () => { + await page.evaluate(`events = ${JSON.stringify(customElementDefineClass)}`); + + const displayValue = await page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.pause(200); + const customElement = replayer.iframe.contentDocument.querySelector('custom-element'); + window.getComputedStyle(customElement).display; + `); + // If the custom element is not defined, the display value will be 'none'. + // If the custom element is defined, the display value will be 'block'. + expect(displayValue).toEqual('block'); + }); }); From eff0cc540fa60a148849b495507863ba1be1cfc3 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Thu, 2 Mar 2023 11:23:54 +1100 Subject: [PATCH 11/60] add isCustom flag to serialized elements Applying Justin's review suggestion --- .changeset/smart-ears-refuse.md | 7 +++++++ packages/rrweb-snapshot/src/rebuild.ts | 5 +++-- packages/rrweb-snapshot/src/snapshot.ts | 8 ++++++++ packages/rrweb-snapshot/src/types.ts | 2 ++ .../test/__snapshots__/integration.test.ts.snap | 1 + packages/rrweb/test/events/custom-element-define-class.ts | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 .changeset/smart-ears-refuse.md diff --git a/.changeset/smart-ears-refuse.md b/.changeset/smart-ears-refuse.md new file mode 100644 index 0000000000..0aaaabcf0f --- /dev/null +++ b/.changeset/smart-ears-refuse.md @@ -0,0 +1,7 @@ +--- +'rrweb-snapshot': patch +--- + +Feat: Add 'isCustom' flag to serialized elements. + +This flag is used to indicate whether the element is a custom element or not. This is useful for replaying the :defined pseudo-class of custom elements. diff --git a/packages/rrweb-snapshot/src/rebuild.ts b/packages/rrweb-snapshot/src/rebuild.ts index d80242e2e1..c3b15babba 100644 --- a/packages/rrweb-snapshot/src/rebuild.ts +++ b/packages/rrweb-snapshot/src/rebuild.ts @@ -144,8 +144,9 @@ function buildNode( } else { if ( // If the tag name is a custom element name - n.tagName.includes('-') && - doc.defaultView && + n.isCustom && + // If the browser supports custom elements + doc.defaultView?.customElements && // If the custom element hasn't been defined yet !doc.defaultView.customElements.get(n.tagName) ) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index f2053d2245..8182e12b90 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -942,6 +942,13 @@ function serializeElementNode( delete attributes.src; // prevent auto loading } + let isCustomElement: true | undefined; + try { + if (customElements.get(tagName)) isCustomElement = true; + } catch (e) { + // In case old browsers don't support customElements + } + return { type: NodeType.Element, tagName, @@ -950,6 +957,7 @@ function serializeElementNode( isSVG: isSVGElement(n as Element) || undefined, needBlock, rootId, + isCustom: isCustomElement, }; } diff --git a/packages/rrweb-snapshot/src/types.ts b/packages/rrweb-snapshot/src/types.ts index 9edb4dd6d4..9d448e6a74 100644 --- a/packages/rrweb-snapshot/src/types.ts +++ b/packages/rrweb-snapshot/src/types.ts @@ -38,6 +38,8 @@ export type elementNode = { childNodes: serializedNodeWithId[]; isSVG?: true; needBlock?: boolean; + // This is a custom element or not. + isCustom?: true; }; export type textNode = { diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index 1728e7efab..179cf7e8ad 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -845,6 +845,7 @@ exports[`shadow DOM integration tests snapshot shadow DOM 1`] = ` \\"isShadow\\": true } ], + \\"isCustom\\": true, \\"id\\": 16, \\"isShadowHost\\": true }, diff --git a/packages/rrweb/test/events/custom-element-define-class.ts b/packages/rrweb/test/events/custom-element-define-class.ts index f7763cad57..3f9bd9fa6b 100644 --- a/packages/rrweb/test/events/custom-element-define-class.ts +++ b/packages/rrweb/test/events/custom-element-define-class.ts @@ -71,6 +71,7 @@ const events: eventWithTime[] = [ type: 2, tagName: 'custom-element', childNodes: [], + isCustom: true, }, ], }, From be9ef6ab4fa3ca426305eafe817a6be7209b0e16 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Sun, 5 Mar 2023 11:37:54 +1100 Subject: [PATCH 12/60] add custom element event --- packages/rrweb/src/record/index.ts | 11 +++++++ packages/rrweb/src/record/observer.ts | 45 +++++++++++++++++++++++++++ packages/rrweb/src/types.ts | 2 ++ packages/types/src/index.ts | 16 +++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 0e84f89fe3..4e20b79a0a 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -531,6 +531,17 @@ function record( }), ); }, + customElementCb: (c) => { + wrappedEmit( + wrapEvent({ + type: EventType.IncrementalSnapshot, + data: { + source: IncrementalSource.CustomElement, + ...c, + }, + }), + ); + }, blockClass, ignoreClass, ignoreSelector, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 61c9087ff6..c6b0b6c841 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -47,6 +47,7 @@ import { IWindow, SelectionRange, selectionCallback, + customElementCallback, } from '@rrweb/types'; import MutationBuffer from './mutation'; import { callbackWrapper } from './error-handler'; @@ -1198,6 +1199,41 @@ function initSelectionObserver(param: observerParam): listenerHandler { return on('selectionchange', updateSelection); } +function initCustomElementObserver({ + doc, + customElementCb, +}: observerParam): listenerHandler { + const win = doc.defaultView as IWindow; + if (!win || !win.customElements) return () => {}; + const restoreHandler = patch( + win.customElements, + 'define', + function ( + original: ( + name: string, + constructor: CustomElementConstructor, + options?: ElementDefinitionOptions, + ) => void, + ) { + return function ( + name: string, + constructor: CustomElementConstructor, + options?: ElementDefinitionOptions, + ) { + try { + customElementCb({ + define: { + name, + }, + }); + } catch (e) {} + return original.apply(this, [name, constructor, options]); + }; + }, + ); + return restoreHandler; +} + function mergeHooks(o: observerParam, hooks: hooksParam) { const { mutationCb, @@ -1212,6 +1248,7 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { canvasMutationCb, fontCb, selectionCb, + customElementCb, } = o; o.mutationCb = (...p: Arguments) => { if (hooks.mutation) { @@ -1285,6 +1322,12 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { } selectionCb(...p); }; + o.customElementCb = (...c: Arguments) => { + if (hooks.customElement) { + hooks.customElement(...c); + } + customElementCb(...c); + }; } export function initObservers( @@ -1320,6 +1363,7 @@ export function initObservers( // }; const selectionObserver = initSelectionObserver(o); + const customElementObserver = initCustomElementObserver(o); // plugins const pluginHandlers: listenerHandler[] = []; @@ -1343,6 +1387,7 @@ export function initObservers( styleDeclarationObserver(); fontObserver(); selectionObserver(); + customElementObserver(); pluginHandlers.forEach((h) => h()); }); } diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index dd988708e0..39b42fde96 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -17,6 +17,7 @@ import type { addedNodeMutation, blockClass, canvasMutationCallback, + customElementCallback, eventWithTime, fontCallback, hooksParam, @@ -103,6 +104,7 @@ export type observerParam = { styleSheetRuleCb: styleSheetRuleCallback; styleDeclarationCb: styleDeclarationCallback; canvasMutationCb: canvasMutationCallback; + customElementCb: customElementCallback; fontCb: fontCallback; sampling: SamplingStrategy; recordCanvas: boolean; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index f63c35a1f3..8b8dfd8292 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -83,6 +83,7 @@ export enum IncrementalSource { StyleDeclaration, Selection, AdoptedStyleSheet, + CustomElement, } export type mutationData = { @@ -142,6 +143,10 @@ export type adoptedStyleSheetData = { source: IncrementalSource.AdoptedStyleSheet; } & adoptedStyleSheetParam; +export type customElementData = { + source: IncrementalSource.CustomElement; +} & customElementParam; + export type incrementalData = | mutationData | mousemoveData @@ -155,7 +160,8 @@ export type incrementalData = | fontData | selectionData | styleDeclarationData - | adoptedStyleSheetData; + | adoptedStyleSheetData + | customElementData; export type event = | domContentLoadedEvent @@ -594,6 +600,14 @@ export type selectionParam = { export type selectionCallback = (p: selectionParam) => void; +export type customElementParam = { + define?: { + name: string; + }; +}; + +export type customElementCallback = (c: customElementParam) => void; + export type DeprecatedMirror = { map: { [key: number]: INode; From 7d8f7abf3886de8ad4fe89948bd1495feefef440 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 7 Jul 2023 11:11:27 +0200 Subject: [PATCH 13/60] feat: Better masking of option/radio/checkbox values --- .changeset/little-moons-camp.md | 6 + packages/rrweb-snapshot/src/snapshot.ts | 55 +- packages/rrweb-snapshot/src/types.ts | 2 + packages/rrweb-snapshot/src/utils.ts | 31 +- packages/rrweb/src/record/index.ts | 2 + packages/rrweb/src/record/mutation.ts | 6 +- packages/rrweb/src/record/observer.ts | 38 +- .../__snapshots__/integration.test.ts.snap | 1148 +++++++++++------ packages/rrweb/test/html/form.html | 16 +- .../cross-origin-iframes.test.ts.snap | 373 ++++-- 10 files changed, 1159 insertions(+), 518 deletions(-) create mode 100644 .changeset/little-moons-camp.md diff --git a/.changeset/little-moons-camp.md b/.changeset/little-moons-camp.md new file mode 100644 index 0000000000..776f214f40 --- /dev/null +++ b/.changeset/little-moons-camp.md @@ -0,0 +1,6 @@ +--- +'rrweb-snapshot': minor +'rrweb': minor +--- + +feat: Better masking of option/radio/checkbox values diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 8182e12b90..e73d62ea6b 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -21,7 +21,9 @@ import { isNativeShadowDom, stringifyStylesheet, getInputType, + getInputValue, toLowerCase, + toUpperCase, } from './utils'; let _id = 1; @@ -636,6 +638,7 @@ function serializeTextNode( }, ): serializedNode { const { +<<<<<<< HEAD maskAllText, maskTextClass, unmaskTextClass, @@ -644,6 +647,13 @@ function serializeTextNode( maskTextFn, maskInputOptions, maskInputFn, +======= + maskTextClass, + maskTextSelector, + maskTextFn, + maskInputFn, + maskInputOptions, +>>>>>>> b310e6f (feat: Better masking of option/radio/checkbox values) rootId, } = options; // The parent node may not be a html element which has a tagName attribute. @@ -700,6 +710,18 @@ function serializeTextNode( : textContent.replace(/[\S]/g, '*'); } + // Handle
      +
      masked from maskAllText
      diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 1c04e97f93..39ccc7017b 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -1451,6 +1451,37 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); + it('should mask texts using maskAllText', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskAllText: true, + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should not mask inputs when maskAllText:true and maskAllInputs:false', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form.html', { + maskAllText: true, + maskAllInputs: false, + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + it('can mask character data mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); From 6c29ea037dbb1be381ba5fe2d07457a8cb27c396 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Sat, 29 Jul 2023 13:21:08 -0400 Subject: [PATCH 26/60] feat: Ensure password is always masked by default --- packages/rrweb-snapshot/src/snapshot.ts | 5 +- packages/rrweb-snapshot/src/types.ts | 2 +- packages/rrweb-snapshot/src/utils.ts | 5 +- packages/rrweb/src/record/index.ts | 3 +- .../__snapshots__/integration.test.ts.snap | 1209 ++++++++++------- packages/rrweb/test/html/form.html | 3 + packages/rrweb/test/html/password.html | 2 +- packages/rrweb/test/integration.test.ts | 7 +- .../cross-origin-iframes.test.ts.snap | 302 ++-- 9 files changed, 941 insertions(+), 597 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index c1f2d59cb1..7166474c71 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -1512,12 +1512,9 @@ function snapshot( week: true, textarea: true, select: true, - password: true, } : maskAllInputs === false - ? { - password: true, - } + ? {} : maskAllInputs; const slimDOMOptions: SlimDOMOptions = slimDOM === true || slimDOM === 'all' diff --git a/packages/rrweb-snapshot/src/types.ts b/packages/rrweb-snapshot/src/types.ts index f36343b3d1..5405e8ec9c 100644 --- a/packages/rrweb-snapshot/src/types.ts +++ b/packages/rrweb-snapshot/src/types.ts @@ -134,7 +134,7 @@ export type MaskInputOptions = Partial<{ // unify textarea and select element with text input textarea: boolean; select: boolean; - password: boolean; + // password is _always_ masked, can't opt out of this radio: boolean; checkbox: boolean; }>; diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 987ed64b8b..905686343a 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -228,7 +228,10 @@ export function shouldMaskInput({ const actualType = type && toLowerCase(type); return Boolean( maskInputOptions[tagName.toLowerCase() as keyof MaskInputOptions] || - (actualType && maskInputOptions[actualType as keyof MaskInputOptions]), + (actualType && maskInputOptions[actualType as keyof MaskInputOptions]) || + actualType === 'password' || + // Default to "text" option for inputs without a "type" attribute defined + (tagName === 'INPUT' && !type && maskInputOptions['text']) ); } diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index abf691cbe3..c306011f18 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -146,13 +146,12 @@ function record( week: true, textarea: true, select: true, - password: true, radio: true, checkbox: true, } : _maskInputOptions !== undefined ? _maskInputOptions - : { password: true }; + : {}; const slimDOMOptions: SlimDOMOptions = _slimDOMOptions === true || _slimDOMOptions === 'all' diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index fbc6ea9aae..cb02e03c27 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -2105,8 +2105,8 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -2139,9 +2139,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -2175,7 +2173,8 @@ exports[`record integration tests can record form interactions 1`] = ` \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -2196,9 +2195,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -2209,7 +2206,9 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -2230,7 +2229,9 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -2241,9 +2242,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -2261,6 +2260,40 @@ exports[`record integration tests can record form interactions 1`] = ` \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -2271,7 +2304,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -2284,20 +2317,20 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -2309,7 +2342,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -2323,7 +2356,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -2336,15 +2369,15 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"Option A\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -2356,31 +2389,31 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -2392,7 +2425,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -2401,20 +2434,20 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -2422,7 +2455,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -2432,15 +2465,15 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -2506,7 +2539,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2522,7 +2555,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2530,7 +2563,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2538,7 +2571,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -2548,7 +2581,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2557,7 +2590,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 } }, { @@ -2566,7 +2599,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"radio-off\\", \\"isChecked\\": false, - \\"id\\": 37 + \\"id\\": 42 } }, { @@ -2574,7 +2607,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -2582,7 +2615,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2590,7 +2623,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -2598,7 +2631,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -2606,7 +2639,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 42, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -2616,7 +2649,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -2624,7 +2657,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -2632,7 +2665,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2641,7 +2674,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2650,7 +2683,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2659,7 +2692,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2668,7 +2701,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2677,7 +2710,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2686,7 +2719,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2695,7 +2728,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2704,7 +2737,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2713,7 +2746,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2722,7 +2755,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2731,7 +2764,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2740,7 +2773,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2749,7 +2782,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -2758,7 +2791,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": false, - \\"id\\": 57 + \\"id\\": 62 } } ]" @@ -4514,8 +4547,8 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -4548,9 +4581,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -4584,7 +4615,8 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -4605,9 +4637,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -4618,7 +4648,9 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -4639,7 +4671,9 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -4650,9 +4684,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -4670,6 +4702,40 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -4680,7 +4746,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -4693,20 +4759,20 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -4718,7 +4784,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -4732,7 +4798,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -4745,15 +4811,15 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"Option A\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -4765,31 +4831,31 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -4801,7 +4867,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -4810,20 +4876,20 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -4831,7 +4897,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -4841,15 +4907,15 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -4914,16 +4980,32 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 3, \\"data\\": { \\"source\\": 2, - \\"type\\": 1, + \\"type\\": 6, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, \\"id\\": 27 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 32 + } + }, { \\"type\\": 3, \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 22 + \\"id\\": 27 } }, { @@ -4931,7 +5013,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -4939,7 +5021,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -4947,7 +5029,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -4957,7 +5039,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -4966,7 +5048,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 } }, { @@ -4975,7 +5057,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"radio-off\\", \\"isChecked\\": false, - \\"id\\": 37 + \\"id\\": 42 } }, { @@ -4983,7 +5065,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -4991,7 +5073,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -4999,7 +5081,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5007,7 +5089,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5015,7 +5097,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 42, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -5025,7 +5107,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5033,7 +5115,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5041,7 +5123,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5050,7 +5132,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5059,7 +5141,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5068,7 +5150,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5077,7 +5159,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5086,7 +5168,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5095,7 +5177,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5104,7 +5186,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5113,7 +5195,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5122,7 +5204,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5131,7 +5213,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5140,7 +5222,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5149,7 +5231,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5158,7 +5240,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5166,7 +5248,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5174,7 +5256,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5183,7 +5265,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5192,7 +5274,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5201,7 +5283,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5210,7 +5292,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5219,7 +5301,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5228,7 +5310,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5237,7 +5319,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5246,7 +5328,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5255,7 +5337,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": false, - \\"id\\": 57 + \\"id\\": 62 } } ]" @@ -5449,8 +5531,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -5483,9 +5565,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -5519,7 +5599,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -5540,9 +5621,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -5553,7 +5632,9 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -5574,7 +5655,9 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -5585,9 +5668,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -5605,6 +5686,40 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -5615,7 +5730,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -5628,20 +5743,20 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -5653,7 +5768,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -5667,7 +5782,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -5680,15 +5795,15 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"Option A\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -5700,31 +5815,31 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -5736,7 +5851,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -5745,20 +5860,20 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -5766,7 +5881,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -5776,15 +5891,15 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -5823,7 +5938,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5839,7 +5954,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5847,7 +5962,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5855,7 +5970,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -5865,7 +5980,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5874,7 +5989,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 } }, { @@ -5883,7 +5998,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"radio-off\\", \\"isChecked\\": false, - \\"id\\": 37 + \\"id\\": 42 } }, { @@ -5891,7 +6006,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5899,7 +6014,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5907,7 +6022,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5915,7 +6030,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5923,7 +6038,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 42, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -5933,7 +6048,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5941,7 +6056,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -5949,7 +6064,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5958,7 +6073,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5966,7 +6081,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -5974,7 +6089,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5983,7 +6098,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -5992,7 +6107,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": false, - \\"id\\": 57 + \\"id\\": 62 } } ]" @@ -6743,7 +6858,7 @@ exports[`record integration tests mutations should work when blocked class is un \\"attributes\\": { \\"class\\": \\"rr-block\\", \\"rr_width\\": \\"1904px\\", - \\"rr_height\\": \\"21px\\" + \\"rr_height\\": \\"21.5px\\" }, \\"childNodes\\": [], \\"id\\": 84 @@ -7602,8 +7717,8 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -7636,9 +7751,7 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -7672,7 +7785,8 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -7693,9 +7807,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -7706,7 +7818,9 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -7727,7 +7841,9 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -7738,9 +7854,7 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -7758,6 +7872,40 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -7768,7 +7916,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -7781,20 +7929,20 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -7806,7 +7954,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -7820,7 +7968,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -7833,15 +7981,15 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"Option A\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -7853,31 +8001,31 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -7889,7 +8037,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -7898,20 +8046,20 @@ exports[`record integration tests should mask attribute via function call 1`] = \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -7919,7 +8067,7 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -7929,15 +8077,15 @@ exports[`record integration tests should mask attribute via function call 1`] = { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -10172,6 +10320,14 @@ exports[`record integration tests should nest record iframe 1`] = ` \\"attributes\\": [], \\"isAttachIframe\\": true } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 4, + \\"width\\": 1920, + \\"height\\": 1080 + } } ]" `; @@ -10364,8 +10520,8 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -10398,9 +10554,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -10434,7 +10588,8 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -10455,9 +10610,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -10468,7 +10621,9 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -10489,7 +10644,9 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -10500,9 +10657,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -10520,6 +10675,40 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -10530,7 +10719,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -10543,20 +10732,20 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -10568,7 +10757,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -10582,7 +10771,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -10595,15 +10784,15 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"****** *\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -10615,31 +10804,31 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"**** *\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -10651,7 +10840,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -10660,20 +10849,20 @@ exports[`record integration tests should not mask inputs when maskAllText:true a \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -10681,7 +10870,7 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -10691,15 +10880,15 @@ exports[`record integration tests should not mask inputs when maskAllText:true a { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -12178,8 +12367,8 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"*******\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -12207,6 +12396,39 @@ exports[`record integration tests should not record input values if maskAllInput \\"textContent\\": \\"\\\\n \\", \\"id\\": 31 }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\" + }, + \\"childNodes\\": [], + \\"id\\": 32 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 33 + } + ], + \\"id\\": 30 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 34 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 36 + }, { \\"type\\": 2, \\"tagName\\": \\"input\\", @@ -12217,20 +12439,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"checked\\": true }, \\"childNodes\\": [], - \\"id\\": 32 + \\"id\\": 37 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 33 + \\"id\\": 38 } ], - \\"id\\": 30 + \\"id\\": 35 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 34 + \\"id\\": 39 }, { \\"type\\": 2, @@ -12240,7 +12462,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 36 + \\"id\\": 41 }, { \\"type\\": 2, @@ -12251,20 +12473,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"value\\": \\"*********\\" }, \\"childNodes\\": [], - \\"id\\": 37 + \\"id\\": 42 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 38 + \\"id\\": 43 } ], - \\"id\\": 35 + \\"id\\": 40 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 39 + \\"id\\": 44 }, { \\"type\\": 2, @@ -12276,7 +12498,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 46 }, { \\"type\\": 2, @@ -12285,20 +12507,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 47 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 48 } ], - \\"id\\": 40 + \\"id\\": 45 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 49 }, { \\"type\\": 2, @@ -12308,7 +12530,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 51 }, { \\"type\\": 2, @@ -12319,20 +12541,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"checked\\": true }, \\"childNodes\\": [], - \\"id\\": 47 + \\"id\\": 52 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 53 } ], - \\"id\\": 45 + \\"id\\": 50 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 49 + \\"id\\": 54 }, { \\"type\\": 2, @@ -12344,7 +12566,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -12357,20 +12579,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -12382,7 +12604,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -12396,7 +12618,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -12408,15 +12630,15 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"********\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -12428,31 +12650,31 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"******\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -12464,7 +12686,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -12473,20 +12695,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -12494,7 +12716,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -12504,15 +12726,15 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -12578,7 +12800,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -12594,7 +12816,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -12602,7 +12824,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -12610,7 +12832,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -12620,7 +12842,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -12629,7 +12851,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 } }, { @@ -12638,7 +12860,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*********\\", \\"isChecked\\": false, - \\"id\\": 37 + \\"id\\": 42 } }, { @@ -12646,7 +12868,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -12654,7 +12876,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -12662,7 +12884,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -12670,7 +12892,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -12678,7 +12900,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 42, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -12688,7 +12910,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -12696,7 +12918,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -12704,7 +12926,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12713,7 +12935,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12722,7 +12944,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12731,7 +12953,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12740,7 +12962,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12749,7 +12971,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12758,7 +12980,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12767,7 +12989,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12776,7 +12998,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12784,7 +13006,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -12792,7 +13014,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12801,7 +13023,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12810,7 +13032,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12819,7 +13041,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12828,7 +13050,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12837,7 +13059,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12846,7 +13068,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12855,7 +13077,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12864,7 +13086,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12873,7 +13095,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*********\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12882,7 +13104,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12891,7 +13113,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"***********\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12900,7 +13122,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"************\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12909,7 +13131,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*************\\", \\"isChecked\\": false, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -12918,7 +13140,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": false, - \\"id\\": 57 + \\"id\\": 62 } } ]" @@ -13982,6 +14204,34 @@ exports[`record integration tests should record canvas mutations 1`] = ` \\"top\\": 0 } } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 9, + \\"id\\": 16, + \\"type\\": 0, + \\"commands\\": [ + { + \\"property\\": \\"moveTo\\", + \\"args\\": [ + 0, + 0 + ] + }, + { + \\"property\\": \\"lineTo\\", + \\"args\\": [ + 200, + 100 + ] + }, + { + \\"property\\": \\"stroke\\", + \\"args\\": [] + } + ] + } } ]" `; @@ -15518,14 +15768,6 @@ exports[`record integration tests should record images inside iframe with blob u \\"isAttachIframe\\": true } }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 4, - \\"width\\": 1920, - \\"height\\": 1080 - } - }, { \\"type\\": 3, \\"data\\": { @@ -16187,8 +16429,8 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -16221,9 +16463,7 @@ exports[`record integration tests should record input userTriggered values if us \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -16257,7 +16497,8 @@ exports[`record integration tests should record input userTriggered values if us \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"id\\": 37 @@ -16278,9 +16519,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -16291,7 +16530,9 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\" }, \\"childNodes\\": [], \\"id\\": 42 @@ -16312,7 +16553,9 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -16323,9 +16566,7 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"id\\": 47 @@ -16343,6 +16584,40 @@ exports[`record integration tests should record input userTriggered values if us \\"textContent\\": \\"\\\\n \\", \\"id\\": 49 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-on\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -16353,7 +16628,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 56 }, { \\"type\\": 2, @@ -16366,20 +16641,20 @@ exports[`record integration tests should record input userTriggered values if us \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 53 + \\"id\\": 58 } ], - \\"id\\": 50 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 59 }, { \\"type\\": 2, @@ -16391,7 +16666,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 61 }, { \\"type\\": 2, @@ -16405,7 +16680,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 63 }, { \\"type\\": 2, @@ -16418,15 +16693,15 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"Option A\\", - \\"id\\": 60 + \\"id\\": 65 } ], - \\"id\\": 59 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 66 }, { \\"type\\": 2, @@ -16438,31 +16713,31 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", - \\"id\\": 63 + \\"id\\": 68 } ], - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 64 + \\"id\\": 69 } ], - \\"id\\": 57 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 65 + \\"id\\": 70 } ], - \\"id\\": 55 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -16474,7 +16749,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -16483,20 +16758,20 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 70 + \\"id\\": 75 } ], - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 71 + \\"id\\": 76 } ], \\"id\\": 18 @@ -16504,7 +16779,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 72 + \\"id\\": 77 }, { \\"type\\": 2, @@ -16514,15 +16789,15 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 74 + \\"id\\": 79 } ], - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 75 + \\"id\\": 80 } ], \\"id\\": 16 @@ -16592,7 +16867,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -16608,7 +16883,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -16616,7 +16891,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -16624,7 +16899,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -16635,7 +16910,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"\\", \\"isChecked\\": true, \\"userTriggered\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -16645,7 +16920,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"radio-on\\", \\"isChecked\\": false, \\"userTriggered\\": false, - \\"id\\": 32 + \\"id\\": 37 } }, { @@ -16655,7 +16930,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"radio-off\\", \\"isChecked\\": false, \\"userTriggered\\": false, - \\"id\\": 37 + \\"id\\": 42 } }, { @@ -16663,7 +16938,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -16671,7 +16946,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -16679,7 +16954,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -16687,7 +16962,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -16695,7 +16970,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 42, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -16706,7 +16981,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"\\", \\"isChecked\\": true, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -16714,7 +16989,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 47 } }, { @@ -16722,7 +16997,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16732,7 +17007,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16742,7 +17017,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"**\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16752,7 +17027,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"***\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16762,7 +17037,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"****\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16772,7 +17047,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*****\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16782,7 +17057,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"******\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16792,7 +17067,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*******\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16802,7 +17077,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"********\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16810,7 +17085,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 69 + \\"id\\": 74 } }, { @@ -16818,7 +17093,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16828,7 +17103,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"t\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16838,7 +17113,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"te\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16848,7 +17123,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"tex\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16858,7 +17133,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"text\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16868,7 +17143,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"texta\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16878,7 +17153,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textar\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16888,7 +17163,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textare\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16898,7 +17173,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16908,7 +17183,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea \\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16918,7 +17193,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea t\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16928,7 +17203,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea te\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16938,7 +17213,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16948,7 +17223,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea test\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 52 + \\"id\\": 57 } }, { @@ -16958,7 +17233,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"\\", \\"isChecked\\": false, \\"userTriggered\\": false, - \\"id\\": 57 + \\"id\\": 62 } } ]" @@ -18326,14 +18601,6 @@ exports[`record integration tests should record nested iframes and shadow doms 1 \\"isAttachIframe\\": true } }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 4, - \\"width\\": 1920, - \\"height\\": 1080 - } - }, { \\"type\\": 3, \\"data\\": { diff --git a/packages/rrweb/test/html/form.html b/packages/rrweb/test/html/form.html index cafda95073..0cb5ba3f41 100644 --- a/packages/rrweb/test/html/form.html +++ b/packages/rrweb/test/html/form.html @@ -12,6 +12,9 @@ + diff --git a/packages/rrweb/test/html/password.html b/packages/rrweb/test/html/password.html index aace66abf4..fe07d69881 100644 --- a/packages/rrweb/test/html/password.html +++ b/packages/rrweb/test/html/password.html @@ -15,6 +15,6 @@ document.getElementById('show-password').addEventListener('click', function() { password.setAttribute('type', password.getAttribute('type') === 'password' ? 'text' : 'password'); }); - + diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 39ccc7017b..68d859719c 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -420,12 +420,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'); @@ -466,9 +467,7 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent( getHtml.call(this, 'password.html', { - maskInputOptions: { - password: true, - }, + maskInputOptions: {}, }), ); 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 320c63754b..e351ef5171 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 @@ -1312,8 +1312,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1351,9 +1351,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1392,7 +1390,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1417,9 +1416,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -1431,7 +1428,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-off\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1456,7 +1455,9 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -1468,9 +1469,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1492,6 +1491,45 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"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-on\\", + \\"checked\\": true + }, + \\"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\\", @@ -1503,7 +1541,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 68 }, { \\"type\\": 2, @@ -1517,23 +1555,23 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -1546,7 +1584,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -1561,7 +1599,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 75 }, { \\"type\\": 2, @@ -1575,17 +1613,17 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 2, @@ -1598,37 +1636,37 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", \\"rootId\\": 11, - \\"id\\": 75 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 76 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 77 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 78 + \\"id\\": 83 }, { \\"type\\": 2, @@ -1641,7 +1679,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 80 + \\"id\\": 85 }, { \\"type\\": 2, @@ -1651,23 +1689,23 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 81 + \\"id\\": 86 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 82 + \\"id\\": 87 } ], \\"rootId\\": 11, - \\"id\\": 79 + \\"id\\": 84 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 83 + \\"id\\": 88 } ], \\"rootId\\": 11, @@ -1677,7 +1715,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 84 + \\"id\\": 89 } ], \\"rootId\\": 11, @@ -1747,7 +1785,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1763,7 +1801,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1771,7 +1809,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1779,7 +1817,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 39, + \\"id\\": 44, \\"pointerType\\": 0 } }, @@ -1789,7 +1827,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1798,7 +1836,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 44 + \\"id\\": 49 } }, { @@ -1807,7 +1845,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"radio-off\\", \\"isChecked\\": false, - \\"id\\": 49 + \\"id\\": 54 } }, { @@ -1815,7 +1853,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 54 + \\"id\\": 59 } }, { @@ -1823,7 +1861,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1831,7 +1869,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 54 + \\"id\\": 59 } }, { @@ -1839,7 +1877,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 54 + \\"id\\": 59 } }, { @@ -1847,7 +1885,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 54, + \\"id\\": 59, \\"pointerType\\": 0 } }, @@ -1857,7 +1895,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": true, - \\"id\\": 54 + \\"id\\": 59 } }, { @@ -1865,7 +1903,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 54 + \\"id\\": 59 } }, { @@ -1873,7 +1911,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1882,7 +1920,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1891,7 +1929,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1900,7 +1938,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1909,7 +1947,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1918,7 +1956,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1927,7 +1965,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1936,7 +1974,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1945,7 +1983,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1953,7 +1991,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 81 + \\"id\\": 86 } }, { @@ -1961,7 +1999,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -1970,7 +2008,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -1979,7 +2017,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -1988,7 +2026,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -1997,7 +2035,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2006,7 +2044,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2015,7 +2053,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2024,7 +2062,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2033,7 +2071,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2042,7 +2080,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2051,7 +2089,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2060,7 +2098,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2069,7 +2107,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2078,7 +2116,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 64 + \\"id\\": 69 } }, { @@ -2087,7 +2125,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"\\", \\"isChecked\\": false, - \\"id\\": 69 + \\"id\\": 74 } } ]" @@ -2397,8 +2435,8 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2436,9 +2474,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-on\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2477,7 +2513,8 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"attributes\\": { \\"type\\": \\"radio\\", \\"name\\": \\"toggle\\", - \\"value\\": \\"radio-off\\" + \\"value\\": \\"radio-on\\", + \\"checked\\": true }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2502,9 +2539,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -2516,7 +2551,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-off\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2541,7 +2578,9 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": {}, + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, \\"childNodes\\": [ { \\"type\\": 3, @@ -2553,9 +2592,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\", - \\"value\\": \\"check-on\\", - \\"checked\\": true + \\"type\\": \\"checkbox\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2577,6 +2614,45 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"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-on\\", + \\"checked\\": true + }, + \\"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\\", @@ -2588,7 +2664,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 68 }, { \\"type\\": 2, @@ -2602,23 +2678,23 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 71 }, { \\"type\\": 2, @@ -2631,7 +2707,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 73 }, { \\"type\\": 2, @@ -2646,7 +2722,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 75 }, { \\"type\\": 2, @@ -2660,17 +2736,17 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 78 }, { \\"type\\": 2, @@ -2683,37 +2759,37 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"Opt. B\\", \\"rootId\\": 11, - \\"id\\": 75 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 76 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 77 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 78 + \\"id\\": 83 }, { \\"type\\": 2, @@ -2726,7 +2802,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 80 + \\"id\\": 85 }, { \\"type\\": 2, @@ -2736,23 +2812,23 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 81 + \\"id\\": 86 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 82 + \\"id\\": 87 } ], \\"rootId\\": 11, - \\"id\\": 79 + \\"id\\": 84 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 83 + \\"id\\": 88 } ], \\"rootId\\": 11, @@ -2762,7 +2838,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 84 + \\"id\\": 89 } ], \\"rootId\\": 11, From dc182d199e474f3f6f92f4691aee54ecfb34fd5f Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Sat, 29 Jul 2023 13:41:04 -0400 Subject: [PATCH 27/60] add textarea tests, add maskAllInputs test --- packages/rrweb-snapshot/src/utils.ts | 2 +- .../rrweb-snapshot/test/html/form-fields.html | 8 +- .../__snapshots__/integration.test.ts.snap | 316 ++++++++++++++++++ packages/rrweb/test/integration.test.ts | 16 +- 4 files changed, 338 insertions(+), 4 deletions(-) diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index 905686343a..1efa6ffc66 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -231,7 +231,7 @@ export function shouldMaskInput({ (actualType && maskInputOptions[actualType as keyof MaskInputOptions]) || actualType === 'password' || // Default to "text" option for inputs without a "type" attribute defined - (tagName === 'INPUT' && !type && maskInputOptions['text']) + (tagName === 'INPUT' && !type && maskInputOptions['text']), ); } diff --git a/packages/rrweb-snapshot/test/html/form-fields.html b/packages/rrweb-snapshot/test/html/form-fields.html index 31a35afa10..7b5add5a96 100644 --- a/packages/rrweb-snapshot/test/html/form-fields.html +++ b/packages/rrweb-snapshot/test/html/form-fields.html @@ -19,7 +19,10 @@ + + + + +