@@ -36,30 +36,55 @@ function installVisibleErrorRecorder(
3636 const seen = new Set < string > ( )
3737 const errors : VisibleError [ ] = [ ]
3838 target . __cnVisibleErrors = errors
39- const sample = ( ) => {
39+ const record = ( surface : string , element : Element ) => {
40+ if (
41+ ! ( element instanceof HTMLElement ) ||
42+ ! element . checkVisibility ( {
43+ checkOpacity : true ,
44+ checkVisibilityCSS : true
45+ } )
46+ )
47+ return
48+ const text = ( element . innerText || element . textContent || '' )
49+ . replace ( / \s + / g, ' ' )
50+ . trim ( )
51+ . slice ( 0 , 300 )
52+ const key = `${ surface } \u0000${ text } `
53+ if ( seen . has ( key ) ) return
54+ seen . add ( key )
55+ errors . push ( { surface, text } )
56+ }
57+ const sampleElement = ( element : Element , includeDescendants : boolean ) => {
4058 for ( const { surface, selector } of selectors ) {
41- for ( const element of document . querySelectorAll ( selector ) ) {
42- if (
43- ! ( element instanceof HTMLElement ) ||
44- ! element . checkVisibility ( {
45- checkOpacity : true ,
46- checkVisibilityCSS : true
47- } )
48- )
49- continue
50- const text = ( element . innerText || element . textContent || '' )
51- . replace ( / \s + / g, ' ' )
52- . trim ( )
53- . slice ( 0 , 300 )
54- const key = `${ surface } \u0000${ text } `
55- if ( seen . has ( key ) ) continue
56- seen . add ( key )
57- errors . push ( { surface, text } )
58- }
59+ const closest = element . closest ( selector )
60+ if ( closest ) record ( surface , closest )
61+ if ( ! includeDescendants ) continue
62+ for ( const descendant of element . querySelectorAll ( selector ) )
63+ record ( surface , descendant )
5964 }
6065 }
61- sample ( )
62- new MutationObserver ( sample ) . observe ( document , {
66+ for ( const { surface, selector } of selectors )
67+ for ( const element of document . querySelectorAll ( selector ) )
68+ record ( surface , element )
69+ new MutationObserver ( ( mutations ) => {
70+ const exact = new Set < Element > ( )
71+ const subtrees = new Set < Element > ( )
72+ for ( const mutation of mutations ) {
73+ if ( mutation . type === 'childList' ) {
74+ if ( mutation . target instanceof Element ) exact . add ( mutation . target )
75+ for ( const node of mutation . addedNodes ) {
76+ if ( node instanceof Element ) subtrees . add ( node )
77+ else if ( node . parentElement ) exact . add ( node . parentElement )
78+ }
79+ } else if ( mutation . target instanceof Element ) {
80+ subtrees . add ( mutation . target )
81+ } else if ( mutation . target . parentElement ) {
82+ exact . add ( mutation . target . parentElement )
83+ }
84+ }
85+ for ( const element of exact ) sampleElement ( element , false )
86+ for ( const element of subtrees ) sampleElement ( element , true )
87+ } ) . observe ( document , {
6388 attributes : true ,
6489 characterData : true ,
6590 childList : true ,
0 commit comments