@@ -14,8 +14,14 @@ import type {
1414 ChromeReleaseChannel ,
1515 LaunchOptions ,
1616 Target ,
17+ BrowsersChromeReleaseChannel ,
18+ } from './third_party/index.js' ;
19+ import {
20+ puppeteer ,
21+ resolveDefaultUserDataDir ,
22+ detectBrowserPlatform ,
23+ BrowserEnum ,
1724} from './third_party/index.js' ;
18- import { puppeteer } from './third_party/index.js' ;
1925
2026let browser : Browser | undefined ;
2127
@@ -49,6 +55,7 @@ export async function ensureBrowserConnected(options: {
4955 wsHeaders ?: Record < string , string > ;
5056 devtools : boolean ;
5157 channel ?: Channel ;
58+ userDataDir ?: string ;
5259} ) {
5360 const { channel} = options ;
5461 if ( browser ?. connected ) {
@@ -68,15 +75,57 @@ export async function ensureBrowserConnected(options: {
6875 }
6976 } else if ( options . browserURL ) {
7077 connectOptions . browserURL = options . browserURL ;
71- } else if ( channel ) {
72- const puppeteerChannel =
73- channel !== 'stable'
74- ? ( `chrome-${ channel } ` as ChromeReleaseChannel )
75- : 'chrome' ;
76- connectOptions . channel = puppeteerChannel ;
78+ } else if ( channel || options . userDataDir ) {
79+ let userDataDir = options . userDataDir ;
80+ if ( ! userDataDir ) {
81+ if ( ! channel ) {
82+ throw new Error ( 'Channel must be provided if userDataDir is missing' ) ;
83+ }
84+ const platform = detectBrowserPlatform ( ) ;
85+ if ( ! platform ) {
86+ throw new Error ( 'Could not detect required browser platform' ) ;
87+ }
88+ userDataDir = resolveDefaultUserDataDir (
89+ BrowserEnum . CHROME ,
90+ platform ,
91+ ( channel === 'stable'
92+ ? 'chrome'
93+ : `chrome-${ channel } ` ) as BrowsersChromeReleaseChannel ,
94+ ) ;
95+ }
96+
97+ // TODO: re-expose this logic via Puppeteer.
98+ const portPath = path . join ( userDataDir , 'DevToolsActivePort' ) ;
99+ try {
100+ const fileContent = await fs . promises . readFile ( portPath , 'utf8' ) ;
101+ const [ rawPort , rawPath ] = fileContent
102+ . split ( '\n' )
103+ . map ( line => {
104+ return line . trim ( ) ;
105+ } )
106+ . filter ( line => {
107+ return ! ! line ;
108+ } ) ;
109+ if ( ! rawPort || ! rawPath ) {
110+ throw new Error ( `Invalid DevToolsActivePort '${ fileContent } ' found` ) ;
111+ }
112+ const port = parseInt ( rawPort , 10 ) ;
113+ if ( isNaN ( port ) || port <= 0 || port > 65535 ) {
114+ throw new Error ( `Invalid port '${ rawPort } ' found` ) ;
115+ }
116+ const browserWSEndpoint = `ws://127.0.0.1:${ port } ${ rawPath } ` ;
117+ connectOptions . browserWSEndpoint = browserWSEndpoint ;
118+ } catch ( error ) {
119+ throw new Error (
120+ `Could not connect to Chrome in ${ userDataDir } . Check if Chrome is running and remote debugging is enabled.` ,
121+ {
122+ cause : error ,
123+ } ,
124+ ) ;
125+ }
77126 } else {
78127 throw new Error (
79- 'Either browserURL, wsEndpoint or channel must be provided' ,
128+ 'Either browserURL, wsEndpoint, channel or userDataDir must be provided' ,
80129 ) ;
81130 }
82131
0 commit comments