Skip to content

Commit d4eae57

Browse files
authored
Merge pull request #55 from webdriverio/feature/browserstack-tunnel
feat: Integrate auto-start BrowserStack Local tunnel on session start & management
2 parents 3752aea + 0084513 commit d4eae57

13 files changed

Lines changed: 569 additions & 58 deletions

File tree

CLAUDE.md

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,19 @@ Single active session model in `src/session/state.ts`:
4141
// Private state — access via getState() or getBrowser()
4242
export function getBrowser(): WebdriverIO.Browser { ... }
4343
export function getState() { return state; }
44-
export interface SessionMetadata { type: 'browser' | 'ios' | 'android'; capabilities: Record<string, unknown>; isAttached: boolean; }
44+
export interface SessionMetadata {
45+
type: 'browser' | 'ios' | 'android';
46+
capabilities: Record<string, unknown>;
47+
isAttached: boolean;
48+
provider?: 'local' | 'browserstack'; // set at session start; used by lifecycle to call provider hooks
49+
tunnelHandle?: unknown; // opaque handle returned by provider.startTunnel(), passed back to onSessionClose()
50+
}
4551
```
4652

4753
Session lifecycle managed via `src/session/lifecycle.ts`:
48-
- `registerSession()` — registers browser + metadata + history, handles transition sentinel
54+
- `registerSession()` — registers browser + metadata + history, handles transition sentinel; calls `provider.onSessionClose()` on orphaned sessions
4955
- `handleSessionTransition()` — appends `__session_transition__` step to outgoing session
50-
- `closeSession()` — terminates or detaches, marks endedAt, cleans up maps
56+
- `closeSession()` — terminates or detaches, marks endedAt, calls `provider.onSessionClose()`, cleans up maps
5157

5258
### Tool Pattern
5359

@@ -98,8 +104,11 @@ MCP resources expose live session data — all at fixed URIs discoverable via Li
98104
- `wdio://session/current/cookies` — browser cookies
99105
- `wdio://session/current/tabs` — open browser tabs
100106
- `wdio://session/current/contexts` — native/webview contexts (mobile)
107+
- `wdio://session/current/context` — currently active context (mobile)
101108
- `wdio://session/current/app-state` — mobile app state
102109
- `wdio://session/current/geolocation` — device geolocation
110+
- `wdio://session/current/capabilities` — resolved WebDriver capabilities for the active session
111+
- `wdio://browserstack/local-binary` — platform-specific download URL and daemon start command for BrowserStack Local binary
103112

104113
### Build
105114

@@ -115,7 +124,8 @@ MCP resources expose live session data — all at fixed URIs discoverable via Li
115124
| `src/session/state.ts` | Session state maps, `getBrowser()`, `getState()` |
116125
| `src/session/lifecycle.ts` | `registerSession()`, `closeSession()`, session transitions |
117126
| `src/providers/registry.ts` | `getProvider()` — routes to local or cloud provider |
118-
| `src/providers/cloud/browserstack.provider.ts` | BrowserStack session provider |
127+
| `src/providers/types.ts` | `SessionProvider` interface — `startTunnel()`, `onSessionClose()` lifecycle hooks |
128+
| `src/providers/cloud/browserstack.provider.ts` | BrowserStack provider — tunnel lifecycle + session result marking via `onSessionClose()` |
119129
| `src/tools/session.tool.ts` | `start_session` (browser + mobile), `close_session` |
120130
| `src/tools/get-elements.tool.ts` | `get_elements` — all elements with filtering + pagination |
121131
| `src/tools/browserstack.tool.ts` | `list_apps`, `upload_app` — BrowserStack App Automate |

README.md

Lines changed: 60 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -353,23 +353,22 @@ All session types support `reporting` labels that appear in the BrowserStack Aut
353353

354354
### Session Management
355355

356-
| Tool | Description |
357-
|---------------------|------------------------------------------------------------------------------------------|
358-
| `start_browser` | Start a browser session (Chrome, Firefox, Edge, Safari; headless/headed, custom dimensions) |
359-
| `start_app_session` | Start an iOS or Android app session via Appium (supports state preservation via noReset) |
360-
| `close_session` | Close or detach from the current browser or app session (supports detach mode) |
361-
| `attach_browser` | Attach to a running Chrome instance via `--remote-debugging-port` (CDP) |
362-
| `emulate_device` | Emulate a mobile/tablet device preset (viewport, DPR, UA, touch); requires BiDi session |
356+
| Tool | Description |
357+
|------------------|------------------------------------------------------------------------------------------|
358+
| `start_session` | Start a browser or app session. Use `platform: 'browser'` for web, `platform: 'ios'`/`'android'` for mobile, or `attach: true` to connect to a running Chrome instance |
359+
| `launch_chrome` | Launch a new Chrome instance with remote debugging enabled (for use with `start_session({ attach: true })`) |
360+
| `close_session` | Close or detach from the current session (supports `detach: true` to disconnect without terminating) |
361+
| `emulate_device` | Emulate a mobile/tablet device preset (viewport, DPR, UA, touch); requires BiDi session |
363362

