npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@testrelic/appium-analytics

v1.0.2

Published

Appium test analytics reporter with device log capture, command tracking, network interception, and interactive HTML reports for Android and iOS

Readme

@testrelic/appium-analytics

npm version license node

Appium test analytics reporter with device log capture, command tracking, network interception, and interactive HTML reports for Android and iOS.


Table of Contents


Features

  • Appium command tracking — records every WebDriver command with timing, category, arguments, and return values; sensitive arguments are automatically redacted
  • Device log capture — streams Android logcat and iOS syslog / crashlog per test
  • Network interception — captures HTTP requests and responses via Chrome DevTools Protocol (Android), safariNetwork (iOS), or an automatic proxy fallback using adb when CDP is not available
  • Console log capture — collects webview / browser console output via BiDi log.entryAdded or falls back to browser / safariConsole log polling
  • Screenshot collection — captures screenshots after every test, only on failure, or never
  • Video recording — records the device screen using Appium recording commands or adb screenrecord on Android
  • Interactive HTML reports — self-contained report with a timeline view for commands, logs, network requests, screenshots, and video
  • Cloud upload — upload results to the TestRelic platform in batch or realtime mode
  • CLI — merge multiple report files, serve the report directory, or open the report in a browser

Requirements

| Requirement | Version | |-------------|---------| | Node.js | >= 18 (Appium 3.x requires >= 20.19) | | WebdriverIO | >= 9.0.0 (peer dependency) | | @wdio/reporter | >= 9.0.0 (peer dependency) | | Appium | 3.x (npm install -g appium@latest) | | Android driver | UiAutomator2 (appium driver install uiautomator2) | | iOS driver | XCUITest on macOS (appium driver install xcuitest) |

iOS note: iOS testing requires macOS 13+ with Xcode 15+. iOS tests cannot run on Windows or Linux.


Installation

# npm
npm install @testrelic/appium-analytics
npm install --save-dev webdriverio @wdio/reporter

# yarn
yarn add @testrelic/appium-analytics
yarn add --dev webdriverio @wdio/reporter

# pnpm
pnpm add @testrelic/appium-analytics
pnpm add --save-dev webdriverio @wdio/reporter

Quick Start

Add TestRelicService to services and TestRelicReporter to reporters in your WDIO config, then implement onComplete:

// wdio.conf.ts
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';

const REPORT_DIR = join(process.cwd(), 'test-results');

async function onComplete() {
  try {
    await TestRelicReporter.finalize(process.cwd());
  } catch (err) {
    process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
  }
}

export const config = {
  runner: 'local',
  port: 4723,
  path: '/',

  specs: ['./tests/**/*.test.ts'],
  maxInstances: 1,

  capabilities: [{
    platformName: 'Android',
    'appium:automationName': 'UiAutomator2',
    'appium:deviceName': 'emulator-5554',
    'appium:app': join(process.cwd(), 'apps', 'MyApp.apk'),
  }],

  framework: 'mocha',
  mochaOpts: { ui: 'bdd', timeout: 60000 },

  services: [
    [TestRelicService, {
      outputPath: REPORT_DIR,
      includeDeviceLogs: true,
      includeNetworkLogs: true,
      screenshotOnEvery: 'failure',
    }],
  ],

  reporters: [
    'spec',
    [TestRelicReporter, {
      outputPath: join(REPORT_DIR, 'report.json'),
      htmlReportPath: join(REPORT_DIR, 'report.html'),
      openReport: true,
    }],
  ],

  onComplete,
};

WDIO Integration

The package provides two WebdriverIO plugins that work together: a service and a reporter. Both accept the same AppiumReporterConfig options.

TestRelicService

Import path: @testrelic/appium-analytics/service

TestRelicService is a WDIO service plugin that runs inside the worker process alongside your live Appium/WebDriver session. It registers the following hooks:

