@@ -144,6 +144,105 @@ test("Should unobserve when triggerOnce comes into view", () => {
144144 expect ( instance . unobserve ) . toHaveBeenCalled ( ) ;
145145} ) ;
146146
147+ test ( "Should resume observing when triggerOnce is disabled while in view" , ( ) => {
148+ const callback = vi . fn ( ) ;
149+ const { container, rerender } = render (
150+ < InView triggerOnce onChange = { callback } >
151+ Inner
152+ </ InView > ,
153+ ) ;
154+ const element = container . children [ 0 ] ;
155+ const initialObserver = intersectionMockInstance ( element ) ;
156+ vi . spyOn ( initialObserver , "unobserve" ) ;
157+
158+ mockAllIsIntersecting ( true ) ;
159+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
160+ expect ( callback ) . toHaveBeenNthCalledWith (
161+ 1 ,
162+ true ,
163+ expect . objectContaining ( { isIntersecting : true } ) ,
164+ ) ;
165+ expect ( initialObserver . unobserve ) . toHaveBeenCalledWith ( element ) ;
166+
167+ callback . mockClear ( ) ;
168+ rerender (
169+ < InView triggerOnce = { false } onChange = { callback } >
170+ Inner
171+ </ InView > ,
172+ ) ;
173+ const resumedObserver = intersectionMockInstance ( element ) ;
174+ expect ( resumedObserver ) . not . toBe ( initialObserver ) ;
175+
176+ // A fresh observer reports the element's current state.
177+ mockAllIsIntersecting ( true ) ;
178+ expect ( callback ) . toHaveBeenNthCalledWith (
179+ 1 ,
180+ true ,
181+ expect . objectContaining ( { isIntersecting : true } ) ,
182+ ) ;
183+
184+ mockAllIsIntersecting ( false ) ;
185+ expect ( callback ) . toHaveBeenNthCalledWith (
186+ 2 ,
187+ false ,
188+ expect . objectContaining ( { isIntersecting : false } ) ,
189+ ) ;
190+
191+ mockAllIsIntersecting ( true ) ;
192+ expect ( callback ) . toHaveBeenNthCalledWith (
193+ 3 ,
194+ true ,
195+ expect . objectContaining ( { isIntersecting : true } ) ,
196+ ) ;
197+ expect ( callback ) . toHaveBeenCalledTimes ( 3 ) ;
198+ } ) ;
199+
200+ test ( "Should stop observing when triggerOnce is enabled while in view" , ( ) => {
201+ const callback = vi . fn ( ) ;
202+ const { container, rerender } = render (
203+ < InView triggerOnce = { false } onChange = { callback } >
204+ Inner
205+ </ InView > ,
206+ ) ;
207+ const element = container . children [ 0 ] ;
208+ const initialObserver = intersectionMockInstance ( element ) ;
209+ vi . spyOn ( initialObserver , "unobserve" ) ;
210+
211+ mockAllIsIntersecting ( true ) ;
212+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
213+ expect ( callback ) . toHaveBeenNthCalledWith (
214+ 1 ,
215+ true ,
216+ expect . objectContaining ( { isIntersecting : true } ) ,
217+ ) ;
218+
219+ callback . mockClear ( ) ;
220+ rerender (
221+ < InView triggerOnce onChange = { callback } >
222+ Inner
223+ </ InView > ,
224+ ) ;
225+ expect ( initialObserver . unobserve ) . toHaveBeenCalledWith ( element ) ;
226+
227+ const triggerOnceObserver = intersectionMockInstance ( element ) ;
228+ expect ( triggerOnceObserver ) . not . toBe ( initialObserver ) ;
229+ vi . spyOn ( triggerOnceObserver , "unobserve" ) ;
230+
231+ // A fresh observer reports the element's current state before triggerOnce stops it.
232+ mockAllIsIntersecting ( true ) ;
233+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
234+ expect ( callback ) . toHaveBeenNthCalledWith (
235+ 1 ,
236+ true ,
237+ expect . objectContaining ( { isIntersecting : true } ) ,
238+ ) ;
239+ expect ( triggerOnceObserver . unobserve ) . toHaveBeenCalledWith ( element ) ;
240+
241+ mockAllIsIntersecting ( false ) ;
242+ mockAllIsIntersecting ( true ) ;
243+ expect ( callback ) . toHaveBeenCalledTimes ( 1 ) ;
244+ } ) ;
245+
147246test ( "Should unobserve when unmounted" , ( ) => {
148247 const { container, unmount } = render ( < InView triggerOnce > Inner</ InView > ) ;
149248 const instance = intersectionMockInstance ( container . children [ 0 ] ) ;
0 commit comments