1

I have an app where clicking on a row toggles state, and doing a left swipe performs a delete of the item.

My problem is that UI test calls like swipeRight() do not engage the swipe action. Rather, they engage the click action. I need to test both.

I've tried different speeds for the swipe but it doesn't seem to help.

Anyone have any ideas?

Here is a simplified version of my test:

func testSwipe() throws { let app = XCUIApplication() app.launch() app.buttons["mybutton"].swipeLeft() // this toggles the state instead of deleting the item 

And a simplified version of the related view code:

var body: some View { List { ForEach ($items) { $item in HStack { Label("", systemImage:"checkmark").foregroundStyle(.green) Button(item.title, action: { // run code here to toggle state of item }) } .swipeActions(edge: .trailing) { // swipe left Button (action:{ /* call logic to delete item */) { Label("Delete", systemImage: "minus.circle") } } } } } 
0

1 Answer 1

2
+25

I've found that UITests are a but finicky in Xcode especially when it comes to gestures like swiping.

In my project, I have a horizontal scrollview that tests successfully when an element inside each item in the scrollview has the .swipeLeft action. Is there another element inside the row you can attempt to swipe on? If so I would try attempt to use a gesture on that element instead of the row itself.

If not, then another solution is to use swipe on the row at the coordinate level. This is an extension I have that will press (and hold) on an element and then drag in a specified direction to simulate the swipe behavior.

extension XCUIElement { enum Direction: Int { case up, down, left, right, fromBottom } func gentleSwipe(_ direction: Direction) { let half: CGFloat = 0.5 let adjustment: CGFloat = 0.25 let largeAdjustment: CGFloat = 0.4 let pressDuration: TimeInterval = 0.09 let lessThanHalf = half - adjustment let moreThanHalf = half + adjustment let nearFull = half + largeAdjustment let center = self.coordinate(withNormalizedOffset: CGVector(dx: half, dy: half)) let aboveCenter = self.coordinate(withNormalizedOffset: CGVector(dx: half, dy: lessThanHalf)) let belowCenter = self.coordinate(withNormalizedOffset: CGVector(dx: half, dy: moreThanHalf)) let leftOfCenter = self.coordinate(withNormalizedOffset: CGVector(dx: lessThanHalf, dy: half)) let rightOfCenter = self.coordinate(withNormalizedOffset: CGVector(dx: moreThanHalf, dy: half)) let nearBottom = self.coordinate(withNormalizedOffset: CGVector(dx: half, dy: nearFull)) switch direction { case .up: center.press(forDuration: pressDuration, thenDragTo: aboveCenter) case .down: center.press(forDuration: pressDuration, thenDragTo: belowCenter) case .left: center.press(forDuration: pressDuration, thenDragTo: leftOfCenter) case .right: center.press(forDuration: pressDuration, thenDragTo: rightOfCenter) case .fromBottom: nearBottom.press(forDuration: pressDuration, thenDragTo: center) } } } 

After implemented you should just be able to go

app.buttons["mybutton"].gentleSwipe(XCUIElement.Direction.left) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.