364363
### Navigation & Page Interaction (Web & Mobile)
365364

366-
| Tool | Description |
367-
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
368-
| `navigate` | Navigate to a URL |
369-
| `get_visible_elements` | Get visible, interactable elements on the page. Supports `inViewportOnly` (default: true) to filter viewport elements, and `includeContainers` (default: false) to include layout containers on mobile |
370-
| `get_accessibility` | Get accessibility tree with semantic element information |
371-
| `scroll` | Scroll in a direction (up/down) by specified pixels |
372-
| `take_screenshot` | Capture a screenshot |
365+
| Tool | Description |
366+
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
367+
| `navigate` | Navigate to a URL |
368+
| `get_elements` | Get visible, interactable elements on the page. Supports `inViewportOnly` (default: true) to filter viewport elements, and `includeContainers` (default: false) to include layout containers on mobile |
369+
| `scroll` | Scroll in a direction (up/down) by specified pixels |
370+
| `execute_script` | Execute arbitrary JavaScript in the browser context |
371+
| `switch_tab` | Switch to a different browser tab by index or URL |
373372

374373
### Element Interaction (Web & Mobile)
375374

@@ -382,7 +381,6 @@ All session types support `reporting` labels that appear in the BrowserStack Aut
382381

383382
| Tool | Description |
384383
|------------------|--------------------------------------------------------|
385-
| `get_cookies` | Get all cookies or a specific cookie by name |
386384
| `set_cookie` | Set a cookie with name, value, and optional attributes |
387385
| `delete_cookies` | Delete all cookies or a specific cookie |
388386

@@ -394,27 +392,40 @@ All session types support `reporting` labels that appear in the BrowserStack Aut
394392
| `swipe` | Swipe in a direction (up/down/left/right) |
395393
| `drag_and_drop` | Drag from one location to another |
396394

397-
### App Lifecycle (iOS/Android)
398-
399-
| Tool | Description |
400-
|-----------------|--------------------------------------------------------------|
401-
| `get_app_state` | Check app state (installed, running, background, foreground) |
402-
403395
### Context Switching (Hybrid Apps)
404396

405-
| Tool | Description |
406-
|-----------------------|-------------------------------------------------|
407-
| `get_contexts` | List available contexts (NATIVE_APP, WEBVIEW_*) |
408-
| `get_current_context` | Show the currently active context |
409-
| `switch_context` | Switch between native and webview contexts |
397+
| Tool | Description |
398+
|------------------|-------------------------------------------------|
399+
| `switch_context` | Switch between native and webview contexts |
410400

411401
### Device Control (iOS/Android)
412402

413-
| Tool | Description |
414-
|---------------------------------------|---------------------------------|
415-
| `rotate_device` | Rotate to portrait or landscape |
416-
| `hide_keyboard` | Hide on-screen keyboard |
417-
| `get_geolocation` / `set_geolocation` | Get or set device GPS location |
403+
| Tool | Description |
404+
|-------------------|---------------------------------|
405+
| `rotate_device` | Rotate to portrait or landscape |
406+
| `hide_keyboard` | Hide on-screen keyboard |
407+
| `set_geolocation` | Set device GPS location |
408+
409+
### MCP Resources (read-only, no tool call needed)
410+
411+
| Resource | Description |
412+
|-------------------------------------------|--------------------------------------------------------|
413+
| `wdio://sessions` | Index of all recorded sessions |
414+
| `wdio://session/current/steps` | Step log for the active session |
415+
| `wdio://session/current/code` | Generated runnable WebdriverIO JS for the active session |
416+
| `wdio://session/{id}/steps` | Step log for any past session by ID |
417+
| `wdio://session/{id}/code` | Generated JS for any past session by ID |
418+
| `wdio://session/current/elements` | Interactable elements (viewport-only by default) |
419+
| `wdio://session/current/accessibility` | Accessibility tree |
420+
| `wdio://session/current/screenshot` | Screenshot (base64) |
421+
| `wdio://session/current/cookies` | Browser cookies |
422+
| `wdio://session/current/tabs` | Open browser tabs |
423+
| `wdio://session/current/contexts` | Native/webview contexts (mobile) |
424+
| `wdio://session/current/context` | Currently active context (mobile) |
425+
| `wdio://session/current/app-state` | Mobile app state |
426+
| `wdio://session/current/geolocation` | Device geolocation |
427+
| `wdio://session/current/capabilities` | Resolved WebDriver capabilities for the active session |
428+
| `wdio://browserstack/local-binary` | BrowserStack Local binary download URL and start command |
418429