| Hook | What it does | |------|-------------| | before | Detects platform/capabilities, starts DeviceLogCollector, ConsoleLogCollector, NetworkInterceptor, and prepares ScreenshotCollector | | after | Stops log and network collectors | | beforeTest / afterTest | Marks per-test log slice boundaries; captures screenshots; starts/stops video recording | | beforeCommand / afterCommand | Delegates to CommandTracker — records every Appium command with timing and redacted arguments | | beforeAssertion / afterAssertion | Delegates to AssertionTracker — records WebdriverIO v9 assertion steps |

TestRelicReporter

Import path: @testrelic/appium-analytics

TestRelicReporter extends @wdio/reporter and runs in the same worker process. It consumes data collected by TestRelicService and writes the final reports:

| Event | What it does | |-------|-------------| | onRunnerStart | Initializes the optional CloudClient | | onTestEnd | Pulls collected data from TestRelicService, builds a TimelineBuildInput, and optionally performs a realtime cloud upload | | onRunnerEnd | Builds the full timeline and summary, writes the JSON report, generates the HTML report, prints the console summary, and writes a cloud finalization manifest |

onComplete Hook

This is required for cloud upload to work correctly.

TestRelicReporter.finalize() is a static method that must be called from the WDIO launcher process (i.e., in onComplete) after all worker processes have exited. It reads the .testrelic-finalize-<testRunId>.json manifest written by each worker and sends the final upload payload to the cloud.

async function onComplete() {
  try {
    await TestRelicReporter.finalize(process.cwd());
  } catch (err) {
    process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
  }
}

export const config = {
  // ...
  onComplete,
};

Even when cloud upload is not configured, including onComplete is harmless — finalize() exits immediately if no manifest files are found.

Android Configuration

Full example using the Android emulator:

// wdio.android.conf.ts
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';

const APP_PATH = join(process.cwd(), 'apps', 'MyApp.apk');
const REPORT_DIR = join(process.cwd(), 'test-results');

async function onComplete() {
  try {
    await TestRelicReporter.finalize(process.cwd());
  } catch (err) {
    process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
  }
}

export const config = {
  runner: 'local',
  port: 4723,
  path: '/',

  specs: ['./tests/android/**/*.test.ts'],
  maxInstances: 1,

  capabilities: [{
    platformName: 'Android',
    'appium:automationName': 'UiAutomator2',
    'appium:deviceName': 'emulator-5554',
    'appium:app': APP_PATH,
    'appium:autoGrantPermissions': true,
    'appium:newCommandTimeout': 240,
    'appium:appWaitActivity': '*',
    'appium:noReset': false,
  }],

  logLevel: 'warn',
  waitforTimeout: 15000,
  connectionRetryTimeout: 120000,
  connectionRetryCount: 3,

  framework: 'mocha',
  mochaOpts: { ui: 'bdd', timeout: 90000 },

  services: [
    [TestRelicService, {
      outputPath: REPORT_DIR,
      includeDeviceLogs: true,
      includeNetworkLogs: true,
      includeConsoleLogs: true,
      includeCommands: true,
      includeAssertions: true,
      includeScreenshots: true,
      screenshotOnEvery: 'failure',
      includeVideoRecording: true,
    }],
  ],

  reporters: [
    'spec',
    [TestRelicReporter, {
      outputPath: join(REPORT_DIR, 'report.json'),
      htmlReportPath: join(REPORT_DIR, 'report.html'),
      openReport: false,
    }],
  ],

  onComplete,

  autoCompileOpts: {
    tsNodeOpts: { project: './tsconfig.json' },
  },
};

iOS Configuration

Requires macOS 13+ with Xcode 15+. iOS tests cannot run on Windows or Linux.

// wdio.ios.conf.ts
import { join } from 'node:path';
import { TestRelicService } from '@testrelic/appium-analytics/service';
import { TestRelicReporter } from '@testrelic/appium-analytics';

const APP_PATH = join(process.cwd(), 'apps', 'MyApp.app');
const REPORT_DIR = join(process.cwd(), 'test-results');

