From e9e75cea94d15cf8035956635d52c2a5a5a2231c Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 13:24:59 +0100 Subject: [PATCH 1/3] add ability to mask passwords --- guide.md | 37 +- guide.zh_CN.md | 39 +- src/record/index.ts | 3 +- src/record/observer.ts | 5 +- test/__snapshots__/integration.test.ts.snap | 735 +++++++++----------- test/html/form.html | 3 + test/html/ignore.html | 1 - test/integration.test.ts | 4 +- 8 files changed, 370 insertions(+), 457 deletions(-) diff --git a/guide.md b/guide.md index 81ffd52e87..90a1d84d1d 100644 --- a/guide.md +++ b/guide.md @@ -135,22 +135,25 @@ setInterval(save, 10 * 1000); The parameter of `rrweb.record` accepts the following options. -| key | default | description | -| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| emit | required | the callback function to get emitted events | -| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | -| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | -| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | -| maskAllInputs | false | mask all input content as \* | -| maskInputOptions | {} | mask some kinds of input \*
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | -| inlineStylesheet | true | whether to inline the stylesheet in the events | -| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | -| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | -| recordCanvas | false | whether to record the canvas element | -| collectFonts | false | whether to collect fonts in the website | -| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | +| key | default | description | +| ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| emit | required | the callback function to get emitted events | +| checkoutEveryNth | - | take a full snapshot after every N events
refer to the [checkout](#checkout) chapter | +| checkoutEveryNms | - | take a full snapshot after every N ms
refer to the [checkout](#checkout) chapter | +| blockClass | 'rr-block' | Use a string or RegExp to configure which elements 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 | +| blockSelector | null | Use a string or RegExp to configure which selector should be blocked, 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-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | +| maskInputFn | - | customize mask input content recording logic | +| slimDOMOptions | {} | remove unnecessary parts of the DOM
refer to the [list](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | +| inlineStylesheet | true | whether to inline the stylesheet in the events | +| hooks | {} | hooks for events
refer to the [list](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | +| packFn | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| sampling | - | refer to the [storage optimization recipe](./docs/recipes/optimize-storage.md) | +| recordCanvas | false | whether to record the canvas element | +| collectFonts | false | whether to collect fonts in the website | +| recordLog | false | whether to record console output, refer to the [console recipe](./docs/recipes/console.md) | #### Privacy @@ -158,8 +161,8 @@ 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. -- `input[type="password"]` will be ignored as default. - Mask options to mask the content in input elements. +- `input[type="password"]` will be masked as default. #### Checkout diff --git a/guide.zh_CN.md b/guide.zh_CN.md index 893c2789cd..967d2ab230 100644 --- a/guide.zh_CN.md +++ b/guide.zh_CN.md @@ -131,22 +131,25 @@ setInterval(save, 10 * 1000); `rrweb.record(config)` 的 config 部分接受以下参数 -| key | 默认值 | 功能 | -| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| emit | 必填 | 获取当前录制的数据 | -| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | -| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | -| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 | -| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 | -| maskAllInputs | false | 将所有输入内容记录为 \* | -| maskInputOptions | {} | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | -| inlineStylesheet | true | 是否将样式表内联 | -| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | -| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | -| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | -| recordCanvas | false | 是否记录 canvas 内容 | -| collectFonts | false | 是否记录页面中的字体文件 | -| recordLog | false | 是否记录console 输出,详见[console录制和播放](./docs/recipes/console.zh_CN.md) | +| key | 默认值 | 功能 | +| ---------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| emit | 必填 | 获取当前录制的数据 | +| checkoutEveryNth | - | 每 N 次事件重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | +| checkoutEveryNms | - | 每 N 毫秒重新制作一次全量快照
详见[“重新制作快照”](#重新制作快照)章节 | +| blockClass | 'rr-block' | 字符串或正则表达式,可用于自定义屏蔽元素的类名,详见[“隐私”](#隐私)章节 | +| blockSelector | null | 字符串或正则表达式,可用于自定义屏蔽元素的选择器,详见[“隐私”](#隐私)章节 | +| ignoreClass | 'rr-ignore' | 字符串或正则表达式,可用于自定义忽略元素的类名,详见[“隐私”](#隐私)章节 | +| maskAllInputs | false | 将所有输入内容记录为 \* | +| maskInputOptions | { password: true } | 选择将特定类型的输入框内容记录为 \*
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L72) | +| maskInputFn | - | 自定义特定类型的输入框内容记录逻辑 | +| slimDOMOptions | {} | 去除 DOM 中不必要的部分
类型详见[列表](https://github.com/rrweb-io/rrweb-snapshot/blob/6728d12b3cddd96951c86d948578f99ada5749ff/src/types.ts#L91) | +| inlineStylesheet | true | 是否将样式表内联 | +| hooks | {} | 各类事件的回调
类型详见[列表](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L207) | +| packFn | - | 数据压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | +| sampling | - | 数据抽样策略,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | +| recordCanvas | false | 是否记录 canvas 内容 | +| collectFonts | false | 是否记录页面中的字体文件 | +| recordLog | false | 是否记录 console 输出,详见[console 录制和播放](./docs/recipes/console.zh_CN.md) | #### 隐私 @@ -154,8 +157,8 @@ setInterval(save, 10 * 1000); - 在 HTML 元素中添加类名 `.rr-block` 将会避免该元素及其子元素被录制,回放时取而代之的是一个同等宽高的占位元素。 - 在 HTML 元素中添加类名 `.rr-ignore` 将会避免录制该元素的输入事件。 -- `input[type="password"]` 类型的密码输入框默认不会录制输入事件。 - 配置中还有更为丰富的隐私保护选项。 +- `input[type="password"]` 类型的密码输入框默认不会录制输入事件。 #### 重新制作快照 @@ -288,7 +291,7 @@ replayer.pause(5000); | UNSAFE_replayCanvas | false | 回放时是否回放 canvas 内容,**开启后将会关闭沙盒策略,导致一定风险** | | mouseTail | true | 是否在回放时增加鼠标轨迹。传入 false 可关闭,传入对象可以定制轨迹持续时间、样式等,配置详见[类型](https://github.com/rrweb-io/rrweb/blob/9488deb6d54a5f04350c063d942da5e96ab74075/src/types.ts#L407) | | unpackFn | - | 数据解压缩函数,详见[优化存储策略](./docs/recipes/optimize-storage.zh_CN.md) | -| logConfig | - | console logger数据播放设置,详见[console录制和播放](./docs/recipes/console.zh_CN.md) | +| logConfig | - | console logger 数据播放设置,详见[console 录制和播放](./docs/recipes/console.zh_CN.md) | #### 使用 rrweb-player diff --git a/src/record/index.ts b/src/record/index.ts index fdaad963f7..30aed33af5 100644 --- a/src/record/index.ts +++ b/src/record/index.ts @@ -76,10 +76,11 @@ function record( week: true, textarea: true, select: true, + password: true, } : _maskInputOptions !== undefined ? _maskInputOptions - : {}; + : { password: true }; const slimDOMOptions: SlimDOMOptions = _slimDOMOptions === true || _slimDOMOptions === 'all' diff --git a/src/record/observer.ts b/src/record/observer.ts index 895ca39d67..55b559c7aa 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -253,10 +253,7 @@ function initInputObserver( return; } const type: string | undefined = (target as HTMLInputElement).type; - if ( - type === 'password' || - (target as HTMLElement).classList.contains(ignoreClass) - ) { + if ((target as HTMLElement).classList.contains(ignoreClass)) { return; } let text = (target as HTMLInputElement).value; diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index 19f34fb608..4e87e9964b 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -1229,8 +1229,42 @@ exports[`form 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -1238,7 +1272,7 @@ exports[`form 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -1248,15 +1282,15 @@ exports[`form 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -1869,7 +1903,7 @@ exports[`ignore 1`] = ` \\"type\\": 2, \\"tagName\\": \\"label\\", \\"attributes\\": { - \\"for\\": \\"password\\" + \\"for\\": \\"ignore text\\" }, \\"childNodes\\": [ { @@ -1881,7 +1915,8 @@ exports[`ignore 1`] = ` \\"type\\": 2, \\"tagName\\": \\"input\\", \\"attributes\\": { - \\"type\\": \\"password\\" + \\"type\\": \\"text\\", + \\"class\\": \\"rr-ignore\\" }, \\"childNodes\\": [], \\"id\\": 22 @@ -1894,45 +1929,10 @@ exports[`ignore 1`] = ` ], \\"id\\": 20 }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", - \\"id\\": 24 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"label\\", - \\"attributes\\": { - \\"for\\": \\"ignore text\\" - }, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\" \\", - \\"id\\": 26 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"input\\", - \\"attributes\\": { - \\"type\\": \\"text\\", - \\"class\\": \\"rr-ignore\\" - }, - \\"childNodes\\": [], - \\"id\\": 27 - }, - { - \\"type\\": 3, - \\"textContent\\": \\" \\", - \\"id\\": 28 - } - ], - \\"id\\": 25 - }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\", - \\"id\\": 29 + \\"id\\": 24 } ], \\"id\\": 18 @@ -1940,195 +1940,7 @@ exports[`ignore 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\", - \\"id\\": 30 - }, - { - \\"type\\": 2, - \\"tagName\\": \\"script\\", - \\"attributes\\": {}, - \\"childNodes\\": [ - { - \\"type\\": 3, - \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 32 - } - ], - \\"id\\": 31 - }, - { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 33 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 6, - \\"id\\": 22 - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 2, - \\"type\\": 5, - \\"id\\": 27 - } - } -]" -`; - -exports[`log`] = ` -"[ - { - \\"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\\": \\"Log record\\", - \\"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 + \\"id\\": 25 }, { \\"type\\": 2, @@ -2138,188 +1950,37 @@ exports[`log`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 19 + \\"id\\": 27 } ], - \\"id\\": 18 + \\"id\\": 26 }, { - \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 20 - } - ], - \\"id\\": 16 - } - ], - \\"id\\": 3 - } - ], - \\"id\\": 1 - }, - \\"initialOffset\\": { - \\"left\\": 0, - \\"top\\": 0 - } - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"assert\\", - \\"payload\\": [ - \\"true\\", - \\"\\"assert\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"count\\", - \\"payload\\": [ - \\"\\"count\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"countReset\\", - \\"payload\\": [ - \\"\\"count\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"debug\\", - \\"payload\\": [ - \\"\\"debug\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dir\\", - \\"payload\\": [ - \\"\\"dir\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"dirxml\\", - \\"payload\\": [ - \\"\\"dirxml\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"group\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"groupCollapsed\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"info\\", - \\"payload\\": [ - \\"\\"info\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"log\\", - \\"payload\\": [ - \\"\\"log\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"table\\", - \\"payload\\": [ - \\"\\"table\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"time\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeEnd\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"timeLog\\", - \\"payload\\": [] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"trace\\", - \\"payload\\": [ - \\"\\"trace\\"\\" - ] - } - }, - { - \\"type\\": 3, - \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"warn\\", - \\"payload\\": [ - \\"\\"warn\\"\\" - ] + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", + \\"id\\": 28 + } + ], + \\"id\\": 16 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } } }, { \\"type\\": 3, \\"data\\": { - \\"source\\": 11, - \\"level\\": \\"clear\\", - \\"payload\\": [] + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 22 } } ]" @@ -3073,8 +2734,42 @@ exports[`mask 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -3082,7 +2777,7 @@ exports[`mask 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -3092,15 +2787,15 @@ exports[`mask 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -3267,6 +2962,94 @@ exports[`mask 1`] = ` \\"id\\": 32 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"********\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 54 + } + }, { \\"type\\": 3, \\"data\\": { @@ -3761,8 +3544,42 @@ exports[`maskInputOptions 1`] = ` }, { \\"type\\": 3, - \\"textContent\\": \\"\\\\n \\", + \\"textContent\\": \\"\\\\n \\", \\"id\\": 51 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 53 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 54 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 55 + } + ], + \\"id\\": 52 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 56 } ], \\"id\\": 18 @@ -3770,7 +3587,7 @@ exports[`maskInputOptions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"\\\\n\\\\n \\", - \\"id\\": 52 + \\"id\\": 57 }, { \\"type\\": 2, @@ -3780,15 +3597,15 @@ exports[`maskInputOptions 1`] = ` { \\"type\\": 3, \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", - \\"id\\": 54 + \\"id\\": 59 } ], - \\"id\\": 53 + \\"id\\": 58 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\\\n\\", - \\"id\\": 55 + \\"id\\": 60 } ], \\"id\\": 16 @@ -4080,6 +3897,94 @@ exports[`maskInputOptions 1`] = ` \\"id\\": 37 } }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 37 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"**\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"***\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*****\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"*******\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 5, + \\"text\\": \\"********\\", + \\"isChecked\\": false, + \\"id\\": 54 + } + }, { \\"type\\": 3, \\"data\\": { diff --git a/test/html/form.html b/test/html/form.html index 14120fd30e..9d4a0c7116 100644 --- a/test/html/form.html +++ b/test/html/form.html @@ -28,6 +28,9 @@ + diff --git a/test/html/ignore.html b/test/html/ignore.html index 91e0652d9e..f46c2efd00 100644 --- a/test/html/ignore.html +++ b/test/html/ignore.html @@ -9,7 +9,6 @@
-
diff --git a/test/integration.test.ts b/test/integration.test.ts index 767dc413c0..61ef26ca1c 100644 --- a/test/integration.test.ts +++ b/test/integration.test.ts @@ -171,7 +171,6 @@ describe('record integration tests', function (this: ISuite) { await page.goto('about:blank'); await page.setContent(getHtml.call(this, 'ignore.html')); - await page.type('input[type="password"]', 'password'); await page.type('.rr-ignore', 'secret'); const snapshots = await page.evaluate('window.snapshots'); @@ -188,6 +187,7 @@ describe('record integration tests', function (this: ISuite) { 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'); @@ -203,6 +203,7 @@ describe('record integration tests', function (this: ISuite) { maskInputOptions: { text: false, textarea: false, + password: true, }, }), ); @@ -211,6 +212,7 @@ describe('record integration tests', function (this: ISuite) { 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'); From cd159568f5bfa293c802f48ca8f6f652e47c5d63 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 15:06:58 +0100 Subject: [PATCH 2/3] add `userTriggered` --- src/record/observer.ts | 4 +++- src/types.ts | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/record/observer.ts b/src/record/observer.ts index 55b559c7aa..83a1e1aaa1 100644 --- a/src/record/observer.ts +++ b/src/record/observer.ts @@ -244,6 +244,7 @@ function initInputObserver( ): listenerHandler { function eventHandler(event: Event) { const { target } = event; + const userTriggered = event.isTrusted; if ( !target || !(target as Element).tagName || @@ -272,7 +273,7 @@ function initInputObserver( text = '*'.repeat(text.length); } } - cbWithDedup(target, { text, isChecked }); + cbWithDedup(target, { text, isChecked, userTriggered }); // if a radio was checked // the other radios with the same name attribute will be unchecked. const name: string | undefined = (target as HTMLInputElement).name; @@ -284,6 +285,7 @@ function initInputObserver( cbWithDedup(el, { text: (el as HTMLInputElement).value, isChecked: !isChecked, + userTriggered: false, }); } }); diff --git a/src/types.ts b/src/types.ts index 02f5ce1c0d..dcc1a4f7fe 100644 --- a/src/types.ts +++ b/src/types.ts @@ -440,6 +440,12 @@ export type viewportResizeCallback = (d: viewportResizeDimention) => void; export type inputValue = { text: string; isChecked: boolean; + + // `userTriggered` indicates if this event was triggered directly by user (userTriggered: true) + // or was triggered indirectly (userTriggered: false) + // Example of `userTriggered` in action: + // User clicks on radio element (userTriggered: true) which triggers the other radio element to change (userTriggered: false) + userTriggered: boolean; }; export type inputCallback = (v: inputValue & { id: number }) => void; From 13f9fda7bf60a3ae039447893d8b8d2c5354ec48 Mon Sep 17 00:00:00 2001 From: Justin Halsall Date: Thu, 18 Feb 2021 15:11:50 +0100 Subject: [PATCH 3/3] update snapshots to add userTriggered --- test/__snapshots__/integration.test.ts.snap | 787 +++++++++++++++++++- 1 file changed, 785 insertions(+), 2 deletions(-) diff --git a/test/__snapshots__/integration.test.ts.snap b/test/__snapshots__/integration.test.ts.snap index 4e87e9964b..665eabf84d 100644 --- a/test/__snapshots__/integration.test.ts.snap +++ b/test/__snapshots__/integration.test.ts.snap @@ -1321,6 +1321,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1330,6 +1331,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1339,6 +1341,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1348,6 +1351,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -1397,6 +1401,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -1446,6 +1451,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -1471,6 +1477,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1480,6 +1487,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1489,6 +1497,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1498,6 +1507,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1507,6 +1517,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1516,6 +1527,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1525,6 +1537,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1534,6 +1547,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1543,6 +1557,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1552,6 +1567,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1561,6 +1577,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1570,6 +1587,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1579,6 +1597,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -1588,6 +1607,7 @@ exports[`form 1`] = ` \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } } @@ -1953,12 +1973,719 @@ exports[`ignore 1`] = ` \\"id\\": 27 } ], - \\"id\\": 26 + \\"id\\": 28 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n\\", + \\"id\\": 30 + } + ], + \\"id\\": 17 + } + ], + \\"id\\": 3 + } + ], + \\"id\\": 1 + }, + \\"initialOffset\\": { + \\"left\\": 0, + \\"top\\": 0 + } + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 17, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"iframe\\", + \\"attributes\\": { + \\"id\\": \\"two\\" + }, + \\"childNodes\\": [], + \\"id\\": 31 + } + } + ] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"adds\\": [ + { + \\"parentId\\": 47, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"rootId\\": 48, + \\"id\\": 50 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"rootId\\": 48, + \\"id\\": 51 + } + ], + \\"rootId\\": 48, + \\"id\\": 49 + } + ], + \\"id\\": 48 + } + } + ], + \\"removes\\": [], + \\"texts\\": [], + \\"attributes\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"adds\\": [ + { + \\"parentId\\": 53, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"rootId\\": 54, + \\"id\\": 55 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 54, + \\"id\\": 58 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 54, + \\"id\\": 59 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 54, + \\"id\\": 60 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 54, + \\"id\\": 61 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 54, + \\"id\\": 62 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Frame 2\\", + \\"rootId\\": 54, + \\"id\\": 64 + } + ], + \\"rootId\\": 54, + \\"id\\": 63 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 54, + \\"id\\": 65 + } + ], + \\"rootId\\": 54, + \\"id\\": 57 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 54, + \\"id\\": 66 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n frame 2\\\\n \\\\n \\", + \\"rootId\\": 54, + \\"id\\": 68 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"rootId\\": 54, + \\"id\\": 70 + } + ], + \\"rootId\\": 54, + \\"id\\": 69 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n\\\\n\\", + \\"rootId\\": 54, + \\"id\\": 71 + } + ], + \\"rootId\\": 54, + \\"id\\": 67 + } + ], + \\"rootId\\": 54, + \\"id\\": 56 + } + ], + \\"id\\": 54 + } + } + ], + \\"removes\\": [], + \\"texts\\": [], + \\"attributes\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"adds\\": [ + { + \\"parentId\\": 31, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 1, + \\"name\\": \\"html\\", + \\"publicId\\": \\"\\", + \\"systemId\\": \\"\\", + \\"rootId\\": 32, + \\"id\\": 33 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": { + \\"lang\\": \\"en\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 36 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"charset\\": \\"UTF-8\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 32, + \\"id\\": 37 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 38 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"meta\\", + \\"attributes\\": { + \\"name\\": \\"viewport\\", + \\"content\\": \\"width=device-width, initial-scale=1.0\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 32, + \\"id\\": 39 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 40 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"title\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"Frame 1\\", + \\"rootId\\": 32, + \\"id\\": 42 + } + ], + \\"rootId\\": 32, + \\"id\\": 41 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 43 + } + ], + \\"rootId\\": 32, + \\"id\\": 35 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 44 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n frame 1\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 46 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"iframe\\", + \\"attributes\\": { + \\"id\\": \\"three\\", + \\"frameborder\\": \\"0\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 32, + \\"id\\": 47 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"rootId\\": 32, + \\"id\\": 52 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"iframe\\", + \\"attributes\\": { + \\"id\\": \\"four\\", + \\"frameborder\\": \\"0\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 32, + \\"id\\": 53 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n\\\\n\\", + \\"rootId\\": 32, + \\"id\\": 72 + } + ], + \\"rootId\\": 32, + \\"id\\": 45 + } + ], + \\"rootId\\": 32, + \\"id\\": 34 + } + ], + \\"id\\": 32 + } + } + ], + \\"removes\\": [], + \\"texts\\": [], + \\"attributes\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"adds\\": [ + { + \\"parentId\\": 73, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 0, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"html\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 2, + \\"tagName\\": \\"head\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"rootId\\": 74, + \\"id\\": 76 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"body\\", + \\"attributes\\": {}, + \\"childNodes\\": [], + \\"rootId\\": 74, + \\"id\\": 77 + } + ], + \\"rootId\\": 74, + \\"id\\": 75 + } + ], + \\"id\\": 74 + } + } + ], + \\"removes\\": [], + \\"texts\\": [], + \\"attributes\\": [] + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 0, + \\"texts\\": [], + \\"attributes\\": [], + \\"removes\\": [], + \\"adds\\": [ + { + \\"parentId\\": 67, + \\"nextId\\": null, + \\"node\\": { + \\"type\\": 2, + \\"tagName\\": \\"iframe\\", + \\"attributes\\": { + \\"id\\": \\"five\\" + }, + \\"childNodes\\": [], + \\"rootId\\": 54, + \\"id\\": 73 + } + } + ] + } + } +]" +`; + +exports[`ignore 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\\": \\"ignore 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\\": \\"password\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\" \\", + \\"id\\": 21 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"password\\" + }, + \\"childNodes\\": [], + \\"id\\": 22 + }, + { + \\"type\\": 3, + \\"textContent\\": \\" \\", + \\"id\\": 23 + } + ], + \\"id\\": 20 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 24 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"label\\", + \\"attributes\\": { + \\"for\\": \\"ignore text\\" + }, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\" \\", + \\"id\\": 26 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"input\\", + \\"attributes\\": { + \\"type\\": \\"text\\", + \\"class\\": \\"rr-ignore\\" + }, + \\"childNodes\\": [], + \\"id\\": 27 + }, + { + \\"type\\": 3, + \\"textContent\\": \\" \\", + \\"id\\": 28 + } + ], + \\"id\\": 25 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\", + \\"id\\": 29 + } + ], + \\"id\\": 18 + }, + { + \\"type\\": 3, + \\"textContent\\": \\"\\\\n \\\\n \\", + \\"id\\": 30 + }, + { + \\"type\\": 2, + \\"tagName\\": \\"script\\", + \\"attributes\\": {}, + \\"childNodes\\": [ + { + \\"type\\": 3, + \\"textContent\\": \\"SCRIPT_PLACEHOLDER\\", + \\"id\\": 32 + } + ], + \\"id\\": 31 }, { \\"type\\": 3, \\"textContent\\": \\"\\\\n \\\\n \\\\n\\\\n\\", - \\"id\\": 28 + \\"id\\": 33 } ], \\"id\\": 16 @@ -1982,6 +2709,22 @@ exports[`ignore 1`] = ` \\"type\\": 5, \\"id\\": 22 } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 6, + \\"id\\": 22 + } + }, + { + \\"type\\": 3, + \\"data\\": { + \\"source\\": 2, + \\"type\\": 5, + \\"id\\": 27 + } } ]" `; @@ -2826,6 +3569,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -2835,6 +3579,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -2844,6 +3589,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -2853,6 +3599,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -2902,6 +3649,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -2951,6 +3699,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -3064,6 +3813,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3073,6 +3823,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3082,6 +3833,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3091,6 +3843,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3100,6 +3853,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*****\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3109,6 +3863,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3118,6 +3873,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*******\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3127,6 +3883,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3136,6 +3893,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3145,6 +3903,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"**********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3154,6 +3913,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"***********\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3163,6 +3923,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"************\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3172,6 +3933,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*************\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3181,6 +3943,7 @@ exports[`mask 1`] = ` \\"source\\": 5, \\"text\\": \\"*\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } } @@ -3636,6 +4399,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3645,6 +4409,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3654,6 +4419,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3663,6 +4429,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 22 } }, @@ -3712,6 +4479,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 27 } }, @@ -3761,6 +4529,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"on\\", \\"isChecked\\": true, + \\"userTriggered\\": true, \\"id\\": 32 } }, @@ -3786,6 +4555,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3795,6 +4565,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3804,6 +4575,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"tex\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3813,6 +4585,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"text\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3822,6 +4595,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"texta\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3831,6 +4605,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textar\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3840,6 +4615,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textare\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3849,6 +4625,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3858,6 +4635,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea \\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3867,6 +4645,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea t\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3876,6 +4655,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea te\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3885,6 +4665,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea tes\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3894,6 +4675,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"textarea test\\", \\"isChecked\\": false, + \\"userTriggered\\": true, \\"id\\": 37 } }, @@ -3991,6 +4773,7 @@ exports[`maskInputOptions 1`] = ` \\"source\\": 5, \\"text\\": \\"1\\", \\"isChecked\\": false, + \\"userTriggered\\": false, \\"id\\": 42 } }