Resource library

QA How-To

Appium 3 Test Android Foldable Devices Tutorial (2026)

Learn how to use Appium 3 test Android foldable devices with emulator fold commands, resilient locators, state checks, screenshots, and CI-ready code.

18 min read | 2,787 words

TL;DR

Start one Appium session on a foldable Android Virtual Device, issue `adb -s <serial> emu fold` and `unfold`, then wait for the reported window dimensions to change. Assert layout semantics, selected content, and process continuity after each transition instead of relying on fixed coordinates.

Key Takeaways

  • Drive a foldable Android Emulator with the official `adb emu fold` and `adb emu unfold` commands.
  • Measure window dimensions after every posture change instead of assuming a model-specific width.
  • Keep one Appium session alive across transitions to expose activity recreation and lost state.
  • Use accessibility IDs and semantic assertions that remain valid in compact and expanded layouts.
  • Save named screenshots and page source on failure so fold-only defects are diagnosable in CI.
  • Separate deterministic emulator coverage from a smaller physical-device compatibility suite.

To use Appium 3 test Android foldable devices reliably, keep the application open while the Android Emulator changes between folded and unfolded postures, then assert both geometry and user-visible state. A useful test proves more than screen rotation: it detects the new window size, confirms the responsive layout, and verifies that a selected item survives any activity recreation caused by the configuration change.

This tutorial builds that test with Appium 3, UiAutomator2, WebdriverIO, TypeScript, and official Android Emulator console commands. It complements the Appium 3 mobile automation complete guide, but focuses on the failure modes unique to foldables: changing window bounds, alternate navigation, hinge-aware layouts, and continuity during a live transition.

You will use a sample catalog app contract with stable accessibility IDs. Point the environment variables at your own debug APK and preserve the same semantic IDs, or map the selectors to equivalent controls in your app. No proprietary device-cloud command is required.

What You Will Build

You will create a small, runnable project that:

  • starts a UiAutomator2 session on a foldable Android Virtual Device (AVD);
  • opens a catalog screen and selects an item in the unfolded two-pane layout;
  • folds the emulator without ending the WebDriver session;
  • verifies the compact layout and retained item details;
  • unfolds again, checks the expanded layout, and saves evidence;
  • relaunches the app to distinguish saved state from accidental in-memory state.

The example assumes the APK exposes catalog-grid, catalog-list, catalog-detail, selected-item-title, and layout-mode as accessibility IDs. The layout-mode element contains either expanded or compact. This contract is intentionally semantic. A RecyclerView, Compose LazyColumn, or custom view can satisfy it without exposing implementation details to the test.

Prerequisites

Use these exact versions for a reproducible baseline dated August 2026:

Component Version Purpose
Node.js 22 LTS Runs Appium and the TypeScript test
Appium 3.6.0 WebDriver server
UiAutomator2 driver 8.2.1 Android automation backend
WebdriverIO 9.30.0 JavaScript WebDriver client
TypeScript 5.9.2 Type checking and compilation
Android Studio 2025.2.2 or newer Provides Device Manager and Emulator
Android platform API 36 Foldable system image and SDK tools

Appium 3 requires Node.js 20.19.0 or newer and npm 10 or newer. Set ANDROID_HOME, put platform-tools, emulator, and cmdline-tools/latest/bin on PATH, and install an API 36 Google APIs image. In Android Studio Device Manager, create a foldable hardware profile such as Pixel 9 Pro Fold. Name this tutorial's AVD Pixel_9_Pro_Fold_API_36.

You also need a debug APK whose package and launch activity are known. The commands below default to ./apps/foldable-catalog-debug.apk, package com.example.foldablecatalog, and activity .MainActivity. If you are new to the Android toolchain, complete the Appium Android setup guide first.

Verify the machine before creating the project:

node --version
npm --version
adb version
emulator -version
emulator -list-avds

