• English
  • Integrate with Vitest

    We recommend Vitest for writing JavaScript and TypeScript tests on Android, iOS, HarmonyOS, and desktop. Vitest 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 vitest dotenv @midscene/android

    2. Configure Vitest

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

    vitest.config.ts
    import { defineConfig } from 'vitest/config';
    
    export default defineConfig({
      test: {
        include: ['e2e/**/*.test.ts'],
        environment: 'node',
        testTimeout: 90_000,
        hookTimeout: 90_000,
        fileParallelism: false,
        sequence: { concurrent: false },
      },
    });

    Because model calls and device connections take longer than standard unit tests, adjust testTimeout and hookTimeout to fit your test cases. When running against a single shared device, disable file parallelism (fileParallelism: false) and run tests sequentially (sequence.concurrent: false), and avoid test.concurrent or describe.concurrent. For details, see the Vitest documentation on fileParallelism, testTimeout, and hookTimeout.

    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 'vitest';
    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 Vitest 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 Vitest's expect. For more interaction and extraction methods, see the Agent API reference.

    4. Run the test and view the report

    pnpm exec vitest run e2e/settings.test.ts

    Vitest 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, Vitest integration uses the SDK's built-in report generation directly and does not require a custom reporter. Vitest 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: Vitest'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.

    For complete working projects, see the Vitest examples for Android, iOS, HarmonyOS, and desktop.