@@ -32,7 +32,9 @@ describe('rectangles', () => {
3232
3333 mockBrowserInstance = {
3434 execute : mockExecute ,
35- getElementRect : mockGetElementRect
35+ getElementRect : mockGetElementRect ,
36+ $ : vi . fn ( ) ,
37+ $$ : vi . fn ( ) ,
3638 } as unknown as WebdriverIO . Browser
3739 } )
3840
@@ -772,19 +774,20 @@ describe('rectangles', () => {
772774 desktopOptions . browserInstance = mockBrowserInstance
773775 } )
774776
775- it ( 'should resolve elements via raw BCR on desktop and apply DPR' , async ( ) => {
777+ it ( 'should resolve elements via raw BCR on desktop and apply DPR without re-querying ' , async ( ) => {
776778 const mockElement = { elementId : 'el1' , selector : '.nav' } as WebdriverIO . Element
777779 mockExecute . mockResolvedValueOnce ( { x : 10 , y : 20 , width : 200 , height : 50 } )
778780
779781 const result = await determineWebScreenIgnoreRegions ( desktopOptions , [ mockElement ] )
780782
781783 expect ( mockExecute ) . toHaveBeenCalledOnce ( )
784+ expect ( mockBrowserInstance . $ ) . not . toHaveBeenCalled ( )
782785 expect ( result ) . toEqual ( [
783786 { x : 20 , y : 40 , width : 400 , height : 100 } ,
784787 ] )
785788 } )
786789
787- it ( 'should add DPR-scaled viewport offset on iOS' , async ( ) => {
790+ it ( 'should add DPR-scaled viewport offset on iOS and re-query elements via $$ ' , async ( ) => {
788791 const iosDeviceRectangles = {
789792 ...baseDeviceRectangles ,
790793 viewport : { y : 94 , x : 0 , width : 390 , height : 650 } ,
@@ -796,18 +799,59 @@ describe('rectangles', () => {
796799 isIOS : true ,
797800 }
798801 const mockElement = { elementId : 'el1' , selector : '.hero' } as WebdriverIO . Element
802+ const freshElement = { elementId : 'el1-fresh' , selector : '.hero' } as unknown as WebdriverIO . Element
803+ vi . mocked ( mockBrowserInstance . $$ ) . mockResolvedValueOnce ( [ freshElement ] as any )
799804 mockExecute . mockResolvedValueOnce ( { x : 0 , y : 100 , width : 390 , height : 200 } )
800805
801806 const result = await determineWebScreenIgnoreRegions ( iosOptions , [ mockElement ] )
802807
803- // iOS viewport offset added in CSS space, then floor/ceil for DPR:
804- // x: floor((0+0)*3)=0, y: floor((100+94)*3)=582
805- // right: ceil((0+390)*3)=1170, bottom: ceil((100+200+94)*3)=1182
808+ expect ( mockBrowserInstance . $$ ) . toHaveBeenCalledWith ( '.hero' )
809+ expect ( mockBrowserInstance . $ ) . not . toHaveBeenCalled ( )
806810 expect ( result ) . toEqual ( [
807811 { x : 0 , y : 582 , width : 1170 , height : 600 } ,
808812 ] )
809813 } )
810814
815+ it ( 'should correctly resolve multiple elements sharing the same selector on iOS' , async ( ) => {
816+ const iosDeviceRectangles = {
817+ ...baseDeviceRectangles ,
818+ viewport : { y : 94 , x : 0 , width : 390 , height : 650 } ,
819+ }
820+ const iosOptions = {
821+ ...desktopOptions ,
822+ devicePixelRatio : 1 ,
823+ deviceRectangles : iosDeviceRectangles ,
824+ isIOS : true ,
825+ }
826+ const el1 = { elementId : 'a' , selector : '.card' } as WebdriverIO . Element
827+ const el2 = { elementId : 'b' , selector : '.card' } as WebdriverIO . Element
828+ const el3 = { elementId : 'c' , selector : '.card' } as WebdriverIO . Element
829+
830+ const fresh1 = { elementId : 'f1' , selector : '.card' } as unknown as WebdriverIO . Element
831+ const fresh2 = { elementId : 'f2' , selector : '.card' } as unknown as WebdriverIO . Element
832+ const fresh3 = { elementId : 'f3' , selector : '.card' } as unknown as WebdriverIO . Element
833+ vi . mocked ( mockBrowserInstance . $$ ) . mockResolvedValueOnce ( [ fresh1 , fresh2 , fresh3 ] as any )
834+
835+ mockExecute
836+ . mockResolvedValueOnce ( { x : 0 , y : 100 , width : 390 , height : 50 } )
837+ . mockResolvedValueOnce ( { x : 0 , y : 200 , width : 390 , height : 50 } )
838+ . mockResolvedValueOnce ( { x : 0 , y : 300 , width : 390 , height : 50 } )
839+
840+ const result = await determineWebScreenIgnoreRegions ( iosOptions , [ [ el1 , el2 , el3 ] ] )
841+
842+ // $$ called once for the shared selector, not $ three times
843+ expect ( mockBrowserInstance . $$ ) . toHaveBeenCalledTimes ( 1 )
844+ expect ( mockBrowserInstance . $$ ) . toHaveBeenCalledWith ( '.card' )
845+ // execute called with each fresh element
846+ expect ( mockExecute ) . toHaveBeenCalledTimes ( 3 )
847+ // Each region has different y (viewport offset 94 added)
848+ expect ( result ) . toEqual ( [
849+ { x : 0 , y : 194 , width : 390 , height : 50 } ,
850+ { x : 0 , y : 294 , width : 390 , height : 50 } ,
851+ { x : 0 , y : 394 , width : 390 , height : 50 } ,
852+ ] )
853+ } )
854+
811855 it ( 'should add device-pixel viewport offset on Android native web screenshot' , async ( ) => {
812856 const androidDeviceRectangles = {
813857 ...baseDeviceRectangles ,
0 commit comments