Expected: Node prints v22.x, npm prints 10.x or newer, and the AVD list includes Pixel_9_Pro_Fold_API_36.

Step 1: Install Appium 3 and UiAutomator2

Create a dedicated directory so dependency upgrades are reviewed through package-lock.json rather than changing a shared global installation.

mkdir appium-foldable-test
cd appium-foldable-test
npm init -y
npm install --save-dev appium@3.6.0 webdriverio@9.30.0 typescript@5.9.2 tsx@4.20.3 @types/node@22.15.30
npx appium driver install uiautomator2@8.2.1

Appium Core does not bundle platform drivers. The second command registers UiAutomator2 in Appium's extension home. Pinning Core, driver, and client independently makes the combination visible and prevents an unrelated install from silently changing the automation backend. For broader extension lifecycle guidance, see Appium 3 driver version management.

Run the built-in doctor and inspect the installed driver:

npx appium --version
npx appium driver list --installed
npx appium driver doctor uiautomator2

Verify Step 1: Appium reports 3.6.0, the driver list contains uiautomator2@8.2.1, and Doctor ends with 0 required fixes needed. Optional recommendations do not block this tutorial, but required Android SDK or Java findings do.

Step 2: Start and Prove the Foldable Emulator

Start the named AVD from a separate terminal. Disable snapshot loading for the first run so a stale posture or half-completed boot cannot contaminate the test.

emulator @Pixel_9_Pro_Fold_API_36 -no-snapshot-load

Wait for Android to finish booting, capture the serial, then prove the console accepts posture commands. The first emulator normally uses emulator-5554, but always read it from adb devices.

adb wait-for-device
adb shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done'
adb devices
adb -s emulator-5554 emu unfold
adb -s emulator-5554 shell wm size
adb -s emulator-5554 emu fold
adb -s emulator-5554 shell wm size
adb -s emulator-5554 emu unfold

adb emu fold and adb emu unfold are official Android Emulator console commands. They are preferable to coordinate clicks on the emulator toolbar because they are scriptable and addressable by serial. The wm size output may show the display's physical size rather than the exact application window, so the automated test will use WebDriver's getWindowSize() for its pass condition.

Verify Step 2: the emulator visibly moves between its large and small display configurations, every console command returns OK, and it ends unfolded. If two emulators are connected, every command must retain -s emulator-5554 to avoid changing the wrong device.

Step 3: Define the TypeScript Project and Session

Create tsconfig.json with Node's modern ESM resolution:

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "noEmit": true,
    "types": ["node"]
  },
  "include": ["test/**/*.ts"]
}

Add useful scripts to package.json while keeping the dependencies installed in Step 1:

{
  "type": "module",
  "scripts": {
    "appium": "appium --log-level info",
    "test:foldable": "tsx test/foldable.ts",
    "typecheck": "tsc"
  }
}

Now create test/session.ts. All app-specific values are environment variables, so the same code can run locally and in CI.

import { remote, type Browser } from 'webdriverio';

export type MobileBrowser = Browser;

export async function createSession(): Promise<MobileBrowser> {
  const udid = process.env.ANDROID_UDID ?? 'emulator-5554';
  return remote({
    hostname: process.env.APPIUM_HOST ?? '127.0.0.1',
    port: Number(process.env.APPIUM_PORT ?? '4723'),
    path: '/',
    logLevel: 'info',
    capabilities: {
      platformName: 'Android',
      'appium:automationName': 'UiAutomator2',
      'appium:udid': udid,
      'appium:deviceName': 'Android Foldable',
      'appium:app': process.env.APP_PATH ?? './apps/foldable-catalog-debug.apk',
      'appium:appPackage': process.env.APP_PACKAGE ?? 'com.example.foldablecatalog',
      'appium:appActivity': process.env.APP_ACTIVITY ?? '.MainActivity',
      'appium:autoGrantPermissions': true,
      'appium:newCommandTimeout': 120
    }
  });
}