419430
## Usage Examples
420431

@@ -458,28 +469,26 @@ You are a Testing expert, and want to assess the basic workflows of a web applic
458469
459470
```javascript
460471
// Default settings (headed mode, 1280x1080)
461-
start_browser()
472+
start_session({platform: 'browser'})
462473
463474
// Firefox
464-
start_browser({browser: 'firefox'})
475+
start_session({platform: 'browser', browser: 'firefox'})
465476
466477
// Edge
467-
start_browser({browser: 'edge'})
478+
start_session({platform: 'browser', browser: 'edge'})
468479
469480
// Safari (headed only; requires macOS)
470-
start_browser({browser: 'safari'})
481+
start_session({platform: 'browser', browser: 'safari'})
471482
472483
// Headless mode
473-
start_browser({headless: true})
484+
start_session({platform: 'browser', headless: true})
474485
475486
// Custom dimensions
476-
start_browser({windowWidth: 1920, windowHeight: 1080})
477-
478-
// Headless with custom dimensions
479-
start_browser({headless: true, windowWidth: 1920, windowHeight: 1080})
487+
start_session({platform: 'browser', windowWidth: 1920, windowHeight: 1080})
480488
481489
// Pass custom capabilities (e.g. Chrome extensions, profile, prefs)
482-
start_browser({
490+
start_session({
491+
platform: 'browser',
483492
headless: false,
484493
capabilities: {
485494
'goog:chromeOptions': {
@@ -504,9 +513,9 @@ start_browser({
504513
// google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-debug &
505514
//
506515
// Verify it's ready: curl http://localhost:9222/json/version
507-
attach_browser()
508-
attach_browser({port: 9333})
509-
attach_browser({port: 9222, navigationUrl: 'https://app.example.com'})
516+
start_session({attach: true})
517+
start_session({attach: true, port: 9333})
518+
start_session({attach: true, port: 9222, navigationUrl: 'https://app.example.com'})
510519
```
511520

512521
**Device emulation (requires BiDi session):**
@@ -647,8 +656,8 @@ Control app state when creating new sessions using the `noReset` and `fullReset`
647656

648657
```javascript
649658
// Preserve login state between test runs
650-
start_app_session({
651-
platform: 'Android',
659+
start_session({
660+
platform: 'android',
652661
appPath: '/path/to/app.apk',
653662
deviceName: 'emulator-5554',
654663
noReset: true, // Don't reset app state
@@ -717,10 +726,12 @@ This eliminates the need to manually handle permission popups during automated t
717726
Every tool call is automatically recorded to a session history. You can inspect sessions and export runnable code via MCP resources — no extra tool calls needed:
718727

719728
- `wdio://sessions` — lists all recorded sessions with type, timestamps, and step count
720-
- `wdio://session/current/steps` — step log for the active session, plus a generated WebdriverIO JS script ready to run with `webdriverio`
721-
- `wdio://session/{sessionId}/steps` — same for any past session by ID
729+
- `wdio://session/current/steps` — step log for the active session
730+
- `wdio://session/current/code` — generated runnable WebdriverIO JS for the active session
731+
- `wdio://session/{sessionId}/steps` — step log for any past session by ID
732+
- `wdio://session/{sessionId}/code` — generated JS for any past session by ID
722733

723-
The generated script reconstructs the full session — including capabilities, navigation, clicks, and inputs — as a standalone `import { remote } from 'webdriverio'` file.
734+
The generated script reconstructs the full session — including capabilities, navigation, clicks, and inputs — as a standalone `import { remote } from 'webdriverio'` file. For BrowserStack sessions it includes the full try/catch/finally with automatic session result marking.
724735

725736
## Troubleshooting
726737

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"@toon-format/toon": "^2.1.0",
4949
"@wdio/protocols": "^9.27.0",
5050
"@xmldom/xmldom": "^0.8.12",
51+
"browserstack-local": "^1.5.12",
5152
"puppeteer-core": "^24.40.0",
5253
"sharp": "^0.34.5",
5354
"webdriverio": "^9.27.0",

pnpm-lock.yaml

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)