async function onComplete() {
  try {
    await TestRelicReporter.finalize(process.cwd());
  } catch (err) {
    process.stderr.write(`[TestRelic] Cloud finalization failed: ${err}\n`);
  }
}

export const config = {
  runner: 'local',
  port: 4723,
  path: '/',

  specs: ['./tests/ios/**/*.test.ts'],
  maxInstances: 1,

  capabilities: [{
    platformName: 'iOS',
    'appium:automationName': 'XCUITest',
    'appium:deviceName': 'iPhone 15',
    'appium:platformVersion': '17.5',
    'appium:app': APP_PATH,
    'appium:newCommandTimeout': 240,
    'appium:noReset': false,
  }],

  logLevel: 'warn',
  waitforTimeout: 10000,
  connectionRetryTimeout: 120000,
  connectionRetryCount: 3,

  framework: 'mocha',
  mochaOpts: { ui: 'bdd', timeout: 60000 },

  services: [
    [TestRelicService, {
      outputPath: REPORT_DIR,
      includeDeviceLogs: true,
      includeNetworkLogs: true,
      includeConsoleLogs: true,
      includeCommands: true,
      includeAssertions: true,
      includeScreenshots: true,
      screenshotOnEvery: 'failure',
      includeVideoRecording: false,
    }],
  ],

  reporters: [
    'spec',
    [TestRelicReporter, {
      outputPath: join(REPORT_DIR, 'report.json'),
      htmlReportPath: join(REPORT_DIR, 'report.html'),
      openReport: false,
    }],
  ],

  onComplete,

  autoCompileOpts: {
    tsNodeOpts: { project: './tsconfig.json' },
  },
};

Configuration Reference

Both TestRelicService and TestRelicReporter accept Partial<AppiumReporterConfig>. Options set on TestRelicService control data collection; options set on TestRelicReporter control report output and cloud upload. You can share the same options object between both plugins.

Core Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | outputPath | string | './test-results/testrelic-timeline.json' | File path for the JSON report. Directories are created automatically. | | htmlReportPath | string | outputPath with .html extension | File path for the HTML report. | | openReport | boolean | true | Automatically open the HTML report in the default browser after the run completes. | | includeDeviceLogs | boolean | true | Capture Android logcat / iOS syslog and crashlog entries. | | includeNetworkLogs | boolean | true | Capture HTTP network requests and responses. | | includeConsoleLogs | boolean | true | Capture webview and browser console output. | | includeScreenshots | boolean | true | Capture device screenshots. | | screenshotOnEvery | 'test' \| 'failure' \| 'never' | 'failure' | When to take screenshots: after every test, only on test failure, or never. | | includeVideoRecording | boolean | false | Record the device screen for each test. | | includeCommands | boolean | true | Record every Appium / WebDriver command with timing and arguments. | | includeAssertions | boolean | true | Record WebdriverIO assertion steps (WDIO v9+). | | deviceLogPollInterval | number (ms) | 1000 | Interval between device log polls. Minimum value is 100. | | preferBiDi | boolean | true | Use the WebDriver BiDi log.entryAdded event for console log capture when the driver supports it, falling back to polling otherwise. | | redactPatterns | (string \| RegExp)[] | [] | Additional patterns to redact from command arguments and log entries. Built-in patterns are always applied (see Redaction). | | quiet | boolean | false | Suppress the console summary table printed at the end of a run. | | metadata | Record<string, unknown> | null | Arbitrary key-value pairs attached to the test run report. Useful for build numbers, branch names, or environment tags. | | cloud | CloudReporterOptions | — | Cloud upload configuration. See Cloud Options below. |

Cloud Options