The root path is / in Appium 3. Do not copy the old /wd/hub default from Appium 1 tutorials. udid binds the session to the same serial used by the emulator commands. Review Appium desired capabilities if your activity aliases or signing variants require different values.

Verify Step 3: run npm run typecheck. It must exit with code 0. Then start npm run appium and confirm the server log lists UiAutomator2 8.2.1 as an available driver.

Step 4: Appium 3 Test Android Foldable Devices With a Posture Helper

The test needs a deterministic bridge between Android's posture command and WebDriver's view of the application window. Create test/foldable-device.ts:

import { execFileSync } from 'node:child_process';
import type { MobileBrowser } from './session.js';

export type Posture = 'folded' | 'unfolded';
export type WindowRect = { width: number; height: number };

function adb(serial: string, args: string[]): string {
  return execFileSync('adb', ['-s', serial, ...args], {
    encoding: 'utf8',
    timeout: 15_000
  }).trim();
}

export async function setPosture(
  browser: MobileBrowser,
  posture: Posture,
  previous: WindowRect
): Promise<WindowRect> {
  const serial = process.env.ANDROID_UDID ?? 'emulator-5554';
  const response = adb(serial, ['emu', posture === 'folded' ? 'fold' : 'unfold']);
  if (!response.includes('OK')) {
    throw new Error(`Emulator rejected ${posture}: ${response}`);
  }

  await browser.waitUntil(async () => {
    const current = await browser.getWindowSize();
    return current.width !== previous.width || current.height !== previous.height;
  }, {
    timeout: 15_000,
    interval: 300,
    timeoutMsg: `Window bounds did not change after ${posture}`
  });

  return browser.getWindowSize();
}

export function assertDifferentWindows(a: WindowRect, b: WindowRect): void {
  if (a.width === b.width && a.height === b.height) {
    throw new Error(`Expected different bounds, both were ${a.width}x${a.height}`);
  }
}

execFileSync passes arguments without a shell, which avoids quoting bugs and accidental command injection from a serial. The helper waits for observable geometry instead of sleeping for an arbitrary number of seconds. It does not assert that unfolded always means landscape or that a particular dimension must double because foldable profiles and user rotation settings differ.

Verify Step 4: run npm run typecheck again. With the emulator unfolded, compare adb -s emulator-5554 emu fold to a manual getWindowSize() call in an Appium Inspector session. Both dimensions do not need to change, but the width-height pair must. Return the emulator to unfolded before continuing.

Step 5: Assert Expanded and Compact Layout Semantics

A foldable test should assert user behavior, not only pixels. Create test/catalog-screen.ts to model the stable accessibility contract:

import type { MobileBrowser } from './session.js';

export class CatalogScreen {
  constructor(private readonly browser: MobileBrowser) {}

  private get grid() { return this.browser.$('~catalog-grid'); }
  private get list() { return this.browser.$('~catalog-list'); }
  private get detail() { return this.browser.$('~catalog-detail'); }
  private get title() { return this.browser.$('~selected-item-title'); }
  private get mode() { return this.browser.$('~layout-mode'); }

  async chooseItem(name: string): Promise<void> {
    const item = this.browser.$(`android=new UiSelector().description("catalog-item-${name}")`);
    await item.waitForDisplayed({ timeout: 10_000 });
    await item.click();
    await this.title.waitForDisplayed({ timeout: 10_000 });
    const actual = await this.title.getText();
    if (actual !== name) throw new Error(`Expected ${name}, received ${actual}`);
  }

  async expectExpanded(selected: string): Promise<void> {
    await this.grid.waitForDisplayed({ timeout: 10_000 });
    await this.detail.waitForDisplayed({ timeout: 10_000 });
    if (await this.mode.getText() !== 'expanded') throw new Error('Expanded mode not reported');
    if (await this.title.getText() !== selected) throw new Error('Selection was not retained');
  }

