스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Explore Digital Crown, Trackpad, and iPad pointer automation
Learn how you can interact with devices in UI Tests in Xcode 13. Discover newly-automatable input methods including iPadOS pointer, watchOS Digital Crown, and enhanced macOS trackpad scrolling APIs.
리소스
관련 비디오
WWDC21
-
다운로드
Hello and welcome to WWDC. I'm Jeremy Goldman, an engineer on the XCTest team. In this session, we're going to explore some exciting new ways to interact with devices from UI Tests in Xcode 13. In particular, we're going to focus on three new interactions across three different platforms: the iPadOS Pointer, the watchOS Digital Crown, and the macOS trackpad.
Let's start with the iPadOS Pointer.
In iPadOS 13.4, Apple introduced mouse and trackpad support, providing users with a brand new way to interact with iPad, using accessories like the Magic Keyboard. Many developers have taken full advantage of this by adding pointer-specific behavior and interactions to their iPad apps, like custom hover animations. In Xcode 13, we're providing a powerful new API for controlling the iPadOS Pointer in UI Tests. This API will enable you to create robust automated tests for multiple types of pointer interactions in your iPad apps and will be available for use with devices running iPadOS 15 and later.
Let's examine this new API in more detail. First, we're adding a new property on XCUIDevice to indicate whether or not a device supports pointer interaction. Next, we're adding new methods on XCUIElement for performing different pointer interactions, like hovering, multiple types of clicking, and two-finger scrolling. We're also adding methods for more advanced click-and-drag use cases as well as a class method for executing blocks of code with one or more modifier keys held down. These methods are also available on XCUICoordinate, if additional precision is required. Let's explore how these new APIs work in practice by creating a new UI Test for a pointer interaction in an iOS app.
In this demo, I'll be using the Fruta app, which has a sidebar that's initially hidden on launch. I recently added pointer-specific functionality on iPad, where a horizontal two-finger trackpad swipe opens the sidebar. Let's add a UI Test for that. Here I have an empty UI Test class, which is where I'll add my new UI Test.
Let's quickly walk through what this test is doing. It starts by launching the app and then asserting that the sidebar is not initially present on launch. Then it performs a horizontal two-finger trackpad swipe and asserts that the sidebar is now present. One other thing I'd like to point out is this availability attribute I've added on the test method. This is necessary whenever you're using methods that are only available starting with a specific iOS version. In this case, the pointer interaction APIs were introduced in iOS 15.0.
Let's try running the test on the iPad simulator. You can follow along with the cursor indicator, which is the dark circle near the bottom left corner of the screen. Great! It looks like our test works on iPad. However, this app is also available on iPhone, which does not support pointer interaction. Let's try running this test on the iPhone simulator. So it appears the test failed with an error message that "Pointer events are not supported on this device." To resolve this, we need to modify our test so that it only executes on devices that do support pointer interaction. We can do this by using XCTSkipUnless with the new supportsPointerInteraction property on XCUIDevice to skip the test on unsupported devices, instead of failing. Now let's try running the test on the iPhone simulator again. Perfect. So now this test will be skipped on devices that don't support pointer interaction. Let's talk about some new ways to interact with devices on other platforms, more specifically, watchOS and the Digital Crown. As you may already know, Xcode 12.5 introduced UI Testing support for watchOS apps. This support includes methods newly available on watchOS for synthesizing touch events as well as hardware button events, like clicking the crown.
In Xcode 13, we're expanding this support with a new method for synthesizing Digital Crown rotation. This method requires just one parameter, the number of rotations, and has an optional velocity parameter to specify the speed at which the crown should be rotated. This velocity parameter has type XCUIGestureVelocity, which means you can either use one of the preset values, like slow, fast, and default, or you can specify a custom decimal value in rotations per second.
Let's see how this new method works in practice.
Say I have a simple weather app for watchOS that displays the current temperature outside. The app has a feature where users can scroll the digital crown forward to see forecasted temperatures at future times or scroll backward to see the recorded temperature at past times.
Let's walk through a basic UI Test that makes sure this crown rotation functionality behaves as expected.
The test starts by launching the app and then asserting that the forecast time label initially says Current Temperature. Then, we rotate the digital crown one full rotation forward, and assert the label updated to say "One hour from now." After that, we rotate the crown two full rotations backward, and the test finishes by asserting that the label updated to say "One hour ago." Finally, let's talk about the macOS trackpad. More specifically, let's focus on scrolling. Scrolling can be broken down into two different categories: discrete and continuous. Discrete scrolling has precise incremental movement. Think about rotating the scroll wheel on a physical mouse. The on-screen content moves in uniform increments for each tick on the scroll wheel, and the movement is non-inertial, meaning it stops moving immediately when you stop rotating the scroll wheel. On the other hand, continuous, or phased scrolling, has fluid and dynamic movement. Picture swiping with two fingers on a trackpad. The on-screen content scrolls smoothly while you're swiping, and the movement is inertial, meaning it continues moving after you lift your fingers off until it gradually comes to a stop.
XCTest currently provides a scroll method on macOS that enables you to perform discrete pixel-precise scrolling in your UI Tests. This method requires two parameters to specify the exact horizontal and vertical distance in pixels to scroll.
In Xcode 13, we're introducing new methods for synthesizing continuous or trackpad-like scrolling on macOS. These methods accept an optional velocity parameter to specify the speed at which you'd like to scroll. This velocity parameter has type XCUIGestureVelocity which means, just like in the rotateDigitalCrown method we explored earlier, you can either use the presets or you can specify a custom decimal value in pixels per second.
Xcode 13 introduces APIs across multiple platforms to enable automation of new input methods and provide support for more specialized use cases.
Use this new functionality to create UI Tests for pointer-specific interactions in your iPad apps, automate digital crown rotation in your watchOS UI Tests, and perform continuous, trackpad-like scrolling on macOS with the new swipe methods. If you're interested in learning more, make sure to check out these related sessions.
Thanks for watching and enjoy the rest of WWDC. [music]
-
-
1:28 - New supportsPointerInteraction property on XCUIDevice
extension XCUIDevice { public var supportsPointerInteraction: Bool }
-
1:37 - New methods on XCUIElement and XCUICoordinate for pointer interactions on iOS
extension XCUIElement { open func hover() open func click() open func rightClick() open func doubleClick() open func scroll(byDeltaX: CGFloat, deltaY: CGFloat) open func click(forDuration: TimeInterval, thenDragToElement: XCUIElement) open func click(forDuration: TimeInterval, thenDragToElement: XCUIElement, withVelocity: XCUIGestureVelocity, thenHoldForDuration: TimeInterval) open class func perform(withKeyModifiers flags: XCUIElement.KeyModifiers, block: () -> Void) }
-
2:31 - Empty UI test class
import XCTest class Pointer_UI_Tests: XCTestCase { }
-
2:43 - UI test for opening the sidebar with a two-finger horizontal trackpad swipe
import XCTest class Pointer_UI_Tests: XCTestCase { @available(iOS 15.0, *) func testHorizontalScrollRevealsSidebar() throws { let app = XCUIApplication() app.launch() let sidebar = app.tables["Sidebar"] // Make sure sidebar menu is not present initially. XCTAssertFalse(sidebar.exists, "Sidebar should not be present initially") // Swipe horizontally to reveal sidebar. app.staticTexts["Select a smoothie"].scroll(byDeltaX: -200, deltaY: 0) // Verify sidebar is now present. XCTAssertTrue(sidebar.waitForExistence(timeout: 5), "Sidebar did not appear within 5 second timeout") } }
-
import XCTest class Pointer_UI_Tests: XCTestCase { @available(iOS 15.0, *) func testHorizontalScrollRevealsSidebar() throws { try XCTSkipUnless(XCUIDevice.shared.supportsPointerInteraction, "Device does not support pointer interaction") let app = XCUIApplication() app.launch() let sidebar = app.tables["Sidebar"] // Make sure sidebar menu is not present initially. XCTAssertFalse(sidebar.exists, "Sidebar should not be present initially") // Swipe horizontally to reveal sidebar. app.staticTexts["Select a smoothie"].scroll(byDeltaX: -200, deltaY: 0) // Verify sidebar is now present. XCTAssertTrue(sidebar.waitForExistence(timeout: 5), "Sidebar did not appear within 5 second timeout") } }
-
5:27 - New method on XCUIDevice for Digital Crown rotation on watchOS
// New rotateDigitalCrown API extension XCUIDevice { open func rotateDigitalCrown(delta: CGFloat, velocity: XCUIGestureVelocity = .default) }
-
6:22 - UI test to verify the app's Digital Crown rotation functionality behaves as expected
// Example use of watchOS Digital Crown API func testForecastScrolling() { let app = XCUIApplication() app.launch() let forecastTime = app.staticTexts["forecast-time"] XCTAssertEqual(forecastTime.label, "Current Temperature") // Scroll 1 full rotation forward. XCUIDevice.shared.rotateDigitalCrown(delta: 1.0) XCTAssertEqual(forecastTime.label, "One hour from now") // Scroll 2 full rotations backward. XCUIDevice.shared.rotateDigitalCrown(delta: -2.0) XCTAssertEqual(forecastTime.label, "One hour ago") }
-
7:46 - Existing API for performing discrete (mouse wheel-like) scrolling on macOS
extension XCUIElement { // Use the existing API for discrete (mouse wheel-like) scrolling. open func scroll(byDeltaX: CGFloat, deltaY: CGFloat) }
-
8:05 - New API for performing continuous (trackpad-like) scrolling on macOS
extension XCUIElement { // Use the new API for continuous (trackpad-like) scrolling. open func swipeUp(velocity: XCUIGestureVelocity = .default) open func swipeDown(velocity: XCUIGestureVelocity = .default) open func swipeLeft(velocity: XCUIGestureVelocity = .default) open func swipeRight(velocity: XCUIGestureVelocity = .default) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.