Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reland iOS landscape mode support #1974

Merged
merged 11 commits into from
Sep 9, 2024
Merged

Reland iOS landscape mode support #1974

merged 11 commits into from
Sep 9, 2024

Conversation

bartekpacia
Copy link
Contributor

@bartekpacia bartekpacia commented Aug 29, 2024

Context for the reviewer:

Copy link

Make sure to run ./maestro-ios-xctest-runner/build-maestro-ios-runner.sh with every swift change

@bartekpacia bartekpacia force-pushed the feature/ios-landscape branch 2 times, most recently from b654f84 to 8f2a2d6 Compare August 29, 2024 22:21
@bartekpacia bartekpacia changed the title Reapply "Fix iOS landscape mode, PR #1809" (#1916) Reland iOS landscape mode support Aug 29, 2024
@bartekpacia
Copy link
Contributor Author

bartekpacia commented Aug 30, 2024

The problem is that XCUIDevice.shared.orientation returns UIDeviceOrientation.unknown when the iOS simulator is first started. This effectively makes it impossible to query the iOS simulator for its orientation.

Plot twist

When the iOS simulator's orientation is manually changed (screenshot below), then [XCUIDevice.shared.orientation] starts returning correct value:

Screenshot 2024-08-30 at 14 47 04

[XCUIDevice.shared.orientation] also starts returning correct value when it's assigned a value:

XCUIDevice.shared.orientation = .portrait

Possible fix 1

If XCUIDevice.shared.orientation returns UIDeviceOrientation.unknown, let's assume that orientation is UIDeviceOrientation.portrait .

Possible fix 2

Introduce a new setOrientation command that will set orientation programatically, as shown above. Educate users that they have to call that command to change their app to a different orientation.

@bartekpacia
Copy link
Contributor Author

@bartekpacia bartekpacia force-pushed the feature/ios-landscape branch from 1cbab3e to e9a3b44 Compare September 9, 2024 07:39
@bartekpacia bartekpacia force-pushed the feature/ios-landscape branch 2 times, most recently from 45a17aa to 806c533 Compare September 9, 2024 08:30
@bartekpacia
Copy link
Contributor Author

bartekpacia commented Sep 9, 2024

Good thing 1 is that (from my testing) all iOS (and iPadOS) simulator always startup in portrait orientation, so defaulting to portrait when XCUIDevice.shared.orientation returns unknown seems like a good-enough workaround.

Good thing 2 is that even after I changed orientation of the simulator to portrait and then closed them (and killed Simulator.app), they all start up again in portrait.

Screenshot 2024-09-09 at 10 43 18

@bartekpacia
Copy link
Contributor Author

Demo:

demo_2x.mp4

@bartekpacia bartekpacia force-pushed the feature/ios-landscape branch from 55a2ce8 to d75bd93 Compare September 9, 2024 11:20
This was a source of bugs when device orientation changed.

AndroidDriver has never cached values, instead it was always requesting them
for each new command that used them. Now iOS driver does the same.
@bartekpacia bartekpacia marked this pull request as ready for review September 9, 2024 13:37
@herval
Copy link
Collaborator

herval commented Sep 9, 2024

The problem is that XCUIDevice.shared.orientation returns UIDeviceOrientation.unknown when the iOS simulator is first started. This effectively makes it impossible to query the iOS simulator for its orientation.

Plot twist

When the iOS simulator's orientation is manually changed (screenshot below), then [XCUIDevice.shared.orientation] starts returning correct value:

Screenshot 2024-08-30 at 14 47 04 `[XCUIDevice.shared.orientation]` also starts returning correct value when it's assigned a value:
XCUIDevice.shared.orientation = .portrait

Possible fix 1

If XCUIDevice.shared.orientation returns UIDeviceOrientation.unknown, let's assume that orientation is UIDeviceOrientation.portrait .

Possible fix 2

Introduce a new setOrientation command that will set orientation programatically, as shown above. Educate users that they have to call that command to change their app to a different orientation.

how about option 3 - if it returns unknown, set it to portrait (the difference from that to option 1 is it would correct the behavior from there on, so if there's anything else that requires device orientation, it'd receive the correct value)

val deviceName: String
get() = driver.name()

private var _cachedDeviceInfo: DeviceInfo? = null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't these two (this and the original code) functionally the same? My understanding is this is what by lazy does behind the scenes

Copy link
Contributor Author

@bartekpacia bartekpacia Sep 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is.

I changed it away from using lazy because I needed _cachedDeviceInfo to be a var instead of val for $reasons which are no longer valid because I changed the code and forgot to bring it back.

@@ -160,8 +163,10 @@ class Maestro(
}

fun swipeFromCenter(swipeDirection: SwipeDirection, durationMs: Long) {
val deviceInfo = deviceInfo()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesnt seem to use the cached info - is that the intent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

If we use the cached version, then swipe will completely break if the device is rotated mid-flow (or when running maestro test in --continuous mode).

@@ -529,3 +507,14 @@ class IOSDriver(
private const val SCREEN_SETTLE_TIMEOUT_MS: Long = 3000
}
}

private fun Double.asPercentOf(total: Int): Int {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the advantage of this over the regular private functions from before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conciseness, mainly.

If I were to keep using widthPercentToPoint(percent: Double) I'd have to refactor it to widthPercentToPoint(percent: Double, width: Double) which becomes a bit long and repetitive.

if orientation == .unknown {
// If orientation is "unknown", we assume it is "portrait" to
// work around https://stackoverflow.com/q/78932288/7009800
return UIDeviceOrientation.portrait
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would be the implications of setting it to portrait as a side-effect here, when it's unknown?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As of now, I'm not aware of any. See "good things" above.

@bartekpacia bartekpacia merged commit 92c1984 into main Sep 9, 2024
7 checks passed
@bartekpacia bartekpacia deleted the feature/ios-landscape branch September 9, 2024 15:04
@bartekpacia
Copy link
Contributor Author

bartekpacia commented Sep 12, 2024

Updated caveats

Consider this older list of caveats to be out-of-date and not true.

Here's the actual list of caveats, as of now:

  • (iOS) breaks when simulator is "physically" in landscape, but app is locked to portrait. I consider this a rare edge case and suggest we are fine with it.

    What exactly happens?

    • taps made in Maestro Studio don't work (likely cause: coordinates aren't translated correctly)
    • preview in Maestro Studio is broken (see example below)
    Example

    Screenshot 2024-09-12 at 20 14 22

    Screenshot 2024-09-12 at 20 14 50

    possible fix: find iOS/XCUITest APIs that allow us to detect this situation and handle accordingly

  • (Android) Maestro Studio is broken when the device and app are in horizontal orientation Fixed in fix landscape mode in Maestro Studio on both Android and iOS #2050

    Example

    Screenshot 2024-09-12 at 15 14 53

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants