@@ -33,6 +33,30 @@ function generateStep(step: RecordedStep, history: SessionHistory): string {
3333 switch ( step . tool ) {
3434 case 'start_session' : {
3535 const platform = p . platform as string ;
36+ const isBrowserStack = 'bstack:options' in history . capabilities ;
37+ const capJson = indentJson ( history . capabilities )
38+ . split ( '\n' )
39+ . map ( ( line , i ) => ( i > 0 ? ` ${ line } ` : line ) )
40+ . join ( '\n' ) ;
41+
42+ if ( isBrowserStack ) {
43+ const nav =
44+ platform === 'browser' && p . navigationUrl
45+ ? `\nawait browser.url('${ escapeStr ( p . navigationUrl ) } ');`
46+ : '' ;
47+ return [
48+ 'const browser = await remote({' ,
49+ " protocol: 'https'," ,
50+ " hostname: 'hub.browserstack.com'," ,
51+ ' port: 443,' ,
52+ " path: '/wd/hub'," ,
53+ ' user: process.env.BS_USER,' ,
54+ ' key: process.env.BS_KEY,' ,
55+ ` capabilities: ${ capJson } ` ,
56+ `});${ nav } ` ,
57+ ] . join ( '\n' ) ;
58+ }
59+
3660 if ( platform === 'browser' ) {
3761 const nav = p . navigationUrl ? `\nawait browser.url('${ escapeStr ( p . navigationUrl ) } ');` : '' ;
3862 return `const browser = await remote({\n capabilities: ${ indentJson ( history . capabilities ) } \n});${ nav } ` ;
@@ -81,12 +105,77 @@ function generateStep(step: RecordedStep, history: SessionHistory): string {
81105 }
82106}
83107
108+ function bsStatusUpdateLines ( sessionType : 'browser' | 'ios' | 'android' ) : string [ ] {
109+ const apiUrl = sessionType === 'browser'
110+ ? 'https://api.browserstack.com/automate/sessions/'
111+ : 'https://api-cloud.browserstack.com/app-automate/sessions/' ;
112+ return [
113+ " const bsAuth = Buffer.from(`${process.env.BS_USER}:${process.env.BS_KEY}`).toString('base64');" ,
114+ ` await fetch('${ apiUrl } ' + browser.sessionId + '.json', {` ,
115+ " method: 'PUT'," ,
116+ " headers: { Authorization: 'Basic ' + bsAuth, 'Content-Type': 'application/json' }," ,
117+ ' body: JSON.stringify({ status: bsStatus, ...(bsReason ? { reason: bsReason } : {}) })' ,
118+ ' });' ,
119+ ] ;
120+ }
121+
84122export function generateCode ( history : SessionHistory ) : string {
123+ const bstackOptions = history . capabilities [ 'bstack:options' ] as Record < string , unknown > | undefined ;
124+ const isBrowserStack = bstackOptions !== undefined ;
125+ const usesBrowserstackLocal = bstackOptions ?. local === true ;
126+
85127 const steps = history . steps
86128 . map ( step => generateStep ( step , history ) )
87129 . join ( '\n' )
88130 . split ( '\n' )
89131 . map ( line => ` ${ line } ` )
90132 . join ( '\n' ) ;
133+
134+ if ( isBrowserStack ) {
135+ const bsSteps = steps . replace ( / c o n s t b r o w s e r = a w a i t r e m o t e \( / g, 'browser = await remote(' ) ;
136+ const statusUpdate = bsStatusUpdateLines ( history . type ) . join ( '\n' ) ;
137+ const preamble = 'let browser;\nlet bsStatus = \'passed\';\nlet bsReason;' ;
138+ const catchBlock = '} catch (e) {\n bsStatus = \'failed\';\n bsReason = String(e);\n throw e;' ;
139+ const finallyBody = ` if (browser) {\n${ statusUpdate } \n await browser.deleteSession();\n }` ;
140+
141+ if ( usesBrowserstackLocal ) {
142+ const tunnelSetup = [
143+ '' ,
144+ 'const tunnel = new BrowserstackTunnel();' ,
145+ 'const startTunnel = promisify(tunnel.start.bind(tunnel));' ,
146+ 'const stopTunnel = promisify(tunnel.stop.bind(tunnel));' ,
147+ 'await startTunnel({ key: process.env.BROWSERSTACK_ACCESS_KEY });' ,
148+ '' ,
149+ ] . join ( '\n' ) ;
150+
151+ return [
152+ "import { remote } from 'webdriverio';" ,
153+ "import { Local as BrowserstackTunnel } from 'browserstack-local';" ,
154+ "import { promisify } from 'node:util';" ,
155+ tunnelSetup ,
156+ preamble ,
157+ 'try {' ,
158+ bsSteps ,
159+ catchBlock ,
160+ '} finally {' ,
161+ finallyBody ,
162+ ' await stopTunnel();' ,
163+ '}' ,
164+ ] . join ( '\n' ) ;
165+ }
166+
167+ return [
168+ "import { remote } from 'webdriverio';" ,
169+ '' ,
170+ preamble ,
171+ 'try {' ,
172+ bsSteps ,
173+ catchBlock ,
174+ '} finally {' ,
175+ finallyBody ,
176+ '}' ,
177+ ] . join ( '\n' ) ;
178+ }
179+
91180 return `import { remote } from 'webdriverio';\n\ntry {\n${ steps } \n} finally {\n await browser.deleteSession();\n}` ;
92181}
0 commit comments