Testing on Foldable Devices
iPhone Duo has two displays: an outer display you use when the device is closed, and a larger inner display you use when it's open. With Digital.ai Testing you can fold and unfold the device, set any hinge angle between 0° and 180°, and choose which display your test works with. This lets you test how your app behaves in each posture and during the switch between them.
Supported devices and prerequisites
| Target | Requirements |
|---|---|
| iPhone Duo simulator | The host Mac needs Xcode 27.1 or later and an iOS 27.1 or later simulator runtime. |
| iPhone Duo real device | Supported in Digital.ai Testing 26.10 and later. |
| Appium sessions | Set the appiumVersion capability to 3.8.1 or later. Appium 3.8.1 and later is available in Digital.ai Testing 26.10 and later. |
To select an iPhone Duo, use the FOLDABLE category in your device query:
capabilities.setCapability("digitalai:deviceQuery", "@os='ios' and @category='FOLDABLE'");
Displays and postures
| Posture | Hinge angle | Active display |
|---|---|---|
folded | 0° | Outer |
halfOpened | 90° | Inner |
continuous (unfolded) | 180° | Inner |
Use listDisplays to get each display's ID, size and state. In our tests, the outer display had ID 1 (1398 × 2034 px) and the inner display had ID 3 (2007 × 2853 px). Don't hard-code these values; read them from listDisplays.
Supported commands by execution mode
| Command | Appium Server (Docker Swarm, Local Appium) | Appium Grid | SeeTest Client / STA | Appium Studio |
|---|---|---|---|---|
| Set hinge angle | mobile: setSimulatedHingeAngle | mobile: setSimulatedHingeAngle | setSimulatedHingeAngle(angle) | [TBD] |
| Get hinge angle | mobile: getSimulatedHingeAngle | mobile: getSimulatedHingeAngle | getSimulatedHingeAngle() | [TBD] |
| List displays | mobile: listDisplays | mobile: listDisplays | listDisplays() | [TBD] |
| Set posture | mobile: setDevicePosture | mobile: setDevicePosture | setDevicePosture(posture) | [TBD] |
| Reset posture | mobile: clearDevicePosture | mobile: clearDevicePosture | [TBD] | [TBD] |
| Choose a display | currentDisplayId setting | [TBD] | – | – |
Command reference
| Command | Arguments | Returns / effect |
|---|---|---|
mobile: setSimulatedHingeAngle | angle: A number from 0 to 180. Fractional values are allowed. | Sets the hinge angle. The command returns after the device reaches the specified angle. The command name is the same for simulators and real devices. |
mobile: getSimulatedHingeAngle | – | Returns the current hinge angle. |
mobile: listDisplays | – | Returns a list of displays. Each display includes id, metrics (widthPixels, heightPixels, xStart, yStart), isDefault, and active. |
mobile: setDevicePosture | posture: folded, halfOpened, or continuous. The value is not case-sensitive. | Moves the hinge to 0°, 90°, or 180°, respectively. The same command works on Android foldables, where halfOpened is not supported. |
mobile: clearDevicePosture | – | Returns the device to the session default posture: unfolded, at 180°. |
currentDisplayId (setting) | A display ID returned by listDisplays, or null for the main display. | Sets the display that receives screenshots, taps, and swipes. |
Code examples
- Appium (Java)
- Appium (Python)
- SeeTest Client (Java)
// Close the device and work on the outer display
driver.executeScript("mobile: setDevicePosture", Map.of("posture", "folded"));
driver.findElement(AppiumBy.accessibilityId("Search")).click();
// Open the device fully
driver.executeScript("mobile: setDevicePosture", Map.of("posture", "continuous"));
// Set an exact angle and read it back
driver.executeScript("mobile: setSimulatedHingeAngle", Map.of("angle", 120));
Object angle = driver.executeScript("mobile: getSimulatedHingeAngle");
// Inspect the displays
Object displays = driver.executeScript("mobile: listDisplays");
// Return to the default posture
driver.executeScript("mobile: clearDevicePosture");
driver.execute_script("mobile: setDevicePosture", {"posture": "folded"})
driver.execute_script("mobile: setSimulatedHingeAngle", {"angle": 90})
displays = driver.execute_script("mobile: listDisplays")
driver.update_settings({"currentDisplayId": None}) # back to the main display
client.setDevicePosture("folded");
client.setSimulatedHingeAngle(90);
String angle = client.getSimulatedHingeAngle();
String displays = client.listDisplays();
Following the active display
After each fold or hinge change, the cloud switches currentDisplayId to the active display: the outer display when the device is closed, and the inner display when it's open. Screenshots, page source, element lookup, gestures, window size, the Mobile Studio stream and the video all follow the active display.
To pick a display yourself, set currentDisplayId. Your choice stays in place until the next fold or hinge command. To turn off automatic switching for a session, set the capability digitalai:autoFollowActiveDisplay to false.
Session behavior
- Every session starts with the device unfolded (180°) and the inner display active.
- When the session ends, the device returns to 180°.
- If a fold or hinge command is already running on the device (from Appium, SeeTest Client or Mobile Studio), a second one fails until the first finishes.
- When a test changes the posture, Mobile Studio switches to the matching skin (Open or Folded).
Reports and Video
Each fold, posture or hinge command appears as its own step in the test report, with a screenshot of the active display. The video keeps recording across fold changes and follows the active display.
Known limitations
- Apps built with an older iOS SDK: apps built with an iOS SDK older than 27 can miss taps at some hinge angles. Build your app with iOS SDK 27.1 or later.
- The path to an angle matters: 90° reached from closed can lay out differently from 90° reached from open. Define the full sequence of postures in your test.
- Don't change the posture during a gesture: wait for a scroll or swipe to finish before you fold or unfold the device.
- Read-back tolerance: the angle reported after a change can differ from the requested angle by a few degrees. For example, it can read 85° or 87° after you request 90°.
Error messages
| Error | Cause |
|---|---|
Hinge control is supported only on iPhone Duo devices. Current device: <model> (iOS <version>). | The device isn't an iPhone Duo. |
Invalid hinge angle '<value>'. Use a number between 0 and 180. | The angle is missing, isn't a number, or is outside the range of 0–180. |
Invalid posture '<value>'. Supported on iPhone Duo: folded, continuous, halfOpened. | The posture value is not recognized. |
iPhone Duo did not reach the requested hinge angle <n>° within <t>s (current: <m>°, active display: <id>). | The operation timed out before the device reached the requested hinge angle. |
Another fold operation is in progress on this device. Retry after it completes. | Another hinge or fold operation is running on the device. |
iPhone Duo hinge control requires Xcode 27.1 or later and an iOS 27.1+ simulator runtime. | The required simulator prerequisites are missing. |