Skip to content

testingbot/testingbot-api

Repository files navigation

npm version npm downloads Tests

testingbot-api

Official NodeJS client for the TestingBot REST API.

TestingBot provides a cloud-based test infrastructure for automated cross-browser testing. This client library allows you to interact with the TestingBot API to manage tests, retrieve browser information, handle test artifacts, and more.

Table of Contents

Features

Core Features

  • Full support for all TestingBot REST API endpoints
  • Both callback and async/await patterns supported
  • Manage browser sessions and tests
  • Upload and manage test artifacts
  • Team management capabilities
  • Screenshot generation across multiple browsers
  • Tunnel management for local testing
  • Codeless test management (create, schedule, trigger, alerts, reports)
  • Built-in workflow helpers (auto-pagination, polling, batch operations, statistics)
  • Typed errors (AuthenticationError, RateLimitError, ValidationError, …)

Requirements

  • NodeJS >= 18.0.0
  • A TestingBot account with API credentials

Installation

npm install testingbot-api

Quick Start

1. Get your credentials

Sign up for a TestingBot account and obtain your API key and secret from the account settings.

2. Set up authentication

You can authenticate in three ways:

Environment variables (recommended)

export TESTINGBOT_KEY="your-api-key"
export TESTINGBOT_SECRET="your-api-secret"

Constructor options

const tb = new TestingBot({
  api_key: 'your-api-key',
  api_secret: 'your-api-secret'
});

Configuration file

Create a ~/.testingbot file with your credentials

3. Initialize the client

const TestingBot = require('testingbot-api');

const tb = new TestingBot({
  api_key: process.env.TESTINGBOT_KEY,
  api_secret: process.env.TESTINGBOT_SECRET
});

Usage

All methods support both callback style and async/await patterns. When using async/await, simply omit the callback parameter.

List responses are paginated. Endpoints that return a list (getTests, getBuilds, getStorageFiles, getScreenshotList, getCodelessTests, getUsersInTeam) resolve to a { data: [...], meta: { offset, count, total } } object — read the array from .data. See Responses & Pagination. (getBrowsers, getDevices and getTunnelList return a plain array.)

Errors are typed. A failed request rejects (or calls back) with a TestingBotError subclass carrying .statusCode and .response. See Error Handling.

API Reference

Browser & Device Management

getBrowsers

Gets a list of browsers you can test on. Returns a plain array.

// Callback style
tb.getBrowsers(type, function(error, browsers) {});

// Async/await style
const browsers = await tb.getBrowsers();

// With optional type parameter ('webdriver' (default) or 'rc' for legacy Selenium RC)
const rcBrowsers = await tb.getBrowsers('rc');

getDevices

Gets a list of physical mobile devices you can test on. Returns a plain array.

// Callback style
tb.getDevices(function(error, devices) {});

// Async/await style
const devices = await tb.getDevices();

// Filter by OS family: Android, iOS, REAL_ANDROID or REAL_IOS
const androidDevices = await tb.getDevices({ platform: 'Android' });

getIpRanges

Gets the list of TestingBot IP ranges, useful for firewall allow-lists. No authentication required.

// Callback style
tb.getIpRanges(function(error, ipRanges) {});

// Async/await style
const ipRanges = await tb.getIpRanges();

getAvailableDevices

Gets a list of available physical mobile devices for your account

// Callback style
tb.getAvailableDevices(function(error, availableDevices) {});

// Async/await style
const availableDevices = await tb.getAvailableDevices();

getDevice

Gets details for a specific physical device

// Callback style
tb.getDevice(deviceId, function(error, deviceDetails) {});

// Async/await style
const deviceDetails = await tb.getDevice(deviceId);

Session Management

createSession

Creates a remote browser on TestingBot and returns its CDP URL, which can be used to interface with the remote browser.

const options = {
  capabilities: {
    browserName: 'chrome',
    browserVersion: 'latest',
    platform: 'WIN11'
  }
};

// Callback style
tb.createSession(options, function(error, data) {});

// Async/await style
const session = await tb.createSession(options);

This will return a response with this structure:

{
  "session_id": "cb8aaba38ddb-88fd98fca537-a0070d8f1815-175888519321-14646637",
  "cdp_url": "wss://cloud.testingbot.com/session/cb8aaba38ddb-88fd98fca537-a0070d8f1815-175888519321-14646637"
}

You can now connect to the cdp_url with a CDP client to instruct the remote browser.

User Management

getUserInfo

Gets your user information

// Callback style
tb.getUserInfo(function(error, userInfo) {});

// Async/await style
const userInfo = await tb.getUserInfo();

updateUserInfo

Updates your user information. Only first_name and last_name are mutable. Pass the fields directly — they are wrapped in a user object for you.

// Callback style
tb.updateUserInfo({ first_name: 'Jane', last_name: 'Doe' }, function(error, userInfo) {});

// Async/await style
const userInfo = await tb.updateUserInfo({ first_name: 'Jane', last_name: 'Doe' });

getUserKeys

Returns the account's API key and secret ({ key, secret }).

// Callback style
tb.getUserKeys(function(error, keys) {});

// Async/await style
const keys = await tb.getUserKeys();

Test Management

getTests

Gets a list of your latest tests. Resolves to { data, meta } — the tests are in .data.

// Callback style
tb.getTests(offset, limit, function(error, result) {});

// Async/await style
const result = await tb.getTests();
console.log(result.data, result.meta);

// With pagination
const page = await tb.getTests(10, 20); // offset: 10, count: 20

// With filters (options form) — since (UNIX ts), group, build, browser_id, skip_fields
const filtered = await tb.getTests({ offset: 0, count: 50, build: 'ci-42', skip_fields: 'logs' });

getTestDetails

Gets details for a single test, pass the WebDriver's SessionID

// Callback style
tb.getTestDetails(sessionId, function(error, testDetails) {});

// Async/await style
const testDetails = await tb.getTestDetails(sessionId);

// Omit heavy fields from the response
const lean = await tb.getTestDetails(sessionId, { skip_fields: 'logs,thumbs' });

updateTest

Updates a single test. For example, update the passed state of a test (whether it was successful or not).

const testData = { "test[success]" : "1", "test[status_message]" : "test" };

// Callback style
tb.updateTest(testData, sessionId, function(error, testDetails) {});

// Async/await style
const testDetails = await tb.updateTest(testData, sessionId);

// Array values (e.g. multiple groups) are encoded correctly and all preserved
await tb.updateTest({ groups: ['regression', 'smoke'] }, sessionId);

deleteTest

Deletes a single test, pass the WebDriver's SessionID

// Callback style
tb.deleteTest(sessionId, function(error, success) {});

// Async/await style
const success = await tb.deleteTest(sessionId);

stopTest

Stops a single test, pass the WebDriver's SessionID

// Callback style
tb.stopTest(sessionId, function(error, success) {});

// Async/await style
const success = await tb.stopTest(sessionId);

Tunnel Management

getTunnel

Gets the account's currently active tunnel (handy when you only run one).

// Callback style
tb.getTunnel(function(error, tunnel) {});

// Async/await style
const tunnel = await tb.getTunnel();

getTunnelList

Gets list of active tunnels. Returns a plain array.

// Callback style
tb.getTunnelList(function(error, tunnelList) {});

// Async/await style
const tunnelList = await tb.getTunnelList();

getTunnelById

Gets a single tunnel by its ID.

// Callback style
tb.getTunnelById(tunnelId, function(error, tunnel) {});

// Async/await style
const tunnel = await tb.getTunnelById(tunnelId);

deleteTunnel

Deletes a single Tunnel by ID

// Callback style
tb.deleteTunnel(tunnelId, function(error, success) {});

// Async/await style
const success = await tb.deleteTunnel(tunnelId);

deleteActiveTunnel

Tears down whichever tunnel is currently active, without needing an ID.

// Callback style
tb.deleteActiveTunnel(function(error, success) {});

// Async/await style
const success = await tb.deleteActiveTunnel();

