@@ -691,7 +691,11 @@ class Puppeteer extends Helper {
691691
692692 async _withinEnd ( ) {
693693 this . withinLocator = null
694- this . context = await this . page . mainFrame ( ) . $ ( 'body' )
694+ if ( this . page && ! this . page . isClosed ?. ( ) ) {
695+ this . context = await this . page . mainFrame ( ) . $ ( 'body' )
696+ } else {
697+ this . context = null
698+ }
695699 }
696700
697701 _extractDataFromPerformanceTiming ( timing , ...dataNames ) {
@@ -2120,6 +2124,12 @@ class Puppeteer extends Helper {
21202124
21212125 this . debug ( `Screenshot is saving to ${ outputFile } ` )
21222126
2127+ // Safety check: ensure page exists and is not closed
2128+ if ( ! this . page || this . page . isClosed ?. ( ) ) {
2129+ this . debugSection ( 'Screenshot' , 'Page is not available, skipping screenshot' )
2130+ return
2131+ }
2132+
21232133 await this . page . screenshot ( {
21242134 path : outputFile ,
21252135 fullPage : fullPageOption ,
@@ -2133,7 +2143,7 @@ class Puppeteer extends Helper {
21332143
21342144 this . debug ( `${ sessionName } - Screenshot is saving to ${ outputFile } ` )
21352145
2136- if ( activeSessionPage ) {
2146+ if ( activeSessionPage && ! activeSessionPage . isClosed ?. ( ) ) {
21372147 await activeSessionPage . screenshot ( {
21382148 path : outputFile ,
21392149 fullPage : fullPageOption ,
@@ -2867,12 +2877,49 @@ async function findElements(matcher, locator) {
28672877
28682878 // Use proven legacy approach - Puppeteer Locator API doesn't have .all() method
28692879 if ( ! locator . isXPath ( ) ) return matcher . $$ ( locator . simplify ( ) )
2880+
28702881 // puppeteer version < 19.4.0 is no longer supported. This one is backward support.
28712882 if ( puppeteer . default ?. defaultBrowserRevision ) {
28722883 return matcher . $$ ( `xpath/${ locator . value } ` )
28732884 }
2874- // For newer Puppeteer versions, use $x for XPath
2875- return matcher . $x ( locator . value )
2885+
2886+ // For newer Puppeteer versions, use $x for XPath (only available on Page/Frame)
2887+ if ( matcher . $x ) {
2888+ return matcher . $x ( locator . value )
2889+ }
2890+
2891+ // ElementHandles don't support XPath directly
2892+ // Get the frame/page containing this element and use that for XPath search
2893+ try {
2894+ const frame = matcher . contentFrame ? await matcher . contentFrame ( ) : null
2895+ const executionContext = frame || ( await matcher . executionContext ( ) )
2896+ const frameOrPage = executionContext ?. _world ?. _frameManager ?. _page || await this . _getContext ( )
2897+
2898+ if ( frameOrPage . $x ) {
2899+ // Search within the element by getting its descendants
2900+ // We need to make XPath relative to the element
2901+ const relativeXPath = locator . value . startsWith ( './/' ) ? locator . value : `.//${ locator . value . replace ( / ^ \/ \/ / , '' ) } `
2902+
2903+ // Use the element as context by evaluating XPath from it
2904+ const elements = await matcher . evaluateHandle ( ( element , xpath ) => {
2905+ const iterator = document . evaluate ( xpath , element , null , XPathResult . ORDERED_NODE_SNAPSHOT_TYPE , null )
2906+ const results = [ ]
2907+ for ( let i = 0 ; i < iterator . snapshotLength ; i ++ ) {
2908+ results . push ( iterator . snapshotItem ( i ) )
2909+ }
2910+ return results
2911+ } , relativeXPath )
2912+
2913+ // Convert JSHandle to array of ElementHandles
2914+ const properties = await elements . getProperties ( )
2915+ return Array . from ( properties . values ( ) )
2916+ }
2917+ } catch ( e ) {
2918+ this . debug ( `XPath within element failed: ${ e . message } ` )
2919+ }
2920+
2921+ // Fallback: return empty array
2922+ return [ ]
28762923}
28772924
28782925/**
0 commit comments