Passed as the cloud key inside the reporter options, or loaded automatically from .testrelic/testrelic-config.json and environment variables.

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiKey | string | — | TestRelic API key. Required for cloud upload. | | endpoint | string | 'https://platform.testrelic.ai/api/v1' | TestRelic API endpoint. Override for self-hosted or staging environments. | | upload | 'batch' \| 'realtime' \| 'both' | 'batch' | Upload strategy. 'batch' uploads after onComplete; 'realtime' uploads results as each test finishes; 'both' does both. | | timeout | number (ms) | — | HTTP request timeout for cloud API calls. | | projectName | string | — | Override the project name shown in the TestRelic dashboard. Defaults to the git repository name. | | uploadArtifacts | boolean | — | Whether to upload screenshots and video files as run artifacts. | | artifactMaxSizeMb | number | — | Maximum size in MB for a single artifact file to be uploaded. Files exceeding this limit are skipped. |


Platform Setup

Android

Prerequisites

  • Node.js >= 20.19
  • Java JDK 17+
  • Windows 10/11, macOS, or Linux with hardware acceleration enabled for the emulator

Step 1 — Install Android SDK Command-Line Tools

Download from developer.android.com/studio#command-line-tools-only, extract to a directory (e.g. C:\Android\cmdline-tools\latest\), and set the following environment variables:

# Windows (PowerShell)
[System.Environment]::SetEnvironmentVariable("ANDROID_HOME", "C:\Android", "User")
[System.Environment]::SetEnvironmentVariable(
  "Path",
  "$env:Path;C:\Android\cmdline-tools\latest\bin;C:\Android\platform-tools;C:\Android\emulator",
  "User"
)
# macOS / Linux (~/.zshrc or ~/.bashrc)
export ANDROID_HOME=$HOME/Android
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator

Accept SDK licenses:

sdkmanager --licenses

Step 2 — Install Platform Tools, Emulator, and System Image

sdkmanager "platform-tools" "emulator"
sdkmanager "platforms;android-34"
sdkmanager "system-images;android-34;google_apis;x86_64"

Step 3 — Create an Android Virtual Device

avdmanager create avd -n MyEmulator -k "system-images;android-34;google_apis;x86_64" -d "pixel_7"

Step 4 — Start the Emulator

emulator -avd MyEmulator -no-snapshot-load

Wait for the emulator to fully boot, then verify:

adb devices
# emulator-5554   device

Step 5 — Install Appium and UiAutomator2 Driver

npm install -g appium@latest
appium driver install uiautomator2

Verify:

appium --version          # 3.x.x
appium driver list --installed  # uiautomator2

Step 6 — Start the Appium Server

appium --address 127.0.0.1 --port 4723

For the full Android setup guide see docs/ANDROID_SETUP.md.


iOS

macOS only. iOS testing requires macOS 13+ with Xcode 15+. These tests cannot run on Windows or Linux.

Prerequisites

  • macOS 13+ (Ventura or later recommended)
  • Xcode 15+ with iOS Simulator
  • Node.js >= 20.19
  • Xcode Command Line Tools: xcode-select --install

Step 1 — Install Appium and XCUITest Driver

npm install -g appium@latest
appium driver install xcuitest

Verify:

appium driver list --installed  # xcuitest

Step 2 — Boot an iOS Simulator

xcrun simctl boot "iPhone 15"
open -a Simulator

List available simulators if iPhone 15 is not found:

xcrun simctl list devices

Step 3 — Start the Appium Server

appium --address 127.0.0.1 --port 4723

For the full iOS setup guide see docs/IOS_SETUP.md.


Cloud Upload

Results can be uploaded to the TestRelic cloud platform. Cloud upload is optional — reports are always written locally regardless.

Config File

Create .testrelic/testrelic-config.json in your project root. The file is discovered automatically by the reporter:

{
  "cloud": {
    "apiKey": "<your-api-key>",
    "endpoint": "https://platform.testrelic.ai/api/v1",
    "upload": "batch"
  }
}

Add this file to .gitignore to keep your API key out of version control.

Environment Variables

| Variable | Description | |----------|-------------| | TESTRELIC_API_KEY | TestRelic API key | | TESTRELIC_CLOUD_ENDPOINT | API endpoint URL | | TESTRELIC_UPLOAD_STRATEGY | Upload strategy: batch, realtime, or both |