Build Management

getBuilds

Retrieves the latest builds

// Callback style
tb.getBuilds(offset, limit, function(error, builds) {});

// Async/await style
const builds = await tb.getBuilds();

// With pagination
const builds = await tb.getBuilds(10, 20); // offset: 10, limit: 20

getTestsForBuild

Retrieves the tests for a single build

// Callback style
tb.getTestsForBuild(buildId, function(error, tests) {});

// Async/await style
const tests = await tb.getTestsForBuild(buildId);

deleteBuild

Deletes a single build

// Callback style
tb.deleteBuild(buildId, function(error, success) {});

// Async/await style
const success = await tb.deleteBuild(buildId);

Storage Management

uploadFile

Uploads a local file to TestingBot Storage

// Callback style
tb.uploadFile(localFilePath, function(error, appUrl) {});

// Async/await style
const appUrl = await tb.uploadFile(localFilePath);

uploadRemoteFile

Uploads a remote file to TestingBot Storage

// Callback style
tb.uploadRemoteFile(remoteFileUrl, function(error, appUrl) {});

// Async/await style
const appUrl = await tb.uploadRemoteFile(remoteFileUrl);

getStorageFile

Retrieve data from a previously uploaded file

// Callback style
tb.getStorageFile(appUrl, function(error, fileDetails) {});

// Async/await style
const fileDetails = await tb.getStorageFile(appUrl);

getStorageFiles

Retrieve list of previously uploaded files

// Callback style
tb.getStorageFiles(offset, limit, function(error, fileDetails) {});

// Async/await style
const fileDetails = await tb.getStorageFiles();

// With pagination
const fileDetails = await tb.getStorageFiles(10, 20); // offset: 10, limit: 20

deleteStorageFile

Delete a previously uploaded file

// Callback style
tb.deleteStorageFile(appUrl, function(error, success) {});

// Async/await style
const success = await tb.deleteStorageFile(appUrl);

getAuthenticationHashForSharing

Calculates the authentication hash for sharing, pass the WebDriver's SessionID. This is used to share a test's detail page on TestingBot

// This method is synchronous and returns the hash directly
const hash = tb.getAuthenticationHashForSharing(sessionId);

Screenshots

takeScreenshot

Takes screenshots for the specific browsers

// Callback style — note the parameter order: url, browsers, resolution, waitTime, fullPage, callbackURL
tb.takeScreenshot(url, browsers, resolution, waitTime, fullPage, callbackURL, function(error, screenshots) {});

// Async/await style
const screenshots = await tb.takeScreenshot(
  'https://example.com',  // url - required
  [{ browserName: 'chrome', version: 'latest', os: 'WIN11' }],  // browsers - required
  '1920x1080',           // resolution - required
  5,                      // waitTime (seconds) - optional
  true,                   // fullPage - optional
  'https://your-callback.com' // callbackURL - optional
);

Once a screenshot job is running, you can use retrieveScreenshots to poll for the results.

retrieveScreenshots

Retrieves screenshots for a specific takeScreenshot call

// Callback style
tb.retrieveScreenshots(screenshotId, function(error, screenshots) {});

// Async/await style
const screenshots = await tb.retrieveScreenshots(screenshotId);

// Delta-fetch: exclude screenshot IDs you already have
const delta = await tb.retrieveScreenshots(screenshotId, { excludeIds: '101,102' });

getScreenshotList

Retrieves all screenshots previously generated with your account

// Callback style
tb.getScreenshotList(offset, limit, function(error, screenshots) {});

// Async/await style
const screenshots = await tb.getScreenshotList();

// With pagination
const screenshots = await tb.getScreenshotList(10, 20); // offset: 10, limit: 20

Team Management

getTeam

Retrieves team settings

// Callback style
tb.getTeam(function(error, data) {});

// Async/await style
const teamInfo = await tb.getTeam();

getUsersInTeam

Get all users in your team

// Callback style
tb.getUsersInTeam(function(error, users) {});

// Async/await style
const users = await tb.getUsersInTeam();

