WWDC22 SALE: Save 50% on all my Swift books and bundles! >>

SOLVED: UI Tests, screenshots, and fastlane

Forums > iOS

I've just spent the past two days wrestling with fastlane and with my laptop's ruby installation, but now I've got my project set up so that it can generate all my app screenshots for the App Store. Yay!

Except.

Some of the necessary screen shots are for devices that have a Home button, and some are for devices that do not. For example, the 3rd generation iPad Pro (12.9" display) doesn't have a Home button and the screen shot will therefore have the little widget at the bottom, while the 2nd generation iPad Pro (12.9" display) does have a Home button, and so those screen shots will not have a bar at the bottom.

Which is fine, in itself, as we have simulators for all these devices and can run the UI tests against them all, and take the screen shots. But, and this is the part that's tripping me up, the widget hierarchy on the screen is different, depending on which of these device types we've got!

In order to get the corner tile in my game board and tap on it, to show what the screen looks like when a tile is selected, here's what I do for a classic iPad with a home button:

    func testWithHomeButton() throws {
        snapshot("01MainMenu")
        app.buttons["Medium Board"].tap()

        snapshot("02MediumBoard")
        let element = app.windows.children(matching: .other)
            .element.children(matching: .other)
            .element.children(matching: .other)
            .element

        element.children(matching: .image).matching(identifier: "1").element(boundBy: 0).tap()
        snapshot("03SelectATile")
        element.children(matching: .image).matching(identifier: "1").element(boundBy: 1).tap()
        snapshot("04SelectAMatch")
    }

Now, here's what I have to do on a device with no home button:

    func testWithoutHomeButton() throws {
        snapshot("01MainMenu")
        app.buttons["Medium Board"].tap()

        snapshot("02MediumBoard")
        let element = app.windows.children(matching: .other)
            .element.children(matching: .other)
            .element.children(matching: .other)
            .element.children(matching: .other)
            .element

        element.children(matching: .image).matching(identifier: "1").element(boundBy: 0).tap()
        snapshot("03SelectATile")
        element.children(matching: .image).matching(identifier: "1").element(boundBy: 1).tap()
        snapshot("04SelectAMatch")
    }

The only difference is that the game board is nested one layer deeper without a Home button. This makes me think there must be a better way to get hold of these things, better than this .element.children(matching: .other)... for a magic number of times. Is there a label I should be applying in my SwiftUI code, that the test could then look for?

1      

Aha! It was as simple as changing one children to descendants, and using the shallower tree.

        element.descendants(matching: .image).matching(identifier: "1").element(boundBy: 0).tap()

Thanks for the article, Paul!

1      

Save 50% in my Black Friday sale.

SAVE 50% To celebrate WWDC22, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.