For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /sdk/rstest.md.
  • English
  • Integrate with Rstest

    We recommend Rstest or Vitest for writing JavaScript and TypeScript tests on Android, iOS, HarmonyOS, and desktop. This guide covers Rstest. Rstest organizes test cases, runs lifecycle hooks, and aggregates test results, while Midscene Agents connect to devices, interact with the UI, and perform assertions.

    Before you begin

    • Runtime: Install Node.js ^20.19.0 || ^22.12.0 || >=24.0.0 and pnpm. Use an existing project or run pnpm init to create one (skip if package.json already exists).
    • Model configuration and verification: Complete model configuration and model verification, then save the configuration in the project's .env file or shell environment.
    • Platform environment: Complete the environment setup for Android, iOS, HarmonyOS, or desktop, including device connections and required permissions.
    • (Optional) Try Playground first: Run an action and an assertion against your target interface in the Playground for your platform to verify screenshots, interactions, and model behavior.
    Choose your platform

    1. Install dependencies

    pnpm add -D @rstest/core dotenv @midscene/android

    2. Configure Rstest

    Create rstest.config.ts. If your project already uses Rstest for unit tests, you can save this configuration separately as rstest.device.config.ts and pass --config rstest.device.config.ts when running device tests, leaving your existing test configuration untouched.

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      include: ['e2e/**/*.test.ts'],
      testEnvironment: 'node',
      testTimeout: 90_000,
      hookTimeout: 90_000,
      pool: { maxWorkers: 1 },
      maxConcurrency: 1,
      output: {
        externals: {
          '@silvia-odwyer/photon': 'commonjs @silvia-odwyer/photon',
        },
      },
    });

    Model calls and device connections can take longer than unit tests, so adjust testTimeout and hookTimeout for your cases. For a shared device, use one worker (pool.maxWorkers: 1) and maxConcurrency: 1, and avoid test.concurrent and describe.concurrent. The external declaration keeps the Photon native addon out of the test bundle. See the Rstest configuration reference.

    3. Write a test

    Create e2e/settings.test.ts, initializing a new Agent for each test in beforeEach and destroying it in afterEach:

    e2e/settings.test.ts
    import 'dotenv/config';
    import { afterEach, beforeEach, test } from '@rstest/core';
    import { agentFromAdbDevice } from '@midscene/android';
    
    let agent: Awaited<ReturnType<typeof agentFromAdbDevice>> | undefined;
    
    beforeEach(async () => {
      agent = await agentFromAdbDevice();
    });
    
    afterEach(async () => {
      const currentAgent = agent;
      agent = undefined;
      await currentAgent?.destroy();
    });
    
    test('scroll through settings', async () => {
      if (!agent) throw new Error('Agent was not initialized');
    
      await agent.launch('com.android.settings');
      await agent.aiWaitFor('The Settings app is visible');
      await agent.aiAct('Scroll down one screen');
      await agent.aiAssert('The Settings app is still visible');
    });

    If multiple devices are connected, pass a device ID to agentFromAdbDevice(deviceId). See the Android SDK guide for connection options.

    dotenv/config loads model settings from the project's .env file (settings in the Playground are not automatically shared with test runs).

    When an aiAssert check fails, it throws an error, causing the test runner to mark the test as failed before running afterEach to clean up the Agent. You can also extract data from the screen with methods like aiQuery and pass the result to the test runner's expect. For more interaction and extraction methods, see the Agent API reference.

    4. Run the test and view the report

    pnpm exec rstest run e2e/settings.test.ts

    Rstest prints the pass or fail status of each test in the terminal, while the Midscene SDK generates an execution report for each Agent under midscene_run/report/ by default and prints the report path. Open the generated HTML file in a browser to inspect step-by-step screenshots, AI execution details, and assertion results.

    Unlike Playwright Test, Rstest integration uses the SDK's built-in report generation directly and does not require a custom reporter. Rstest test results and Midscene Agent reports are generated separately; to merge or further process report files, see Process report files.

    Common methods

    CategoryRepresentative methodsDescription
    Auto-planningaiActDescribe a goal in natural language and let the Agent plan and execute multiple steps.
    Direct interactionaiTap, aiInputLocate a UI element by description and perform a single specified action without multi-step planning.
    Data extractionaiQuery, aiString, aiNumber, aiBooleanExtract structured or primitive data from the current UI for further processing in code.
    AssertionsaiAssertVerify that the current UI meets an expectation; throws an error if it does not.
    WaitingaiWaitForWait until the UI meets a specified condition; throws an error on timeout.

    In practice, you typically perform actions with aiAct or direct interaction methods and then verify the outcome with aiAssert—completing an action does not guarantee that the expected UI state was reached. For full parameter and return value details, see the Agent API reference.

    Lifecycle and exclusive device access

    • Isolate Agents per test: Create a new Agent for each test case. Each Device instance belongs to a single Agent, and agent.destroy() cleans up the associated Device as well—do not reuse a destroyed instance in subsequent tests.
    • Manage application state explicitly: Destroying an Agent does not reset app data or close the app. Each test should explicitly prepare the required initial screen and data, and clean up state as needed so tests can be retried or run individually.
    • Avoid device contention across processes: The runner's sequential settings only apply to the current test runner process; other local processes, CI jobs, or manual input can still contend for the same device. To run tests in parallel, assign a dedicated device or desktop session to each worker and explicitly specify its connection target in code.