1- import { fireEvent , render , screen } from '@testing-library/react' ;
1+ import { act , fireEvent , render , screen } from '@testing-library/react' ;
22import type { ReactNode , Ref } from 'react' ;
33import { ZoomableImage } from '../ZoomableImage' ;
44
@@ -17,6 +17,8 @@ const mockSetTransform = jest.fn(
1717 } ,
1818) ;
1919let mockWrapperComponent : HTMLDivElement | null = null ;
20+ let mockContentComponent : HTMLDivElement | null = null ;
21+ let mockShouldExposeContentComponent = true ;
2022
2123jest . mock ( '@tauri-apps/api/core' , ( ) => ( {
2224 convertFileSrc : ( path : string ) => path ,
@@ -32,6 +34,11 @@ jest.mock('react-zoom-pan-pinch', () => {
3234 get wrapperComponent ( ) {
3335 return mockWrapperComponent ;
3436 } ,
37+ get contentComponent ( ) {
38+ return mockShouldExposeContentComponent
39+ ? mockContentComponent
40+ : null ;
41+ } ,
3542 transformState : mockTransformState ,
3643 } ,
3744 setTransform : mockSetTransform ,
@@ -48,7 +55,16 @@ jest.mock('react-zoom-pan-pinch', () => {
4855 ) ;
4956
5057 const TransformComponent = ( { children } : { children : ReactNode } ) =>
51- React . createElement ( 'div' , null , children ) ;
58+ React . createElement (
59+ 'div' ,
60+ {
61+ 'data-testid' : 'transform-content' ,
62+ ref : ( node : HTMLDivElement | null ) => {
63+ mockContentComponent = node ;
64+ } ,
65+ } ,
66+ children ,
67+ ) ;
5268
5369 return {
5470 TransformWrapper,
@@ -122,9 +138,11 @@ const setupWheelScene = ({
122138 const { container } = renderZoomableImage ( ) ;
123139 const wheelArea = container . firstElementChild as HTMLElement ;
124140 const transformWrapper = screen . getByTestId ( 'transform-wrapper' ) ;
141+ const transformContent = screen . getByTestId ( 'transform-content' ) ;
125142 const image = screen . getByAltText ( 'test image' ) ;
126143
127144 mockWrapperComponent = transformWrapper as HTMLDivElement ;
145+ mockContentComponent = transformContent as HTMLDivElement ;
128146
129147 mockElementRect (
130148 wheelArea ,
@@ -180,6 +198,8 @@ describe('ZoomableImage wheel behavior', () => {
180198 // Keep the internal wrapper unavailable by default so tests cover the
181199 // production fallback path where the wheel area owns scroll handling.
182200 mockWrapperComponent = null ;
201+ mockContentComponent = null ;
202+ mockShouldExposeContentComponent = true ;
183203 mockTransformState . scale = 1 ;
184204 mockTransformState . positionX = 0 ;
185205 mockTransformState . positionY = 0 ;
@@ -345,6 +365,52 @@ describe('ZoomableImage wheel behavior', () => {
345365 expectLatestTransform ( - 90 , - 70 , 0.6 ) ;
346366 } ) ;
347367
368+ test ( 'retries initial fit until the transform content is ready' , ( ) => {
369+ jest . useFakeTimers ( ) ;
370+ mockShouldExposeContentComponent = false ;
371+
372+ const { container } = renderZoomableImage ( ) ;
373+
374+ const wheelArea = container . firstElementChild as HTMLElement ;
375+ const transformWrapper = screen . getByTestId ( 'transform-wrapper' ) ;
376+ const transformContent = screen . getByTestId ( 'transform-content' ) ;
377+ const image = screen . getByAltText ( 'test image' ) ;
378+
379+ mockWrapperComponent = transformWrapper as HTMLDivElement ;
380+ mockElementRect (
381+ wheelArea ,
382+ { width : 500 , height : 400 , left : 0 , top : 0 } ,
383+ { clientWidth : 500 , clientHeight : 400 } ,
384+ ) ;
385+ mockElementRect (
386+ transformWrapper ,
387+ { width : 500 , height : 400 , left : 0 , top : 0 } ,
388+ { clientWidth : 500 , clientHeight : 400 } ,
389+ ) ;
390+ mockElementRect (
391+ image ,
392+ { width : 1000 , height : 800 , left : 0 , top : 0 } ,
393+ { clientWidth : 1000 , clientHeight : 800 } ,
394+ ) ;
395+
396+ fireEvent . load ( image ) ;
397+
398+ act ( ( ) => {
399+ jest . runOnlyPendingTimers ( ) ;
400+ } ) ;
401+ expect ( mockSetTransform ) . not . toHaveBeenCalled ( ) ;
402+
403+ mockShouldExposeContentComponent = true ;
404+ mockContentComponent = transformContent as HTMLDivElement ;
405+
406+ act ( ( ) => {
407+ jest . runOnlyPendingTimers ( ) ;
408+ } ) ;
409+
410+ expectLatestTransform ( 0 , 0 , 0.5 ) ;
411+ jest . useRealTimers ( ) ;
412+ } ) ;
413+
348414 test ( 'starts from the new image fit transform after switching images' , ( ) => {
349415 const { container, rerender } = renderZoomableImage ( {
350416 imagePath : '/tmp/photo-a.jpg' ,
0 commit comments