  async expectCompact(selected: string): Promise<void> {
    await this.list.waitForDisplayed({ timeout: 10_000 });
    await this.detail.waitForDisplayed({ timeout: 10_000 });
    if (await this.mode.getText() !== 'compact') throw new Error('Compact mode not reported');
    if (await this.title.getText() !== selected) throw new Error('Selection was not retained');
  }
}

Accessibility IDs survive a switch from grid to list better than XPath based on hierarchy position. The one UiSelector is used for a dynamic item key, and the value is fixed by the test. If the compact design moves details to a separate route, adapt expectCompact to assert a back affordance and the detail route instead of requiring both panes. The invariant is access to the selected content, not identical composition. For a deeper selector strategy, read Appium locator strategies.

Verify Step 5: inspect the app in both postures. Each selector must resolve exactly once, the item catalog-item-Pixel Camera must be visible before selection, and layout-mode must expose text rather than color or geometry alone. npm run typecheck must remain clean.

Step 6: Run the Complete Fold, Unfold, and State Test

Create test/foldable.ts using the modules already defined. The test captures screenshots at meaningful checkpoints and always closes its session.

import { mkdir } from 'node:fs/promises';
import { createSession } from './session.js';
import { CatalogScreen } from './catalog-screen.js';
import { assertDifferentWindows, setPosture } from './foldable-device.js';

await mkdir('artifacts', { recursive: true });
const browser = await createSession();

try {
  const catalog = new CatalogScreen(browser);
  const selected = 'Pixel Camera';
  const initial = await browser.getWindowSize();

  await catalog.chooseItem(selected);
  await catalog.expectExpanded(selected);
  await browser.saveScreenshot('artifacts/01-unfolded-selected.png');

  const folded = await setPosture(browser, 'folded', initial);
  assertDifferentWindows(initial, folded);
  await catalog.expectCompact(selected);
  await browser.saveScreenshot('artifacts/02-folded-retained.png');

  const unfolded = await setPosture(browser, 'unfolded', folded);
  assertDifferentWindows(folded, unfolded);
  await catalog.expectExpanded(selected);
  await browser.saveScreenshot('artifacts/03-unfolded-restored.png');

  const appId = process.env.APP_PACKAGE ?? 'com.example.foldablecatalog';
  await browser.terminateApp(appId);
  await browser.activateApp(appId);
  await catalog.expectExpanded(selected);
  await browser.saveScreenshot('artifacts/04-relaunch-restored.png');

  console.log({ initial, folded, unfolded, selected, result: 'PASS' });
} catch (error) {
  await browser.saveScreenshot('artifacts/failure.png').catch(() => undefined);
  const source = await browser.getPageSource().catch(() => '<source unavailable>');
  console.error(source);
  throw error;
} finally {
  await browser.deleteSession();
}

Start Appium in terminal one, keep the emulator running, and execute the test in terminal two:

npm run appium
# In another terminal:
ANDROID_UDID=emulator-5554 \
APP_PATH=./apps/foldable-catalog-debug.apk \
npm run test:foldable

The relaunch assertion is deliberately stronger than the posture assertions. Fold and unfold can recreate an Activity while leaving the process alive. Terminate and activate proves that the selection is restored from saved application state. If product requirements say selection should reset after a cold launch, replace the final expectation with the documented default screen.

Verify Step 6: the command prints three distinct window records and result: 'PASS'. The artifacts directory contains four PNG files. Open them and confirm that the selected item is visible, controls are not clipped by the fold, and the compact screenshot is genuinely different from the expanded screenshots.

Step 7: Add Coverage for Rotation, Backgrounding, and Repeated Transitions

One happy-path cycle catches basic adaptive-layout failures. Production suites should exercise transitions that users actually combine. Add this bounded stress loop after selecting an item, not as an unbounded soak test:

let current = await browser.getWindowSize();
for (let cycle = 1; cycle <= 3; cycle += 1) {
  const target = cycle % 2 === 1 ? 'folded' : 'unfolded';
  const next = await setPosture(browser, target, current);
  assertDifferentWindows(current, next);
  current = next;
}

await browser.background(2);
await browser.setOrientation('PORTRAIT');
const finalWindow = await browser.getWindowSize();
console.log({ finalWindow, transitionCycles: 3 });

Do not combine every posture, orientation, font scale, theme, and locale into one enormous matrix. Use pairwise risk selection. A practical pull-request suite might cover one unfold-to-fold transition in portrait and one background-resume transition. A nightly suite can add repeated transitions, landscape, large font, dark theme, split screen, and process death. Physical devices should cover hinge feel and vendor behavior, while the emulator supplies deterministic state changes and fast failure artifacts.

The background(2) command moves the app away for two seconds, then restores it. setOrientation('PORTRAIT') uses the WebDriver orientation endpoint. Keep assertions after these operations, because successful commands do not prove the app kept its route or data.

Verify Step 7: the loop logs three successful geometry changes, the app returns from the background, and the selected content remains accessible. Confirm the final orientation with await browser.getOrientation() if orientation is a contractual requirement for your screen.

Step 8: Make the Foldable Test CI-Ready

Emulator hardware acceleration and graphics differ by runner. Start with a self-hosted Android runner or a CI image that explicitly supports hardware virtualization. Boot one named AVD, wait for sys.boot_completed, start Appium with a log file, and run the same npm script. Preserve artifacts, the Appium log, and emulator logcat on failure.

set -euo pipefail
export ANDROID_UDID=emulator-5554

emulator @Pixel_9_Pro_Fold_API_36 \
  -no-window -no-audio -no-boot-anim -gpu swiftshader_indirect \
  -no-snapshot -port 5554 > artifacts/emulator.log 2>&1 &

adb -s "$ANDROID_UDID" wait-for-device
until [[ "$(adb -s "$ANDROID_UDID" shell getprop sys.boot_completed | tr -d '\r')" == "1" ]]; do
  sleep 2
done

npx appium --log artifacts/appium.log &
APPIUM_PID=$!
trap 'kill $APPIUM_PID 2>/dev/null || true' EXIT

until curl --fail --silent http://127.0.0.1:4723/status >/dev/null; do sleep 1; done
npm run test:foldable

This script uses a fixed emulator console port, making the serial deterministic. Run one worker per emulator and assign a unique even port for parallel workers. A shared AVD cannot safely process two posture-changing tests at once. If your pipeline needs a larger matrix, use isolated AVD copies or a provider with a documented fold-state API. The mobile device farm testing guide helps decide which cases belong on hosted hardware.

Verify Step 8: run the shell fragment on the intended runner, not only on a laptop. The status endpoint must become healthy, the test must pass headlessly, and all logs plus screenshots must upload even when the test fails. Record emulator version in the job output so future image upgrades are traceable.

Troubleshooting

Problem: adb emu fold returns KO: Command not supported -> The active AVD does not advertise foldable hardware or its emulator binary is old. Confirm adb -s <serial> emu avd name, launch the foldable AVD created in Prerequisites, update Android Emulator through SDK Manager, and retry manually before blaming Appium.

Problem: The emulator folds, but getWindowSize() never changes -> Android may not have completed the display reconfiguration, auto-rotation may be locked into an unexpected state, or the command reached a different serial. Remove parallel emulators, specify ANDROID_UDID, inspect adb devices, and compare screenshots. Do not fix this with a long static sleep because it hides routing mistakes.

Problem: The session fails with an unknown capability or cannot find /wd/hub -> Use W3C-prefixed Appium capabilities such as appium:udid and connect to path /. Appium 3's default base path is not the historical /wd/hub; configure a custom server base path only when an existing grid truly requires it.

