I prefer to use the debugger built into Xcode, lldb, when learning how to locate elements on the screen. I have the ability to display the elements tree for every screen in my app. From that I can see accessibility identifiers, labels, values for UI elements plus coordinates for each element. From this information, I am able to work out the path to each element. I can then directly enter queries on the command line which I can later use when implementing a screen class.

In Xcode, the debugger is active when your program stops execution at a breakpoint. The name for the window’s pane is the Debugger Area
. Below, are several common command lines I use when I have hit a breakpoint. You can set a breakpoint on the first line of your test to get into the debugger.

Where I have a class var named app
set to value of XCUIApplication()
po self.app
. If there is no variable for XCUIApplication() then typing po XCUIApplication()
also will output the same element tree as shown below.
Attributes: Application, pid: 75589, label: 'DemoAuto'
Element subtree:
→Application, 0x600003e3cb60, pid: 75589, label: 'DemoAuto'
Window (Main), 0x600003e3cd00, {{0.0, 0.0}, {375.0, 667.0}}
Other, 0x600003e3cdd0, {{0.0, 0.0}, {375.0, 667.0}}
Button, 0x600003e3cea0, {{22.0, 80.0}, {136.0, 30.0}}, identifier: 'show-text-button', label: 'Show Label'
StaticText, 0x600003e3ca90, {{22.0, 129.0}, {136.0, 21.0}}, identifier: 'show-text-label'
Button, 0x600003e3c8f0, {{22.0, 226.0}, {136.0, 30.0}}, label: 'Open Settings'
Button, 0x600003e3c9c0, {{22.0, 264.0}, {136.0, 30.0}}, identifier: 'open-safari-button', label: 'Open Safari'
Button, 0x600003e3c820, {{36.0, 327.0}, {30.0, 30.0}}
StaticText, 0x600003e3c680, {{22.0, 365.0}, {94.0, 21.0}}, label: 'No Identifier'
TextField, 0x600003e3c750, {{16.0, 405.0}, {107.0, 30.0}}, value: Default Value
Window, 0x600003e3c5b0, {{0.0, 0.0}, {375.0, 667.0}}
StatusBar, 0x600003e3c4e0, {{0.0, 0.0}, {375.0, 20.0}}
Other, 0x600003e3c410, {{0.0, 0.0}, {375.0, 20.0}}
Other, 0x600003e3c340, {{0.0, 0.0}, {375.0, 20.0}}
Other, 0x600003e3c270, {{6.0, 0.0}, {39.0, 20.0}}
Other, 0x600003e3c1a0, {{50.0, 0.0}, {15.0, 20.0}}, label: '3 of 3 Wi-Fi bars', value: SSID
Other, 0x600003e3c0d0, {{164.0, 0.0}, {51.0, 20.0}}, label: '8:05 AM'
Other, 0x600003e3c000, {{335.0, 0.0}, {35.0, 20.0}}, label: '51% battery power'
Path to element:
→Application, pid: 75589, label: 'DemoAuto'
Query chain:
→Find: Target Application 'com.joeferrara.DemoAuto'
Output: {
Application, pid: 75589, label: 'DemoAuto'
}
The main window for your app is shown in Window (Main), 0x600003e3cd00, {{0.0, 0.0}, {375.0, 667.0}}
. The most useful information here is the frame
for your main window. These screen coordinates are taken from an instance of the iPhone 8
simulator. The second window node is for the iOS screen which includes the status bar. Your UI test need not take this into account.
The UI elements for this bare bones single screen app are :
Window (Main), 0x600003e3cd00, {{0.0, 0.0}, {375.0, 667.0}}
Other, 0x600003e3cdd0, {{0.0, 0.0}, {375.0, 667.0}}
Button, 0x600003e3cea0, {{22.0, 80.0}, {136.0, 30.0}}, identifier: 'show-text-button', label: 'Show Label'
StaticText, 0x600003e3ca90, {{22.0, 129.0}, {136.0, 21.0}}, identifier: 'show-text-label'
Button, 0x600003e3c8f0, {{22.0, 226.0}, {136.0, 30.0}}, label: 'Open Settings'
Button, 0x600003e3c9c0, {{22.0, 264.0}, {136.0, 30.0}}, identifier: 'open-safari-button', label: 'Open Safari'
Button, 0x600003e3c820, {{36.0, 327.0}, {30.0, 30.0}}
StaticText, 0x600003e3c680, {{22.0, 365.0}, {94.0, 21.0}}, label: 'No Identifier'
TextField, 0x600003e3c750, {{16.0, 405.0}, {107.0, 30.0}}, value: Default Value
Query an Element by Label
You can see that the first and fourth elements are buttons each with an accessibility identifier. It is best to locate an element with an identifier to make it likely that the element is unique and in cases where it is not unique, it is easy to see on the screen and possible to craft an appropriate query.
Executing Gestures with Debugger Variables
From the debugger command line, you can enter p XCUIApplication().buttons["show-test-button"]
. If this is the first command used, then this text below is printed.
(XCUIElement) $R0 = 0x0000600003c4a060 {
ObjectiveC.NSObject = {
isa = XCUIElement
}
}
To see what happens when you tap on this element you can then enter p $R2.tap()
and observe the simulator. The text printed is below.
t = 52.69s Tap "show-text-button" Button
t = 52.69s Wait for com.joeferrara.DemoAuto to idle
t = 52.71s Find the "show-text-button" Button
t = 52.74s Check for interrupting elements affecting "show-text-button" Button
t = 52.74s Synthesize event
t = 52.85s Wait for com.joeferrara.DemoAuto to idle
Any functions or variables in an XCUIElement class can be used from the command line. This is useful for changing the state on the screen. This allows for writing the test code in a live mode. You just need to make sure to copy the lines needed and incorporate into your code.
After tapping the element identifier by show-test-button
, the sample app we’re using looks like this. The second label gets populated with the text “My Label”.

Show Label
causes text to appear in label belowRefresh Element Tree
Here is a way to refresh the element tree so it included the contents of the static text identified as show-text-label
.
Use p XCUIApplications.windows.count
so that the XCUITest proxy app requests all of the elements currently on the screen. Note that when you run a query then the framework will refresh its elements. I have seen some situation where that doesn’t happen automatically hence the usefulness of refreshing the elements tree explicitly. Also, as explained in the next paragraph, refreshing the element tree by getting a count of window does not require changing the app’s state.
If you are working with a more complex multi screen app then manually navigating through the app and issuing this command will update the element tree. This makes it possible to learn all of the screen elements for your app in one debugging session if desired.
The element tree line for the text label referenced above now reads :
StaticText, 0x600003e305b0, {{22.0, 129.0}, {136.0, 21.0}}, identifier: 'show-text-label', label: 'My Label'
Query an Element by Value
The lines for the Field element in the element tree looks like this :
TextField, 0x600003e3c750, {{16.0, 405.0}, {107.0, 30.0}}, value: Default Value
If you really wanted to do so, you could query for this element by using the value with XCUIApplication().values["Default Value"]
.
Query an Element by Path
The fourth button element has no identifier, label or value. The only way to access this element is by path.
p XCUIApplication().buttons.element(boundBy: 3)
Conclusion
In this post, I’ve given several examples of the things that can be done when using the Xcode command line debugger to support writing XCUITest tests. In addition to using the debugger while writing code, it is also very important to have some basic knowledge to help with debugging your code.
Resources
An in depth post on how to use the Xcode debugger for general coding is Dancing in the Debugger — A Waltz with LLDB. I read this a while back and it inspired me to use the debugger more often when writing test code.