getUserFromTeam

Retrieves information about a specific user in your team

// Callback style
tb.getUserFromTeam(userId, function(error, user) {});

// Async/await style
const user = await tb.getUserFromTeam(userId);

createUserInTeam

Add a user to your team. You need ADMIN rights for this. Pass the fields at the top level; email and password are required.

const userData = {
  email: 'john@example.com',
  password: 'a-strong-password',
  first_name: 'John',
  last_name: 'Doe'
};

// Callback style
tb.createUserInTeam(userData, function(error, result) {});

// Async/await style
const result = await tb.createUserInTeam(userData);

updateUserInTeam

Update a user in your team. You need ADMIN rights for this. Pass the fields at the top level (first_name, last_name, email, password, credits, device_credits, concurrency, concurrencyPhysical).

const userData = {
  first_name: 'Jane',
  last_name: 'Smith'
};

// Callback style
tb.updateUserInTeam(userId, userData, function(error, result) {});

// Async/await style
const result = await tb.updateUserInTeam(userId, userData);

getUserClientKey

Gets a sub-account's client key ({ client_key }). You need ADMIN rights for this.

// Callback style
tb.getUserClientKey(userId, function(error, result) {});

// Async/await style
const result = await tb.getUserClientKey(userId);

resetCredentials

Resets credentials for a specific user in your team. You need ADMIN rights for this.

// Callback style
tb.resetCredentials(userId, function(error, result) {});

// Async/await style
const result = await tb.resetCredentials(userId);

Codeless Tests

Codeless tests allow you to create automated tests without writing code. These tests can be configured to run on a schedule and include AI-powered test generation.

getCodelessTests

Retrieves a list of codeless tests

// Callback style
tb.getCodelessTests(offset, limit, function(error, tests) {});

// Async/await style
const tests = await tb.getCodelessTests(0, 10); // offset: 0, limit: 10

createCodelessTest

Creates a new codeless test

const testData = {
  name: 'My Codeless Test',           // Required: Test name
  url: 'https://example.com',         // Required: URL to test
  cron: '0 0 * * *',                  // Optional: Cron schedule
  screenshot: true,                    // Optional: Take screenshots
  video: false,                        // Optional: Record video
  idletimeout: 60,                    // Optional: Idle timeout in seconds
  screenresolution: '1920x1080',      // Optional: Screen resolution
  ai_prompt: 'Test the login flow'    // Optional: AI test agent prompt
};

// Callback style
tb.createCodelessTest(testData, function(error, result) {});

// Async/await style
const result = await tb.createCodelessTest(testData);

updateCodelessTest

Updates an existing codeless test

const updateData = {
  test: {
    name: 'Updated Test Name',
    cron: '0 12 * * *'
  }
};

// Callback style
tb.updateCodelessTest(updateData, testId, function(error, result) {});

// Async/await style
const result = await tb.updateCodelessTest(updateData, testId);

getCodelessTest

Gets a single codeless test by ID

const test = await tb.getCodelessTest(testId);

deleteCodelessTest

Deletes a codeless test

// Callback style
tb.deleteCodelessTest(testId, function(error, result) {});

// Async/await style
const result = await tb.deleteCodelessTest(testId);

Running & scheduling

await tb.triggerCodelessTest(testId);              // run now
await tb.triggerAllCodelessTests();                // run every codeless test
await tb.stopCodelessTest(testId);                 // stop a running test

// Schedule: once / daily / weekly preset, or a raw cron expression
await tb.scheduleCodelessTest(testId, { type: 'daily', hour: '09:00' });
await tb.scheduleCodelessTest(testId, { type: 'custom', cronFormat: '0 9 * * 1' });

Steps & browsers

const steps = await tb.getCodelessSteps(testId);
await tb.addCodelessStep(testId, { /* step definition */ });

const browsers = await tb.getCodelessBrowsers(testId);
await tb.setCodelessBrowsers(testId, { /* browser selection */ });

Alerts & reports