Problem: Selection disappears only after folding -> The app is probably losing state during activity recreation. Check adb logcat for Activity lifecycle messages, reproduce with Android's developer option to destroy activities, and have the app retain the selected identifier through SavedStateHandle, rememberSaveable, a ViewModel plus persistent storage, or the architecture approved by the Android team. The test should not reselect the item after transition because that would conceal the defect.

Problem: Accessibility IDs work unfolded but vanish in compact mode -> The compact component does not expose the same semantic contract, or a parent has merged Compose semantics. Inspect both page sources, add stable contentDescription or test tags mapped to accessibility where appropriate, and avoid positional XPath. Coordinate taps are especially fragile near hinges and changing window bounds.

Problem: Headless CI screenshots are blank or rendering differs locally -> Change the emulator GPU mode supported by the runner, verify hardware acceleration, and capture emulator -version plus startup logs. Treat a rendering-mode change as an infrastructure change. Keep at least one physical foldable job for vendor-specific composition and hinge behavior.

Interview Questions and Answers

Q: How would you automate a fold transition with Appium?

Use an Android foldable emulator and send adb -s <serial> emu fold while keeping the Appium session alive. Wait until getWindowSize() changes, then assert the compact layout and retained user state. The command response alone only proves the emulator accepted the request.

Q: Why is a fixed delay weak after a posture change?

Recomposition and activity recreation take different amounts of time across hosts. A fixed delay can be both unnecessarily slow and intermittently insufficient. Poll a user-visible condition or changed window bounds with a bounded timeout.

Q: What should a foldable UI test assert?

Assert accessible content, correct navigation pattern, unclipped primary actions, retained selection, and correct responsive mode. Geometry is a synchronization signal, not the complete product outcome. Add screenshot review for visual problems that semantic assertions cannot detect.

Q: Should every foldable test run on physical hardware?

No. Emulator tests are deterministic and inexpensive for frequent posture and state checks. Keep a smaller physical-device suite for vendor firmware, hinge angles, performance, display crease effects, cameras, and behaviors the emulator cannot represent faithfully.

Q: How do you avoid flaky selectors across layouts?

Expose the same accessibility identity for the same user concept in compact and expanded components. Prefer accessibility IDs or resource IDs over hierarchy-based XPath. Model alternate navigation explicitly when the product deliberately changes interaction structure.

Q: How do you diagnose state loss during folding?

Keep the WebDriver session alive, capture logcat and page source before and after the transition, and inspect activity lifecycle events. Compare a posture transition with terminate-and-activate behavior to determine whether state lives only in the current Activity, the process, or durable storage.

Best Practices for Appium 3 Test Android Foldable Devices

  • Start every test from a declared posture. A previous failure may leave the AVD folded.
  • Bind both Appium and adb to the same explicit serial. Never depend on whichever device adb selects first.
  • Wait on window or UI state, then make business assertions. A successful shell command is not a successful user journey.
  • Preserve one session across the fold. Recreating the driver after each posture removes the lifecycle risk you intended to test.
  • Use named screenshots such as folded-retained.png, not a single overwritten screenshot.png.
  • Keep responsive assertions semantic. Exact pixels belong in a separate visual baseline with controlled fonts, density, system image, and emulator version.
  • Reset posture in cleanup when other tests share the emulator, but do not erase evidence before artifacts are collected.
  • Test multiple transition directions. Bugs can appear only when expanding because the two-pane detail view is restored differently.
  • Limit pull-request coverage to fast critical paths and schedule larger state combinations nightly.

Where To Go Next

Once this test is stable, extend the framework deliberately:

For a real application, add a foldable scenario to the release-risk checklist, link screenshots to the test result, and upload the role details in the QAJobFit dashboard to focus interview preparation on the mobile skills the job actually requests.

Conclusion

A credible foldable test changes posture inside an active Appium session and proves the application adapts without losing the user's work. The combination of official emulator commands, WebDriver window polling, semantic accessibility IDs, state assertions, and diagnostic artifacts gives you a repeatable signal instead of a visual demo.

Run the complete test once on the API 36 foldable emulator, then place its critical path in CI and reserve vendor-specific risks for physical hardware. That layered approach catches responsive-layout regressions quickly while acknowledging what emulation cannot reproduce.

Interview Questions and Answers

How would you design an Appium test for an Android foldable device?

I would start a UiAutomator2 session on a foldable AVD in a declared posture, navigate to meaningful state, and issue the emulator's fold command without recreating the session. I would wait for changed window bounds, assert the compact layout and retained data, then unfold and repeat the assertions. Screenshots, page source, Appium logs, and logcat would be retained for diagnosis.

What is the difference between testing rotation and testing a fold transition?

Rotation changes orientation, while a fold transition can change usable display area, aspect ratio, responsive size class, navigation pattern, and activity lifecycle behavior. A foldable test therefore checks continuity and alternate layouts, not merely portrait versus landscape.

Why keep the Appium session alive during fold and unfold?

The main risk is how the running app responds to a live configuration change. Starting a fresh session after the fold can reset the app and hide state loss, crashes, duplicate navigation, or broken lifecycle restoration.

How would you synchronize an Appium foldable test?

I would first require an `OK` response from the targeted emulator console, then use `waitUntil` on changed WebDriver window bounds or a semantic layout-mode element. After synchronization, I would assert the actual user outcome such as selected content and usable controls.

How do you choose between emulator and real foldable coverage?

I put repeatable responsive-layout and state tests on emulators for pull requests and nightly matrices. I reserve a smaller physical suite for vendor implementations, hinge-angle behavior, thermal and performance observations, cameras, and other hardware-dependent risks.

What causes locator failures after an Android app folds?

Compact and expanded layouts may render different component trees, and Activity recreation can invalidate previously resolved element references. I reacquire elements after the transition and use stable accessibility or resource IDs shared by both representations rather than cached elements or positional XPath.

How would you test state restoration on a foldable?

I would select a specific item, fold and unfold while asserting that identifier after each transition, then terminate and activate the application for a stronger persistence check. Comparing those outcomes separates Activity-level restoration from process memory and durable saved state.

Frequently Asked Questions

Can Appium 3 fold and unfold an Android emulator directly?

Appium does not provide a cross-platform WebDriver posture endpoint. For the Android Emulator, call the official `adb emu fold` and `adb emu unfold` console commands while the Appium session remains active, then verify the resulting window and UI state.

Which Appium driver is used for Android foldable testing?

Use the UiAutomator2 driver for native, hybrid, and mobile web automation on Android. The tutorial pins UiAutomator2 8.2.1 with Appium 3.6.0 and validates installation through `appium driver doctor uiautomator2`.

Do I need a physical foldable phone for Appium testing?

Not for every scenario. A foldable AVD is effective for deterministic layout, lifecycle, and state-continuity checks, while physical devices remain important for vendor firmware, intermediate hinge angles, performance, and hardware-specific behavior.

How should an Appium test wait after folding the emulator?

Poll `getWindowSize()` or a semantic layout indicator until it changes, using a bounded timeout. Avoid relying only on a fixed sleep because transition time varies and a sleep cannot prove that the correct emulator received the command.

Why does my app restart when the foldable posture changes?

A posture change can alter window configuration and trigger Activity recreation, depending on the app and manifest configuration. The app should restore required user state, and the test should keep the same Appium session so lost state remains visible.

What selectors are most stable across folded and unfolded layouts?

Prefer accessibility IDs or stable Android resource IDs tied to user concepts. Avoid coordinate taps and hierarchy-position XPath because compact and expanded layouts often use different component trees and bounds.

Can foldable Appium tests run in CI?

Yes, if the runner supports Android Emulator acceleration and the selected AVD exposes fold controls. Use a fixed emulator port, wait for Android and Appium health, run one posture-changing worker per AVD, and retain screenshots, logcat, and Appium logs.

Related Guides