feat(testrun): route iOS simulators through the native companion driver

This commit is contained in:
pj committed 2026-06-06 23:45:13 +05:30
1 parent 966aeba6c0
commit 75d4294601
2 files changed
+62 -16

No files matched your search

+24 -5
View File
@@ -14,14 +14,15 @@ import (
"github.com/priyanshujain/sanderling/internal/android" "github.com/priyanshujain/sanderling/internal/android"
"github.com/priyanshujain/sanderling/internal/driver" "github.com/priyanshujain/sanderling/internal/driver"
"github.com/priyanshujain/sanderling/internal/driver/chrome" "github.com/priyanshujain/sanderling/internal/driver/chrome"
"github.com/priyanshujain/sanderling/internal/driver/ioscompanion"
driverSidecar "github.com/priyanshujain/sanderling/internal/driver/sidecar" driverSidecar "github.com/priyanshujain/sanderling/internal/driver/sidecar"
"github.com/priyanshujain/sanderling/internal/ios"
"github.com/priyanshujain/sanderling/internal/sidecarassets" "github.com/priyanshujain/sanderling/internal/sidecarassets"
) )
// buildDriver creates the appropriate DeviceDriver for the platform and returns // buildDriver creates the appropriate DeviceDriver for the platform and returns
// a cleanup function. For web, ChromeDriver is used directly; for android/ios // a cleanup function. For web, ChromeDriver is used directly. An iOS simulator
// the JVM sidecar is extracted, spawned, and dialed. // is driven by the native simulator companion (no JVM). Android and physical
// iOS devices use the JVM sidecar, which is extracted, spawned, and dialed.
func buildDriver(ctx context.Context, options Options, stdout io.Writer) (driver.DeviceDriver, func(), error) { func buildDriver(ctx context.Context, options Options, stdout io.Writer) (driver.DeviceDriver, func(), error) {
if err := Preflight(ctx, options.Platform); err != nil { if err := Preflight(ctx, options.Platform); err != nil {
return nil, nil, err return nil, nil, err
@@ -31,6 +32,24 @@ func buildDriver(ctx context.Context, options Options, stdout io.Writer) (driver
return d, func() { _ = d.Terminate(context.Background()) }, nil return d, func() { _ = d.Terminate(context.Background()) }, nil
} }
if options.Platform == "ios" && options.iosIsSimulator {
d, err := ioscompanion.New(ctx, ioscompanion.Options{
UniqueDeviceIdentifier: options.iosUDID,
BundleID: options.BundleID,
AppPath: options.IosAppPath,
Output: stdout,
})
if err != nil {
return nil, nil, fmt.Errorf("ios simulator driver: %w", err)
}
return d, d.Close, nil
}
// Physical iOS devices and Android use the JVM sidecar, which requires java.
if err := preflightDevice(options.Platform); err != nil {
return nil, nil, err
}
sidecarDirectory := os.TempDir() + "/sanderling-sidecar" sidecarDirectory := os.TempDir() + "/sanderling-sidecar"
jarPath, err := sidecarassets.Extract(sidecarDirectory) jarPath, err := sidecarassets.Extract(sidecarDirectory)
if err != nil { if err != nil {
@@ -47,8 +66,8 @@ func buildDriver(ctx context.Context, options Options, stdout io.Writer) (driver
"--platform", options.Platform, "--platform", options.Platform,
} }
if options.Platform == "ios" { if options.Platform == "ios" {
if udid := ios.BootedUDID(ctx); udid != "" { if options.iosUDID != "" {
sidecarArgs = append(sidecarArgs, "--udid", udid) sidecarArgs = append(sidecarArgs, "--udid", options.iosUDID)
} }
} }
sidecarCommand := exec.CommandContext(ctx, "java", sidecarArgs...) sidecarCommand := exec.CommandContext(ctx, "java", sidecarArgs...)
+38 -11
View File
@@ -23,15 +23,21 @@ const sidecarStartupTimeout = 30 * time.Second
// Options are the parameters for a single test pipeline run. // Options are the parameters for a single test pipeline run.
type Options struct { type Options struct {
Spec string Spec string
BundleID string BundleID string
Platform string Platform string
AVD string AVD string
IosDevice string IosDevice string
Duration time.Duration IosAppPath string
Seed int64 Duration time.Duration
Output string Seed int64
ClearData bool Output string
ClearData bool
// iosUDID and iosIsSimulator are filled by Execute after resolving the iOS
// target, then read by buildDriver to choose the companion or sidecar path.
iosUDID string
iosIsSimulator bool
} }
// Execute runs the full test pipeline: bundle, launch app, verify properties. // Execute runs the full test pipeline: bundle, launch app, verify properties.
@@ -42,9 +48,30 @@ func Execute(ctx context.Context, options Options, stdout io.Writer) error {
return err return err
} }
case "ios": case "ios":
if err := ios.EnsureSimulator(ctx, options.IosDevice, stdout); err != nil { udid, isSimulator, err := ios.ResolveTarget(ctx, options.IosDevice)
return err if err != nil {
// No query and nothing booted: keep boot-first behavior, then resolve
// the simulator that EnsureSimulator just brought up.
if options.IosDevice == "" {
if bootErr := ios.EnsureSimulator(ctx, "", stdout); bootErr != nil {
return bootErr
}
udid, isSimulator, err = ios.ResolveTarget(ctx, "")
}
if err != nil {
return err
}
} else if isSimulator {
if err := ios.EnsureSimulator(ctx, options.IosDevice, stdout); err != nil {
return err
}
udid, isSimulator, err = ios.ResolveTarget(ctx, options.IosDevice)
if err != nil {
return err
}
} }
options.iosUDID = udid
options.iosIsSimulator = isSimulator
} }
prep, err := prepareBundleInputs(options) prep, err := prepareBundleInputs(options)
if err != nil { if err != nil {