Vebidor - W3C WebDriver Protocol Implementation
June 3, 2026 ยท View on GitHub
A V language implementation of the W3C WebDriver protocol for browser automation.
Version 5.1.0 | Playwright-style API + WebDriver-BiDi + native iOS/Android + codegen | 100% Selenium parity | Production Ready
โก Modern API (Playwright-style)
Beyond the raw W3C WebDriver methods, Vebidor ships a higher-level ergonomic layer: one-call browser launch, lazy auto-waiting Locators, semantic selector engines, and retrying web-first assertions.
import vebidor.webdriver
fn main() {
// Auto-detects the driver + browser, picks a free port, and tears
// everything down on close(). No manual "start chromedriver" step.
mut b := webdriver.launch_edge(webdriver.LaunchOptions{ headless: true })!
defer { b.close() }
b.goto('https://example.com')!
// Locators are lazy and auto-wait for the element to be actionable.
b.wd.get_by_role('link', 'More information...').click()!
// Web-first assertions poll until the condition holds (or time out).
webdriver.expect(b.wd.get_by_role('heading', '')).to_be_visible()!
}
Selector engines: get_by_role, get_by_text, get_by_label,
get_by_placeholder, get_by_test_id, plus wd.locator('css=...' | 'xpath=...')
with chaining (row.locator('td')) and nth(i) / first().
Auto-waiting actions: click, fill, type_text, clear wait for the
element to be attached, visible, enabled, and scrolled into view.
Assertions: to_be_visible / to_be_hidden / to_be_enabled /
to_be_disabled, to_have_text / to_contain_text / to_have_value /
to_have_attribute / to_have_count, each invertible via .not() and tunable
via .with_timeout(ms).
WebDriver-BiDi (bidirectional)
Launch with bidi: true to get a persistent WebSocket alongside the Classic
session, unlocking event-driven features Classic cannot offer โ network
interception/mocking, console/network listeners, isolated contexts, and more.
mut b := webdriver.launch_edge(webdriver.LaunchOptions{ headless: true, bidi: true })!
defer { b.close() }
mut bidi := b.bidi()!
defer { bidi.close() }
ctx := bidi.first_context()!
// Mock a response (Playwright route.fulfill style).
bidi.route(fn (req webdriver.InterceptedRequest) {
if req.url.contains('/api') {
req.fulfill(200, 'application/json', '{"mocked":true}') or {}
} else {
req.continue_request() or {}
}
})!
bidi.add_preload_script('() => { window.__patched = true }')! // runs before page scripts
bidi.navigate(ctx, 'https://example.com')!
bidi.on_log(fn (e webdriver.LogEntry) { println('${e.level}: ${e.text}') })!
BiDi capabilities: request/response interception + mocking (route,
route_response, fulfill/abort/continue), HTTP auth (on_auth),
console/network events (on_log/on_request/on_response), wait_for_event,
isolated user contexts (with per-context proxy, geolocation,
permissions, and storageState session reuse), preload scripts +
call_function, viewport emulation, partition-aware cookies
(get_cookies(user_context: uc)) + on_cookie_changed, screenshots/PDF, file
upload (set_files), and a Tracer. Capability probing via status() /
supports(). Any unwrapped command/event is reachable via send/on (or
on_sync for inline observers).
Mobile emulation (Playwright-style): device presets
(emulate_device(ctx, 'iPhone 14'), 9 built-in), emulate() for viewport/DPR/UA/
touch flags, Locator.tap(), set_request_user_agent (server-side UA), and
set_locale/set_timezone/set_screen_orientation. (Real touch-event dispatch
needs a CDP/mobileEmulation capability BiDi doesn't expose; touch detection is
emulated.)
See COMPARISON_WITH_PLAYWRIGHT.md for the full Playwright/Selenium feature mapping.
๐ Features
โ Fully Implemented (100% Coverage) ๐
Core Features:
- Modern API - One-call
launch(), lazy auto-waiting Locators, selector engines, and web-first assertions (see โก Modern API) - WebDriver-BiDi - Bidirectional WebSocket transport: network interception/mocking, console/network events, isolated contexts, preload scripts, file upload, tracing
- Session Management - Create, manage, and quit browser sessions
- Navigation - Navigate, back, forward, refresh
- Element Location - Find elements by CSS selector, XPath, ID, class name, tag name, link text
- Element Interaction - Click, send keys, clear, submit forms โ 100% Complete
- JavaScript Execution - Execute synchronous and asynchronous scripts โ 100% Complete
- Cookies - Get, add, delete, clear all cookies
- Screenshots - Capture page and element screenshots (base64)
- Frame Switching - Switch between frames, iframes, and parent frame
- Actions API - Complete keyboard, mouse, wheel, drag-and-drop โ 100% Complete
Phase 1 & 5 - Element Properties โจ โ 100% Complete:
- Get element text, attributes, and DOM properties
- Check visibility (
is_displayed), enabled state (is_enabled), selection state (is_selected) - Get tag names, clear input fields
- Get computed CSS property values (
get_css_value) - colors, fonts, dimensions, spacing
Phase 2 - Alert Handling โจ:
- Accept and dismiss alert/confirm/prompt dialogs
- Read alert text messages
- Send text input to prompt dialogs
Phase 3 - Page Information โจ:
- Get page title and current URL
- Get complete HTML page source
- Navigation verification
Phase 4 - Window & Waits โจ:
- Switch between windows and tabs
- Create new windows/tabs
- Maximize, minimize, and fullscreen windows
- Implicit waits for auto-waiting elements
- Configurable page load and script timeouts
Phase 6 - Expected Conditions โจ:
- Wait for elements to be clickable, visible, or present
- Wait for specific text in elements
- Get current timeout configuration
- Robust wait patterns with 500ms polling
Phase 7 - Advanced Actions โจ:
- Context click (right-click) on elements
- Click and hold + release for drag operations
- Drag and drop to element or by pixel offset
- Get element position and size (rect)
- Submit forms easily
Phase 8 - Async JS & Shadow DOM โจ โ 100% Complete:
- Execute asynchronous JavaScript with callbacks
- Support for setTimeout, Promises, async/await patterns
- Access Shadow DOM roots
- Find elements within Shadow DOM
- Test modern web components (Lit, Stencil, etc.)
Edge-Specific:
- Network condition simulation
- Device emulation
- Browser version detection
๐ฆ Installation
Prerequisites
- V compiler installed
- A supported browser (Edge, Chrome, Firefox, or Safari)
- Matching WebDriver:
- Edge: EdgeDriver (port 9515)
- Chrome: ChromeDriver (port 9515)
- Firefox: GeckoDriver (port 4444)
- Safari: Built-in SafariDriver on macOS (port 4445)
Install the module
The fastest way to get vebidor onto V's module path:
v install vebidor
This pulls the module so import vebidor.webdriver and import vebidor.mobile
resolve from anywhere. To track main instead of a published release, clone and
symlink the checkout:
git clone https://github.com/quaesitor-scientiam/vebidor.git
cd vebidor
mkdir -p ~/.vmodules
ln -s "$(pwd)" ~/.vmodules/vebidor
# (Alternatively: `v install` from this directory.)
Quick Setup
Tip: With the Modern API
launch(), you can skip the manual driver-start step below โ Vebidor finds the driver onPATH(or viaEDGEDRIVER/CHROMEDRIVER/GECKODRIVER), starts it on a free port, and stops it for you. The steps below are for the classicnew_*_driver(url, caps)flow that connects to a driver you started yourself.
# Start your browser's WebDriver
# Edge/Chrome:
.\msedgedriver.exe --port=9515 # or chromedriver.exe
# Firefox:
.\geckodriver.exe --port=4444
# Safari (macOS):
safaridriver --enable
safaridriver -p 4445
Need help? See TEST_ENVIRONMENT_SETUP.md for detailed setup instructions.
๐ฏ Quick Start
Microsoft Edge
import vebidor.webdriver
fn main() {
caps := webdriver.Capabilities{
browser_name: 'msedge'
edge_options: webdriver.EdgeOptions{
args: ['--headless=new']
binary: r'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
}
}
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
title := wd.get_title()!
println('Page title: ${title}')
}
Google Chrome
import vebidor.webdriver
fn main() {
caps := webdriver.Capabilities{
browser_name: 'chrome'
chrome_options: webdriver.ChromeOptions{
args: ['--headless=new', '--disable-gpu']
binary: r'C:\Program Files\Google\Chrome\Application\chrome.exe'
}
}
wd := webdriver.new_chrome_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
println('Chrome automation working!')
}
Mozilla Firefox
import vebidor.webdriver
fn main() {
caps := webdriver.Capabilities{
browser_name: 'firefox'
firefox_options: webdriver.FirefoxOptions{
args: ['-headless']
binary: r'C:\Program Files\Mozilla Firefox\firefox.exe'
}
}
wd := webdriver.new_firefox_driver('http://127.0.0.1:4444', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
println('Firefox automation working!')
}
Safari (macOS)
import vebidor.webdriver
fn main() {
caps := webdriver.Capabilities{
browser_name: 'safari'
safari_options: webdriver.SafariOptions{
automatic_inspection: false
automatic_profiling: false
}
}
wd := webdriver.new_safari_driver('http://127.0.0.1:4445', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
println('Safari automation working!')
}
๐ Comprehensive Examples
Complete Automation Example (All Phases)
import vebidor.webdriver
fn main() {
caps := webdriver.Capabilities{
browser_name: 'msedge'
edge_options: webdriver.EdgeOptions{
args: ['--headless=new']
}
}
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
// Set timeouts (Phase 4)
wd.set_implicit_wait(10000)!
wd.set_page_load_timeout(30000)!
// Navigate and get page info (Phase 3)
wd.get('https://example.com')!
title := wd.get_title()!
url := wd.get_current_url()!
println('Page: ${title} at ${url}')
// Element properties (Phase 1)
heading := wd.find_element('css selector', 'h1')!
text := wd.get_text(heading)!
tag := wd.get_tag_name(heading)!
visible := wd.is_displayed(heading)!
println('Found <${tag}>: "${text}" (visible: ${visible})')
// Handle alerts (Phase 2)
wd.execute_script('alert("Test")', [])!
alert_text := wd.get_alert_text()!
println('Alert says: ${alert_text}')
wd.accept_alert()!
// Multi-window (Phase 4)
new_tab := wd.new_window('tab')!
wd.switch_to_window(new_tab.handle)!
wd.get('https://www.iana.org')!
wd.maximize_window()!
}
Form Automation
import vebidor.webdriver
fn login_example() ! {
caps := webdriver.Capabilities{
browser_name: 'msedge'
}
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com/login')!
// Find form elements
username := wd.find_element('css selector', '#username')!
password := wd.find_element('css selector', '#password')!
submit := wd.find_element('css selector', 'button[type="submit"]')!
// Fill the form
wd.send_keys(username, 'testuser')!
wd.send_keys(password, 'password123')!
wd.click(submit)!
}
Working with Cookies
import vebidor.webdriver
fn cookie_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
// Add a cookie
cookie := webdriver.Cookie{
name: 'session_id'
value: 'abc123'
path: '/'
domain: 'example.com'
}
wd.add_cookie(cookie)!
// Get all cookies
cookies := wd.get_cookies()!
println('Cookies: ${cookies.len}')
// Delete a cookie
wd.delete_cookie('session_id')!
}
Using Actions API
import vebidor.webdriver
fn actions_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
// Type text using actions
wd.type_text('Hello World')!
// Scroll down
wd.scroll_by(0, 500)!
// Click at coordinates
wd.click_at(100, 200)!
}
Element Properties (Phase 1)
import vebidor.webdriver
fn element_properties_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
link := wd.find_element('css selector', 'a')!
// Get element properties
text := wd.get_text(link)! // Visible text
href := wd.get_attribute(link, 'href')! // HTML attribute
tag := wd.get_tag_name(link)! // Tag name
// Check element state
visible := wd.is_displayed(link)!
enabled := wd.is_enabled(link)!
println('Link: ${text} -> ${href}')
println('Visible: ${visible}, Enabled: ${enabled}')
}
Alert Handling (Phase 2)
import vebidor.webdriver
fn alert_handling_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
// Handle alert
wd.execute_script('alert("Hello!")', [])!
text := wd.get_alert_text()!
println('Alert: ${text}')
wd.accept_alert()!
// Handle prompt
wd.execute_script('window.name = prompt("Your name?")', [])!
wd.send_alert_text('Claude')!
wd.accept_alert()!
}
Page Information (Phase 3)
import vebidor.webdriver
fn page_info_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
// Get page metadata
title := wd.get_title()!
url := wd.get_current_url()!
source := wd.get_page_source()!
println('Title: ${title}')
println('URL: ${url}')
println('HTML length: ${source.len} bytes')
// Verify navigation
assert title == 'Example Domain'
assert url == 'https://example.com/'
}
Multi-Window Management (Phase 4)
import vebidor.webdriver
fn multi_window_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
wd.get('https://example.com')!
// Get current window
main_window := wd.get_window_handle()!
// Create new tab
new_tab := wd.new_window('tab')!
wd.switch_to_window(new_tab.handle)!
// Navigate in new tab
wd.get('https://www.iana.org')!
new_title := wd.get_title()!
// Switch back to main window
wd.switch_to_window(main_window)!
// Window state management
wd.maximize_window()!
wd.fullscreen_window()!
}
Timeouts and Waits (Phase 4)
import vebidor.webdriver
fn timeouts_example() ! {
caps := webdriver.Capabilities{ browser_name: 'msedge' }
wd := webdriver.new_edge_driver('http://127.0.0.1:9515', caps)!
defer { wd.quit() or {} }
// Configure timeouts
wd.set_implicit_wait(10000)! // Auto-wait 10s for elements
wd.set_page_load_timeout(30000)! // 30s page load timeout
wd.set_script_timeout(15000)! // 15s script timeout
wd.get('https://example.com')!
// Now element finding automatically waits
element := wd.find_element('css selector', 'h1')!
// Custom wait condition
wd.wait_for(fn (wd webdriver.WebDriver) !bool {
title := wd.get_title()!
return title.len > 0
}, 5000, 500)!
}
๐งช Testing
Run Quick Tests (~10 seconds)
v test webdriver/quick_test.v
Run Full Test Suite (~1-2 minutes)
v test webdriver/
Run Integration Tests (~2-3 minutes)
v run integration_test.v
Run Simple Standalone Test
v simple_test.v
.\simple_test.exe
๐ Latency Benchmark
examples/webdriver_latency_bench.v measures round-trip latency for common WebDriver commands (get_title, get_current_url, execute_script) and reports min/avg/p50/p95/p99/max in milliseconds.
Prerequisites: a WebDriver must already be running before launching the benchmark.
# Default (stdlib net.http)
v run examples/webdriver_latency_bench.v
# Raw TCP transport (opt-in, avoids keep-alive stall)
v -d wd_use_raw_tcp run examples/webdriver_latency_bench.v
Options:
| Flag | Default | Description |
|---|---|---|
--browser=edge|chrome|firefox|safari | edge | Browser to use |
--driver=URL | http://127.0.0.1:9515 | WebDriver URL |
--iters=N | 200 | Number of timed iterations |
--warmup=N | 20 | Warmup iterations (not measured) |
--binary=PATH | (env var) | Path to browser executable |
--headless / --headed | headless | Run browser headlessly or not |
Example output:
Command: get_title
count: 200 min: 2.007 ms avg: 2.460 ms p50: 2.344 ms p95: 3.045 ms p99: 4.023 ms max: 4.545 ms
๐ฑ Native Mobile (iOS + Android)
Beyond browser automation, Vebidor ships a native mobile module
(vebidor.mobile) that drives real apps on iOS and Android โ by
talking directly to WebDriverAgent (iOS) and the UiAutomator2 server
(Android), the same on-device backends Appium uses, but with no Node
middleware.
import vebidor.mobile
mut s := mobile.launch_android(mobile.AndroidOptions{
mode: .spawn
udid: 'emulator-5554'
app_package: 'com.android.settings'
app_activity: '.Settings'
uia2_server_apk: server_apk
uia2_server_test_apk: test_apk
})!
defer { s.close() }
// Same Playwright-style surface as the web module:
mobile.expect(s.get_by_text('Battery')).to_be_visible()!
s.get_by_label('Battery').tap()!
s.set_orientation(.landscape)!
One API, two backends. Cross-platform get_by_label/text/test_id/role
selectors, lazy auto-waiting locators, expect() assertions, touch
gestures, app lifecycle, and device state (orientation, lock, geolocation,
network) โ all sharing the web module's transport and polling engine. The
Android path is verified live on an emulator; iOS on a Simulator.
See COMPARISON_WITH_APPIUM.md for the Appium feature mapping and MOBILE_TESTING.md for setup.
๐ Documentation
- COMPARISON.md - Four-way at-a-glance: vebidor vs Selenium, Playwright & Appium
- COMPARISON_WITH_SELENIUM.md - Feature comparison with Selenium
- COMPARISON_WITH_PLAYWRIGHT.md - Comparison with Playwright & roadmap
- COMPARISON_WITH_APPIUM.md - Native mobile vs Appium
- TESTING.md - Testing guide (web)
- MOBILE_TESTING.md - Mobile setup guide (iOS Simulator + Android Emulator)
- MOBILE_PLAN.md - Mobile module architecture & phase status
- TEST_ENVIRONMENT_SETUP.md - Test environment setup
- CHANGELOG.md - Change history
๐ฏ Feature Coverage
Current: ๐ 100% feature parity with Selenium WebDriver! ๐ ALL Phases Complete! ๐
| Category | Status |
|---|---|
| Session Management | โ 100% |
| Navigation | โ 100% |
| Element Location | โ 100% |
| Cookies | โ 100% |
| Screenshots | โ 100% |
| Frames | โ 100% |
| Element Properties | โ 100% (Phase 1, 5 & 7) |
| Alerts | โ 100% (Phase 2) |
| Page Information | โ 100% (Phase 3) |
| Window Management | โ 100% (Phase 4) |
| Timeouts & Waits | โ 100% (Phase 4 & 6) |
| Actions API | โ 100% (Phase 7) |
| Element Interaction | โ 100% (Phase 7) |
| JavaScript Execution | โ 100% (Phase 8) โจ NEW |
| Shadow DOM | โ 100% (Phase 8) โจ NEW |
๐ 100% FEATURE PARITY ACHIEVED! ๐
See COMPARISON_WITH_PLAYWRIGHT.md for the full Playwright/Selenium feature mapping.
โจ What's New in v5.1.0
๐ฌ Codegen / session recorder โ record a live session and emit runnable
vebidor source via tools/codegen.v. Web capture runs over
WebDriver-BiDi; native mobile capture is new โ Android is passive (taps read
from adb getevent, hit-tested against the live accessibility tree), iOS is an
assisted REPL. Both synthesize semantic get_by_* locators rather than brittle
coordinates. Verified live on the Android emulator (5/5 synthesized selectors
re-resolved on-device). See CODEGEN_HANDOFF.md.
โจ What's New in v5.0.0
๐ฑ Native mobile automation โ a new vebidor.mobile module that drives
real apps on iOS (via WebDriverAgent) and Android (via the UiAutomator2 server)
directly over their HTTP sockets โ the same backends Appium uses, with no Node middleware.
Sibling to vebidor.webdriver; shares its HttpTransport, lazy auto-waiting locator, and
poll_until_true assertion engine.
- โ
One-call launch โ
launch_ios(.simulator)/launch_android(.spawn)boot the Simulator/emulator, spawn the backend, port-forward, poll readiness, and tear it all down onclose() - โ
Cross-platform selectors โ
get_by_role/get_by_label/get_by_text/get_by_test_idcompile to XCUITest predicates (iOS) and UiAutomator selectors (Android) - โ
Auto-waiting actions + W3C-actions gestures โ
tap/fill/swipe_*/long_press/drag_to/scroll_into_view - โ
Web-first assertions โ
mobile.expect(loc).to_be_visible()with.not()/.with_timeout() - โ
App lifecycle + device state โ
activate_app/terminate_app/query_app_state,lock/unlock,set_orientation,set_geolocation,set_network_condition - ๐ See COMPARISON_WITH_APPIUM.md and MOBILE_TESTING.md
Verified live: full Android path on an Android Emulator (Pixel AVD, API 34); iOS sessions, selectors, assertions, and gestures on an iOS Simulator.
โจ What's New in v4.2.0
๐ฑ Playwright-style mobile-web emulation (over WebDriver-BiDi):
- โ
Device presets โ
emulate_device(ctx, 'iPhone 14')(9 built-in: iPhone, Pixel, Galaxy, iPad) - โ
emulate()โ viewport + DPR + JS-visible UA +isMobile/hasTouch - โ
Locator.tap()(touch pointer) - โ
set_request_user_agentโ server-side UA (HTTP header rewrite) - โ
set_locale/set_timezone/set_screen_orientation - โ ๏ธ Real touch-event dispatch needs a CDP/
mobileEmulationcapability BiDi doesn't expose (touch detection is emulated;tapsynthesizes a click)
(v4.1.0: per-context conveniences + capability probing; v4.0.1: partition-aware cookies + inline dispatch โ see CHANGELOG.)
โจ What's New in v4.0.0
๐ญ Playwright-style API + WebDriver-BiDi โ verified live against headless Edge
- โ
Locators: lazy, auto-waiting, chainable, staleness-immune (
get_by_role/text/label/placeholder/test_id,nth/first) - โ
Web-first assertions:
expect(loc).to_be_visible()etc., polling,.not()/.with_timeout() - โ
launch(): auto-detect driver+browser, free port, teardown โ no manual driver start - โ WebDriver-BiDi transport: persistent WebSocket coexisting with the Classic session
- โ
Network interception/mocking:
route/route_response,fulfill/abort/continue,on_auth - โ
Events: console/network listeners,
wait_for_event,on_cookie_changed - โ
Isolated user contexts, preload scripts,
call_function, viewport emulation - โ
File upload (
set_files), BiDi cookies, screenshots/PDF,Tracer - ๐ Fixed: W3C screenshot endpoints now use GET (were POST)
vebidor now offers Playwright-style ergonomics and WebDriver-BiDi coverage that meets or exceeds Selenium's, on a native V API. See COMPARISON_WITH_PLAYWRIGHT.md.
โจ What's New in v3.1.1
๐ Multi-Browser Bug Fixes - All 4 browsers now fully functional!
- โ
v3.1.1: Fixed compile error (
new_session()helper), Safari W3C JSON tags, movednew_edge_driver()toedge.v, standardized parameter names - โ v3.1.0: Added Chrome, Firefox, and Safari browser support alongside Edge
- โ
v3.0.1: Added
find_edge_binaryhelper for automatic Edge binary detection - โ v3.0.0: Phase 8 Complete - 100% Feature Parity with Selenium achieved!
Total: 40 methods added across all phases, raising feature parity from 55% to 100%! ๐
๐ 100% FEATURE PARITY WITH SELENIUM WEBDRIVER ACHIEVED! ๐
See individual phase documentation for detailed examples and usage.
๐๏ธ Project Structure
v-webdriver/
โโโ webdriver/
โ โโโ client.v # Core WebDriver client + Transport seam
โ โโโ elements.v # Element finding and interaction
โ โโโ locator.v # Lazy auto-waiting Locator
โ โโโ selectors.v # get_by_* selector engines
โ โโโ assertions.v # Web-first expect() assertions
โ โโโ launcher.v # launch(): driver/browser lifecycle
โ โโโ fixtures.v # v test fixtures (with_browser, etc.)
โ โโโ script.v # JavaScript execution
โ โโโ window.v # Window management
โ โโโ cookies.v # Cookie operations (Classic)
โ โโโ screenshot.v # Screenshot capture
โ โโโ actions.v # Actions API
โ โโโ frame.v # Frame switching
โ โโโ wait.v # Wait utilities
โ โโโ capabiities.v # Capabilities configuration
โ โโโ types.v # Common types
โ โโโ errors.v # Error handling
โ โโโ bidi.v # WebDriver-BiDi transport (WebSocket)
โ โโโ bidi_modules.v # BiDi browsingContext/script/log helpers
โ โโโ bidi_network.v # BiDi network interception/mocking + auth
โ โโโ bidi_context.v # BiDi user contexts, viewport, PDF, history
โ โโโ bidi_script.v # BiDi preload scripts + call_function
โ โโโ bidi_storage.v # BiDi cookies + cookieChanged
โ โโโ bidi_screenshot.v # BiDi per-context screenshots
โ โโโ bidi_dom.v # BiDi node handles + setFiles (upload)
โ โโโ bidi_trace.v # Lightweight Tracer
โ โโโ webdriver_test.v # Unit tests
โ โโโ quick_test.v # Quick smoke tests
โโโ examples/
โ โโโ webdriver_latency_bench.v # Latency benchmark tool
โโโ integration_test.v # Integration tests
โโโ README.md # This file
๐ Multi-Browser Support
Vebidor now supports 4 major browsers:
| Browser | Driver | Default Port | Function |
|---|---|---|---|
| Edge | EdgeDriver | 9515 | new_edge_driver() |
| Chrome | ChromeDriver | 9515 | new_chrome_driver() |
| Firefox | GeckoDriver | 4444 | new_firefox_driver() |
| Safari | SafariDriver | 4445 | new_safari_driver() |
Browser-Specific Options
EdgeOptions / ChromeOptions:
edge_options: webdriver.EdgeOptions{
args: ['--headless=new', '--disable-gpu', '--no-sandbox']
binary: r'C:\Program Files\...\browser.exe'
extensions: ['extension1.crx', 'extension2.crx']
}
FirefoxOptions:
firefox_options: webdriver.FirefoxOptions{
args: ['-headless', '-private']
binary: r'C:\Program Files\Mozilla Firefox\firefox.exe'
prefs: {
'browser.download.folderList': json.Any(2)
'browser.download.dir': json.Any('/tmp/downloads')
}
profile: '/path/to/firefox/profile'
}
SafariOptions:
safari_options: webdriver.SafariOptions{
automatic_inspection: false // Disable Web Inspector auto-open
automatic_profiling: false // Disable profiling auto-start
}
All browsers support standard W3C capabilities like accept_insecure_certs, page_load_strategy, timeouts, and proxy settings.
๐ค Contributing
Contributions are welcome! Now that 100% feature parity is achieved, focus areas include:
- Browser Testing - Help test Chrome, Firefox, Safari drivers on different platforms
- Performance Optimizations - Connection pooling, parallel execution
- Advanced Features - BiDi protocol support, enhanced logging
- Platform Support - macOS, Linux testing and optimization
Vebidor has achieved 100% feature parity with Selenium's core functionality!
๐ License
[Your License Here]
๐ Acknowledgments
- Built following the W3C WebDriver Specification
- Inspired by Selenium WebDriver
- Powered by the V Programming Language
๐ Support
For issues, questions, or contributions:
- Open an issue on GitHub
- Check existing documentation
- Review test files for usage examples
Status: Production-ready for web automation (Playwright-style API + WebDriver-BiDi on top of 100% Selenium parity) and native mobile automation (iOS via WebDriverAgent + Android via UiAutomator2). ๐
Version: 5.1.0 (adds a codegen recorder for web + native mobile โ emits semantic get_by_* locators; on top of v5.0.0's vebidor.mobile and the unchanged web stack: Playwright-style Locators/assertions, launch(), WebDriver-BiDi, mobile emulation, 4-browser support)
Selenium-parity phases: โ Phase 1 | โ Phase 2 | โ Phase 3 | โ Phase 4 | โ Phase 5 | โ Phase 6 | โ Phase 7 | โ Phase 8
Playwright-parity roadmap: โ Phase 0 (transport seam) | โ Phase 1 (locators/assertions) | โ Phase 2 (launch) | โ Phase 3 (BiDi transport) | โ Phase 4 (BiDi features) | โ Phase 5 (tooling) | โ BiDi gap closure vs Selenium
Latest Update: 2026-06-03 - v5.1.0 codegen recorder for web + native mobile (a11y-tree โ semantic get_by_* locators; mobile capture verified live on the Android emulator)