await tb.createCodelessAlert(testId, { /* alert config */ });
await tb.updateCodelessAlert(testId, { /* alert config */ });

await tb.createCodelessReport(testId, { /* report config */ });
await tb.updateCodelessReport(testId, { /* report config */ });

Workflow Helpers

Promise-based conveniences built on the methods above. These always return promises.

// Fetch every test, paging automatically (returns a flat array)
const allTests = await tb.getAllTests();

// Poll a test until it reaches a terminal state (or the timeout elapses)
const finished = await tb.waitForTestCompletion(sessionId, 300000, 5000);

// Create a session and wait for it to finish
const result = await tb.runTestAndWait({ capabilities: { browserName: 'chrome' } });

// Fetch details for many tests at once
const { results, errors } = await tb.batchGetTestDetails([id1, id2, id3]);

// Aggregate pass/fail/state and browser/platform counts over the last N days
const stats = await tb.getTestStatistics(7);

// Bulk uploads / screenshots
const uploads = await tb.uploadFiles(['/path/a.apk', '/path/b.ipa']);
const shots = await tb.takeMultipleScreenshots(
  ['https://example.com', 'https://example.com/pricing'],
  [{ browserName: 'chrome', version: 'latest', os: 'WIN11' }],
  '1920x1080',
  { waitTime: 3, fullPage: true }
);

// Cleanup helpers (destructive)
await tb.cleanupOldTests(30);                                   // delete tests older than 30 days
await tb.smartCleanup({ keepDays: 30, keepFailed: true, keepMax: 1000 });

Error Handling

Every failed request rejects (or calls back) with a typed error that extends TestingBotError and carries .statusCode and .response (the raw response body). The classes are exported from the package:

const TestingBot = require('testingbot-api');
const { TestingBotError, AuthenticationError, RateLimitError, ValidationError, NotFoundError, NetworkError } = TestingBot;

try {
  await tb.getTestDetails('does-not-exist');
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Bad credentials');
  } else if (error instanceof RateLimitError) {
    console.error('Slow down, retry after', error.retryAfter);
  } else {
    console.error(error.name, error.statusCode, error.message);
  }
}
Status Error class
400 ValidationError (has .fields)
401 AuthenticationError
429 RateLimitError (has .retryAfter)
other non-2xx TestingBotError
no response (transport failure) NetworkError

Responses & Pagination

List endpoints return a { data, meta } envelope rather than a bare array:

const result = await tb.getTests(0, 20);
// {
//   data: [ /* tests */ ],
//   meta: { offset: 0, count: 20, total: 1234 }
// }
result.data.forEach(test => console.log(test.id, test.state));

This applies to getTests, getBuilds, getStorageFiles, getScreenshotList, getCodelessTests and getUsersInTeam. The getAllTests() workflow helper unwraps and concatenates these pages for you. getBrowsers, getDevices and getTunnelList return a plain array.

CLI Usage

The TestingBot API package includes a command-line interface for quick access to API functionality.

Installation

# Install globally for CLI access
npm install -g testingbot-api

# Or use npx with local installation
npx testingbot <command>

Authentication

The CLI uses the same authentication methods as the API client:

  • Environment variables: TB_KEY and TB_SECRET or TESTINGBOT_KEY and TESTINGBOT_SECRET
  • Configuration file: ~/.testingbot with api_key and api_secret

Available Commands

# User management
testingbot user info                    # Get user information
testingbot user keys                    # Get your API key and secret
testingbot user update <json>           # Update user information

# Test management
testingbot tests list [offset] [limit]  # List tests
testingbot tests get <id>               # Get test details
testingbot tests delete <id>            # Delete a test
testingbot tests stop <id>              # Stop a running test

