@@ -2150,29 +2150,59 @@ class CdpDriver implements AppDriver {
21502150 client.close ();
21512151
21522152 final tabs = jsonDecode (body) as List ;
2153- // Prefer tab already showing the target URL
2154- for (final tab in tabs) {
2155- if (tab is Map && tab['type' ] == 'page' && tab['url' ] == _url) {
2153+ final pageTabs = tabs.where ((t) => t is Map && t['type' ] == 'page' ).cast <Map >().toList ();
2154+
2155+ // 1. Exact URL match
2156+ for (final tab in pageTabs) {
2157+ if (tab['url' ] == _url) {
2158+ connectedToExistingTab = true ;
21562159 return tab['webSocketDebuggerUrl' ] as String ? ;
21572160 }
21582161 }
2159- // Prefer page with actual content (not devtools/about:blank)
2160- for (final tab in tabs) {
2161- if (tab is Map &&
2162- tab['type' ] == 'page' &&
2163- tab['url' ] is String &&
2164- ! tab['url' ].toString ().startsWith ('devtools://' ) &&
2165- ! tab['url' ].toString ().startsWith ('chrome://' ) &&
2166- tab['url' ] != 'about:blank' ) {
2167- return tab['webSocketDebuggerUrl' ] as String ? ;
2162+ // 2. Same-origin match (e.g. URL with different query params)
2163+ if (_url.isNotEmpty) {
2164+ final targetUri = Uri .tryParse (_url);
2165+ if (targetUri != null ) {
2166+ final targetOrigin = '${targetUri .scheme }://${targetUri .host }' ;
2167+ final targetPath = targetUri.path;
2168+ for (final tab in pageTabs) {
2169+ final tabUrl = tab['url' ]? .toString () ?? '' ;
2170+ final tabUri = Uri .tryParse (tabUrl);
2171+ if (tabUri != null ) {
2172+ final tabOrigin = '${tabUri .scheme }://${tabUri .host }' ;
2173+ // Same origin + same path = very likely the same page
2174+ if (tabOrigin == targetOrigin && tabUri.path == targetPath) {
2175+ connectedToExistingTab = true ;
2176+ return tab['webSocketDebuggerUrl' ] as String ? ;
2177+ }
2178+ }
2179+ }
2180+ // 3. Same-origin only (different path — will navigate within same tab)
2181+ for (final tab in pageTabs) {
2182+ final tabUrl = tab['url' ]? .toString () ?? '' ;
2183+ final tabUri = Uri .tryParse (tabUrl);
2184+ if (tabUri != null ) {
2185+ final tabOrigin = '${tabUri .scheme }://${tabUri .host }' ;
2186+ if (tabOrigin == targetOrigin) {
2187+ return tab['webSocketDebuggerUrl' ] as String ? ;
2188+ }
2189+ }
2190+ }
21682191 }
21692192 }
2170- // Fall back to first page tab
2171- for (final tab in tabs) {
2172- if (tab is Map && tab['type' ] == 'page' ) {
2193+ // 4. Prefer page with actual content (not devtools/about:blank)
2194+ for (final tab in pageTabs) {
2195+ final tabUrl = tab['url' ]? .toString () ?? '' ;
2196+ if (! tabUrl.startsWith ('devtools://' ) &&
2197+ ! tabUrl.startsWith ('chrome://' ) &&
2198+ tabUrl != 'about:blank' ) {
21732199 return tab['webSocketDebuggerUrl' ] as String ? ;
21742200 }
21752201 }
2202+ // 5. Fall back to first page tab
2203+ if (pageTabs.isNotEmpty) {
2204+ return pageTabs.first['webSocketDebuggerUrl' ] as String ? ;
2205+ }
21762206 } catch (_) {
21772207 await Future .delayed (const Duration (milliseconds: 500 ));
21782208 }
0 commit comments