11/// <reference lib="dom" />
22
3- import sinon from 'sinon'
4-
53import {
64 getSafeText ,
7- shouldCaptureDomEvent ,
8- shouldCaptureElement ,
5+ shouldAutocaptureEvent ,
96 isSensitiveElement ,
107 shouldCaptureValue ,
118 isAngularStyleAttr ,
@@ -14,6 +11,8 @@ import {
1411 getElementsChainString ,
1512 getClassNames ,
1613 makeSafeText ,
14+ isExplicitNoCapture ,
15+ isExplicitCapture ,
1716} from '../autocapture-utils'
1817import { document } from '../utils/globals'
1918import { makeMouseEvent } from './autocapture.test'
@@ -121,6 +120,30 @@ describe(`Autocapture utility functions`, () => {
121120 el . innerHTML = `Mixed "double" and 'single' quotes`
122121 expect ( getSafeText ( el ) ) . toBe ( `Mixed "double" and 'single' quotes` )
123122 } )
123+
124+ it ( `should collect text from sensitive elements with ph-include class` , ( ) => {
125+ const input = document ! . createElement ( `input` )
126+ input . className = `ph-include`
127+ input . appendChild ( document . createTextNode ( `Hello world` ) )
128+ document ! . body . appendChild ( input )
129+ expect ( getSafeText ( input ) ) . toBe ( `Hello world` )
130+ } )
131+
132+ it ( `shouldn't collect text from elements with ph-no-capture class` , ( ) => {
133+ const el = document ! . createElement ( `div` )
134+ el . className = `ph-no-capture`
135+ el . innerHTML = `Hello world`
136+ document ! . body . appendChild ( el )
137+ expect ( getSafeText ( el ) ) . toBe ( `` )
138+ } )
139+
140+ it ( `shouldn't collect text from elements with ph-sensitive class` , ( ) => {
141+ const el = document ! . createElement ( `div` )
142+ el . className = `ph-sensitive`
143+ el . innerHTML = `Hello world`
144+ document ! . body . appendChild ( el )
145+ expect ( getSafeText ( el ) ) . toBe ( `` )
146+ } )
124147 } )
125148
126149 describe ( `makeSafeText` , ( ) => {
@@ -175,22 +198,22 @@ describe(`Autocapture utility functions`, () => {
175198 describe ( `shouldCaptureDomEvent` , ( ) => {
176199 it ( `should capture "submit" events on <form> elements` , ( ) => {
177200 expect (
178- shouldCaptureDomEvent ( document ! . createElement ( `form` ) , {
201+ shouldAutocaptureEvent ( document ! . createElement ( `form` ) , {
179202 type : `submit` ,
180203 } as unknown as Event )
181204 ) . toBe ( true )
182205 } )
183206
184207 it . each ( [ `input` , `SELECT` , `textarea` ] ) ( `should capture "change" events on <%s> elements` , ( tagName ) => {
185208 expect (
186- shouldCaptureDomEvent ( document ! . createElement ( tagName ) , {
209+ shouldAutocaptureEvent ( document ! . createElement ( tagName ) , {
187210 type : `change` ,
188211 } as unknown as Event )
189212 ) . toBe ( true )
190213 } )
191214
192215 it . each ( [ `A` , `a` ] ) ( `should capture "click" events on <%s> elements` , ( tagName ) => {
193- expect ( shouldCaptureDomEvent ( document ! . createElement ( tagName ) , makeMouseEvent ( { } ) ) ) . toBe ( true )
216+ expect ( shouldAutocaptureEvent ( document ! . createElement ( tagName ) , makeMouseEvent ( { } ) ) ) . toBe ( true )
194217 } )
195218
196219 it ( `should capture "click" events on <button> elements` , ( ) => {
@@ -200,22 +223,22 @@ describe(`Autocapture utility functions`, () => {
200223 const button3 = document ! . createElement ( `input` )
201224 button3 . setAttribute ( `type` , `submit` )
202225 ; [ button1 , button2 , button3 ] . forEach ( ( button ) => {
203- expect ( shouldCaptureDomEvent ( button , makeMouseEvent ( { } ) ) ) . toBe ( true )
226+ expect ( shouldAutocaptureEvent ( button , makeMouseEvent ( { } ) ) ) . toBe ( true )
204227 } )
205228 } )
206229
207230 it ( `should protect against bad inputs` , ( ) => {
208- expect ( shouldCaptureDomEvent ( null as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
209- expect ( shouldCaptureDomEvent ( undefined as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
210- expect ( shouldCaptureDomEvent ( `div` as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
231+ expect ( shouldAutocaptureEvent ( null as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
232+ expect ( shouldAutocaptureEvent ( undefined as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
233+ expect ( shouldAutocaptureEvent ( `div` as unknown as Element , makeMouseEvent ( { } ) ) ) . toBe ( false )
211234 } )
212235
213236 it ( `should NOT capture "click" events on <form> elements` , ( ) => {
214- expect ( shouldCaptureDomEvent ( document ! . createElement ( `form` ) , makeMouseEvent ( { } ) ) ) . toBe ( false )
237+ expect ( shouldAutocaptureEvent ( document ! . createElement ( `form` ) , makeMouseEvent ( { } ) ) ) . toBe ( false )
215238 } )
216239
217240 it . each ( [ `html` , 'body' ] ) ( `should NOT capture "click" events on <%s> elements` , ( tagName ) => {
218- expect ( shouldCaptureDomEvent ( document ! . createElement ( tagName ) , makeMouseEvent ( { } ) ) ) . toBe ( false )
241+ expect ( shouldAutocaptureEvent ( document ! . createElement ( tagName ) , makeMouseEvent ( { } ) ) ) . toBe ( false )
219242 } )
220243
221244 describe ( 'css selector allowlist' , ( ) => {
@@ -317,7 +340,7 @@ describe(`Autocapture utility functions`, () => {
317340 ] ,
318341 ] ) ( 'correctly respects the allow list: %s' , ( _ , clickTarget , autoCaptureConfig , shouldCapture ) => {
319342 expect (
320- shouldCaptureDomEvent ( clickTarget , makeMouseEvent ( { } ) , autoCaptureConfig as AutocaptureConfig )
343+ shouldAutocaptureEvent ( clickTarget , makeMouseEvent ( { } ) , autoCaptureConfig as AutocaptureConfig )
321344 ) . toBe ( shouldCapture )
322345 } )
323346 } )
@@ -348,110 +371,64 @@ describe(`Autocapture utility functions`, () => {
348371 } )
349372 } )
350373
351- describe ( `shouldCaptureElement` , ( ) => {
374+ describe ( `isExplicitCapture` , ( ) => {
375+ it ( `should return true for elements with class "ph-include"` , ( ) => {
376+ const el = document ! . createElement ( `div` )
377+ el . className = `test1 ph-include test2`
378+ expect ( isExplicitCapture ( el ) ) . toBe ( true )
379+ } )
380+
381+ it ( `should return false for elements without class "ph-include"` , ( ) => {
382+ const el = document ! . createElement ( `div` )
383+ el . className = `test1 test2`
384+ expect ( isExplicitCapture ( el ) ) . toBe ( false )
385+ } )
386+ } )
387+
388+ describe ( `isExplicitNoCapture` , ( ) => {
352389 let el : HTMLDivElement
353- let input : HTMLInputElement
354390 let parent1 : HTMLDivElement
355391 let parent2 : HTMLDivElement
356392
357393 beforeEach ( ( ) => {
358394 el = document ! . createElement ( `div` )
359- input = document ! . createElement ( `input` )
360395 parent1 = document ! . createElement ( `div` )
361396 parent2 = document ! . createElement ( `div` )
362397 parent1 . appendChild ( el )
363- parent1 . appendChild ( input )
364398 parent2 . appendChild ( parent1 )
365399 document ! . body . appendChild ( parent2 )
366400 } )
367401
368- it ( `should include sensitive elements with class "ph-include"` , ( ) => {
369- el . className = `test1 ph-include test2`
370- expect ( shouldCaptureElement ( el ) ) . toBe ( true )
371- } )
372-
373- it ( `should never include inputs with class "ph-sensitive"` , ( ) => {
402+ it ( `should return true for elements with class "ph-sensitive"` , ( ) => {
374403 el . className = `test1 ph-include ph-sensitive test2`
375- expect ( shouldCaptureElement ( el ) ) . toBe ( false )
404+ expect ( isExplicitNoCapture ( el ) ) . toBe ( true )
376405 } )
377406
378- it ( `should not include elements with class "ph-no-capture" as properties ` , ( ) => {
407+ it ( `should return true for elements with class "ph-no-capture"` , ( ) => {
379408 el . className = `test1 ph-no-capture test2`
380- expect ( shouldCaptureElement ( el ) ) . toBe ( false )
409+ expect ( isExplicitNoCapture ( el ) ) . toBe ( true )
381410 } )
382411
383- it ( `should not include elements with a parent that have class "ph-no-capture" as properties ` , ( ) => {
384- expect ( shouldCaptureElement ( el ) ) . toBe ( true )
412+ it ( `should return true for elements with a parent that has class "ph-no-capture"` , ( ) => {
413+ expect ( isExplicitNoCapture ( el ) ) . toBe ( false )
385414
386415 parent2 . className = `ph-no-capture`
387416
388- expect ( shouldCaptureElement ( el ) ) . toBe ( false )
417+ expect ( isExplicitNoCapture ( el ) ) . toBe ( true )
389418 } )
419+ } )
390420
391- it ( `should not include hidden fields` , ( ) => {
421+ describe ( `isSensitiveElement - hidden and password inputs` , ( ) => {
422+ it ( `should return true for hidden fields` , ( ) => {
423+ const input = document ! . createElement ( `input` )
392424 input . type = `hidden`
393- expect ( shouldCaptureElement ( input ) ) . toBe ( false )
425+ expect ( isSensitiveElement ( input ) ) . toBe ( true )
394426 } )
395427
396- it ( `should not include password fields` , ( ) => {
428+ it ( `should return true for password fields` , ( ) => {
429+ const input = document ! . createElement ( `input` )
397430 input . type = `password`
398- expect ( shouldCaptureElement ( input ) ) . toBe ( false )
399- } )
400-
401- it ( `should not include fields with sensitive names` , ( ) => {
402- const sensitiveNames = [
403- `cc_name` ,
404- `card-num` ,
405- `ccnum` ,
406- `credit-card_number` ,
407- `credit_card[number]` ,
408- `csc num` ,
409- `CVC` ,
410- `Expiration` ,
411- `password` ,
412- `pwd` ,
413- `routing` ,
414- `routing-number` ,
415- `security code` ,
416- `seccode` ,
417- `security number` ,
418- `social sec` ,
419- `SsN` ,
420- ]
421- sensitiveNames . forEach ( ( name ) => {
422- input . name = ''
423- expect ( shouldCaptureElement ( input ) ) . toBe ( true )
424-
425- input . name = name
426- expect ( shouldCaptureElement ( input ) ) . toBe ( false )
427- } )
428- } )
429-
430- // See https://github.com/posthog/posthog-js/issues/165
431- // Under specific circumstances a bug caused .replace to be called on a DOM element
432- // instead of a string, removing the element from the page. Ensure this issue is mitigated.
433- it ( `shouldn't inadvertently replace DOM nodes` , ( ) => {
434- // setup
435- ; ( el as any ) . replace = sinon . spy ( )
436-
437- // test
438- input . name = el as any
439- shouldCaptureElement ( parent1 ) // previously this would cause el.replace to be called
440- expect ( ( el as any ) . replace . called ) . toBe ( false )
441- input . name = ''
442-
443- parent1 . id = el as any
444- shouldCaptureElement ( parent2 ) // previously this would cause el.replace to be called
445- expect ( ( el as any ) . replace . called ) . toBe ( false )
446- parent1 . id = ''
447-
448- input . type = el as any
449- shouldCaptureElement ( parent2 ) // previously this would cause el.replace to be called
450- expect ( ( el as any ) . replace . called ) . toBe ( false )
451- input . type = ''
452-
453- // cleanup
454- ; ( el as any ) . replace = undefined
431+ expect ( isSensitiveElement ( input ) ) . toBe ( true )
455432 } )
456433 } )
457434
0 commit comments