22import 'intersection-observer' ;
33import React , { Component } from 'react' ;
44import renderer from 'react-test-renderer' ;
5- import IntersectionObserver , { getOptions } from '../IntersectionObserver' ;
5+ import GuardedIntersectionObserver , {
6+ IntersectionObserver ,
7+ getOptions ,
8+ } from '../IntersectionObserver' ;
69import { callback , observerElementsMap } from '../observer' ;
710import Config from '../config' ;
811
@@ -19,6 +22,8 @@ jest.mock('react-dom', () => {
1922 } ,
2023 } ;
2124} ) ;
25+ // the default "undefined" can't be re-assigned, so we preemptively set it as an empty function
26+ Config . errorReporter = function ( ) { } ;
2227
2328const target = { nodeType : 1 , type : 'span' } ;
2429const targets = { div : { nodeType : 1 , type : 'div' } , span : target } ;
@@ -71,6 +76,71 @@ test('throws trying to observe children without a DOM node', () => {
7176 expect ( observerElementsMap . size ) . toBe ( sizeBeforeObserving ) ;
7277} ) ;
7378
79+ test ( 'reports error trying to observe children without a DOM node' , ( ) => {
80+ global . spyOn ( console , 'error' ) ; // suppress error boundary warning
81+ const sizeBeforeObserving = observerElementsMap . size ;
82+ const originalErrorReporter = Config . errorReporter ;
83+ const spy = jest . fn ( ) ;
84+ Config . errorReporter = spy ;
85+
86+ const tree = renderer
87+ . create (
88+ < GuardedIntersectionObserver onChange = { noop } >
89+ < ProxyComponent > { null } </ ProxyComponent >
90+ </ GuardedIntersectionObserver >
91+ )
92+ . toTree ( ) ;
93+
94+ expect ( observerElementsMap . size ) . toBe ( sizeBeforeObserving ) ;
95+ expect ( spy ) . toBeCalledTimes ( 1 ) ;
96+ expect ( spy ) . toBeCalledWith (
97+ expect . any ( Error ) ,
98+ expect . objectContaining ( { componentStack : expect . any ( String ) } )
99+ ) ;
100+ // Tree stayed mounted because of the error boundary
101+ expect ( tree . props . children . type ) . toEqual ( ProxyComponent ) ;
102+
103+ Config . errorReporter = originalErrorReporter ;
104+ } ) ;
105+
106+ test ( 'reports errors by re-throwing trying observer children without a DOM node' , ( ) => {
107+ global . spyOn ( console , 'error' ) ; // suppress error boundary warning
108+ const originalErrorReporter = Config . errorReporter ;
109+ let called = false ;
110+ Config . errorReporter = ( err ) => {
111+ called = true ;
112+ throw err ;
113+ } ;
114+ class TestErrorBoundary extends React . Component {
115+ state = { hasError : false } ;
116+
117+ componentDidCatch ( ) {
118+ this . setState ( { hasError : true } ) ;
119+ }
120+
121+ render ( ) {
122+ // eslint-disable-next-line react/prop-types
123+ return this . state . hasError ? 'has-error' : this . props . children ;
124+ }
125+ }
126+
127+ const children = renderer
128+ . create (
129+ < TestErrorBoundary >
130+ < GuardedIntersectionObserver onChange = { noop } >
131+ < ProxyComponent > { null } </ ProxyComponent >
132+ </ GuardedIntersectionObserver >
133+ </ TestErrorBoundary >
134+ )
135+ . toJSON ( ) ;
136+
137+ // Tree changed because of the custom error boundary
138+ expect ( children ) . toBe ( 'has-error' ) ;
139+ expect ( called ) . toBe ( true ) ;
140+
141+ Config . errorReporter = originalErrorReporter ;
142+ } ) ;
143+
74144test ( 'should not observe children that equal null or undefined' , ( ) => {
75145 const sizeBeforeObserving = observerElementsMap . size ;
76146 renderer . create (
@@ -348,37 +418,7 @@ describe('updating', () => {
348418 expect ( observe ) . toBeCalledTimes ( 1 ) ;
349419 } ) ;
350420
351- test ( 'should call a setup errorReporter without a DOM Node' , ( ) => {
352- const spy = jest . fn ( ) ;
353- const origErrorReporter = Config . errorReporter ;
354- Config . errorReporter = spy ;
355- const tree = renderer . create (
356- < IntersectionObserver onChange = { noop } >
357- < ProxyComponent >
358- < div />
359- </ ProxyComponent >
360- </ IntersectionObserver > ,
361- { createNodeMock }
362- ) ;
363- const instance = tree . getInstance ( ) ;
364- const observe = jest . spyOn ( instance , 'observe' ) ;
365- const unobserve = jest . spyOn ( instance , 'unobserve' ) ;
366-
367- tree . update (
368- < IntersectionObserver onChange = { noop } >
369- < ProxyComponent key = "forcesRender" > { null } </ ProxyComponent >
370- </ IntersectionObserver >
371- ) ;
372-
373- expect ( spy ) . toBeCalled ( ) ;
374- expect ( unobserve ) . toBeCalledTimes ( 1 ) ;
375- expect ( observe ) . toBeCalledTimes ( 1 ) ;
376- expect ( observe ) . toReturnWith ( false ) ;
377-
378- Config . errorReporter = origErrorReporter ;
379- } ) ;
380-
381- test ( 'should observe when updating with a DOM Node' , ( ) => {
421+ test ( 'should observe only when updating with a DOM Node' , ( ) => {
382422 global . spyOn ( console , 'error' ) ; // suppress error boundary warning
383423
384424 const sizeAfterUnobserving = observerElementsMap . size ;
0 commit comments