如何通过 Xcode UI 测试确定滚动视图中文本的哪一部分在屏幕上可见?
How can I determine what part of text in a scroll view is visible on screen from an Xcode UI test?
我是 Xcode 用户界面测试框架的新手。我可以成功地操纵屏幕元素,但无法弄清楚如何就滚动视图中可见的文本生成有意义的断言。
我想编写的测试如下:启动应用程序,在文本视图中键入大量文本(足以让第一行滚出视图),断言第一行文本不是可见,将视图向上滚动到顶部,然后断言第一行现在可见。请注意,此测试的目的是确保我的应用程序正确连接,而不是测试 Apple 的代码。
XCUIApplication 允许我在我的 NSTextView 实例中键入内容,还允许我滚动关联的 NSScrollView。但是我如何断言第一行文本当前是否可见? XCUIElement 的 value 属性提供了视图的全部文本内容,无论它当前是否显示。
NSTextView 上的 accessibilityRange(forLine:) 和 accessibilityString(for:) 方法是理想的,但我看不到如何访问它们,因为 UI 测试只能访问 XCUI元素,而不是底层的 NSTextView。
我是不是漏掉了什么,或者是否有更好的方法来解决这个问题?
如果您在故事板或文本视图的代码中设置了可访问性标识符,您可以通过(假设您给它的 ID "textview1" 和它所在的 window 获取文本视图"Window" 的默认可访问性标识符):
let textview1TextView = app.windows["Window"].textViews["textview1"]
但这实际上并不能满足您的需求。
相反,设置滚动视图的可访问性标识符并获取:
let scrollview = app.windows["Window"].scrollViews["scrollview1"]
然后用它来获取滚动条(在这种情况下你应该只有一个;你可以使用 scrollbars.count
来检查。
let scrollbars = scrollview.scrollBars
print("scrollbars count: \(scrollbars.count)")
然后你可以使用滚动条的value属性来获取它的值:
(您正在将 XCUIElemenTypeQueryProvider 转换为 XCUIElement 以便您可以获得它的值):
let val = scrollbars.element.value
顶部为 0,滚动时为浮点值(我的测试代码中的一行文本显示值为 {{0.02409638554216868}}。
有助于您进一步探索的文档:
请注意,您可以在测试中间放置一个断点,运行 然后使用调试器控制台检查内容:
(lldb) po scrollbars.element.value
t = 749.66s Find the ScrollBar ▿ Optional<Any>
- some : 0
(lldb) po scrollbars.element.value
t = 758.17s Find the ScrollBar ▿ Optional<Any>
- some : 0.05421686746987952
在调试器中,您甚至可以与应用程序的 window 交互以手动滚动它(这是我在输入这两个 po
调用之间所做的),或者添加文本和依此类推
OK OP 现在注意到他们感兴趣的是特定文本是否显示,而不是第一行是否显示(这是我之前在上面回答的内容)。
这里有一些技巧,但我认为它会起作用:
使用XCUICoordinate
的click(forDuration:, thenDragTo:)
方法select第一行文字(使用view frame计算坐标)然后使用typeKey( modifierFlags:)
调用编辑菜单 "copy" 命令。然后使用NSPasteboard
方法获取粘贴板内容并检查文本。
这是我为验证该方法所做的快速测试(select如上所述使用 XCUICoordinate
编辑第一行文本留作 reader 的练习):
NSPasteboard.general.clearContents()
// stopped at break point on next line and I manually selected the text of the first line of text in my test app and then hit continue in the debugger
textview1TextView.typeKey("c", modifierFlags:.command)
print( NSPasteboard.general.pasteboardItems?.first?.string(forType: NSPasteboard.PasteboardType.string) ?? "none" );
-> "the text of the first line" 被打印到控制台。
请注意,您可以将 selection 滚动到屏幕外,这样您在执行 select 后就不必滚动,否则您将得不到想要的答案。
我是 Xcode 用户界面测试框架的新手。我可以成功地操纵屏幕元素,但无法弄清楚如何就滚动视图中可见的文本生成有意义的断言。
我想编写的测试如下:启动应用程序,在文本视图中键入大量文本(足以让第一行滚出视图),断言第一行文本不是可见,将视图向上滚动到顶部,然后断言第一行现在可见。请注意,此测试的目的是确保我的应用程序正确连接,而不是测试 Apple 的代码。
XCUIApplication 允许我在我的 NSTextView 实例中键入内容,还允许我滚动关联的 NSScrollView。但是我如何断言第一行文本当前是否可见? XCUIElement 的 value 属性提供了视图的全部文本内容,无论它当前是否显示。
NSTextView 上的 accessibilityRange(forLine:) 和 accessibilityString(for:) 方法是理想的,但我看不到如何访问它们,因为 UI 测试只能访问 XCUI元素,而不是底层的 NSTextView。
我是不是漏掉了什么,或者是否有更好的方法来解决这个问题?
如果您在故事板或文本视图的代码中设置了可访问性标识符,您可以通过(假设您给它的 ID "textview1" 和它所在的 window 获取文本视图"Window" 的默认可访问性标识符):
let textview1TextView = app.windows["Window"].textViews["textview1"]
但这实际上并不能满足您的需求。
相反,设置滚动视图的可访问性标识符并获取:
let scrollview = app.windows["Window"].scrollViews["scrollview1"]
然后用它来获取滚动条(在这种情况下你应该只有一个;你可以使用 scrollbars.count
来检查。
let scrollbars = scrollview.scrollBars
print("scrollbars count: \(scrollbars.count)")
然后你可以使用滚动条的value属性来获取它的值: (您正在将 XCUIElemenTypeQueryProvider 转换为 XCUIElement 以便您可以获得它的值):
let val = scrollbars.element.value
顶部为 0,滚动时为浮点值(我的测试代码中的一行文本显示值为 {{0.02409638554216868}}。
有助于您进一步探索的文档:
请注意,您可以在测试中间放置一个断点,运行 然后使用调试器控制台检查内容:
(lldb) po scrollbars.element.value
t = 749.66s Find the ScrollBar ▿ Optional<Any>
- some : 0
(lldb) po scrollbars.element.value
t = 758.17s Find the ScrollBar ▿ Optional<Any>
- some : 0.05421686746987952
在调试器中,您甚至可以与应用程序的 window 交互以手动滚动它(这是我在输入这两个 po
调用之间所做的),或者添加文本和依此类推
OK OP 现在注意到他们感兴趣的是特定文本是否显示,而不是第一行是否显示(这是我之前在上面回答的内容)。
这里有一些技巧,但我认为它会起作用:
使用XCUICoordinate
的click(forDuration:, thenDragTo:)
方法select第一行文字(使用view frame计算坐标)然后使用typeKey( modifierFlags:)
调用编辑菜单 "copy" 命令。然后使用NSPasteboard
方法获取粘贴板内容并检查文本。
这是我为验证该方法所做的快速测试(select如上所述使用 XCUICoordinate
编辑第一行文本留作 reader 的练习):
NSPasteboard.general.clearContents()
// stopped at break point on next line and I manually selected the text of the first line of text in my test app and then hit continue in the debugger
textview1TextView.typeKey("c", modifierFlags:.command)
print( NSPasteboard.general.pasteboardItems?.first?.string(forType: NSPasteboard.PasteboardType.string) ?? "none" );
-> "the text of the first line" 被打印到控制台。
请注意,您可以将 selection 滚动到屏幕外,这样您在执行 select 后就不必滚动,否则您将得不到想要的答案。