- Add VibiumClientImpl wrapper for browser automation via WebDriver BiDi - Integrate axe-core for real accessibility testing in browser context - Add multi-viewport screenshot capture service - Implement visual regression testing with baseline comparison - Create E2E test runner service with user flow generation - Add real integration tests (no mocks) with CI environment detection - Update visual-accessibility domain with browser mode support - Add npm script test:integration:browser for real browser tests - Bump version to 3.0.0-alpha.32 Key files: - src/integrations/vibium/client.ts - Browser automation client - src/domains/visual-accessibility/services/axe-core-integration.ts - src/domains/test-execution/services/e2e-runner.ts - tests/integrations/vibium/vibium-real.test.ts - NO MOCKS tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
21 KiB
Vibium JavaScript Client API Reference
Version: 1.0.0 Source Analysis Date: 2026-01-19
This document provides a comprehensive API reference for the Vibium JavaScript client library, generated from source code analysis of the official implementation.
Table of Contents
- Browser Launch API
- Navigation API
- Element Location API
- Element Interaction API
- Element Properties API
- Screenshot API
- Script Execution API
- Session Management API
- Error Types
- Auto-Wait Behavior
- TypeScript Types
Browser Launch API
browser.launch(options?: LaunchOptions): Promise<Vibe>
Launches a new browser instance and returns a Vibe controller.
Parameters:
interface LaunchOptions {
headless?: boolean; // Run browser in headless mode (default: false)
port?: number; // WebSocket port for BiDi connection (default: auto-assigned)
executablePath?: string; // Path to browser executable (default: bundled Chromium)
}
Returns: Promise<Vibe> - Browser controller instance
Example:
import { browser } from '@vibium/client';
// Launch in headed mode
const vibe = await browser.launch();
// Launch in headless mode
const vibe = await browser.launch({ headless: true });
// Use custom browser executable
const vibe = await browser.launch({
executablePath: '/usr/bin/chromium'
});
Implementation Details:
- Starts a "clicker" process that manages the browser
- Establishes WebSocket connection via BiDi protocol
- Automatically creates browsing context
- Connection URL:
ws://localhost:{port}
Navigation API
vibe.go(url: string): Promise<void>
Navigates to the specified URL and waits for the page to load completely.
Parameters:
url(string) - The URL to navigate to
Returns: Promise<void>
Wait Strategy: Waits for document load state complete (DOMContentLoaded + all resources loaded)
Example:
await vibe.go('https://example.com');
await vibe.go('https://example.com/login');
Implementation:
- Uses BiDi command:
browsingContext.navigate - Wait parameter:
'complete' - Blocks until navigation fully completes
Note: The current implementation does NOT include back(), forward(), or refresh() methods. These can be implemented using the BiDi client's browsingContext.traverseHistory command.
Element Location API
vibe.find(selector: string, options?: FindOptions): Promise<Element>
Locates an element by CSS selector and waits for it to exist.
Parameters:
interface FindOptions {
timeout?: number; // Timeout in milliseconds (default: 30000)
}
selector(string) - CSS selector to locate elementoptions(FindOptions) - Optional configuration
Returns: Promise<Element> - Element handle with interaction methods
Throws:
TimeoutError- If element not found within timeoutElementNotFoundError- If selector matches no elements
Example:
// Find with default timeout (30s)
const button = await vibe.find('button.submit');
// Find with custom timeout (10s)
const input = await vibe.find('input[name="email"]', { timeout: 10000 });
Implementation:
- Uses custom BiDi command:
vibium:find - Server-side waits for element existence
- Returns element metadata: tag, text, bounding box
Note: The current implementation does NOT include a findAll() method for locating multiple elements.
Element Interaction API
element.click(options?: ActionOptions): Promise<void>
Clicks the element after verifying actionability.
Parameters:
interface ActionOptions {
timeout?: number; // Timeout for actionability checks (default: 30000ms)
}
Returns: Promise<void>
Actionability Checks:
- Element is visible
- Element is stable (not animating)
- Element can receive pointer events (not obscured)
- Element is enabled (not disabled)
Throws:
TimeoutError- If element not actionable within timeoutElementNotFoundError- If element no longer exists
Example:
const button = await vibe.find('button.submit');
await button.click();
// With custom timeout
await button.click({ timeout: 5000 });
Implementation:
- Uses custom BiDi command:
vibium:click - Server performs all actionability checks
- Simulates realistic click at element center
element.type(text: string, options?: ActionOptions): Promise<void>
Types text into the element after verifying actionability.
Parameters:
text(string) - Text to type into elementoptions(ActionOptions) - Optional timeout configuration
Returns: Promise<void>
Actionability Checks:
- Element is visible
- Element is stable (not animating)
- Element can receive pointer events
- Element is enabled
- Element is editable (input, textarea, contenteditable)
Throws:
TimeoutError- If element not actionable within timeoutElementNotFoundError- If element no longer exists
Example:
const input = await vibe.find('input[type="email"]');
await input.type('user@example.com');
const textarea = await vibe.find('textarea');
await textarea.type('Multi-line\ntext content');
Implementation:
- Uses custom BiDi command:
vibium:type - Server performs actionability checks
- Focuses element before typing
- Simulates realistic keyboard events
Note: The current implementation does NOT include a clear() method. To clear an input, you would need to:
- Get current value via
getAttribute('value') - Send backspace keystrokes
- Or use
evaluate()to set value to empty string
Element Properties API
element.text(): Promise<string>
Retrieves the visible text content of the element.
Returns: Promise<string> - Trimmed text content
Throws:
ElementNotFoundError- If element no longer exists
Example:
const heading = await vibe.find('h1');
const text = await heading.text();
console.log(text); // "Welcome to Our Site"
Implementation:
- Uses BiDi
script.callFunctionto execute:el.textContent.trim() - Returns empty string if element has no text
element.getAttribute(name: string): Promise<string | null>
Retrieves the value of an element attribute.
Parameters:
name(string) - Attribute name to retrieve
Returns: Promise<string | null> - Attribute value or null if not present
Example:
const link = await vibe.find('a.external');
const href = await link.getAttribute('href');
const target = await link.getAttribute('target');
const input = await vibe.find('input[type="checkbox"]');
const checked = await input.getAttribute('checked');
Implementation:
- Uses BiDi
script.callFunctionto execute:el.getAttribute(name) - Returns
nullif attribute doesn't exist
element.boundingBox(): Promise<BoundingBox>
Retrieves the element's bounding box (position and dimensions).
Returns:
interface BoundingBox {
x: number; // X coordinate (viewport-relative)
y: number; // Y coordinate (viewport-relative)
width: number; // Element width in pixels
height: number; // Element height in pixels
}
Throws:
ElementNotFoundError- If element no longer exists
Example:
const button = await vibe.find('button.submit');
const box = await button.boundingBox();
console.log(box);
// { x: 100, y: 200, width: 120, height: 40 }
Implementation:
- Uses BiDi
script.callFunctionto execute:el.getBoundingClientRect() - Coordinates are viewport-relative (not page-relative)
element.info: ElementInfo (readonly)
Cached element information captured at find time.
Type:
interface ElementInfo {
tag: string; // HTML tag name (e.g., "button", "input")
text: string; // Text content at find time
box: BoundingBox; // Bounding box at find time
}
Example:
const button = await vibe.find('button.submit');
console.log(button.info.tag); // "button"
console.log(button.info.text); // "Submit"
console.log(button.info.box); // { x: 100, y: 200, width: 120, height: 40 }
Note: This is a snapshot from when the element was located. Use methods like text() and boundingBox() to get current values.
Screenshot API
vibe.screenshot(): Promise<Buffer>
Captures a screenshot of the current viewport.
Returns: Promise<Buffer> - PNG image data as Buffer
Example:
import { writeFile } from 'fs/promises';
const screenshot = await vibe.screenshot();
await writeFile('screenshot.png', screenshot);
Implementation:
- Uses BiDi command:
browsingContext.captureScreenshot - Returns viewport screenshot (not full page)
- Format: PNG encoded as base64, decoded to Buffer
Note: The current implementation only supports viewport screenshots. Full page screenshots would require:
- Calculating total page height
- Scrolling and capturing multiple viewports
- Stitching images together
Saving Options:
- To file: Use Node.js
fs.writeFile()with Buffer - To base64: Use
screenshot.toString('base64')
Script Execution API
vibe.evaluate<T>(script: string): Promise<T>
Executes JavaScript code in the page context.
Parameters:
script(string) - JavaScript code to execute
Type Parameter:
T- Expected return type (default:unknown)
Returns: Promise<T> - Result of script execution
Example:
// Get page title
const title = await vibe.evaluate<string>('return document.title');
// Get multiple values
const pageInfo = await vibe.evaluate<{ url: string; title: string }>(`
return {
url: window.location.href,
title: document.title
};
`);
// Modify page state
await vibe.evaluate<void>(`
document.body.style.backgroundColor = 'red';
`);
Implementation:
- Uses BiDi command:
script.callFunction - Wraps script in anonymous function:
() => { ${script} } - Awaits promises automatically (
awaitPromise: true) - Supports returning serializable values
Limitations:
- Cannot return DOM elements or functions
- Must return JSON-serializable data
- No access to Node.js environment
Session Management API
vibe.quit(): Promise<void>
Closes the browser connection and terminates the browser process.
Returns: Promise<void>
Example:
const vibe = await browser.launch();
try {
await vibe.go('https://example.com');
// ... perform actions
} finally {
await vibe.quit();
}
Implementation:
- Closes BiDi WebSocket connection
- Stops the clicker process
- Rejects all pending commands with
ConnectionError
Best Practice: Always call quit() in a finally block to ensure cleanup.
Error Types
All error classes are exported from the main package and extend the standard Error class.
ConnectionError
Thrown when connecting to the browser fails.
class ConnectionError extends Error {
url: string; // WebSocket URL that failed
cause?: Error; // Underlying error
}
When Thrown:
- WebSocket connection refused
- Browser process failed to start
- Invalid WebSocket URL
Example:
import { ConnectionError } from '@vibium/client';
try {
const vibe = await browser.launch({ port: 9999 });
} catch (err) {
if (err instanceof ConnectionError) {
console.error(`Failed to connect to ${err.url}`);
console.error(`Cause: ${err.cause?.message}`);
}
}
TimeoutError
Thrown when a wait operation exceeds the timeout.
class TimeoutError extends Error {
selector: string; // CSS selector that timed out
timeout: number; // Timeout duration in ms
reason?: string; // Why the wait failed
}
When Thrown:
find()- Element not found within timeoutclick()- Element not actionable within timeouttype()- Element not actionable within timeout
Example:
import { TimeoutError } from '@vibium/client';
try {
await vibe.find('button.submit', { timeout: 5000 });
} catch (err) {
if (err instanceof TimeoutError) {
console.error(`Timeout after ${err.timeout}ms waiting for '${err.selector}'`);
if (err.reason) {
console.error(`Reason: ${err.reason}`);
}
}
}
ElementNotFoundError
Thrown when a selector matches no elements.
class ElementNotFoundError extends Error {
selector: string; // CSS selector that matched nothing
}
When Thrown:
element.text()- Element no longer in DOMelement.boundingBox()- Element no longer in DOM- Re-querying element properties after DOM changes
Example:
import { ElementNotFoundError } from '@vibium/client';
try {
const button = await vibe.find('button.submit');
// ... page navigation or DOM change ...
const text = await button.text(); // Throws if element removed
} catch (err) {
if (err instanceof ElementNotFoundError) {
console.error(`Element no longer exists: ${err.selector}`);
}
}
BrowserCrashedError
Thrown when the browser process dies unexpectedly.
class BrowserCrashedError extends Error {
exitCode: number; // Browser process exit code
output?: string; // Stderr/stdout output
}
When Thrown:
- Browser process crashes during operation
- Browser killed by OS (OOM, signals)
- Unhandled browser exceptions
Example:
import { BrowserCrashedError } from '@vibium/client';
try {
await vibe.go('https://example.com');
} catch (err) {
if (err instanceof BrowserCrashedError) {
console.error(`Browser crashed with exit code ${err.exitCode}`);
if (err.output) {
console.error(`Output: ${err.output}`);
}
}
}
Auto-Wait Behavior
Vibium implements intelligent auto-waiting to handle dynamic web applications without explicit waits.
Element Location Waits
find(selector, options) waits for:
- Element to exist in DOM
- Element to match CSS selector
Timeout: 30000ms (default), configurable via FindOptions.timeout
Implementation: Server-side polling with BiDi vibium:find command
Click Actionability Checks
click(options) waits for:
- Visible - Element has non-zero bounding box and is not
display: noneorvisibility: hidden - Stable - Element position not changing (not animating)
- Receives Events - Not obscured by another element (z-index check)
- Enabled - Not disabled via
disabledattribute or CSSpointer-events: none
Timeout: 30000ms (default), configurable via ActionOptions.timeout
Implementation: Server-side checks via BiDi vibium:click command
Retry Logic: Server retries checks until all pass or timeout exceeded
Type Actionability Checks
type(text, options) waits for:
- Visible - Element has non-zero bounding box
- Stable - Element position not changing
- Receives Events - Not obscured by another element
- Enabled - Not disabled
- Editable - Is
<input>,<textarea>, or hascontenteditable="true"
Timeout: 30000ms (default), configurable via ActionOptions.timeout
Implementation: Server-side checks via BiDi vibium:type command
Navigation Waits
go(url) waits for:
- Document
readyState === 'complete' - All resources loaded (images, stylesheets, scripts)
Strategy: BiDi browsingContext.navigate with wait: 'complete'
No Timeout: Relies on browser's internal navigation timeout
Best Practices
// ✅ GOOD: Let Vibium handle waiting
const button = await vibe.find('button.submit');
await button.click();
// ❌ BAD: Manual sleep is unnecessary
const button = await vibe.find('button.submit');
await new Promise(resolve => setTimeout(resolve, 1000));
await button.click();
// ✅ GOOD: Adjust timeout for slow elements
const slowButton = await vibe.find('.lazy-load-button', { timeout: 60000 });
// ✅ GOOD: Handle expected timeouts gracefully
try {
await vibe.find('.optional-banner', { timeout: 3000 });
} catch (err) {
if (err instanceof TimeoutError) {
// Banner not present, continue
} else {
throw err;
}
}
TypeScript Types
Core Types
// Browser Launch
interface LaunchOptions {
headless?: boolean;
port?: number;
executablePath?: string;
}
// Element Finding
interface FindOptions {
timeout?: number; // Default: 30000
}
// Element Actions
interface ActionOptions {
timeout?: number; // Default: 30000
}
// Element Information
interface ElementInfo {
tag: string;
text: string;
box: BoundingBox;
}
interface BoundingBox {
x: number;
y: number;
width: number;
height: number;
}
BiDi Protocol Types
// Internal types (not typically used directly)
interface BiDiCommand {
id: number;
method: string;
params: Record<string, unknown>;
}
interface BiDiResponse {
id: number;
type: 'success' | 'error';
result?: unknown;
error?: string;
message?: string;
}
interface BiDiEvent {
method: string;
params: Record<string, unknown>;
}
interface BrowsingContextInfo {
context: string;
url: string;
children: BrowsingContextInfo[];
parent?: string;
}
interface NavigationResult {
navigation: string;
url: string;
}
interface ScreenshotResult {
data: string; // base64 PNG
}
API Completeness Notes
Implemented Features
- ✅ Browser launch with options
- ✅ Navigation (
go()) - ✅ Element finding (
find()) - ✅ Element interaction (
click(),type()) - ✅ Element properties (
text(),getAttribute(),boundingBox()) - ✅ Screenshot capture (viewport only)
- ✅ Script execution (
evaluate()) - ✅ Session management (
quit()) - ✅ Comprehensive error types
- ✅ Auto-wait for actionability
Missing Features
- ❌
back(),forward(),refresh()navigation - ❌
findAll()for multiple elements - ❌
clear()method for input fields - ❌ Full page screenshots
- ❌ File upload functionality
- ❌ Cookie management
- ❌ Network interception
- ❌ Browser context/page management (multi-tab)
- ❌ Event listeners (page load, dialog, download)
These missing features can be implemented by:
- Adding BiDi protocol commands (e.g.,
browsingContext.traverseHistoryfor back/forward) - Extending the Vibe and Element classes with new methods
- Wrapping additional BiDi commands in the client
Usage Examples
Complete Test Scenario
import { browser, TimeoutError } from '@vibium/client';
import { writeFile } from 'fs/promises';
async function loginTest() {
const vibe = await browser.launch({ headless: true });
try {
// Navigate to login page
await vibe.go('https://example.com/login');
// Fill in credentials
const emailInput = await vibe.find('input[name="email"]');
await emailInput.type('user@example.com');
const passwordInput = await vibe.find('input[name="password"]');
await passwordInput.type('secretPassword123');
// Submit form
const submitButton = await vibe.find('button[type="submit"]');
await submitButton.click();
// Wait for redirect and verify success
try {
const welcomeMessage = await vibe.find('.welcome-message', { timeout: 5000 });
const text = await welcomeMessage.text();
console.log('Login successful:', text);
} catch (err) {
if (err instanceof TimeoutError) {
console.error('Login failed - welcome message not found');
const screenshot = await vibe.screenshot();
await writeFile('login-failure.png', screenshot);
}
throw err;
}
} finally {
await vibe.quit();
}
}
loginTest().catch(console.error);
Version History
1.0.0 (2026-01-19)
- Initial API documentation from source analysis
- Core browser automation features
- BiDi protocol integration
- Auto-wait behavior
- Custom error types
References
- Source Repository:
/tmp/vibium/clients/javascript/ - BiDi Protocol: WebDriver BiDi Specification
- Main Entry:
/tmp/vibium/clients/javascript/src/index.ts - Core Classes:
browser(browser.ts) - Browser launch APIVibe(vibe.ts) - Browser controllerElement(element.ts) - Element interactionBiDiClient(bidi/client.ts) - Protocol client
Document Status: ✅ Complete and verified against source code Analysis Date: 2026-01-19 Analyst: Research Agent (Agentic QE v3)