Environment variables are the recommended approach for CI/CD pipelines.

Priority Order

Configuration is merged in the following order — higher entries win:

  1. TESTRELIC_API_KEY / TESTRELIC_CLOUD_ENDPOINT / TESTRELIC_UPLOAD_STRATEGY environment variables
  2. cloud inline options inside the TestRelicReporter options block in wdio.conf.ts
  3. .testrelic/testrelic-config.json config file

CLI

The package installs a testrelic-appium binary automatically.

Merge multiple report files (useful after parallel worker runs):

npx testrelic-appium merge ./test-results/report-worker-1.json ./test-results/report-worker-2.json \
  -o ./test-results/merged-report.json

Serve a report directory (serves at http://127.0.0.1:9323 by default):

npx testrelic-appium serve ./test-results
npx testrelic-appium serve ./test-results --port 8080

Serve and open in browser (alias for serve + auto-open):

npx testrelic-appium open ./test-results

Merging Reports

When running tests across multiple WDIO workers, each worker writes its own JSON report. Use mergeReports() or the CLI merge command to combine them into a single timeline.

Programmatic merge (@testrelic/appium-analytics/merge):

import { mergeReports } from '@testrelic/appium-analytics/merge';

await mergeReports(
  ['./test-results/report-1.json', './test-results/report-2.json'],
  { output: './test-results/merged.json' }
);

CLI merge (see CLI section above).


Viewing Reports Locally

After a test run, the HTML report is written to htmlReportPath (default: same location as outputPath with an .html extension) and opened automatically in your browser when openReport: true (the default).

To view a report at any time without running tests:

npx testrelic-appium serve ./test-results
# Open http://127.0.0.1:9323 in your browser

Redaction

The reporter automatically redacts sensitive data from command arguments and log entries using the following built-in patterns:

| Pattern | Matches | |---------|---------| | AWS-style access keys | 20-character alphanumeric strings starting with AKIA, ASIA, etc. | | Bearer tokens | Values following Bearer in headers or strings | | PEM private keys | -----BEGIN * PRIVATE KEY----- blocks | | Embedded credentials | //user:password@ in URLs |

To add custom redaction patterns, use the redactPatterns option:

[TestRelicService, {
  redactPatterns: [
    /my-secret-\w+/,        // regex
    'my-fixed-token-value', // literal string
  ],
}]

Custom patterns are appended to the built-in set — the built-in patterns are always active.


Troubleshooting

Android: emulator won't start

  • Enable Intel VT-x / AMD-V in BIOS settings
  • On Windows 11: ensure the Hyper-V platform feature is enabled in Windows Features
  • Try a cold boot: emulator -avd MyEmulator -no-snapshot

Android: adb not found

  • Ensure $ANDROID_HOME/platform-tools is on your PATH
  • Run adb kill-server && adb start-server to reset the adb daemon

Android: Appium cannot find UiAutomator2

  • Run appium driver install uiautomator2 again
  • If using a non-default Appium home, set APPIUM_HOME to point to the correct directory

Android: tests time out during session creation

  • Ensure the emulator is fully booted before starting tests (adb devices shows device, not offline)
  • Increase connectionRetryTimeout in your WDIO config
  • Verify that the APK path in capabilities is correct and the file exists

iOS: xcrun: error: unable to find utility

  • Run sudo xcode-select --switch /Applications/Xcode.app to point to the correct Xcode installation

iOS: simulator not found

  • Open Xcode > Settings > Platforms and download the required iOS Simulator runtime
  • List available simulators: xcrun simctl list devices

iOS: WebDriverAgent build fails

  • Open ~/.appium/node_modules/appium-xcuitest-driver/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj in Xcode
  • Set a valid signing team under Signing & Capabilities

Report not generated

  • Ensure TestRelicService is listed in services and TestRelicReporter is listed in reporters — both are required
  • Check that outputPath directories are writable by the process

License

MIT — see LICENSE for details.

© TestRelic AI <[email protected]> — testrelic.ai