# How to Use vphone-cli for End-to-End E2E Testing of iOS VMs

> Master end-to-end E2E testing for iOS VMs with vphone-cli. Learn to provision firmware, boot virtual machines, and drive UI interactions for robust testing.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: how-to-guide
- Published: 2026-09-09

---

**vphone-cli enables end-to-end E2E testing of iOS VMs by orchestrating three phases: provisioning patched firmware via [`VPhoneFirmwareSelection.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFirmwareSelection.swift) and `FirmwarePatcher`, booting a `VZVirtualMachine` with a vsock device on port 1337, and driving UI interactions through the `vphoned` daemon using a length-prefixed JSON protocol with unique request-IDs.**

vphone-cli is a full-stack virtualization framework for Apple Silicon that creates programmable iPhone virtual machines for automated testing workflows. By combining firmware patching, DFU restoration, and a host-control socket architecture, it exposes deterministic iOS environments to external test harnesses through a structured communication protocol. This guide explains how to implement complete E2E testing pipelines using the Swift core and command-line interfaces according to the Lakr233/vphone-cli source code.

## Three-Phase E2E Testing Architecture

End-to-end testing with vphone-cli follows a strict lifecycle comprising VM provisioning, boot configuration, and test driver execution. Each phase maps to specific source files in the repository.

### Phase 1: VM Provisioning

The provisioning phase prepares a custom firmware bundle through four sequential operations. First, `fw prepare` in [`VPhoneFirmwareSelection.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFirmwareSelection.swift) downloads the target IPSW and merges the iPhone filesystem with cloudOS components. Next, `fw patch` invokes the `FirmwarePatcher/*` modules—such as [`KernelJBPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/KernelJBPatcher.swift)—to apply firmware variants like `jb` (jailbreak) or `exp` (experimental) to the kernel image.

The process continues with `restore` operations defined in [`VPhoneRestoreOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneRestoreOps.swift), which performs a DFU-mode restoration of the VM's root filesystem. Finally, `cfw install` via [`VPhoneFWCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFWCLI.swift) mounts the custom firmware on the host, making it available for the virtual machine bundle.

### Phase 2: VM Boot Configuration

Once provisioned, [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) constructs the virtual machine environment by creating a `VZVirtualMachineConfiguration` object. This configuration attaches a `VZVirtioSocketDevice` configured for **port 1337**, establishing the communication channel between host and guest. The VM launches with the patched kernel image and an optional USB touch injection device, though iOS 18-based VMs require guest-side touch handling.

The boot process exposes a Unix-domain host-control socket at `<bundle>/vphone.sock`, enabling external test runners to interface with the running VM without direct Swift dependencies.

### Phase 3: Test Driver Integration

After the VM boots, the guest-side `vphoned` daemon (compiled via [`scripts/build.sh`](https://github.com/Lakr233/vphone-cli/blob/main/scripts/build.sh)) listens on the vsock port and advertises capabilities through a `caps` handshake. The host-side client implemented in [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) connects to this socket and communicates via a **length-prefixed JSON protocol** where every request includes a unique **request-ID** and awaits a typed response.

Key protocol operations include:

- `sendTouch` for HID event injection (with `useGuestTouchInjection` enabled for iOS 18+)
- `sendRequest` with type `screenshot` for UI capture
- `installIPA` for application deployment
- `appLaunch` with bundle ID execution
- `accessibilityTree` for UI hierarchy inspection

## Implementing E2E Test Workflows

You can automate E2E tests using either the Swift SDK for type-safe integration or shell scripts for CI pipelines.

### Swift SDK Approach

The following Swift example demonstrates the complete lifecycle from VM creation to UI assertion:

```swift
import VPhoneCore
import VPhoneCLI

// 1️⃣ Create (or reuse) a VM called “e2e‑test”
let vmName = "e2e-test"
let vm = try VPhoneVirtualMachine(name: vmName, variant: .jb)
try vm.create()
try vm.prepare(iphoneVersion: "26.1")
try vm.patch()
try vm.restore()
try vm.installCFW()
try vm.launch()

// 2️⃣ Connect to the guest daemon
let control = VPhoneControl(variant: .jb)
control.connect(device: vm.vsockDevice)

// 3️⃣ Execute test sequence
Task {
    // Verify touch injection capability
    if control.useGuestTouchInjection {
        await control.sendTouch(phase: 0, x: 0.5, y: 0.5)   // down
        await control.sendTouch(phase: 3, x: 0.5, y: 0.5)   // up
    }

    // Take screenshot for AI verification
    let (_, screenshot) = try await control.sendRequest(["t": "screenshot"])
    
    // Install and launch app
    let ipaURL = URL(fileURLWithPath: "/path/to/MyApp.ipa")
    let result = try await control.installIPA(localURL: ipaURL)
    let pid = try await control.appLaunch(bundleId: "com.example.myapp")
    
    // Verify UI state
    let tree = try await control.accessibilityTree()
    
    // Clean-up
    await control.disconnect()
}

```

### CLI Automation Approach

For shell-based CI pipelines, the equivalent workflow uses the `vphone-cli` binary:

```bash

# 1️⃣ Provision the VM

vphone-cli vm create e2e-test -V jb

# 2️⃣ Launch the VM (background)

vphone-cli vm launch e2e-test --dfu &

# 3️⃣ Wait for guest handshake (poll until ready)

# vphone-cli automatically reconnects; verify with `vphone-cli vm info`

# 4️⃣ Inject touch events at screen center

vphone-cli control touch --phase down --x 0.5 --y 0.5
vphone-cli control touch --phase up   --x 0.5 --y 0.5

# 5️⃣ Capture screenshot for diffing

vphone-cli control screenshot > screen.png

# 6️⃣ Install IPA and launch application

vphone-cli install myapp.ipa
vphone-cli control app launch --bundle-id com.example.myapp

```

## Key Implementation Files

| File | Responsibility |
|------|----------------|
| [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) | Orchestrates `VZVirtualMachineConfiguration`, vsock device attachment on port 1337, and lifecycle management. |
| [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) | Implements the host-side JSON protocol client with methods like `sendRequest()`, `sendTouch()`, and `installIPA()`. |
| [`VPhoneFWCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFWCLI.swift) | Exposes `fw` subcommands (`prepare`, `patch`) that drive the firmware modification pipeline. |
| [`FirmwarePatcher/Kernel/KernelJBPatcher.swift`](https://github.com/Lakr233/vphone-cli/blob/main/FirmwarePatcher/Kernel/KernelJBPatcher.swift) | Applies jailbreak and experimental patches to kernel images based on selected variants. |
| [`VPhoneRestoreOps.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneRestoreOps.swift) | Handles DFU restoration sequences for the VM filesystem. |
| `scripts/vphoned` | Guest-side Objective-C daemon listening on vsock port 1337, implementing screenshot capture and touch injection. |

## Summary

- **VM Provisioning** requires executing `prepare`, `patch`, `restore`, and `installCFW` operations through [`VPhoneFirmwareSelection.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFirmwareSelection.swift) and [`VPhoneFWCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneFWCLI.swift) to generate a bootable patched firmware.
- **VM Boot** uses [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) to configure a `VZVirtualMachine` with a `VZVirtioSocketDevice` on **port 1337**, exposing control via Unix socket.
- **Test Execution** relies on [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) communicating with the `vphoned` daemon via a length-prefixed JSON protocol supporting screenshots, touch injection (necessary for iOS 18), IPA installation, and accessibility queries.
- **Both Swift and CLI interfaces** provide deterministic automation suitable for headless CI environments on Apple Silicon hosts with relaxed SIP/AMFI settings.

## Frequently Asked Questions

### What hardware is required for vphone-cli E2E testing?

vphone-cli requires Apple Silicon Macs (M1 or later) with SIP (System Integrity Protection) and AMFI (Apple Mobile File Integrity) relaxed or disabled. The host must run macOS with the Virtualization framework available, as [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) depends on `VZVirtualMachine` and related private APIs declared in [`Package.swift`](https://github.com/Lakr233/vphone-cli/blob/main/Package.swift).

### How does the JSON protocol ensure request/response correlation?

According to [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift), every command sent to the `vphoned` daemon includes a unique **request-ID** field in the JSON payload. The daemon echoes this identifier in its response, allowing the host-side `sendRequest()` method to match asynchronous replies with their originating commands over the vsock connection.

### Why is `useGuestTouchInjection` necessary for iOS 18 VMs?

In iOS 18-based virtual machines, the native `VZUSBPointerDevice` path stops delivering digitizer events to the guest OS. As implemented in [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift), the `useGuestTouchInjection` property enables the fallback mechanism where touch coordinates are forwarded through the vsock JSON protocol to the `vphoned` daemon, which injects HID events directly into the guest's input subsystem.

### Can vphone-cli integrate with existing CI/CD pipelines?

Yes. The tool supports headless operation through the CLI interface, and the host-control socket (`vphone.sock`) allows external test harnesses like `vphone-mcp` to drive VMs without Swift dependencies. Because all interactions use deterministic JSON commands and inline screenshot capture, you can incorporate vphone-cli into GitHub Actions, Jenkins, or custom runners on Apple Silicon build agents.