mobile-dev-inc / maestro

Painless Mobile UI Automation
https://maestro.mobile.dev/
Apache License 2.0
5.88k stars 281 forks source link

iOS miss `-` Launch Arguments when value type is Bool #2113

Open littlema0404 opened 4 weeks ago

littlema0404 commented 4 weeks ago

Is there an existing issue for this?

Steps to reproduce

appId: xxx
- launchApp:
    clearState: true
    permissions:
      userTracking: deny
    arguments:
        argumentA: true
        argumentB: 1
        argumentC: "abc"

Actual results

CommandLine.arguments // ["argumentA", "true", "-argumentB", "1", "-argumentC", "abc"]

Expected results

CommandLine.arguments // ["-argumentA", "true", "-argumentB", "1", "-argumentC", "abc"]

About app

Closed source iOS native app

About environment

Java version

openjdk version "17.0.10" 2024-01-16 LTS
OpenJDK Runtime Environment Corretto-17.0.10.7.1 (build 17.0.10+7-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.10.7.1 (build 17.0.10+7-LTS, mixed mode, sharing)

OS and its version

macOS 14.6.1(23G93)

Processor architecture

M2 arm64

Logs

Logs ``` ```

Maestro version

1.38.1

How did you install Maestro?

install script (https://get.maestro.mobile.dev)

Anything else?

- This is the specification for iOS launch arguments. Currently, only when the YAML value type is Bool, the - sign is not added. However, if the value type is Int or String, the - sign is automatically added.

When I use UserDefaults to retrieve argumentA, I won’t be able to find it.

let standardDefaultsDict = UserDefaults.standard.dictionaryRepresentation()
standardDefaultsDict["argumentA"] as? Bool // will get nil
standardDefaultsDict["argumentB"] as? Int // will get 1

I think the issue might be here.

https://github.com/mobile-dev-inc/maestro/blob/main/maestro-ios-driver/src/main/kotlin/util/IOSLaunchArguments.kt#L10-L18

It seems intentional, but I don’t understand why only boolean values are not prefixed with -.

linear[bot] commented 4 weeks ago

MA-2407 iOS miss `-` Launch Arguments when value type is Bool

Fishbowler commented 3 weeks ago

Looks like the intent in #1018 was that you'd access booleans differently?

littlema0404 commented 3 weeks ago

Looks like the intent in https://github.com/mobile-dev-inc/maestro/pull/1018 was that you'd access booleans differently?

Yeh, for here a little bit confused.

like example from #1018

 ProcessInfo.processInfo.arguments.contains("isMaestro")

The contains method only indicates whether the ‘isMaestro’ launch argument is present, but it doesn’t allow me to retrieve its boolean value.

So I have to use UserDefault to retrieve its boolean value. But I can't find it

johntmcintosh commented 3 weeks ago

I ran into this today as was/am confused as well.

In my case, I was passing one launch argument that was an explicit boolean, and another that was a boolean passed through the yaml environment:

appId: ${APP_ID}
---
- launchApp:
    arguments: 
        argA: true
        argB: ${ARG_B_VALUE}

and then I'm calling this flow with

appId: ${APP_ID}
---
- runFlow: 
    file: common/launch-app.yaml
    env:
      argB: false

and with this setup, I'm receiving the raw arguments in my app as:

["<path>/MyApp.app/MyApp", "argA", "true", "-argB", "false"]

And I have code in my app to extract values directly from ProcessInfo.processInfo.arguments, but that code is based on the expectation of arguments being prefixed with - or -- so it's not finding argA's value.

littlema0404 commented 3 weeks ago

There are two ways to access launch arguments in iOS. The first is through ProcessInfo.processInfo.arguments, which returns a String array containing all keys and values in the raw form. like

["<path>/MyApp.app/MyApp", "argA", "true", "-argB", "false"]

The second way is using UserDefaults.standard, allowing you to retrieve a value by its key directly. like

let standardDefaultsDict = UserDefaults.standard.dictionaryRepresentation()
standardDefaultsDict["argA"]

From my understanding, UserDefaults.standard will correctly retrieve the value only if the launch argument key has a - prefix. Without this prefix, the returned value will be nil. However, all launch arguments remain visible in ProcessInfo.processInfo.arguments, though it no longer provides the key-value pairing.

johntmcintosh commented 3 weeks ago

@littlema0404 looking back at the code you linked I realized that a workaround for passing boolean values is to include the - prefix in the argument name in the yaml. For example, if I define my original example instead as

appId: ${APP_ID}
---
- launchApp:
    arguments: 
        -argA: true
        -argB: ${ARG_B_VALUE}

then the arguments that resolve in the app are:

["<path>/MyApp.app/MyApp", "-argA", "true", "-argB", "false"]
littlema0404 commented 3 weeks ago

@johntmcintosh Yeh, I wanted to try this approach, but the issue with it is that if your YAML is shared with Android, they will also need to use keys with the ‘-’ prefix.