@qapilot/appium-module
v1.1.0
Published
Appium W3C WebDriver module for interacting with devices across BrowserStack, LambdaTest, and local Appium servers
Maintainers
Readme
@qapilot/appium-module
A unified Appium W3C WebDriver client for BrowserStack, LambdaTest, and local Appium servers. One invokeCommand API, any provider, full TypeScript support.
Installation
npm install @qapilot/appium-moduleNo additional @types package is needed — types are bundled with the package.
Usage
Import invokeCommand and call any supported command against any provider.
import { invokeCommand } from '@qapilot/appium-module';BrowserStack
const session = await invokeCommand({
commandName: 'createSession',
provider: 'browserstack',
credentials: {
username: process.env.BS_USER,
accessKey: process.env.BS_KEY,
},
params: {
capabilities: {
platformName: 'Android',
'appium:deviceName': 'Google Pixel 6',
'appium:platformVersion': '12.0',
'appium:app': 'bs://<app-id>',
},
},
});LambdaTest
const session = await invokeCommand({
commandName: 'createSession',
provider: 'lambdatest',
credentials: {
username: process.env.LT_USER,
accessKey: process.env.LT_KEY,
},
params: {
capabilities: {
platformName: 'Android',
'appium:deviceName': 'Galaxy S21',
'appium:app': 'lt://<app-id>',
},
},
});Local Appium
const session = await invokeCommand({
commandName: 'createSession',
provider: 'local',
credentials: {
hubUrl: 'http://localhost:4723',
},
params: {
capabilities: {
platformName: 'Android',
'appium:automationName': 'UiAutomator2',
'appium:deviceName': 'emulator-5554',
},
},
});Supported Commands
All commands are invoked via invokeCommand({ commandName, provider, credentials, params }).
| Category | Command | Key params |
|----------|---------|--------------|
| Session | createSession | capabilities |
| | getSession | sessionId |
| | deleteSession | sessionId |
| Element | findElement | sessionId, using, value |
| | findElements | sessionId, using, value |
| | clickElement | sessionId, elementId |
| | setValue | sessionId, elementId, text |
| | clearElement | sessionId, elementId |
| | getElementText | sessionId, elementId |
| | getElementAttribute | sessionId, elementId, attribute |
| | getElementDisplayed | sessionId, elementId |
| | getElementRect | sessionId, elementId |
| | getElementLocation | sessionId, elementId |
| | getElementSize | sessionId, elementId |
| Page | getScreenshot | sessionId |
| | getSource | sessionId |
| Actions | performActions | sessionId, actions |
| | touchPerform | sessionId, actions |
| Context | getContext | sessionId |
| | setContext | sessionId, name |
| | getContexts | sessionId |
| Window | getWindow | sessionId |
| | getWindowHandles | sessionId |
| | switchWindow | sessionId, handle |
| Device | hideKeyboard | sessionId |
| | isKeyboardShown | sessionId |
| | pressKeycode | sessionId, keycode |
| | activateApp | sessionId, appId |
| | terminateApp | sessionId, appId |
| | setOrientation | sessionId, orientation |
| | setLocation | sessionId, latitude, longitude |
| Script | executeScript | sessionId, script, args |
| | executeScriptSync | sessionId, script, args |
Get the full list at runtime:
import { getSupportedCommands } from '@qapilot/appium-module';
console.log(getSupportedCommands());Response Shape
Every invokeCommand call returns an ExecuteResponse<T>:
{
success: boolean;
data?: T; // present when success is true
error?: { // present when success is false
message: string;
statusCode?: number;
};
}Always check success before accessing data:
const result = await invokeCommand({ commandName: 'findElement', ... });
if (!result.success) {
throw new Error(result.error?.message);
}
const { elementId } = result.data;TypeScript Types
All types are exported from the main entry point:
import type {
ExecuteRequest,
ExecuteResponse,
ProviderName,
ProviderCredentials,
AppiumServiceError,
IAppiumProvider,
} from '@qapilot/appium-module';Extending
Custom Commands
import { registerCommand, BaseCommand } from '@qapilot/appium-module';
class ShakeDeviceCommand extends BaseCommand<{ sessionId: string }, void> {
readonly name = 'shakeDevice';
readonly method = 'POST' as const;
readonly pathTemplate = '/session/{sessionId}/appium/device/shake';
buildBody(_params: { sessionId: string }) {
return {};
}
parseResponse(_raw: unknown): void {
return;
}
}
registerCommand(new ShakeDeviceCommand());Custom Providers
import { registerProvider, BaseProvider } from '@qapilot/appium-module';
import type { IAppiumProvider, ProviderCredentials, AppiumServiceError } from '@qapilot/appium-module';
class SauceLabsProvider extends BaseProvider implements IAppiumProvider {
readonly name = 'saucelabs' as any;
protected readonly hubBaseUrl = 'https://ondemand.us-west-1.saucelabs.com';
protected readonly wdHubPath = '/wd/hub';
buildUrl(_sessionId: string | null, path: string, credentials: ProviderCredentials): string {
return `${this.buildBaseUrl(credentials)}${path}`;
}
buildHeaders(credentials: ProviderCredentials): Record<string, string> {
return {
'Content-Type': 'application/json',
Authorization: this.buildBasicAuthHeader(credentials),
};
}
normalizeCapabilities(caps: Record<string, unknown>): Record<string, unknown> {
return caps;
}
normalizeError(statusCode: number, body: unknown): AppiumServiceError {
return this.mapW3CError(statusCode, body);
}
getDefaultCapabilities(): Record<string, unknown> {
return {};
}
}
registerProvider(new SauceLabsProvider());License
MIT