# Codeless tests (Lab)
testingbot lab list [offset] [limit]    # List codeless tests
testingbot lab get <id>                 # Get a codeless test
testingbot lab create <json>            # Create a codeless test
testingbot lab update <id> <json>       # Update a codeless test
testingbot lab delete <id>              # Delete a codeless test
testingbot lab trigger <id>             # Trigger a run
testingbot lab trigger-all              # Trigger all codeless tests
testingbot lab stop <id>                # Stop a running test
testingbot lab schedule <id> <json>     # Set a schedule
testingbot lab steps <id>               # List steps
testingbot lab add-step <id> <json>     # Add a step
testingbot lab browsers <id>            # List browsers
testingbot lab set-browsers <id> <json> # Set browsers
testingbot lab alert <id> <json>        # Create an alert
testingbot lab update-alert <id> <json> # Update an alert
testingbot lab report <id> <json>       # Create a report
testingbot lab update-report <id> <json> # Update a report

# Browsers and devices
testingbot browsers list [type]         # List browsers (type: webdriver|rc)
testingbot devices list [platform]      # List devices (platform: Android|iOS|REAL_ANDROID|REAL_IOS)
testingbot devices available            # List available devices
testingbot devices get <id>             # Get a device
testingbot config ip-ranges             # List TestingBot IP ranges

# Tunnels
testingbot tunnel info                   # Get the active tunnel
testingbot tunnel list                   # List tunnels
testingbot tunnel get <id>               # Get a tunnel by ID
testingbot tunnel delete <id>            # Delete a tunnel
testingbot tunnel delete-active          # Delete the active tunnel

# Team
testingbot team info                     # Get team info
testingbot team users                    # List team users
testingbot team get-user <id>            # Get a team user
testingbot team client-key <id>          # Get a user's client key
testingbot team create-user <json>       # Create a team user

# Storage
testingbot storage upload <file>        # Upload a file
testingbot storage list [offset] [limit] # List stored files
testingbot storage get <id>             # Get a stored file
testingbot storage delete <id>          # Delete a stored file

# Help
testingbot --help                       # Show help
testingbot --version                    # Show version

CLI Examples

# Create a codeless test
testingbot lab create '{
  "name": "Homepage Test",
  "url": "https://example.com",
  "cron": "0 0 * * *",
  "screenshot": true,
  "ai_prompt": "Test the homepage loads correctly"
}'

# List recent tests
testingbot tests list 0 20

# Get browser list
testingbot browsers list webdriver

# Upload a file to storage
testingbot storage upload ./test-app.zip

Complete Examples

Basic Usage

const TestingBot = require('testingbot-api');

const tb = new TestingBot({
  api_key: "your-tb-key",
  api_secret: "your-tb-secret"
});

async function runTests() {
  try {
    // Get user information
    const userInfo = await tb.getUserInfo();
    console.log('User:', userInfo);

    // Get available browsers (plain array)
    const browsers = await tb.getBrowsers();
    console.log('Available browsers:', browsers.length);

    // Get recent tests (paginated: { data, meta })
    const tests = await tb.getTests(0, 10);
    console.log('Recent tests:', tests.data.length, 'of', tests.meta.total);

    // Get test details for the first test
    if (tests.data.length > 0) {
      const testDetails = await tb.getTestDetails(tests.data[0].id);
      console.log('Test details:', testDetails);
    }

    // Upload a file
    const appUrl = await tb.uploadFile('/path/to/your/app.apk');
    console.log('Uploaded file:', appUrl);

    // Take screenshots
    const screenshots = await tb.takeScreenshot(
      'https://testingbot.com',
      [{ browserName: 'chrome', version: 'latest', os: 'WIN11' }],
      '1280x1024'
    );
    console.log('Screenshots:', screenshots);

  } catch (error) {
    console.error('Error:', error);
  }
}

runTests();

Testing

Run lint + the full test suite:

npm test

Most suites are integration tests that hit the live API and require valid TestingBot credentials set as environment variables (TB_KEY and TB_SECRET). A subset are pure unit tests that need no credentials (typed-error mapping, parameter validation, request shaping, and workflow helpers):

npx mocha --grep "Typed errors|Parameter validation|Request shaping|Workflow helpers"

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

See the LICENSE file for details.

Support

More documentation

Check out the TestingBot REST API for more information.

About

NodeJS module to communicate with the TestingBot API

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors