fix(ios): a failed devicectl uninstall must fail the reinstall

same hole as the simulator path: devicectl install over an app keeps its data, and the discarded uninstall error hid it. Uninstalling a bundle id that is not installed exits 0 with 'App uninstalled.' on a paired iPhone, so a failure here is always real.
This commit is contained in:
pj committed 2026-08-16 00:02:36 +05:30
1 parent abc5e7db3e
commit 6234bf5ba0
2 files changed
+47 -1

No files matched your search

@@ -7,6 +7,7 @@ import (
"net"
"os/exec"
"slices"
"strings"
"testing"
"github.com/priyanshujain/sanderling/internal/driver/ioscompanion/transport"
@@ -182,6 +183,45 @@ func TestNewDeviceReinstallsOnceBeforeTheRunnerSession(t *testing.T) {
}
}
func TestDevicectlReinstallStopsWhenTheUninstallFails(t *testing.T) {
log := scriptedXcrun(t, `"devicectl device uninstall "*) echo "ERROR: Internal logic error: Connection was invalidated"; exit 1;;
"devicectl device install "*) :;;`)
d := &Driver{coreDeviceID: "CORE-DEVICE", bundleID: "app.example", appPath: "/tmp/Sample.app"}
err := d.devicectlReinstall(context.Background())
if err == nil {
t.Fatal("devicectlReinstall reported success while app.example kept the data clear-state was asked to remove")
}
for _, want := range []string{"app.example", "Connection was invalidated"} {
if !strings.Contains(err.Error(), want) {
t.Errorf("error %q does not quote %q", err, want)
}
}
calls := xcrunCalls(t, log)
if slices.ContainsFunc(calls, func(call string) bool { return strings.HasPrefix(call, "devicectl device install") }) {
t.Errorf("xcrun calls = %v: installing over the app carries its data into the run", calls)
}
}
func TestDevicectlReinstallProceedsWhenNothingIsInstalled(t *testing.T) {
log := scriptedXcrun(t, `"devicectl device uninstall "*) echo "App uninstalled.";;
"devicectl device install "*) :;;`)
d := &Driver{coreDeviceID: "CORE-DEVICE", bundleID: "app.example", appPath: "/tmp/Sample.app"}
if err := d.devicectlReinstall(context.Background()); err != nil {
t.Fatalf("devicectlReinstall: %v", err)
}
want := []string{
"devicectl device uninstall app --device CORE-DEVICE app.example",
"devicectl device install app --device CORE-DEVICE /tmp/Sample.app",
}
if got := xcrunCalls(t, log); !slices.Equal(got, want) {
t.Fatalf("xcrun calls = %v, want %v", got, want)
}
}
func TestDeviceClearStateWithoutAppPathWarnsOnce(t *testing.T) {
output := &bytes.Buffer{}
d := &Driver{output: output, deviceMode: true}