Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS UITest - Navigate to all available screens

I am using iOS UITest for a Swift application. I use something like,

func testAllScreenNavigation() {

    let app = XCUIApplication()
    app.tabBars.buttons["Home"].tap()
    app.navigationBars["Home"].buttons["More"].tap()
    app.sheets.buttons["Cancel"].tap()
}

etc. to navigate some of the specific, tabs, buttons, etc. and switch to respective screens. But i want to navigate each and every screens of my Application (It can be BFS style navigation or DFS style navigation, no matter). Is there any way iOS provides so i can get all navigable elements and then explore deeper and deeper automatically for my App?

I also need to keep trace of which xcuoelement in a screen is already processed and which are not yet processed.

like image 783
Sazzad Hissain Khan Avatar asked Mar 10 '23 18:03

Sazzad Hissain Khan


2 Answers

The only way I can think of is using Xcode UI test recorder feature. While you are recording, navigate through all of your screens via the device/simulator and then the XCUIApplication() variable would be recorded with the appropriate references. If the button/nav bar/any element has text on it, it will show up in the recorded code or else it will be referenced numerically.

Hope that helps.

Kind regards, Mukund

like image 127
Mukund Agarwal Avatar answered Mar 20 '23 00:03

Mukund Agarwal


I like your idea for getting all views and check whether the layouting and localization for example is fine.

I think you need to specify your criteria for "screens" and how they are accessed.

Basically, one could thing of the following structure

- UITabBarController
-- UISplitViewController
--- UINavigationController
---- UIViewController
----- UIBarButtonItems
----- UIView
----- UIButton
----- UISwitch
----- UITableViewCell

You could now go top down from the UITabBarController to the next controlling instance (might also skip one, e.g. SplitViewControllers on iPhones).

You can use the general property:

XCUIApplication().tabBars

Nevertheless that transition is the problem: How would you get from one ViewController to another and are they all position in the ViewController's View or do you have to loop the subviews of a view.

UIButton -> Touch Up Inside
UISwitch -> Value Changed
UITableViewCell -> DidSelectRowAtIndexPath
UIView -> UILongPressGestureRecognizer

This is how I would basically set it up: For each UIViewController instance, get the related View (and perform the following call recursively).

Check all the subviews of a view. For UIViews, go even further and check their subviews For UIButtons, perform TouchUpInside and so on. Make sure to have a condition to stop going deeper, as UITableViews got a lot of subviews or your UIWebViews would of course be set up in a different way.

This way you should be able to navigate through a lot Views in your app hierarchy, but you will need some extensions for UIBarButtonItems, custom Gesture Recognizers and of course also for your "special" controls that might listen to value changes and perform a layout-change.


Accessing specific elements

In addition to the above approach where you simply get an array of elements of a specific type, you can access specific elements (e.g. those where you know they are of a very specific type with certain ValueChangeListeners or something)

To access a specific object in particular, like the TabBar example from above, you can use the accessibilityLabel like so. At first you need to declare the accessibilityLabel in your code or in the .xib-file/.storyboard:

// just to illustrate, so you get an idea:
self.tabBarController.isAccessibilityElement = true
self.tabBarController.accessibilityLabel = "tabBar"

And then do:

let tabBar = XCUIApplication().tabBars["tabBar"]

Here is Apple's documentation for setting these accessibilityLabels: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/iPhoneAccessibility/Making_Application_Accessible/Making_Application_Accessible.html

A great way to get the related identifier of an element would be to use the Accessibility Inspector from Apple: https://developer.apple.com/library/content/technotes/TestingAccessibilityOfiOSApps/TestAccessibilityiniOSSimulatorwithAccessibilityInspector/TestAccessibilityiniOSSimulatorwithAccessibilityInspector.html


Accessing elements in general

To access elements in general, you need to make use of the XCUIElementType of these objects, here you will access the objects based on their classes. E.g. you could call: "tabBars", "navBars", "tables", "buttons", and so on from the elements in general.

Still you would be facing the issue with "special controls". As the Apple documentation lacks (imho) some detail about properties and attributes, I do recommend the docs here: https://blog.metova.com/guide-xcode-ui-test/ It provides a great overview of what is accessible and may help you getting some better understanding.

An overview of the available XCUIElementTypes can be found here. Basically, the elementType property is an enumerated value that represents the type of an element. XCUIElementType is a very large enumeration and some of its members do not apply to iOS applications (they apply to MacOS X apps). Some of the more commonly used values are:

Alert
Button
NavigationBar
TabBar
ToolBar
ActivityIndicator
SegmentedControl
Picker
Image
StaticText
TextField
DatePicker
TextView
WebView

https://developer.apple.com/reference/xctest/xcuielementtype?language=objc

like image 33
Lepidopteron Avatar answered Mar 20 '23 00:03

Lepidopteron