From 555d3fca04bf805f3adec1d1043ee313416c5f54 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Mon, 27 Feb 2023 14:30:48 +1100 Subject: [PATCH 01/20] 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 ee01fcde97..2adbf6f2e6 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 cef51f3b127e7910d967c8e84becf02552378546 Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Thu, 2 Mar 2023 11:23:54 +1100 Subject: [PATCH 02/20] 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 2adbf6f2e6..92c96e3ea5 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 5d348a2108..0a67a1336d 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -783,6 +783,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, @@ -791,6 +798,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 dcbf04399b..cfc6d9142d 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 529a51eeff..eb94240008 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -839,6 +839,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 53029122981f3b06503bb298e2fe9c44dad8f20f Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Sat, 4 Mar 2023 15:47:40 +1100 Subject: [PATCH 03/20] fix code lint error --- .changeset/young-timers-grow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/young-timers-grow.md b/.changeset/young-timers-grow.md index e2f9b6b76a..dbb00cc780 100644 --- a/.changeset/young-timers-grow.md +++ b/.changeset/young-timers-grow.md @@ -1,5 +1,5 @@ --- -"rrweb": bugfix +'rrweb': bugfix --- For users of userTriggeredOnInput setting: also set userTriggered to false on Input attribute modifications; this was previously empty this variant of IncrementalSource.Input From d5dae217211d6221486e2f6490cad0dcb3cdc1ee Mon Sep 17 00:00:00 2001 From: Yun Feng Date: Sun, 5 Mar 2023 11:37:54 +1100 Subject: [PATCH 04/20] add custom element event --- .changeset/young-timers-grow.md | 2 +- 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 +++++++++- 5 files changed, 74 insertions(+), 2 deletions(-) diff --git a/.changeset/young-timers-grow.md b/.changeset/young-timers-grow.md index dbb00cc780..4c710b3d3b 100644 --- a/.changeset/young-timers-grow.md +++ b/.changeset/young-timers-grow.md @@ -1,5 +1,5 @@ --- -'rrweb': bugfix +'rrweb': patch --- For users of userTriggeredOnInput setting: also set userTriggered to false on Input attribute modifications; this was previously empty this variant of IncrementalSource.Input diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index c69ee4b80d..a72cf91d5a 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -512,6 +512,17 @@ function record( }), ); }, + customElementCb: (c) => { + wrappedEmit( + wrapEvent({ + type: EventType.IncrementalSnapshot, + data: { + source: IncrementalSource.CustomElement, + ...c, + }, + }), + ); + }, blockClass, ignoreClass, maskTextClass, diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index 2360078445..1a58d3e9ec 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -38,6 +38,7 @@ import { IWindow, SelectionRange, selectionCallback, + customElementCallback, } from '@rrweb/types'; import MutationBuffer from './mutation'; import ProcessedNodeManager from './processed-node-manager'; @@ -1015,6 +1016,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, @@ -1029,6 +1065,7 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { canvasMutationCb, fontCb, selectionCb, + customElementCb, } = o; o.mutationCb = (...p: Arguments) => { if (hooks.mutation) { @@ -1102,6 +1139,12 @@ function mergeHooks(o: observerParam, hooks: hooksParam) { } selectionCb(...p); }; + o.customElementCb = (...c: Arguments) => { + if (hooks.customElement) { + hooks.customElement(...c); + } + customElementCb(...c); + }; } export function initObservers( @@ -1135,6 +1178,7 @@ export function initObservers( // }; const selectionObserver = initSelectionObserver(o); + const customElementObserver = initCustomElementObserver(o); // plugins const pluginHandlers: listenerHandler[] = []; @@ -1158,6 +1202,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 ad35af0039..580b445055 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, @@ -93,6 +94,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 d2ed8ded5b..c5ff272abf 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 @@ -584,6 +590,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 3016fb6464de9f1c4c731c74cf181a89f31a6379 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 6 Jan 2023 14:14:11 -0500 Subject: [PATCH 05/20] support for mask all and unmask by selector and class #1096 --- guide.md | 4 + packages/rrweb-snapshot/src/snapshot.ts | 159 +- 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 | 1725 ++++++++++++++--- packages/rrweb/test/html/unmask-text.html | 23 + packages/rrweb/test/integration.test.ts | 25 + packages/types/src/index.ts | 1 + 10 files changed, 1925 insertions(+), 272 deletions(-) create mode 100644 packages/rrweb/test/html/unmask-text.html diff --git a/guide.md b/guide.md index e2dbf0d23f..7200df1f9e 100644 --- a/guide.md +++ b/guide.md @@ -144,8 +144,11 @@ The parameter of `rrweb.record` accepts the following options. | blockSelector | null | Use a string to configure which selector should be blocked, refer to the [privacy](#privacy) chapter | | ignoreClass | 'rr-ignore' | Use a string or RegExp to configure which elements 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 | @@ -172,6 +175,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 364506fd6a..046d060cd2 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -297,26 +297,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 = @@ -325,21 +388,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 @@ -433,8 +500,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; @@ -454,8 +524,11 @@ function serializeNode( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions = {}, maskTextFn, @@ -507,8 +580,11 @@ function serializeNode( }); case n.TEXT_NODE: return serializeTextNode(n as Text, { + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, maskTextFn, rootId, }); @@ -538,13 +614,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; @@ -579,7 +666,14 @@ function serializeTextNode( !isStyle && !isScript && textContent && - needMaskingText(n, maskTextClass, maskTextSelector) + needMaskingText( + n, + maskTextClass, + maskTextSelector, + unmaskTextClass, + unmaskTextSelector, + maskAllText, + ) ) { textContent = maskTextFn ? maskTextFn(textContent) @@ -928,11 +1022,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; @@ -959,8 +1056,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputOptions = {}, @@ -984,8 +1084,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions, maskTextFn, @@ -1056,8 +1159,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild, inlineStylesheet, maskInputOptions, @@ -1116,8 +1222,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, @@ -1163,8 +1272,11 @@ export function serializeNodeWithId( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, @@ -1204,8 +1316,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; @@ -1233,8 +1348,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, @@ -1299,8 +1417,11 @@ function snapshot( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, skipChild: false, inlineStylesheet, maskInputOptions, 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 c0e69a025f..e5c772cd35 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -63,8 +63,11 @@ function record( blockClass = 'rr-block', blockSelector = null, ignoreClass = 'rr-ignore', + maskAllText = false, maskTextClass = 'rr-mask', + unmaskTextClass = 'rr-unmask', maskTextSelector = null, + unmaskTextSelector = null, inlineStylesheet = true, maskAllInputs, maskInputOptions: _maskInputOptions, @@ -322,8 +325,11 @@ function record( bypassOptions: { blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskInputOptions, dataURLOptions, @@ -365,8 +371,11 @@ function record( mirror, blockClass, blockSelector, + maskAllText, maskTextClass, + unmaskTextClass, maskTextSelector, + unmaskTextSelector, inlineStylesheet, maskAllInputs: maskInputOptions, maskTextFn, @@ -521,8 +530,11 @@ function record( }, blockClass, ignoreClass, + 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 ad97f79915..9946126625 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -162,8 +162,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']; @@ -187,8 +190,11 @@ export default class MutationBuffer { 'mutationCb', 'blockClass', 'blockSelector', + 'maskAllText', 'maskTextClass', + 'unmaskTextClass', 'maskTextSelector', + 'unmaskTextSelector', 'inlineStylesheet', 'maskInputOptions', 'maskTextFn', @@ -288,8 +294,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, @@ -475,6 +484,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 dd9a516709..9c4cbd3600 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, @@ -46,8 +47,11 @@ export type recordOptions = { blockClass?: blockClass; blockSelector?: string; ignoreClass?: string; + maskAllText?: boolean; maskTextClass?: maskTextClass; + unmaskTextClass?: unmaskTextClass; maskTextSelector?: string; + unmaskTextSelector?: string; maskAllInputs?: boolean; maskInputOptions?: MaskInputOptions; maskInputFn?: MaskInputFn; @@ -84,8 +88,11 @@ export type observerParam = { blockClass: blockClass; blockSelector: string | null; ignoreClass: string; + maskAllText: boolean; maskTextClass: maskTextClass; + unmaskTextClass: unmaskTextClass; maskTextSelector: string | null; + unmaskTextSelector: string | null; maskInputOptions: MaskInputOptions; maskInputFn?: MaskInputFn; maskTextFn?: MaskTextFn; @@ -126,8 +133,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 32b56a6019..5e9ea56f79 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -3106,6 +3106,349 @@ exports[`record integration tests can record node mutations 1`] = ` ]" `; +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`] = ` "[ { @@ -3588,34 +3931,861 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"t\\", - \\"isChecked\\": false, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"te\\", - \\"isChecked\\": false, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"tes\\", - \\"isChecked\\": false, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"test\\", + \\"text\\": \\"t\\", + \\"isChecked\\": false, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"te\\", + \\"isChecked\\": false, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"tes\\", + \\"isChecked\\": false, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"test\\", + \\"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 + } + }, + { + \\"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 + } + }, + { + \\"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\\": \\"t\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"te\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"tex\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"text\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"texta\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textar\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textare\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea \\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea t\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea te\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea tes\\", + \\"isChecked\\": false, + \\"id\\": 42 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"textarea test\\", + \\"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\\": \\"**\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, + \\"id\\": 59 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*******\\", + \\"isChecked\\": false, + \\"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 can use maskTextSelector to configure which inputs should be masked 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\\": \\"form fields\\", + \\"id\\": 13 + } + ], + \\"id\\": 12 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 14 + } + ], + \\"id\\": 4 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 15 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 17 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"form\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"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\\" + }, + \\"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 } @@ -3623,319 +4793,148 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"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 - } - }, - { - \\"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 - } - }, - { - \\"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\\": \\"t\\", - \\"isChecked\\": false, - \\"id\\": 42 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"te\\", - \\"isChecked\\": false, - \\"id\\": 42 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"tex\\", - \\"isChecked\\": false, - \\"id\\": 42 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"text\\", - \\"isChecked\\": false, - \\"id\\": 42 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"texta\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textar\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 22 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textare\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 0, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea \\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea t\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea te\\", + \\"text\\": \\"off\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea tes\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 1, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"textarea test\\", - \\"isChecked\\": false, - \\"id\\": 42 + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 27 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 2, - \\"type\\": 6, - \\"id\\": 42 + \\"type\\": 5, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 59 + \\"type\\": 0, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"*\\", - \\"isChecked\\": false, - \\"id\\": 59 + \\"source\\": 2, + \\"type\\": 2, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"**\\", - \\"isChecked\\": false, - \\"id\\": 59 + \\"text\\": \\"on\\", + \\"isChecked\\": true, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"***\\", - \\"isChecked\\": false, - \\"id\\": 59 + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 37 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"****\\", - \\"isChecked\\": false, - \\"id\\": 59 + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*****\\", + \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"******\\", - \\"isChecked\\": false, - \\"id\\": 59 + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 42 } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"*******\\", - \\"isChecked\\": false, + \\"source\\": 2, + \\"type\\": 5, \\"id\\": 59 } }, @@ -3943,7 +4942,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"********\\", + \\"text\\": \\"**********\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -5083,6 +6082,226 @@ exports[`record integration tests should handle recursive console messages 1`] = } } }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"isObjTooDeep (:8503:35)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, + { + \\"type\\": 6, + \\"data\\": { + \\"plugin\\": \\"rrweb/console@1\\", + \\"payload\\": { + \\"level\\": \\"warn\\", + \\"trace\\": [ + \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", + \\"isObjTooDeep (:8503:25)\\", + \\"shouldIgnore (:8567:31)\\", + \\"Object. (:8536:13)\\", + \\"stringify (:8517:19)\\", + \\":8656:47\\", + \\"console.log (:8656:36)\\" + ], + \\"payload\\": [ + \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", + \\"\\\\\\"[object Object]\\\\\\"\\" + ] + } + } + }, { \\"type\\": 6, \\"data\\": { @@ -9109,6 +10328,10 @@ exports[`record integration tests should record after DOMContentLoaded event 1`] \\"type\\": 0, \\"data\\": {} }, + { + \\"type\\": 1, + \\"data\\": {} + }, { \\"type\\": 4, \\"data\\": { @@ -9178,10 +10401,6 @@ exports[`record integration tests should record after DOMContentLoaded event 1`] \\"top\\": 0 } } - }, - { - \\"type\\": 1, - \\"data\\": {} } ]" `; 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 aa564d3177..4a28c9477a 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -1088,6 +1088,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/types/src/index.ts b/packages/types/src/index.ts index 1188ef2fb7..283eeeea63 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<{ /** From 4fc4dcece3eedf11fc8659ba5969b7a9c994e069 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Thu, 12 Jan 2023 12:54:17 -0500 Subject: [PATCH 06/20] apply text mask settings to inputs #1096 --- packages/rrweb-snapshot/src/snapshot.ts | 25 +++++++++++++++++++++++++ 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, 82 insertions(+), 2 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 046d060cd2..a7bb2841f4 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -577,6 +577,11 @@ function serializeNode( keepIframeSrcFn, newlyAddedElement, rootId, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, }); case n.TEXT_NODE: return serializeTextNode(n as Text, { @@ -706,6 +711,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 { @@ -721,6 +731,11 @@ function serializeElementNode( keepIframeSrcFn, newlyAddedElement = false, rootId, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, } = options; const needBlock = _isBlockedElement(n, blockClass, blockSelector); const tagName = getValidTagName(n); @@ -778,12 +793,22 @@ function serializeElementNode( value ) { const type = getInputType(n); + const forceMask = needMaskingText( + n, + maskTextClass, + maskTextSelector, + unmaskTextClass, + unmaskTextSelector, + maskAllText, + ); + attributes.value = maskInputValue({ type, tagName, value, maskInputOptions, maskInputFn, + forceMask, }); } else if (checked) { attributes.checked = checked; diff --git a/packages/rrweb-snapshot/src/utils.ts b/packages/rrweb-snapshot/src/utils.ts index a443cb96c1..f19e1bc47c 100644 --- a/packages/rrweb-snapshot/src/utils.ts +++ b/packages/rrweb-snapshot/src/utils.ts @@ -159,19 +159,22 @@ export function maskInputValue({ type, value, maskInputFn, + forceMask, }: { maskInputOptions: MaskInputOptions; tagName: string; type: string | null; value: string | null; maskInputFn?: MaskInputFn; + forceMask?: boolean; }): string { let text = value || ''; const actualType = type && type.toLowerCase(); 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); diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index e5c772cd35..fe7776b76c 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -378,6 +378,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 9946126625..355f8e084f 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -505,12 +505,22 @@ 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({ maskInputOptions: this.maskInputOptions, tagName: target.tagName, type, value, maskInputFn: this.maskInputFn, + forceMask, }); } if ( diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index bb04dd0300..9f8b7a112d 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -3,6 +3,7 @@ import { maskInputValue, Mirror, getInputType, + needMaskingText, } from 'rrweb-snapshot'; import type { FontFaceSet } from 'css-font-loading-module'; import { @@ -359,6 +360,11 @@ function initInputObserver({ maskInputFn, sampling, userTriggeredOnInput, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, }: observerParam): listenerHandler { function eventHandler(event: Event) { let target = getEventTarget(event) as HTMLElement | null; @@ -388,11 +394,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({ maskInputOptions, @@ -400,6 +416,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 4a28c9477a..0da3c20dba 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -281,6 +281,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 12fa37517c..d0da66306a 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -597,6 +597,7 @@ export function generateRecordSnippet(options: recordOptions) { maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, + maskInputFn: ${options.maskInputFn}, userTriggeredOnInput: ${options.userTriggeredOnInput}, maskTextFn: ${options.maskTextFn}, recordCanvas: ${options.recordCanvas}, From db8c32814035d9e46ab6981a2f9d21aa76d7e5a9 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 10 Feb 2023 12:48:53 -0500 Subject: [PATCH 07/20] 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 7200df1f9e..fd6267a19b 100644 --- a/guide.md +++ b/guide.md @@ -146,7 +146,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 \* | @@ -175,7 +175,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 a7bb2841f4..15402801af 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -348,16 +348,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) { @@ -377,7 +379,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 { @@ -502,7 +504,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; @@ -621,7 +623,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; @@ -713,7 +715,7 @@ function serializeElementNode( rootId: number | undefined; maskAllText: boolean; maskTextClass: string | RegExp; - unmaskTextClass: string | RegExp; + unmaskTextClass: string | RegExp | null; maskTextSelector: string | null; unmaskTextSelector: string | null; }, @@ -1047,7 +1049,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; @@ -1343,7 +1345,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; @@ -1375,7 +1377,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 fe7776b76c..211842fb4a 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -65,7 +65,7 @@ function record( ignoreClass = 'rr-ignore', 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 283eeeea63..27ab5c9819 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 726e7cab2337dfaa53d2a4e3f421a52d1aa95992 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Fri, 10 Feb 2023 13:04:31 -0500 Subject: [PATCH 08/20] 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 15402801af..041768a318 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -390,12 +390,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 4ceaf2a835db647780926d8f02722e2eca55166b Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Mon, 13 Feb 2023 13:48:16 -0500 Subject: [PATCH 09/20] 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 041768a318..891e765b11 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -292,87 +292,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( @@ -392,16 +372,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 f482f58065617f3bcb2282fb7306a589d2fd6bcc Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Thu, 6 Apr 2023 13:25:37 -0400 Subject: [PATCH 10/20] 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 891e765b11..ab552dac79 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -370,21 +370,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 32b726b98e8c52d4bc995dc8aa9a1a4f1ef5e813 Mon Sep 17 00:00:00 2001 From: Michael Dellanoce Date: Mon, 10 Apr 2023 12:28:56 -0400 Subject: [PATCH 11/20] 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 47fbfe5e39..585cff4886 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 }) > = [ // { @@ -30,6 +34,25 @@ const suites: Array< eval: 'window.workload()', times: 10, }, + { + 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 { @@ -94,35 +117,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 5ffcb9fdee24ac678cf023d9c0e99d3540f63d62 Mon Sep 17 00:00:00 2001 From: mdellanoce Date: Mon, 10 Apr 2023 16:51:08 +0000 Subject: [PATCH 12/20] 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 585cff4886..cae4b8154c 100644 --- a/packages/rrweb/test/benchmark/dom-mutation.test.ts +++ b/packages/rrweb/test/benchmark/dom-mutation.test.ts @@ -149,7 +149,7 @@ describe('benchmark: mutation observer', () => { }); }, suite.eval, - suite.recordOptions || {} + suite.recordOptions || {}, )) as number; }; From 3a14f299520c65d0148b4fe0b93fcffa06369f48 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Thu, 6 Jul 2023 19:59:36 -0400 Subject: [PATCH 13/20] feat: add forked sentry tests This adds tests for the features that Sentry has added --- .github/workflows/ci-cd.yml | 9 +- .../__snapshots__/integration.test.ts.snap | 11 +- .../rrweb-snapshot/test/html/form-fields.html | 8 +- packages/rrweb-snapshot/test/snapshot.test.ts | 24 +- packages/rrweb/src/types.ts | 16 + .../integration-sentry.test.ts.snap | 49159 ++++++++++++++++ .../rrweb/test/events/shadow-dom-sentry.ts | 437 + packages/rrweb/test/html/attributes-mask.html | 29 + packages/rrweb/test/html/block.html | 8 + packages/rrweb/test/html/form-masked.html | 41 + packages/rrweb/test/html/form.html | 28 +- packages/rrweb/test/html/mask-text.html | 10 + .../rrweb/test/integration-sentry.test.ts | 434 + packages/rrweb/test/integration.test.ts | 27 +- .../cross-origin-iframes.test.ts.snap | 651 +- packages/rrweb/test/replayer.test.ts | 15 + packages/rrweb/test/utils.ts | 9 + 17 files changed, 50790 insertions(+), 126 deletions(-) create mode 100644 packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap create mode 100644 packages/rrweb/test/events/shadow-dom-sentry.ts create mode 100644 packages/rrweb/test/html/attributes-mask.html create mode 100644 packages/rrweb/test/html/form-masked.html create mode 100644 packages/rrweb/test/integration-sentry.test.ts diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index a1ad8e81cf..fa618e607b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -1,6 +1,11 @@ name: Tests -on: [push, pull_request] +on: + push: + branches: + - master + - release/** + pull_request: concurrency: ${{ github.workflow }}-${{ github.ref }} @@ -8,6 +13,8 @@ jobs: release: name: Tests runs-on: ubuntu-latest + # For now, we know this will fail, so we allow failures + continue-on-error: true steps: - name: Checkout Repo uses: actions/checkout@v3 diff --git a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap index 529a51eeff..5c66b682aa 100644 --- a/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb-snapshot/test/__snapshots__/integration.test.ts.snap @@ -246,7 +246,10 @@ exports[`integration tests [html file]: form-fields.html 1`] = ` + + + + + + + + diff --git a/packages/rrweb/test/html/mask-text.html b/packages/rrweb/test/html/mask-text.html index 2abaaaa511..7610310985 100644 --- a/packages/rrweb/test/html/mask-text.html +++ b/packages/rrweb/test/html/mask-text.html @@ -16,5 +16,15 @@
    mask3
    +
    + mask4 +
    +
    + mask5 +
    + +
    + + diff --git a/packages/rrweb/test/integration-sentry.test.ts b/packages/rrweb/test/integration-sentry.test.ts new file mode 100644 index 0000000000..fc518939a1 --- /dev/null +++ b/packages/rrweb/test/integration-sentry.test.ts @@ -0,0 +1,434 @@ +import * as fs from 'fs'; +import * as path from 'path'; +import type * as puppeteer from 'puppeteer'; +import { + assertSnapshot, + startServer, + getServerURL, + launchPuppeteer, + replaceLast, + generateRecordSnippet, + ISuite, +} from './utils'; +import type { recordOptions } from '../src/types'; +import { eventWithTime, EventType, IncrementalSource } from '@rrweb/types'; + +/** + * Used to filter scroll events out of snapshots as they are flakey + */ +function isNotScroll(snapshot: eventWithTime) { + return !( + snapshot.type === EventType.IncrementalSnapshot && + snapshot.data.source === IncrementalSource.Scroll + ); +} + +describe('record integration tests', function (this: ISuite) { + jest.setTimeout(10_000); + + const getHtml = ( + fileName: string, + options: recordOptions = {}, + ): string => { + const filePath = path.resolve(__dirname, `./html/${fileName}`); + const html = fs.readFileSync(filePath, 'utf8'); + return replaceLast( + html, + '', + ` + + + `, + ); + }; + + let server: ISuite['server']; + let serverURL: string; + let code: ISuite['code']; + let browser: ISuite['browser']; + + beforeAll(async () => { + server = await startServer(); + serverURL = getServerURL(server); + browser = await launchPuppeteer(); + + const bundlePath = path.resolve(__dirname, '../dist/rrweb.min.js'); + const pluginsCode = [ + path.resolve(__dirname, '../dist/plugins/console-record.min.js'), + ] + .map((path) => fs.readFileSync(path, 'utf8')) + .join(); + code = fs.readFileSync(bundlePath, 'utf8') + pluginsCode; + }); + + afterAll(async () => { + await browser.close(); + server.close(); + }); + + it('can configure onMutation', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + + await page.setContent( + getHtml.call(this, 'mutation-observer.html', { + // XXX(sentry) + // onMutation: `(mutations) => { window.lastMutationsLength = mutations.length; return mutations.length < 500 }`, + }), + ); + + await page.evaluate(() => { + const ul = document.querySelector('ul') as HTMLUListElement; + + for (let i = 0; i < 2000; i++) { + const li = document.createElement('li'); + ul.appendChild(li); + const p = document.querySelector('p') as HTMLParagraphElement; + p.appendChild(document.createElement('span')); + } + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + + const lastMutationsLength = await page.evaluate( + 'window.lastMutationsLength', + ); + expect(lastMutationsLength).toBe(4000); + }); + + it('should not record input values on selectively masked elements when maskAllInputs is disabled', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form-masked.html', { + maskAllInputs: false, + // XXX(sentry) + // maskInputSelector: '.rr-mask', + }), + ); + + await page.type('input[type="text"]', 'test'); + await page.click('input[type="radio"]'); + await page.click('input[type="checkbox"]'); + await page.type('input[type="password"]', 'password'); + await page.type('textarea', 'textarea test'); + await page.select('select', '1'); + await page.type('#empty', 'test'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('correctly masks & unmasks attribute values', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'attributes-mask.html', { + // XXX(sentry) + // maskAllText: true, + // unmaskTextSelector: '.rr-unmask', + }), + ); + + // Change attributes, should still be masked + await page.evaluate(() => { + document + .querySelectorAll('body [title]') + .forEach((el) => el.setAttribute('title', 'new title')); + document + .querySelectorAll('body [aria-label]') + .forEach((el) => el.setAttribute('aria-label', 'new aria label')); + document + .querySelectorAll('body [placeholder]') + .forEach((el) => el.setAttribute('placeholder', 'new placeholder')); + document + .querySelectorAll('input[type="button"],input[type="submit"]') + .forEach((el) => el.setAttribute('value', 'new value')); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should record input values if dynamically added and maskAllInputs is false', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: false }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input'; + el.value = 'input should not be masked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record textarea values if dynamically added and maskAllInputs is false', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: false }), + ); + + await page.evaluate(() => { + const el = document.createElement('textarea'); + el.id = 'textarea'; + el.innerText = `textarea should not be masked +`; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#textarea', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record input values if dynamically added, maskAllInputs is false, and mask selector is used', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { + maskAllInputs: false, + // XXX(sentry) + // maskInputSelector: '.rr-mask', + }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input-masked'; + el.className = 'rr-mask'; + el.value = 'input should be masked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input-masked', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should not record textarea values if dynamically added and maskAllInputs is true', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { maskAllInputs: true }), + ); + + await page.evaluate(() => { + const el = document.createElement('textarea'); + el.id = 'textarea'; + el.innerText = `textarea should be masked +`; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#textarea', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should record input values if dynamically added, maskAllInputs is true, and unmask selector is used', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'empty.html', { + maskAllInputs: true, + // XXX(sentry) + // unmaskInputSelector: '.rr-unmask', + }), + ); + + await page.evaluate(() => { + const el = document.createElement('input'); + el.id = 'input-unmasked'; + el.className = 'rr-unmask'; + el.value = 'input should be unmasked'; + + const nextElement = document.querySelector('#one')!; + nextElement.parentNode!.insertBefore(el, nextElement); + }); + + await page.type('#input-unmasked', 'moo'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots.filter(isNotScroll)); + }); + + it('should always mask value attribute of passwords', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'password.html', { + maskInputOptions: {}, + }), + ); + + await page.type('#password', 'secr3t'); + + // Change type to text (simulate "show password") + await page.click('#show-password'); + await page.type('#password', 'XY'); + await page.click('#show-password'); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask text in form elements', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'form.html', { + // XXX(sentry) + // maskAllText: true + }), + ); + + // Ensure also masked when we change stuff + await page.evaluate(() => { + document + .querySelector('input[type="submit"]') + ?.setAttribute('value', 'new value'); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should not record blocked elements from blockSelector, when dynamically added', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'block.html', { + blockSelector: 'video', + }), + ); + + await page.evaluate(() => { + const el2 = document.createElement('video'); + el2.className = 'rr-block'; + el2.style.width = '100px'; + el2.style.height = '100px'; + const source2 = document.createElement('source'); + source2.src = 'file:///foo.mp4'; + // These aren't valid, but doing this for testing + source2.style.width = '100px'; + source2.style.height = '100px'; + el2.appendChild(source2); + + const el = document.createElement('video'); + el.style.width = '100px'; + el.style.height = '100px'; + const source = document.createElement('source'); + source.src = 'file:///foo.mp4'; + // These aren't valid, but doing this for testing + source.style.width = '100px'; + source.style.height = '100px'; + el.appendChild(source); + + const nextElement = document.querySelector('.rr-block')!; + nextElement.parentNode!.insertBefore(el, nextElement); + nextElement.parentNode!.insertBefore(el2, nextElement); + }); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should only record unblocked elements', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'block.html', { + blockSelector: 'img,svg', + // XXX(sentry) + // unblockSelector: '.rr-unblock', + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask only inputs', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskAllInputs: true, + // XXX(sentry) + // maskAllText: false, + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); + + it('should mask all text (except unmaskTextSelector), using maskAllText ', async () => { + const page: puppeteer.Page = await browser.newPage(); + await page.goto('about:blank'); + await page.setContent( + getHtml.call(this, 'mask-text.html', { + maskTextClass: 'none', + // XXX(sentry) + // maskAllText: true, + // unmaskTextSelector: '.rr-unmask', + }), + ); + + const snapshots = (await page.evaluate( + 'window.snapshots', + )) as eventWithTime[]; + assertSnapshot(snapshots); + }); +}); diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index 39e32dbcd6..3bdbe764e7 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -12,7 +12,12 @@ import { ISuite, } from './utils'; import type { recordOptions } from '../src/types'; -import { eventWithTime, EventType, RecordPlugin } from '@rrweb/types'; +import { + eventWithTime, + EventType, + RecordPlugin, + IncrementalSource, +} from '@rrweb/types'; import { visitSnapshot, NodeType } from 'rrweb-snapshot'; describe('record integration tests', function (this: ISuite) { @@ -122,7 +127,7 @@ describe('record integration tests', function (this: ISuite) { assertSnapshot(snapshots); }); - it('can record character data muatations', async () => { + it('can record character data mutations', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); await page.setContent(getHtml.call(this, 'mutation-observer.html')); @@ -167,7 +172,13 @@ describe('record integration tests', function (this: ISuite) { it('handles null attribute values', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); - await page.setContent(getHtml.call(this, 'mutation-observer.html', {})); + await page.setContent( + getHtml.call(this, 'mutation-observer.html', { + maskAllInputs: true, + // XXX(sentry) + // maskAllText: true, + }), + ); await page.evaluate(() => { const li = document.createElement('li'); @@ -262,7 +273,11 @@ describe('record integration tests', function (this: ISuite) { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); await page.setContent( - getHtml.call(this, 'form.html', { maskAllInputs: true }), + getHtml.call(this, 'form.html', { + maskAllInputs: true, + // XXX(sentry) + // unmaskTextSelector: '.rr-unmask', + }), ); await page.type('input[type="text"]', 'test'); @@ -271,6 +286,7 @@ describe('record integration tests', function (this: ISuite) { await page.type('input[type="password"]', 'password'); await page.type('textarea', 'textarea test'); await page.select('select', '1'); + await page.type('#empty', 'test'); const snapshots = (await page.evaluate( 'window.snapshots', @@ -286,12 +302,13 @@ describe('record integration tests', function (this: ISuite) { maskInputOptions: { text: false, textarea: false, - password: true, + color: true, }, }), ); await page.type('input[type="text"]', 'test'); + await page.type('input[type="color"]', '#FF0000'); await page.click('input[type="radio"]'); await page.click('input[type="checkbox"]'); await page.type('textarea', 'textarea test'); diff --git a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap index 48d4bdb33a..a82228fe9f 100644 --- a/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap +++ b/packages/rrweb/test/record/__snapshots__/cross-origin-iframes.test.ts.snap @@ -1310,9 +1310,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1350,9 +1349,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1377,9 +1374,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -1391,7 +1386,9 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -1413,6 +1410,124 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"rootId\\": 11, \\"id\\": 51 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 55 + } + ], + \\"rootId\\": 11, + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 56 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 60 + } + ], + \\"rootId\\": 11, + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 61 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 63 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-val\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 64 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 65 + } + ], + \\"rootId\\": 11, + \\"id\\": 62 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 66 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -1424,7 +1539,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 53 + \\"id\\": 68 }, { \\"type\\": 2, @@ -1438,23 +1553,23 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 54 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 55 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -1467,7 +1582,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -1482,7 +1597,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 60 + \\"id\\": 75 }, { \\"type\\": 2, @@ -1494,19 +1609,19 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", + \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 61 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 78 }, { \\"type\\": 2, @@ -1517,39 +1632,39 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", + \\"textContent\\": \\"Option BB\\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 57 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 83 }, { \\"type\\": 2, @@ -1562,7 +1677,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 85 }, { \\"type\\": 2, @@ -1572,23 +1687,119 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 86 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 87 + } + ], + \\"rootId\\": 11, + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 88 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 90 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 91 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 92 + } + ], + \\"rootId\\": 11, + \\"id\\": 89 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 93 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 95 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 96 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 97 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 94 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 98 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 99 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 100 } ], \\"rootId\\": 11, @@ -1598,7 +1809,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 101 } ], \\"rootId\\": 11, @@ -1668,7 +1879,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1684,7 +1895,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1692,7 +1903,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1700,7 +1911,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 39, + \\"id\\": 44, \\"pointerType\\": 0 } }, @@ -1710,16 +1921,25 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 39 + \\"id\\": 44 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 44 + \\"id\\": 49 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 54 } }, { @@ -1727,7 +1947,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1735,7 +1955,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 39 + \\"id\\": 44 } }, { @@ -1743,7 +1963,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1751,7 +1971,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1759,7 +1979,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 49, + \\"id\\": 59, \\"pointerType\\": 0 } }, @@ -1768,8 +1988,8 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 49 + \\"isChecked\\": false, + \\"id\\": 59 } }, { @@ -1777,7 +1997,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 49 + \\"id\\": 59 } }, { @@ -1785,7 +2005,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1794,7 +2014,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1803,7 +2023,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1812,7 +2032,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1821,7 +2041,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1830,7 +2050,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1839,7 +2059,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1848,7 +2068,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1857,7 +2077,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1865,7 +2085,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 71 + \\"id\\": 86 } }, { @@ -1873,7 +2093,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1882,7 +2102,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1891,7 +2111,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1900,7 +2120,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1909,7 +2129,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1918,7 +2138,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1927,7 +2147,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1936,7 +2156,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1945,7 +2165,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1954,7 +2174,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1963,7 +2183,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1972,7 +2192,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1981,7 +2201,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1990,7 +2210,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 54 + \\"id\\": 69 } }, { @@ -1999,7 +2219,7 @@ exports[`cross origin iframes form.html should map input events correctly 1`] = \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } } ]" @@ -2307,9 +2527,8 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2347,9 +2566,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2374,9 +2591,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -2388,7 +2603,9 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"rootId\\": 11, @@ -2410,6 +2627,124 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"rootId\\": 11, \\"id\\": 51 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 55 + } + ], + \\"rootId\\": 11, + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 56 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 60 + } + ], + \\"rootId\\": 11, + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 61 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 63 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"value\\": \\"check-val\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 64 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 65 + } + ], + \\"rootId\\": 11, + \\"id\\": 62 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 66 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -2421,7 +2756,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 53 + \\"id\\": 68 }, { \\"type\\": 2, @@ -2435,23 +2770,23 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 54 + \\"id\\": 69 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 55 + \\"id\\": 70 } ], \\"rootId\\": 11, - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -2464,7 +2799,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -2479,7 +2814,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 60 + \\"id\\": 75 }, { \\"type\\": 2, @@ -2491,19 +2826,19 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", + \\"textContent\\": \\"Option A\\", \\"rootId\\": 11, - \\"id\\": 62 + \\"id\\": 77 } ], \\"rootId\\": 11, - \\"id\\": 61 + \\"id\\": 76 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 63 + \\"id\\": 78 }, { \\"type\\": 2, @@ -2514,39 +2849,39 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", + \\"textContent\\": \\"Option BB\\", \\"rootId\\": 11, - \\"id\\": 65 + \\"id\\": 80 } ], \\"rootId\\": 11, - \\"id\\": 64 + \\"id\\": 79 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 66 + \\"id\\": 81 } ], \\"rootId\\": 11, - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 67 + \\"id\\": 82 } ], \\"rootId\\": 11, - \\"id\\": 57 + \\"id\\": 72 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 68 + \\"id\\": 83 }, { \\"type\\": 2, @@ -2559,7 +2894,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 70 + \\"id\\": 85 }, { \\"type\\": 2, @@ -2569,23 +2904,119 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = }, \\"childNodes\\": [], \\"rootId\\": 11, - \\"id\\": 71 + \\"id\\": 86 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 87 + } + ], + \\"rootId\\": 11, + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 88 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 90 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 91 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 92 + } + ], + \\"rootId\\": 11, + \\"id\\": 89 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 93 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 95 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 96 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 72 + \\"id\\": 97 } ], \\"rootId\\": 11, - \\"id\\": 69 + \\"id\\": 94 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 11, + \\"id\\": 98 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 11, + \\"id\\": 99 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"rootId\\": 11, - \\"id\\": 73 + \\"id\\": 100 } ], \\"rootId\\": 11, @@ -2595,7 +3026,7 @@ exports[`cross origin iframes form.html should map scroll events correctly 1`] = \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", \\"rootId\\": 11, - \\"id\\": 74 + \\"id\\": 101 } ], \\"rootId\\": 11, diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts index 7756710410..38214cab99 100644 --- a/packages/rrweb/test/replayer.test.ts +++ b/packages/rrweb/test/replayer.test.ts @@ -16,6 +16,7 @@ import inputEvents from './events/input'; import iframeEvents from './events/iframe'; import selectionEvents from './events/selection'; import shadowDomEvents from './events/shadow-dom'; +import shadowDomEventsSentry from './events/shadow-dom-sentry'; import StyleSheetTextMutation from './events/style-sheet-text-mutation'; import canvasInIframe from './events/canvas-in-iframe'; import adoptedStyleSheet from './events/adopted-style-sheet'; @@ -1076,4 +1077,18 @@ describe('replayer', function () { ), ).toBe(':hover'); }); + + it('should have `:defined` web components', async () => { + await page.evaluate(`events = ${JSON.stringify(shadowDomEventsSentry)}`); + const result = await page.evaluate(` + const { Replayer } = rrweb; + const replayer = new Replayer(events); + replayer.play(); + replayer.pause(1000); + replayer.iframe.contentDocument.querySelectorAll(':not(:defined)').length; + `); + await page.waitForTimeout(200); + + expect(result).toEqual(0); + }); }); diff --git a/packages/rrweb/test/utils.ts b/packages/rrweb/test/utils.ts index dd5a8cf7cc..0cbd82507e 100644 --- a/packages/rrweb/test/utils.ts +++ b/packages/rrweb/test/utils.ts @@ -588,6 +588,13 @@ export async function waitForRAF( } export function generateRecordSnippet(options: recordOptions) { + // XXX(sentry) + // maskInputSelector: ${JSON.stringify(options.maskInputSelector)}, + // onMutation: ${options.onMutation || undefined}, + // maskAllText: ${options.maskAllText}, + // unmaskTextSelector: ${JSON.stringify(options.unmaskTextSelector)}, + // unmaskInputSelector: ${JSON.stringify(options.unmaskInputSelector)}, + // unblockSelector: ${JSON.stringify(options.unblockSelector)}, return ` window.snapshots = []; rrweb.record({ @@ -595,11 +602,13 @@ export function generateRecordSnippet(options: recordOptions) { window.snapshots.push(event); }, maskTextSelector: ${JSON.stringify(options.maskTextSelector)}, + blockSelector: ${JSON.stringify(options.blockSelector)}, maskAllInputs: ${options.maskAllInputs}, maskInputOptions: ${JSON.stringify(options.maskAllInputs)}, userTriggeredOnInput: ${options.userTriggeredOnInput}, maskTextFn: ${options.maskTextFn}, maskInputFn: ${options.maskInputFn}, + blockSelector: ${JSON.stringify(options.blockSelector)}, recordCanvas: ${options.recordCanvas}, recordAfter: '${options.recordAfter || 'load'}', inlineImages: ${options.inlineImages}, From bfc4c1a352b6445ab19781a9cd38c555d40c7a71 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 15:06:01 -0400 Subject: [PATCH 14/20] update snapshots --- .../__snapshots__/integration.test.ts.snap | 2377 ++++++++++++++--- 1 file changed, 1932 insertions(+), 445 deletions(-) diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index f244948b67..370a205b1b 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -974,7 +974,7 @@ exports[`record integration tests can record attribute mutation 1`] = ` ]" `; -exports[`record integration tests can record character data muatations 1`] = ` +exports[`record integration tests can record character data mutations 1`] = ` "[ { \\"type\\": 0, @@ -1796,9 +1796,8 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -1831,9 +1830,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -1854,9 +1851,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -1867,7 +1862,9 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -1885,6 +1882,109 @@ exports[`record integration tests can record form interactions 1`] = ` \\"textContent\\": \\"\\\\n \\", \\"id\\": 39 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -1895,7 +1995,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 56 }, { \\"type\\": 2, @@ -1908,20 +2008,20 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -1933,7 +2033,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -1947,7 +2047,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -1959,16 +2059,16 @@ exports[`record integration tests can record form interactions 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -1979,32 +2079,32 @@ exports[`record integration tests can record form interactions 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -2016,7 +2116,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -2025,20 +2125,104 @@ exports[`record integration tests can record form interactions 1`] = ` \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -2046,7 +2230,7 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -2056,15 +2240,15 @@ exports[`record integration tests can record form interactions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -2130,7 +2314,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2146,7 +2330,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2154,7 +2338,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2162,7 +2346,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -2172,16 +2356,25 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 42 } }, { @@ -2189,7 +2382,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -2197,7 +2390,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -2205,7 +2398,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -2213,7 +2406,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -2221,7 +2414,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -2230,8 +2423,8 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 37 + \\"isChecked\\": false, + \\"id\\": 47 } }, { @@ -2239,7 +2432,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -2247,7 +2440,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2256,7 +2449,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2265,7 +2458,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2274,7 +2467,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2283,7 +2476,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2292,7 +2485,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2301,7 +2494,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2310,7 +2503,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2319,7 +2512,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2328,7 +2521,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2337,7 +2530,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2346,7 +2539,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2355,7 +2548,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2364,7 +2557,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -2373,7 +2566,7 @@ exports[`record integration tests can record form interactions 1`] = ` \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 62 } } ]" @@ -3577,9 +3770,8 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -3612,9 +3804,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -3635,9 +3825,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -3648,7 +3836,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-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -3669,15 +3859,118 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"textarea\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", \\"id\\": 41 }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"textarea\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 + }, { \\"type\\": 2, \\"tagName\\": \\"textarea\\", @@ -3689,20 +3982,20 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -3714,7 +4007,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -3728,7 +4021,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -3740,16 +4033,16 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -3760,32 +4053,32 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -3797,7 +4090,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -3806,20 +4099,104 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -3827,7 +4204,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -3837,15 +4214,15 @@ exports[`record integration tests can use maskInputOptions to configure which ty { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -3910,16 +4287,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 } }, { @@ -3927,7 +4320,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -3935,7 +4328,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -3943,7 +4336,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -3953,16 +4346,25 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 42 } }, { @@ -3970,7 +4372,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -3978,7 +4380,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -3986,7 +4388,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -3994,7 +4396,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -4002,7 +4404,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -4011,8 +4413,8 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 37 + \\"isChecked\\": false, + \\"id\\": 47 } }, { @@ -4020,7 +4422,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -4028,7 +4430,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4037,7 +4439,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4046,7 +4448,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4055,7 +4457,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4064,7 +4466,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4073,7 +4475,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4082,7 +4484,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4091,7 +4493,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4100,7 +4502,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4109,7 +4511,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4118,7 +4520,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4127,7 +4529,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4136,7 +4538,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4145,7 +4547,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4153,7 +4555,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -4161,7 +4563,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4170,7 +4572,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4179,7 +4581,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4188,7 +4590,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4197,7 +4599,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4206,7 +4608,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4215,7 +4617,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4224,7 +4626,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4233,7 +4635,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -4242,7 +4644,7 @@ exports[`record integration tests can use maskInputOptions to configure which ty \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 62 } } ]" @@ -5578,9 +5980,8 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"*******\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -5613,9 +6014,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -5636,9 +6035,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -5649,7 +6046,9 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -5667,6 +6066,109 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"textContent\\": \\"\\\\n \\", \\"id\\": 39 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -5677,7 +6179,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 56 }, { \\"type\\": 2, @@ -5690,20 +6192,20 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -5715,7 +6217,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -5729,7 +6231,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -5740,16 +6242,16 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -5760,32 +6262,32 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -5797,7 +6299,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -5806,20 +6308,104 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -5827,7 +6413,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -5837,15 +6423,15 @@ exports[`record integration tests should mask inputs via function call 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -5911,7 +6497,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5927,7 +6513,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5935,7 +6521,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5943,7 +6529,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -5953,16 +6539,25 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 42 } }, { @@ -5970,7 +6565,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5978,7 +6573,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5986,7 +6581,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5994,7 +6589,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -6002,7 +6597,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -6011,8 +6606,8 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 37 + \\"isChecked\\": false, + \\"id\\": 47 } }, { @@ -6020,7 +6615,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -6028,7 +6623,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6037,7 +6632,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6046,7 +6641,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6055,7 +6650,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6064,7 +6659,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6073,7 +6668,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6082,7 +6677,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6091,7 +6686,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6100,7 +6695,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6108,7 +6703,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -6116,7 +6711,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6125,7 +6720,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6134,7 +6729,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6143,7 +6738,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6152,7 +6747,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6161,7 +6756,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6170,7 +6765,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6179,7 +6774,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6188,7 +6783,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6197,7 +6792,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6206,7 +6801,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6215,7 +6810,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6224,7 +6819,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6233,7 +6828,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -6242,7 +6837,7 @@ exports[`record integration tests should mask inputs via function call 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 62 } } ]" @@ -6934,17 +7529,17 @@ exports[`record integration tests should mask texts 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 35 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", + \\"tagName\\": \\"div\\", \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"textContent\\": \\"\\\\n mask4\\\\n \\", \\"id\\": 37 } ], @@ -6952,20 +7547,127 @@ exports[`record integration tests should mask texts 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 38 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n mask5\\\\n \\", + \\"id\\": 40 + } + ], + \\"id\\": 39 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"placeholder\\": \\"mask6\\" + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"title\\": \\"mask7\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 45 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"button\\", + \\"attributes\\": { + \\"aria-label\\": \\"mask8\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mask9\\", + \\"id\\": 47 + } + ], + \\"id\\": 46 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"textarea\\", + \\"attributes\\": { + \\"value\\": \\"mask10\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mask10\\", + \\"id\\": 50 + } + ], + \\"id\\": 49 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 53 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 54 + } + ], + \\"id\\": 44 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, \\"top\\": 0 } } @@ -7212,17 +7914,17 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 35 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", + \\"tagName\\": \\"div\\", \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"textContent\\": \\"\\\\n mask4\\\\n \\", \\"id\\": 37 } ], @@ -7230,8 +7932,115 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 38 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n mask5\\\\n \\", + \\"id\\": 40 + } + ], + \\"id\\": 39 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"placeholder\\": \\"mask6\\" + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"div\\", + \\"attributes\\": { + \\"title\\": \\"mask7\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 45 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"button\\", + \\"attributes\\": { + \\"aria-label\\": \\"mask8\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mask9\\", + \\"id\\": 47 + } + ], + \\"id\\": 46 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"textarea\\", + \\"attributes\\": { + \\"value\\": \\"mask10\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"mask10\\", + \\"id\\": 50 + } + ], + \\"id\\": 49 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 53 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 54 + } + ], + \\"id\\": 44 } ], \\"id\\": 16 @@ -8151,47 +8960,162 @@ exports[`record integration tests should not record blocked elements and its chi }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n\\\\n \\", \\"id\\": 19 }, { \\"type\\": 2, - \\"tagName\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 21 - } - ], + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"class\\": \\"rr-block\\", + \\"rr_width\\": \\"16px\\", + \\"rr_height\\": \\"16px\\" + }, + \\"childNodes\\": [], \\"id\\": 20 }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 21 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"href\\": \\"about:blank#href\\" + }, + \\"childNodes\\": [], \\"id\\": 22 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - } -]" -`; - -exports[`record integration tests should not record blocked elements dynamically added 1`] = ` -"[ + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 23 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"class\\": \\"rr-unblock\\", + \\"src\\": \\"about:blank#href\\" + }, + \\"childNodes\\": [], + \\"id\\": 24 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 25 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"class\\": \\"rr-block\\", + \\"rr_width\\": \\"1904px\\", + \\"rr_height\\": \\"1904px\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 26 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 27 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"viewBox\\": \\"0 0 80 80\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"path\\", + \\"attributes\\": { + \\"d\\": \\"M79 71.91a7.32 7.32 0 0 0 0-7.38L46.4 8A7.22 7.22 0 0 0 40 4.37 7.33 7.33 0 0 0 33.62 8L23.06 26.33l2.66 1.54A51.42 51.42 0 0 1 44.6 46.75a50.41 50.41 0 0 1 6.81 22.72H44a44.34 44.34 0 0 0-5.84-19A43.76 43.76 0 0 0 22.07 34.2l-2.66-1.54-9.83 17.13 2.65 1.54A24.9 24.9 0 0 1 24.3 69.47H7.39a1.2 1.2 0 0 1-1.06-.59 1.21 1.21 0 0 1 0-1.23l4.73-8.14a17.67 17.67 0 0 0-5.38-3.08L1 64.57A7.34 7.34 0 0 0 1 72a7.25 7.25 0 0 0 6.39 3.67h23.24v-3.12a31.32 31.32 0 0 0-4.09-15.38 31.26 31.26 0 0 0-8.67-9.57l3.71-6.39a38 38 0 0 1 11.33 12.28 38.1 38.1 0 0 1 5.1 19v3.08h19.68v-3.02a57.52 57.52 0 0 0-7.76-28.88A57.48 57.48 0 0 0 31.47 24.1l7.51-13a1.18 1.18 0 0 1 1.02-.57 1.16 1.16 0 0 1 1.05.59L73.7 67.61a1.2 1.2 0 0 1 0 1.22 1.13 1.13 0 0 1-1.06.59H65c.1 2.07.1 4.09 0 6.16h7.65A7.1 7.1 0 0 0 79 71.91z\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 29 + } + ], + \\"isSVG\\": true, + \\"id\\": 28 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 30 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"class\\": \\"rr-unblock\\", + \\"viewBox\\": \\"0 0 80 80\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"path\\", + \\"attributes\\": { + \\"d\\": \\"M79 71.91a7.32 7.32 0 0 0 0-7.38L46.4 8A7.22 7.22 0 0 0 40 4.37 7.33 7.33 0 0 0 33.62 8L23.06 26.33l2.66 1.54A51.42 51.42 0 0 1 44.6 46.75a50.41 50.41 0 0 1 6.81 22.72H44a44.34 44.34 0 0 0-5.84-19A43.76 43.76 0 0 0 22.07 34.2l-2.66-1.54-9.83 17.13 2.65 1.54A24.9 24.9 0 0 1 24.3 69.47H7.39a1.2 1.2 0 0 1-1.06-.59 1.21 1.21 0 0 1 0-1.23l4.73-8.14a17.67 17.67 0 0 0-5.38-3.08L1 64.57A7.34 7.34 0 0 0 1 72a7.25 7.25 0 0 0 6.39 3.67h23.24v-3.12a31.32 31.32 0 0 0-4.09-15.38 31.26 31.26 0 0 0-8.67-9.57l3.71-6.39a38 38 0 0 1 11.33 12.28 38.1 38.1 0 0 1 5.1 19v3.08h19.68v-3.02a57.52 57.52 0 0 0-7.76-28.88A57.48 57.48 0 0 0 31.47 24.1l7.51-13a1.18 1.18 0 0 1 1.02-.57 1.16 1.16 0 0 1 1.05.59L73.7 67.61a1.2 1.2 0 0 1 0 1.22 1.13 1.13 0 0 1-1.06.59H65c.1 2.07.1 4.09 0 6.16h7.65A7.1 7.1 0 0 0 79 71.91z\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 32 + } + ], + \\"isSVG\\": true, + \\"id\\": 31 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 33 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 35 + } + ], + \\"id\\": 34 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 36 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + } +]" +`; + +exports[`record integration tests should not record blocked elements dynamically added 1`] = ` +"[ { \\"type\\": 0, \\"data\\": {} @@ -8331,9 +9255,124 @@ exports[`record integration tests should not record blocked elements dynamically }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", + \\"textContent\\": \\"\\\\n\\\\n \\", \\"id\\": 19 }, + { + \\"type\\": 2, + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"class\\": \\"rr-block\\", + \\"rr_width\\": \\"16px\\", + \\"rr_height\\": \\"16px\\" + }, + \\"childNodes\\": [], + \\"id\\": 20 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 21 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"href\\": \\"about:blank#href\\" + }, + \\"childNodes\\": [], + \\"id\\": 22 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 23 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"img\\", + \\"attributes\\": { + \\"class\\": \\"rr-unblock\\", + \\"src\\": \\"about:blank#href\\" + }, + \\"childNodes\\": [], + \\"id\\": 24 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n \\", + \\"id\\": 25 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"class\\": \\"rr-block\\", + \\"rr_width\\": \\"1904px\\", + \\"rr_height\\": \\"1904px\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 26 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 27 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"viewBox\\": \\"0 0 80 80\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"path\\", + \\"attributes\\": { + \\"d\\": \\"M79 71.91a7.32 7.32 0 0 0 0-7.38L46.4 8A7.22 7.22 0 0 0 40 4.37 7.33 7.33 0 0 0 33.62 8L23.06 26.33l2.66 1.54A51.42 51.42 0 0 1 44.6 46.75a50.41 50.41 0 0 1 6.81 22.72H44a44.34 44.34 0 0 0-5.84-19A43.76 43.76 0 0 0 22.07 34.2l-2.66-1.54-9.83 17.13 2.65 1.54A24.9 24.9 0 0 1 24.3 69.47H7.39a1.2 1.2 0 0 1-1.06-.59 1.21 1.21 0 0 1 0-1.23l4.73-8.14a17.67 17.67 0 0 0-5.38-3.08L1 64.57A7.34 7.34 0 0 0 1 72a7.25 7.25 0 0 0 6.39 3.67h23.24v-3.12a31.32 31.32 0 0 0-4.09-15.38 31.26 31.26 0 0 0-8.67-9.57l3.71-6.39a38 38 0 0 1 11.33 12.28 38.1 38.1 0 0 1 5.1 19v3.08h19.68v-3.02a57.52 57.52 0 0 0-7.76-28.88A57.48 57.48 0 0 0 31.47 24.1l7.51-13a1.18 1.18 0 0 1 1.02-.57 1.16 1.16 0 0 1 1.05.59L73.7 67.61a1.2 1.2 0 0 1 0 1.22 1.13 1.13 0 0 1-1.06.59H65c.1 2.07.1 4.09 0 6.16h7.65A7.1 7.1 0 0 0 79 71.91z\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 29 + } + ], + \\"isSVG\\": true, + \\"id\\": 28 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 30 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"svg\\", + \\"attributes\\": { + \\"class\\": \\"rr-unblock\\", + \\"viewBox\\": \\"0 0 80 80\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"path\\", + \\"attributes\\": { + \\"d\\": \\"M79 71.91a7.32 7.32 0 0 0 0-7.38L46.4 8A7.22 7.22 0 0 0 40 4.37 7.33 7.33 0 0 0 33.62 8L23.06 26.33l2.66 1.54A51.42 51.42 0 0 1 44.6 46.75a50.41 50.41 0 0 1 6.81 22.72H44a44.34 44.34 0 0 0-5.84-19A43.76 43.76 0 0 0 22.07 34.2l-2.66-1.54-9.83 17.13 2.65 1.54A24.9 24.9 0 0 1 24.3 69.47H7.39a1.2 1.2 0 0 1-1.06-.59 1.21 1.21 0 0 1 0-1.23l4.73-8.14a17.67 17.67 0 0 0-5.38-3.08L1 64.57A7.34 7.34 0 0 0 1 72a7.25 7.25 0 0 0 6.39 3.67h23.24v-3.12a31.32 31.32 0 0 0-4.09-15.38 31.26 31.26 0 0 0-8.67-9.57l3.71-6.39a38 38 0 0 1 11.33 12.28 38.1 38.1 0 0 1 5.1 19v3.08h19.68v-3.02a57.52 57.52 0 0 0-7.76-28.88A57.48 57.48 0 0 0 31.47 24.1l7.51-13a1.18 1.18 0 0 1 1.02-.57 1.16 1.16 0 0 1 1.05.59L73.7 67.61a1.2 1.2 0 0 1 0 1.22 1.13 1.13 0 0 1-1.06.59H65c.1 2.07.1 4.09 0 6.16h7.65A7.1 7.1 0 0 0 79 71.91z\\" + }, + \\"childNodes\\": [], + \\"isSVG\\": true, + \\"id\\": 32 + } + ], + \\"isSVG\\": true, + \\"id\\": 31 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 33 + }, { \\"type\\": 2, \\"tagName\\": \\"script\\", @@ -8342,15 +9381,15 @@ exports[`record integration tests should not record blocked elements dynamically { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 21 + \\"id\\": 35 } ], - \\"id\\": 20 + \\"id\\": 34 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 22 + \\"id\\": 36 } ], \\"id\\": 16 @@ -8387,7 +9426,7 @@ exports[`record integration tests should not record blocked elements dynamically \\"rr_height\\": \\"100px\\" }, \\"childNodes\\": [], - \\"id\\": 23 + \\"id\\": 37 } } ] @@ -8832,6 +9871,15 @@ exports[`record integration tests should not record input values if dynamically \\"id\\": 21 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 3, + \\"id\\": 21, + \\"x\\": 7, + \\"y\\": 0 + } + }, { \\"type\\": 3, \\"data\\": { @@ -9039,9 +10087,8 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"*******\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -9074,9 +10121,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -9097,9 +10142,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -9110,7 +10153,9 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"checkbox\\" + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -9128,6 +10173,109 @@ exports[`record integration tests should not record input values if maskAllInput \\"textContent\\": \\"\\\\n \\", \\"id\\": 39 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -9138,7 +10286,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 56 }, { \\"type\\": 2, @@ -9151,20 +10299,20 @@ exports[`record integration tests should not record input values if maskAllInput \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -9176,7 +10324,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -9190,7 +10338,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -9201,16 +10349,16 @@ exports[`record integration tests should not record input values if maskAllInput \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -9221,32 +10369,32 @@ exports[`record integration tests should not record input values if maskAllInput \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -9258,7 +10406,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -9267,20 +10415,104 @@ exports[`record integration tests should not record input values if maskAllInput \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -9288,7 +10520,7 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -9298,15 +10530,15 @@ exports[`record integration tests should not record input values if maskAllInput { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -9372,7 +10604,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -9388,7 +10620,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -9396,7 +10628,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -9404,7 +10636,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -9414,16 +10646,25 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 42 } }, { @@ -9431,7 +10672,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -9439,7 +10680,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -9447,7 +10688,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -9455,7 +10696,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -9463,7 +10704,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -9472,8 +10713,8 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 37 + \\"isChecked\\": false, + \\"id\\": 47 } }, { @@ -9481,7 +10722,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -9489,7 +10730,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9498,7 +10739,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9507,7 +10748,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9516,7 +10757,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9525,7 +10766,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9534,7 +10775,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9543,7 +10784,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9552,7 +10793,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9561,7 +10802,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9569,7 +10810,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -9577,7 +10818,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9586,7 +10827,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9595,7 +10836,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9604,7 +10845,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9613,7 +10854,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9622,7 +10863,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9631,7 +10872,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9640,7 +10881,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9649,7 +10890,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9658,7 +10899,7 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"*********\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -9667,43 +10908,95 @@ exports[`record integration tests should not record input values if maskAllInput \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***********\\", + \\"isChecked\\": false, + \\"id\\": 57 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"************\\", + \\"isChecked\\": false, + \\"id\\": 57 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*************\\", + \\"isChecked\\": false, + \\"id\\": 57 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 62 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 57 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 79 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"***********\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 79 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"************\\", + \\"text\\": \\"**\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 79 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*************\\", + \\"text\\": \\"***\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 79 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"*\\", + \\"text\\": \\"****\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 79 } } ]" @@ -12747,9 +14040,8 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -12782,9 +14074,7 @@ exports[`record integration tests should record input userTriggered values if us \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -12805,9 +14095,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -12818,7 +14106,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-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -12836,6 +14126,109 @@ exports[`record integration tests should record input userTriggered values if us \\"textContent\\": \\"\\\\n \\", \\"id\\": 39 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -12846,7 +14239,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 56 }, { \\"type\\": 2, @@ -12859,20 +14252,20 @@ exports[`record integration tests should record input userTriggered values if us \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -12884,7 +14277,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -12898,7 +14291,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -12910,16 +14303,16 @@ exports[`record integration tests should record input userTriggered values if us \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -12930,32 +14323,32 @@ exports[`record integration tests should record input userTriggered values if us \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -12967,7 +14360,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -12976,20 +14369,104 @@ exports[`record integration tests should record input userTriggered values if us \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -12997,7 +14474,7 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -13007,15 +14484,15 @@ exports[`record integration tests should record input userTriggered values if us { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -13085,7 +14562,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -13101,7 +14578,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -13109,7 +14586,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -13117,7 +14594,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27, + \\"id\\": 32, \\"pointerType\\": 0 } }, @@ -13128,17 +14605,27 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"on\\", \\"isChecked\\": true, \\"userTriggered\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, \\"userTriggered\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"userTriggered\\": false, + \\"id\\": 42 } }, { @@ -13146,7 +14633,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -13154,7 +14641,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -13162,7 +14649,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -13170,7 +14657,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -13178,7 +14665,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37, + \\"id\\": 47, \\"pointerType\\": 0 } }, @@ -13187,9 +14674,9 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, + \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -13197,7 +14684,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -13205,7 +14692,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13215,7 +14702,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13225,7 +14712,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"**\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13235,7 +14722,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"***\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13245,7 +14732,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"****\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13255,7 +14742,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*****\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13265,7 +14752,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"******\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13275,7 +14762,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"*******\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13285,7 +14772,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"********\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13293,7 +14780,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -13301,7 +14788,7 @@ exports[`record integration tests should record input userTriggered values if us \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13311,7 +14798,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"t\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13321,7 +14808,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"te\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13331,7 +14818,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"tex\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13341,7 +14828,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"text\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13351,7 +14838,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"texta\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13361,7 +14848,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textar\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13371,7 +14858,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textare\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13381,7 +14868,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13391,7 +14878,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea \\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13401,7 +14888,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea t\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13411,7 +14898,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea te\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13421,7 +14908,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13431,7 +14918,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"textarea test\\", \\"isChecked\\": false, \\"userTriggered\\": true, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -13441,7 +14928,7 @@ exports[`record integration tests should record input userTriggered values if us \\"text\\": \\"1\\", \\"isChecked\\": false, \\"userTriggered\\": false, - \\"id\\": 47 + \\"id\\": 62 } } ]" From 11819e75a818060fb1778e377cdc59715c45b745 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 15:35:19 -0400 Subject: [PATCH 15/20] forgot to save --- packages/rrweb/src/record/observer.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/rrweb/src/record/observer.ts b/packages/rrweb/src/record/observer.ts index ed635da461..1cf5347afa 100644 --- a/packages/rrweb/src/record/observer.ts +++ b/packages/rrweb/src/record/observer.ts @@ -3,11 +3,8 @@ import { maskInputValue, Mirror, getInputType, -<<<<<<< HEAD toLowerCase, -======= needMaskingText, ->>>>>>> pendo-io/md-mask-enhancements-1096 } from 'rrweb-snapshot'; import type { FontFaceSet } from 'css-font-loading-module'; import { From db05c67296b6c5f2db83cbb88bc8f025db1ac321 Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 16:21:09 -0400 Subject: [PATCH 16/20] update tests for maskAllText --- packages/rrweb-snapshot/src/snapshot.ts | 2 +- .../integration-sentry.test.ts.snap | 72 +-- .../__snapshots__/integration.test.ts.snap | 553 ++++++++---------- .../rrweb/test/integration-sentry.test.ts | 27 +- packages/rrweb/test/integration.test.ts | 4 +- 5 files changed, 309 insertions(+), 349 deletions(-) diff --git a/packages/rrweb-snapshot/src/snapshot.ts b/packages/rrweb-snapshot/src/snapshot.ts index 4e3529e9f0..de05160d6c 100644 --- a/packages/rrweb-snapshot/src/snapshot.ts +++ b/packages/rrweb-snapshot/src/snapshot.ts @@ -1361,7 +1361,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/test/__snapshots__/integration-sentry.test.ts.snap b/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap index 37688b0027..06edf96b82 100644 --- a/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap @@ -47083,7 +47083,7 @@ exports[`record integration tests should not record input values on selectively \\"name\\": \\"\\", \\"id\\": \\"\\", \\"class\\": \\"rr-mask\\", - \\"value\\": \\"1\\" + \\"value\\": \\"*\\" }, \\"childNodes\\": [ { @@ -47271,7 +47271,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"t\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, \\"id\\": 22 } @@ -47280,7 +47280,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"te\\", + \\"text\\": \\"**\\", \\"isChecked\\": false, \\"id\\": 22 } @@ -47289,7 +47289,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"tes\\", + \\"text\\": \\"***\\", \\"isChecked\\": false, \\"id\\": 22 } @@ -47298,7 +47298,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"test\\", + \\"text\\": \\"****\\", \\"isChecked\\": false, \\"id\\": 22 } @@ -47432,7 +47432,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"p\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47441,7 +47441,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"pa\\", + \\"text\\": \\"**\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47450,7 +47450,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"pas\\", + \\"text\\": \\"***\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47459,7 +47459,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"pass\\", + \\"text\\": \\"****\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47468,7 +47468,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"passw\\", + \\"text\\": \\"*****\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47477,7 +47477,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"passwo\\", + \\"text\\": \\"******\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47486,7 +47486,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"passwor\\", + \\"text\\": \\"*******\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47495,7 +47495,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"password\\", + \\"text\\": \\"********\\", \\"isChecked\\": false, \\"id\\": 59 } @@ -47520,7 +47520,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"t\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47529,7 +47529,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"te\\", + \\"text\\": \\"**\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47538,7 +47538,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"tex\\", + \\"text\\": \\"***\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47547,7 +47547,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"text\\", + \\"text\\": \\"****\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47556,7 +47556,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"texta\\", + \\"text\\": \\"*****\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47565,7 +47565,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textar\\", + \\"text\\": \\"******\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47574,7 +47574,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textare\\", + \\"text\\": \\"*******\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47583,7 +47583,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea\\", + \\"text\\": \\"********\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47592,7 +47592,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea \\", + \\"text\\": \\"*********\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47601,7 +47601,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea t\\", + \\"text\\": \\"**********\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47610,7 +47610,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea te\\", + \\"text\\": \\"***********\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47619,7 +47619,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea tes\\", + \\"text\\": \\"************\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47628,7 +47628,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"textarea test\\", + \\"text\\": \\"*************\\", \\"isChecked\\": false, \\"id\\": 42 } @@ -47637,7 +47637,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"1\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, \\"id\\": 47 } @@ -47662,7 +47662,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"t\\", + \\"text\\": \\"*\\", \\"isChecked\\": false, \\"id\\": 64 } @@ -47671,7 +47671,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"te\\", + \\"text\\": \\"**\\", \\"isChecked\\": false, \\"id\\": 64 } @@ -47680,7 +47680,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"tes\\", + \\"text\\": \\"***\\", \\"isChecked\\": false, \\"id\\": 64 } @@ -47689,7 +47689,7 @@ exports[`record integration tests should not record input values on selectively \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"test\\", + \\"text\\": \\"****\\", \\"isChecked\\": false, \\"id\\": 64 } @@ -48626,7 +48626,7 @@ exports[`record integration tests should record input values if dynamically adde \\"attributes\\": { \\"id\\": \\"input-masked\\", \\"class\\": \\"rr-mask\\", - \\"value\\": \\"input should be masked\\" + \\"value\\": \\"**********************\\" }, \\"childNodes\\": [], \\"id\\": 21 @@ -48639,7 +48639,7 @@ exports[`record integration tests should record input values if dynamically adde \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"input should be masked\\", + \\"text\\": \\"**********************\\", \\"isChecked\\": false, \\"id\\": 21 } @@ -48656,7 +48656,7 @@ exports[`record integration tests should record input values if dynamically adde \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"input should be maskedm\\", + \\"text\\": \\"***********************\\", \\"isChecked\\": false, \\"id\\": 21 } @@ -48665,7 +48665,7 @@ exports[`record integration tests should record input values if dynamically adde \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"input should be maskedmo\\", + \\"text\\": \\"************************\\", \\"isChecked\\": false, \\"id\\": 21 } @@ -48674,7 +48674,7 @@ exports[`record integration tests should record input values if dynamically adde \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"input should be maskedmoo\\", + \\"text\\": \\"*************************\\", \\"isChecked\\": false, \\"id\\": 21 } diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index b4339c515f..5cb7d1b66e 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -5179,9 +5179,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"on\\" + \\"type\\": \\"color\\", + \\"value\\": \\"#000000\\" }, \\"childNodes\\": [], \\"id\\": 27 @@ -5214,9 +5213,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"radio\\", - \\"name\\": \\"toggle\\", - \\"value\\": \\"off\\", - \\"checked\\": true + \\"name\\": \\"toggle\\" }, \\"childNodes\\": [], \\"id\\": 32 @@ -5237,9 +5234,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 2, \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"checkbox\\" - }, + \\"attributes\\": {}, \\"childNodes\\": [ { \\"type\\": 3, @@ -5250,7 +5245,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-on\\" }, \\"childNodes\\": [], \\"id\\": 37 @@ -5268,6 +5265,109 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"textContent\\": \\"\\\\n \\", \\"id\\": 39 }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 41 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"radio\\", + \\"name\\": \\"toggle\\", + \\"value\\": \\"radio-off\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 42 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 43 + } + ], + \\"id\\": 40 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"checkbox\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"checkbox\\", + \\"checked\\": true + }, + \\"childNodes\\": [], + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 48 + } + ], + \\"id\\": 45 + }, + { + \\"type\\": 3, + \\"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-val\\" + }, + \\"childNodes\\": [], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + } + ], + \\"id\\": 50 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 54 + }, { \\"type\\": 2, \\"tagName\\": \\"label\\", @@ -5278,7 +5378,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 41 + \\"id\\": 56 }, { \\"type\\": 2, @@ -5287,23 +5387,24 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"name\\": \\"\\", \\"id\\": \\"\\", \\"cols\\": \\"30\\", - \\"rows\\": \\"10\\" + \\"rows\\": \\"10\\", + \\"data-unmask-example\\": \\"true\\" }, \\"childNodes\\": [], - \\"id\\": 42 + \\"id\\": 57 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 43 + \\"id\\": 58 } ], - \\"id\\": 40 + \\"id\\": 55 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 44 + \\"id\\": 59 }, { \\"type\\": 2, @@ -5315,7 +5416,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 46 + \\"id\\": 61 }, { \\"type\\": 2, @@ -5329,7 +5430,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 48 + \\"id\\": 63 }, { \\"type\\": 2, @@ -5341,16 +5442,16 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"1\\", - \\"id\\": 50 + \\"textContent\\": \\"Option A\\", + \\"id\\": 65 } ], - \\"id\\": 49 + \\"id\\": 64 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 51 + \\"id\\": 66 }, { \\"type\\": 2, @@ -5361,32 +5462,32 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"2\\", - \\"id\\": 53 + \\"textContent\\": \\"Option BB\\", + \\"id\\": 68 } ], - \\"id\\": 52 + \\"id\\": 67 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 54 + \\"id\\": 69 } ], - \\"id\\": 47 + \\"id\\": 62 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 55 + \\"id\\": 70 } ], - \\"id\\": 45 + \\"id\\": 60 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 56 + \\"id\\": 71 }, { \\"type\\": 2, @@ -5398,7 +5499,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 58 + \\"id\\": 73 }, { \\"type\\": 2, @@ -5407,20 +5508,104 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"type\\": \\"password\\" }, \\"childNodes\\": [], - \\"id\\": 59 + \\"id\\": 74 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 60 + \\"id\\": 75 } ], - \\"id\\": 57 + \\"id\\": 72 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"empty\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 78 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"id\\": \\"empty\\" + }, + \\"childNodes\\": [], + \\"id\\": 79 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 80 + } + ], + \\"id\\": 77 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 81 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"unmask\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 83 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-unmask\\" + }, + \\"childNodes\\": [], + \\"id\\": 84 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 85 + } + ], + \\"id\\": 82 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 86 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"submit\\", + \\"value\\": \\"Submit form\\" + }, + \\"childNodes\\": [], + \\"id\\": 87 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 61 + \\"id\\": 88 } ], \\"id\\": 18 @@ -5428,7 +5613,7 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 62 + \\"id\\": 89 }, { \\"type\\": 2, @@ -5438,15 +5623,15 @@ exports[`record integration tests can use maskTextSelector to configure which in { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 64 + \\"id\\": 91 } ], - \\"id\\": 63 + \\"id\\": 90 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 65 + \\"id\\": 92 } ], \\"id\\": 16 @@ -5485,7 +5670,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5501,7 +5686,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5509,7 +5694,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5517,7 +5702,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 27 + \\"id\\": 32, + \\"pointerType\\": 0 } }, { @@ -5526,16 +5712,25 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, - \\"id\\": 27 + \\"id\\": 32 } }, { \\"type\\": 3, \\"data\\": { \\"source\\": 5, - \\"text\\": \\"off\\", + \\"text\\": \\"radio-on\\", \\"isChecked\\": false, - \\"id\\": 32 + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"radio-off\\", + \\"isChecked\\": false, + \\"id\\": 42 } }, { @@ -5543,7 +5738,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 1, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5551,7 +5746,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 27 + \\"id\\": 32 } }, { @@ -5559,7 +5754,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5567,7 +5762,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 0, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5575,7 +5770,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 2, - \\"id\\": 37 + \\"id\\": 47, + \\"pointerType\\": 0 } }, { @@ -5583,8 +5779,8 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 5, \\"text\\": \\"on\\", - \\"isChecked\\": true, - \\"id\\": 37 + \\"isChecked\\": false, + \\"id\\": 47 } }, { @@ -5592,7 +5788,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 37 + \\"id\\": 47 } }, { @@ -5600,7 +5796,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -5609,7 +5805,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -5617,7 +5813,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 6, - \\"id\\": 42 + \\"id\\": 57 } }, { @@ -5625,7 +5821,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"data\\": { \\"source\\": 2, \\"type\\": 5, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -5634,7 +5830,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, - \\"id\\": 59 + \\"id\\": 74 } }, { @@ -5643,7 +5839,7 @@ exports[`record integration tests can use maskTextSelector to configure which in \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, - \\"id\\": 47 + \\"id\\": 62 } } ]" @@ -6774,226 +6970,6 @@ exports[`record integration tests should handle recursive console messages 1`] = } } }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"isObjTooDeep (:8503:35)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, - { - \\"type\\": 6, - \\"data\\": { - \\"plugin\\": \\"rrweb/console@1\\", - \\"payload\\": { - \\"level\\": \\"warn\\", - \\"trace\\": [ - \\"Object.get (__puppeteer_evaluation_script__:13:33)\\", - \\"isObjTooDeep (:8503:25)\\", - \\"shouldIgnore (:8567:31)\\", - \\"Object. (:8536:13)\\", - \\"stringify (:8517:19)\\", - \\":8656:47\\", - \\"console.log (:8656:36)\\" - ], - \\"payload\\": [ - \\"\\\\\\"proxied was accessed so triggering a console.warn\\\\\\"\\", - \\"\\\\\\"[object Object]\\\\\\"\\" - ] - } - } - }, { \\"type\\": 6, \\"data\\": { @@ -11090,15 +11066,6 @@ exports[`record integration tests should not record input values if dynamically \\"id\\": 21 } }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 3, - \\"id\\": 21, - \\"x\\": 7, - \\"y\\": 0 - } - }, { \\"type\\": 3, \\"data\\": { @@ -12772,10 +12739,6 @@ exports[`record integration tests should record after DOMContentLoaded event 1`] \\"type\\": 0, \\"data\\": {} }, - { - \\"type\\": 1, - \\"data\\": {} - }, { \\"type\\": 4, \\"data\\": { @@ -12845,6 +12808,10 @@ exports[`record integration tests should record after DOMContentLoaded event 1`] \\"top\\": 0 } } + }, + { + \\"type\\": 1, + \\"data\\": {} } ]" `; diff --git a/packages/rrweb/test/integration-sentry.test.ts b/packages/rrweb/test/integration-sentry.test.ts index fc518939a1..b3283a26f1 100644 --- a/packages/rrweb/test/integration-sentry.test.ts +++ b/packages/rrweb/test/integration-sentry.test.ts @@ -70,7 +70,7 @@ describe('record integration tests', function (this: ISuite) { server.close(); }); - it('can configure onMutation', async () => { + it.skip('can configure onMutation', async () => { const page: puppeteer.Page = await browser.newPage(); await page.goto('about:blank'); @@ -109,8 +109,7 @@ describe('record integration tests', function (this: ISuite) { await page.setContent( getHtml.call(this, 'form-masked.html', { maskAllInputs: false, - // XXX(sentry) - // maskInputSelector: '.rr-mask', + maskTextSelector: '.rr-mask', }), ); @@ -133,9 +132,8 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent( getHtml.call(this, 'attributes-mask.html', { - // XXX(sentry) - // maskAllText: true, - // unmaskTextSelector: '.rr-unmask', + maskAllText: true, + unmaskTextSelector: '.rr-unmask', }), ); @@ -216,8 +214,7 @@ describe('record integration tests', function (this: ISuite) { await page.setContent( getHtml.call(this, 'empty.html', { maskAllInputs: false, - // XXX(sentry) - // maskInputSelector: '.rr-mask', + maskTextSelector: '.rr-mask', }), ); @@ -270,8 +267,7 @@ describe('record integration tests', function (this: ISuite) { await page.setContent( getHtml.call(this, 'empty.html', { maskAllInputs: true, - // XXX(sentry) - // unmaskInputSelector: '.rr-unmask', + unmaskTextSelector: '.rr-unmask', }), ); @@ -320,8 +316,7 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent( getHtml.call(this, 'form.html', { - // XXX(sentry) - // maskAllText: true + maskAllText: true }), ); @@ -403,8 +398,7 @@ describe('record integration tests', function (this: ISuite) { await page.setContent( getHtml.call(this, 'mask-text.html', { maskAllInputs: true, - // XXX(sentry) - // maskAllText: false, + maskAllText: false, }), ); @@ -420,9 +414,8 @@ describe('record integration tests', function (this: ISuite) { await page.setContent( getHtml.call(this, 'mask-text.html', { maskTextClass: 'none', - // XXX(sentry) - // maskAllText: true, - // unmaskTextSelector: '.rr-unmask', + maskAllText: true, + unmaskTextSelector: '.rr-unmask', }), ); diff --git a/packages/rrweb/test/integration.test.ts b/packages/rrweb/test/integration.test.ts index dc9954c1e5..a0eae0f3df 100644 --- a/packages/rrweb/test/integration.test.ts +++ b/packages/rrweb/test/integration.test.ts @@ -176,7 +176,7 @@ describe('record integration tests', function (this: ISuite) { getHtml.call(this, 'mutation-observer.html', { maskAllInputs: true, // XXX(sentry) - // maskAllText: true, + maskAllText: true, }), ); @@ -276,7 +276,7 @@ describe('record integration tests', function (this: ISuite) { getHtml.call(this, 'form.html', { maskAllInputs: true, // XXX(sentry) - // unmaskTextSelector: '.rr-unmask', + unmaskTextSelector: '.rr-unmask', }), ); From b9b97f4a40a5cf9862558b020936420f4c93be3c Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 16:40:05 -0400 Subject: [PATCH 17/20] remove old sentry test --- .../rrweb/test/events/shadow-dom-sentry.ts | 437 ------------------ packages/rrweb/test/replayer.test.ts | 15 - 2 files changed, 452 deletions(-) delete mode 100644 packages/rrweb/test/events/shadow-dom-sentry.ts diff --git a/packages/rrweb/test/events/shadow-dom-sentry.ts b/packages/rrweb/test/events/shadow-dom-sentry.ts deleted file mode 100644 index f11bf8b704..0000000000 --- a/packages/rrweb/test/events/shadow-dom-sentry.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { EventType, eventWithTime, IncrementalSource } 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: 'https://localhost', width: 655, height: 846 }, - timestamp: now + 100, - }, - { - type: EventType.FullSnapshot, - 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: 2, - tagName: 'meta', - attributes: { charset: 'utf-8' }, - childNodes: [], - id: 5, - }, - ], - id: 4, - }, - { - type: 2, - tagName: 'body', - attributes: {}, - childNodes: [ - { - type: 2, - tagName: 'editable-list', - attributes: { - title: 'TODO', - 'list-item-0': 'First item on the list', - 'list-item-1': 'Second item on the list', - 'list-item-2': 'Third item on the list', - 'list-item-3': 'Fourth item on the list', - 'list-item-4': 'Fifth item on the list', - listitem: 'This will not appear', - 'add-item-text': 'Add new list item:', - }, - childNodes: [], - id: 12, - isShadowHost: true, - }, - ], - id: 10, - }, - ], - id: 3, - }, - ], - id: 1, - }, - initialOffset: { left: 0, top: 0 }, - }, - timestamp: now + 100, - }, - { - type: EventType.IncrementalSnapshot, - data: { - source: IncrementalSource.Mutation, - texts: [], - attributes: [], - removes: [], - adds: [ - { - parentId: 12, - nextId: null, - node: { - type: 2, - tagName: 'div', - attributes: { class: 'editable-list' }, - childNodes: [], - id: 14, - isShadow: true, - }, - }, - { - parentId: 14, - nextId: 21, - node: { - type: 2, - tagName: 'h3', - attributes: {}, - childNodes: [], - id: 19, - }, - }, - { - parentId: 19, - nextId: null, - node: { type: 3, textContent: 'TODO', id: 20 }, - }, - { - parentId: 14, - nextId: 22, - node: { type: 3, textContent: '\n ', id: 21 }, - }, - { - parentId: 14, - nextId: 54, - node: { - type: 2, - tagName: 'ul', - attributes: { class: 'item-list' }, - childNodes: [], - id: 22, - }, - }, - { - parentId: 22, - nextId: 24, - node: { type: 3, textContent: '\n \n ', id: 23 }, - }, - { - parentId: 22, - nextId: 29, - node: { - type: 2, - tagName: 'li', - attributes: {}, - childNodes: [], - id: 24, - }, - }, - { - parentId: 24, - nextId: 26, - node: { - type: 3, - textContent: 'First item on the list\n ', - id: 25, - }, - }, - { - parentId: 24, - nextId: 28, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-remove-item icon' }, - childNodes: [], - id: 26, - }, - }, - { - parentId: 26, - nextId: null, - node: { type: 3, textContent: '⊖', id: 27 }, - }, - { - parentId: 24, - nextId: null, - node: { type: 3, textContent: '\n ', id: 28 }, - }, - { - parentId: 22, - nextId: 30, - node: { type: 3, textContent: '\n \n ', id: 29 }, - }, - { - parentId: 22, - nextId: 35, - node: { - type: 2, - tagName: 'li', - attributes: {}, - childNodes: [], - id: 30, - }, - }, - { - parentId: 30, - nextId: 32, - node: { - type: 3, - textContent: 'Second item on the list\n ', - id: 31, - }, - }, - { - parentId: 30, - nextId: 34, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-remove-item icon' }, - childNodes: [], - id: 32, - }, - }, - { - parentId: 32, - nextId: null, - node: { type: 3, textContent: '⊖', id: 33 }, - }, - { - parentId: 30, - nextId: null, - node: { type: 3, textContent: '\n ', id: 34 }, - }, - { - parentId: 22, - nextId: 36, - node: { type: 3, textContent: '\n \n ', id: 35 }, - }, - { - parentId: 22, - nextId: 41, - node: { - type: 2, - tagName: 'li', - attributes: {}, - childNodes: [], - id: 36, - }, - }, - { - parentId: 36, - nextId: 38, - node: { - type: 3, - textContent: 'Third item on the list\n ', - id: 37, - }, - }, - { - parentId: 36, - nextId: 40, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-remove-item icon' }, - childNodes: [], - id: 38, - }, - }, - { - parentId: 38, - nextId: null, - node: { type: 3, textContent: '⊖', id: 39 }, - }, - { - parentId: 36, - nextId: null, - node: { type: 3, textContent: '\n ', id: 40 }, - }, - { - parentId: 22, - nextId: 42, - node: { type: 3, textContent: '\n \n ', id: 41 }, - }, - { - parentId: 22, - nextId: 47, - node: { - type: 2, - tagName: 'li', - attributes: {}, - childNodes: [], - id: 42, - }, - }, - { - parentId: 42, - nextId: 44, - node: { - type: 3, - textContent: 'Fourth item on the list\n ', - id: 43, - }, - }, - { - parentId: 42, - nextId: 46, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-remove-item icon' }, - childNodes: [], - id: 44, - }, - }, - { - parentId: 44, - nextId: null, - node: { type: 3, textContent: '⊖', id: 45 }, - }, - { - parentId: 42, - nextId: null, - node: { type: 3, textContent: '\n ', id: 46 }, - }, - { - parentId: 22, - nextId: 48, - node: { type: 3, textContent: '\n \n ', id: 47 }, - }, - { - parentId: 22, - nextId: 53, - node: { - type: 2, - tagName: 'li', - attributes: {}, - childNodes: [], - id: 48, - }, - }, - { - parentId: 48, - nextId: 50, - node: { - type: 3, - textContent: 'Fifth item on the list\n ', - id: 49, - }, - }, - { - parentId: 48, - nextId: 52, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-remove-item icon' }, - childNodes: [], - id: 50, - }, - }, - { - parentId: 50, - nextId: null, - node: { type: 3, textContent: '⊖', id: 51 }, - }, - { - parentId: 14, - nextId: 65, - node: { - type: 2, - tagName: 'div', - attributes: {}, - childNodes: [], - id: 55, - }, - }, - { - parentId: 55, - nextId: 57, - node: { type: 3, textContent: '\n ', id: 56 }, - }, - { - parentId: 55, - nextId: 59, - node: { - type: 2, - tagName: 'label', - attributes: {}, - childNodes: [], - id: 57, - }, - }, - { - parentId: 57, - nextId: null, - node: { type: 3, textContent: 'Add new list item:', id: 58 }, - }, - { - parentId: 55, - nextId: 60, - node: { type: 3, textContent: '\n ', id: 59 }, - }, - { - parentId: 55, - nextId: 61, - node: { - type: 2, - tagName: 'input', - attributes: { class: 'add-new-list-item-input', type: 'text' }, - childNodes: [], - id: 60, - }, - }, - { - parentId: 55, - nextId: 62, - node: { type: 3, textContent: '\n ', id: 61 }, - }, - { - parentId: 55, - nextId: 64, - node: { - type: 2, - tagName: 'button', - attributes: { class: 'editable-list-add-item icon' }, - childNodes: [], - id: 62, - }, - }, - { - parentId: 62, - nextId: null, - node: { type: 3, textContent: '⊕', id: 63 }, - }, - { - parentId: 55, - nextId: null, - node: { type: 3, textContent: '\n ', id: 64 }, - }, - { - parentId: 14, - nextId: null, - node: { type: 3, textContent: '\n ', id: 65 }, - }, - ], - }, - timestamp: now + 400, - }, -]; - -export default events; diff --git a/packages/rrweb/test/replayer.test.ts b/packages/rrweb/test/replayer.test.ts index d781bf7d34..183d2417fb 100644 --- a/packages/rrweb/test/replayer.test.ts +++ b/packages/rrweb/test/replayer.test.ts @@ -16,7 +16,6 @@ import inputEvents from './events/input'; import iframeEvents from './events/iframe'; import selectionEvents from './events/selection'; import shadowDomEvents from './events/shadow-dom'; -import shadowDomEventsSentry from './events/shadow-dom-sentry'; import StyleSheetTextMutation from './events/style-sheet-text-mutation'; import canvasInIframe from './events/canvas-in-iframe'; import adoptedStyleSheet from './events/adopted-style-sheet'; @@ -1079,20 +1078,6 @@ describe('replayer', function () { ).toBe(':hover'); }); - it('should have `:defined` web components', async () => { - await page.evaluate(`events = ${JSON.stringify(shadowDomEventsSentry)}`); - const result = await page.evaluate(` - const { Replayer } = rrweb; - const replayer = new Replayer(events); - replayer.play(); - replayer.pause(1000); - replayer.iframe.contentDocument.querySelectorAll(':not(:defined)').length; - `); - await page.waitForTimeout(200); - - expect(result).toEqual(0); - }) - it('should replay styles with :define pseudo-class', async () => { await page.evaluate(`events = ${JSON.stringify(customElementDefineClass)}`); From 061689cc6eee13f32f29058d17250281af00865b Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 16:40:27 -0400 Subject: [PATCH 18/20] fix types for custom element --- packages/rrweb-snapshot/src/types.ts | 1 + packages/types/src/index.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/rrweb-snapshot/src/types.ts b/packages/rrweb-snapshot/src/types.ts index 9d448e6a74..089afadd40 100644 --- a/packages/rrweb-snapshot/src/types.ts +++ b/packages/rrweb-snapshot/src/types.ts @@ -69,6 +69,7 @@ export type serializedNode = ( rootId?: number; isShadowHost?: boolean; isShadow?: boolean; + isCustom?: boolean; }; export type serializedNodeWithId = serializedNode & { id: number }; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index ad74f4fdac..7f3ac1e5bb 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -269,6 +269,7 @@ export type hooksParam = { canvasMutation?: canvasMutationCallback; font?: fontCallback; selection?: selectionCallback; + customElement?: customElementCallback; }; // https://dom.spec.whatwg.org/#interface-mutationrecord From 7a381214189a8665d27db86d31d09a3366093ded Mon Sep 17 00:00:00 2001 From: Billy Vong Date: Fri, 7 Jul 2023 17:21:53 -0400 Subject: [PATCH 19/20] update snapshot expectations --- .../integration-sentry.test.ts.snap | 759 +++++++++--------- .../__snapshots__/integration.test.ts.snap | 8 +- 2 files changed, 378 insertions(+), 389 deletions(-) diff --git a/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap b/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap index 06edf96b82..8b0083fe78 100644 --- a/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration-sentry.test.ts.snap @@ -44163,358 +44163,358 @@ exports[`record integration tests can configure onMutation 1`] = ` exports[`record integration tests correctly masks & unmasks attribute values 1`] = ` "[ { - \\"type\\": 0, - \\"data\\": {} + "type": 0, + "data": {} }, { - \\"type\\": 1, - \\"data\\": {} + "type": 1, + "data": {} }, { - \\"type\\": 4, - \\"data\\": { - \\"href\\": \\"about:blank\\", - \\"width\\": 1920, - \\"height\\": 1080 + "type": 4, + "data": { + "href": "about:blank", + "width": 1920, + "height": 1080 } }, { - \\"type\\": 2, - \\"data\\": { - \\"node\\": { - \\"type\\": 0, - \\"childNodes\\": [ + "type": 2, + "data": { + "node": { + "type": 0, + "childNodes": [ { - \\"type\\": 1, - \\"name\\": \\"html\\", - \\"publicId\\": \\"\\", - \\"systemId\\": \\"\\", - \\"id\\": 2 + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 }, { - \\"type\\": 2, - \\"tagName\\": \\"html\\", - \\"attributes\\": { - \\"lang\\": \\"en\\" + "type": 2, + "tagName": "html", + "attributes": { + "lang": "en" }, - \\"childNodes\\": [ + "childNodes": [ { - \\"type\\": 2, - \\"tagName\\": \\"head\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 5 + "type": 3, + "textContent": "\\n ", + "id": 5 }, { - \\"type\\": 2, - \\"tagName\\": \\"meta\\", - \\"attributes\\": { - \\"charset\\": \\"UTF-8\\" + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "UTF-8" }, - \\"childNodes\\": [], - \\"id\\": 6 + "childNodes": [], + "id": 6 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 7 + "type": 3, + "textContent": "\\n ", + "id": 7 }, { - \\"type\\": 2, - \\"tagName\\": \\"meta\\", - \\"attributes\\": { - \\"name\\": \\"viewport\\", - \\"content\\": \\"width=device-width, initial-scale=1.0\\" + "type": 2, + "tagName": "meta", + "attributes": { + "name": "viewport", + "content": "width=device-width, initial-scale=1.0" }, - \\"childNodes\\": [], - \\"id\\": 8 + "childNodes": [], + "id": 8 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 9 + "type": 3, + "textContent": "\\n ", + "id": 9 }, { - \\"type\\": 2, - \\"tagName\\": \\"meta\\", - \\"attributes\\": { - \\"http-equiv\\": \\"X-UA-Compatible\\", - \\"content\\": \\"ie=edge\\" + "type": 2, + "tagName": "meta", + "attributes": { + "http-equiv": "X-UA-Compatible", + "content": "ie=edge" }, - \\"childNodes\\": [], - \\"id\\": 10 + "childNodes": [], + "id": 10 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 11 + "type": 3, + "textContent": "\\n ", + "id": 11 }, { - \\"type\\": 2, - \\"tagName\\": \\"title\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "title", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"attributes mask\\", - \\"id\\": 13 + "type": 3, + "textContent": "********** ****", + "id": 13 } ], - \\"id\\": 12 + "id": 12 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 14 + "type": 3, + "textContent": "\\n ", + "id": 14 } ], - \\"id\\": 4 + "id": 4 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 15 + "type": 3, + "textContent": "\\n\\n ", + "id": 15 }, { - \\"type\\": 2, - \\"tagName\\": \\"body\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 17 + "type": 3, + "textContent": "\\n ", + "id": 17 }, { - \\"type\\": 2, - \\"tagName\\": \\"form\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "form", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 19 + "type": 3, + "textContent": "\\n ", + "id": 19 }, { - \\"type\\": 2, - \\"tagName\\": \\"div\\", - \\"attributes\\": { - \\"title\\": \\"Test title\\", - \\"aria-label\\": \\"Test aria label\\", - \\"class\\": \\"rr-unmask\\" + "type": 2, + "tagName": "div", + "attributes": { + "title": "Test title", + "aria-label": "Test aria label", + "class": "rr-unmask" }, - \\"childNodes\\": [ + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n Test content\\\\n \\", - \\"id\\": 21 + "type": 3, + "textContent": "\\n Test content\\n ", + "id": 21 } ], - \\"id\\": 20 + "id": 20 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 22 + "type": 3, + "textContent": "\\n\\n ", + "id": 22 }, { - \\"type\\": 2, - \\"tagName\\": \\"div\\", - \\"attributes\\": { - \\"title\\": \\"Test title 2\\", - \\"aria-label\\": \\"Test aria label 2\\" + "type": 2, + "tagName": "div", + "attributes": { + "title": "**** ***** *", + "aria-label": "**** **** ***** *" }, - \\"childNodes\\": [ + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n Test content 2\\\\n \\", - \\"id\\": 24 + "type": 3, + "textContent": "\\n **** ******* *\\n ", + "id": 24 } ], - \\"id\\": 23 + "id": 23 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 25 + "type": 3, + "textContent": "\\n\\n ", + "id": 25 }, { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"text\\", - \\"placeholder\\": \\"Test placeholder 1\\", - \\"class\\": \\"rr-unmask\\" + "type": 2, + "tagName": "input", + "attributes": { + "type": "text", + "placeholder": "Test placeholder 1", + "class": "rr-unmask" }, - \\"childNodes\\": [], - \\"id\\": 26 + "childNodes": [], + "id": 26 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 27 + "type": 3, + "textContent": "\\n ", + "id": 27 }, { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"text\\", - \\"placeholder\\": \\"Test placeholder 2\\", - \\"class\\": \\"\\" + "type": 2, + "tagName": "input", + "attributes": { + "type": "text", + "placeholder": "**** *********** *", + "class": "" }, - \\"childNodes\\": [], - \\"id\\": 28 + "childNodes": [], + "id": 28 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 29 + "type": 3, + "textContent": "\\n\\n ", + "id": 29 }, { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"submit\\", - \\"value\\": \\"Submit button 1\\", - \\"class\\": \\"rr-unmask\\" + "type": 2, + "tagName": "input", + "attributes": { + "type": "submit", + "value": "Submit button 1", + "class": "rr-unmask" }, - \\"childNodes\\": [], - \\"id\\": 30 + "childNodes": [], + "id": 30 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 31 + "type": 3, + "textContent": "\\n ", + "id": 31 }, { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"submit\\", - \\"value\\": \\"Submit button 2\\", - \\"class\\": \\"\\" + "type": 2, + "tagName": "input", + "attributes": { + "type": "submit", + "value": "****** ****** *", + "class": "" }, - \\"childNodes\\": [], - \\"id\\": 32 + "childNodes": [], + "id": 32 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 33 + "type": 3, + "textContent": "\\n\\n ", + "id": 33 }, { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"button\\", - \\"value\\": \\"Button 1\\", - \\"class\\": \\"\\" + "type": 2, + "tagName": "input", + "attributes": { + "type": "button", + "value": "****** *", + "class": "" }, - \\"childNodes\\": [], - \\"id\\": 34 + "childNodes": [], + "id": 34 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 35 + "type": 3, + "textContent": "\\n ", + "id": 35 } ], - \\"id\\": 18 + "id": 18 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 36 + "type": 3, + "textContent": "\\n \\n ", + "id": 36 }, { - \\"type\\": 2, - \\"tagName\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "script", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 38 + "type": 3, + "textContent": "SCRIPT_PLACEHOLDER", + "id": 38 } ], - \\"id\\": 37 + "id": 37 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 39 + "type": 3, + "textContent": "\\n \\n \\n\\n", + "id": 39 } ], - \\"id\\": 16 + "id": 16 } ], - \\"id\\": 3 + "id": 3 } ], - \\"id\\": 1 + "id": 1 }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 + "initialOffset": { + "left": 0, + "top": 0 } } }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 0, - \\"texts\\": [], - \\"attributes\\": [ + "type": 3, + "data": { + "source": 0, + "texts": [], + "attributes": [ { - \\"id\\": 20, - \\"attributes\\": { - \\"title\\": \\"new title\\", - \\"aria-label\\": \\"new aria label\\" + "id": 20, + "attributes": { + "title": "new title", + "aria-label": "new aria label" } }, { - \\"id\\": 23, - \\"attributes\\": { - \\"title\\": \\"new title\\", - \\"aria-label\\": \\"new aria label\\" + "id": 23, + "attributes": { + "title": "*** *****", + "aria-label": "*** **** *****" } }, { - \\"id\\": 26, - \\"attributes\\": { - \\"placeholder\\": \\"new placeholder\\" + "id": 26, + "attributes": { + "placeholder": "new placeholder" } }, { - \\"id\\": 28, - \\"attributes\\": { - \\"placeholder\\": \\"new placeholder\\" + "id": 28, + "attributes": { + "placeholder": "*** ***********" } }, { - \\"id\\": 30, - \\"attributes\\": { - \\"value\\": \\"new value\\" + "id": 30, + "attributes": { + "value": "new value" } }, { - \\"id\\": 32, - \\"attributes\\": { - \\"value\\": \\"new value\\" + "id": 32, + "attributes": { + "value": "new value" } }, { - \\"id\\": 34, - \\"attributes\\": { - \\"value\\": \\"new value\\" + "id": 34, + "attributes": { + "value": "new value" } } ], - \\"removes\\": [], - \\"adds\\": [] + "removes": [], + "adds": [] } } ]" @@ -45302,7 +45302,7 @@ exports[`record integration tests should mask all text (except unmaskTextSelecto \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"mask10\\", + \\"textContent\\": \\"\\", \\"id\\": 50 } ], @@ -45687,7 +45687,7 @@ exports[`record integration tests should mask only inputs 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"mask10\\", + \\"textContent\\": \\"\\", \\"id\\": 50 } ], @@ -46341,7 +46341,7 @@ exports[`record integration tests should mask text in form elements 1`] = ` \\"tagName\\": \\"input\\", \\"attributes\\": { \\"type\\": \\"submit\\", - \\"value\\": \\"Submit form\\" + \\"value\\": \\"****** ****\\" }, \\"childNodes\\": [], \\"id\\": 87 @@ -47697,244 +47697,233 @@ exports[`record integration tests should not record input values on selectively ]" `; -exports[`record integration tests should not record textarea values if dynamically added and maskAllInputs is true 1`] = ` +exports[`record integration tests should not record input values if dynamically added and maskAllInputs is true 1`] = ` "[ { - \\"type\\": 0, - \\"data\\": {} + "type": 0, + "data": {} }, { - \\"type\\": 1, - \\"data\\": {} + "type": 1, + "data": {} }, { - \\"type\\": 4, - \\"data\\": { - \\"href\\": \\"about:blank\\", - \\"width\\": 1920, - \\"height\\": 1080 + "type": 4, + "data": { + "href": "about:blank", + "width": 1920, + "height": 1080 } }, { - \\"type\\": 2, - \\"data\\": { - \\"node\\": { - \\"type\\": 0, - \\"childNodes\\": [ + "type": 2, + "data": { + "node": { + "type": 0, + "childNodes": [ { - \\"type\\": 1, - \\"name\\": \\"html\\", - \\"publicId\\": \\"\\", - \\"systemId\\": \\"\\", - \\"id\\": 2 + "type": 1, + "name": "html", + "publicId": "", + "systemId": "", + "id": 2 }, { - \\"type\\": 2, - \\"tagName\\": \\"html\\", - \\"attributes\\": { - \\"lang\\": \\"en\\" + "type": 2, + "tagName": "html", + "attributes": { + "lang": "en" }, - \\"childNodes\\": [ + "childNodes": [ { - \\"type\\": 2, - \\"tagName\\": \\"head\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "head", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 5 + "type": 3, + "textContent": "\\n ", + "id": 5 }, { - \\"type\\": 2, - \\"tagName\\": \\"meta\\", - \\"attributes\\": { - \\"charset\\": \\"UTF-8\\" + "type": 2, + "tagName": "meta", + "attributes": { + "charset": "UTF-8" }, - \\"childNodes\\": [], - \\"id\\": 6 + "childNodes": [], + "id": 6 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 7 + "type": 3, + "textContent": "\\n ", + "id": 7 }, { - \\"type\\": 2, - \\"tagName\\": \\"meta\\", - \\"attributes\\": { - \\"name\\": \\"viewport\\", - \\"content\\": \\"width=device-width, initial-scale=1.0\\" + "type": 2, + "tagName": "meta", + "attributes": { + "name": "viewport", + "content": "width=device-width, initial-scale=1.0" }, - \\"childNodes\\": [], - \\"id\\": 8 + "childNodes": [], + "id": 8 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 9 + "type": 3, + "textContent": "\\n ", + "id": 9 }, { - \\"type\\": 2, - \\"tagName\\": \\"title\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "title", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"Empty\\", - \\"id\\": 11 + "type": 3, + "textContent": "Empty", + "id": 11 } ], - \\"id\\": 10 + "id": 10 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 12 + "type": 3, + "textContent": "\\n ", + "id": 12 } ], - \\"id\\": 4 + "id": 4 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 13 + "type": 3, + "textContent": "\\n ", + "id": 13 }, { - \\"type\\": 2, - \\"tagName\\": \\"body\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "body", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 15 + "type": 3, + "textContent": "\\n ", + "id": 15 }, { - \\"type\\": 2, - \\"tagName\\": \\"div\\", - \\"attributes\\": { - \\"id\\": \\"one\\" + "type": 2, + "tagName": "div", + "attributes": { + "id": "one" }, - \\"childNodes\\": [], - \\"id\\": 16 + "childNodes": [], + "id": 16 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 17 + "type": 3, + "textContent": "\\n \\n ", + "id": 17 }, { - \\"type\\": 2, - \\"tagName\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ + "type": 2, + "tagName": "script", + "attributes": {}, + "childNodes": [ { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 19 + "type": 3, + "textContent": "SCRIPT_PLACEHOLDER", + "id": 19 } ], - \\"id\\": 18 + "id": 18 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 20 + "type": 3, + "textContent": "\\n \\n \\n\\n", + "id": 20 } ], - \\"id\\": 14 + "id": 14 } ], - \\"id\\": 3 + "id": 3 } ], - \\"id\\": 1 + "id": 1 }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 + "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\\": \\"*************************\\" + "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 - } - }, - { - \\"parentId\\": 21, - \\"nextId\\": null, - \\"node\\": { - \\"type\\": 2, - \\"tagName\\": \\"br\\", - \\"attributes\\": {}, - \\"childNodes\\": [], - \\"id\\": 22 - } - }, - { - \\"parentId\\": 21, - \\"nextId\\": 22, - \\"node\\": { - \\"type\\": 3, - \\"textContent\\": \\"textarea should be masked\\", - \\"id\\": 23 + "childNodes": [], + "id": 21 } } ] } }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 21 + "type": 3, + "data": { + "source": 5, + "text": "**********************", + "isChecked": false, + "id": 21 } }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"**************************\\", - \\"isChecked\\": false, - \\"id\\": 21 + "type": 3, + "data": { + "source": 2, + "type": 5, + "id": 21 } }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"***************************\\", - \\"isChecked\\": false, - \\"id\\": 21 + "type": 3, + "data": { + "source": 5, + "text": "***********************", + "isChecked": false, + "id": 21 } }, { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 5, - \\"text\\": \\"****************************\\", - \\"isChecked\\": false, - \\"id\\": 21 + "type": 3, + "data": { + "source": 5, + "text": "************************", + "isChecked": false, + "id": 21 + } + }, + { + "type": 3, + "data": { + "source": 5, + "text": "*************************", + "isChecked": false, + "id": 21 } } ]" diff --git a/packages/rrweb/test/__snapshots__/integration.test.ts.snap b/packages/rrweb/test/__snapshots__/integration.test.ts.snap index 5cb7d1b66e..8190a5fb5d 100644 --- a/packages/rrweb/test/__snapshots__/integration.test.ts.snap +++ b/packages/rrweb/test/__snapshots__/integration.test.ts.snap @@ -5905,7 +5905,7 @@ exports[`record integration tests handles null attribute values 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"mutation observer\\", + \\"textContent\\": \\"******** ********\\", \\"id\\": 8 } ], @@ -6000,7 +6000,7 @@ exports[`record integration tests handles null attribute values 1`] = ` { \\"id\\": 20, \\"attributes\\": { - \\"aria-label\\": \\"label\\", + \\"aria-label\\": \\"*****\\", \\"id\\": \\"test-li\\" } } @@ -6014,7 +6014,7 @@ exports[`record integration tests handles null attribute values 1`] = ` \\"type\\": 2, \\"tagName\\": \\"li\\", \\"attributes\\": { - \\"aria-label\\": \\"label\\", + \\"aria-label\\": \\"*****\\", \\"id\\": \\"test-li\\" }, \\"childNodes\\": [], @@ -9205,7 +9205,7 @@ exports[`record integration tests should mask texts using maskTextFn 1`] = ` \\"childNodes\\": [ { \\"type\\": 3, - \\"textContent\\": \\"mask10\\", + \\"textContent\\": \\"\\", \\"id\\": 50 } ], From f286fb5fd1ef9280dd04f614acfe37093e27d72e Mon Sep 17 00:00:00 2001 From: billyvg Date: Fri, 7 Jul 2023 21:23:49 +0000 Subject: [PATCH 20/20] Apply formatting changes --- packages/rrweb/test/integration-sentry.test.ts | 2 +- packages/types/src/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rrweb/test/integration-sentry.test.ts b/packages/rrweb/test/integration-sentry.test.ts index b3283a26f1..982aa9726c 100644 --- a/packages/rrweb/test/integration-sentry.test.ts +++ b/packages/rrweb/test/integration-sentry.test.ts @@ -316,7 +316,7 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent( getHtml.call(this, 'form.html', { - maskAllText: true + maskAllText: true, }), ); diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 7f3ac1e5bb..fe4e770ddd 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -269,7 +269,7 @@ export type hooksParam = { canvasMutation?: canvasMutationCallback; font?: fontCallback; selection?: selectionCallback; - customElement?: customElementCallback; + customElement?: customElementCallback; }; // https://dom.spec.whatwg.org/#interface-mutationrecord