4

I'm currently trying both KIF and Subliminal for iOS integration testing. But I still cannot figure out how to simulate scrolling on table view or collection view using both frameworks. Like how to scroll to the bottom of table view or collection view.

EDIT 1:

I made simple single collection view app here https://github.com/nicnocquee/TestSubliminal

Basically I want to test the last cell's label. I cannot do

SLElement *lastLabel = [SLElement elementWithAccessibilityLabel:@"Label of the last cell"];
[lastLabel scrollToVisible];

because the label doesn't exist yet until the collection view is scrolled to the bottom.

EDIT 2:

I marked Aaron's answer as the answer. But Jeffrey's also works :)

thijsai
  • 1,795
  • 1
  • 18
  • 26
Nico Prananta
  • 474
  • 4
  • 14
  • 1
    There are a few different ways you could make your view scroll with Subliminal. You could identify a particular cell at or near the bottom of your scroll/collection view, as an `SLElement`, and call `[theCell scrollToVisible]` or you could use the `dragWithStartOffset:endOffset:` method on the `[SLWindow mainWindow]` element to simulate dragging across arbitrary regions of the window. Do you have any not-yet-working test code you could post? – Aaron Golden Aug 15 '13 at 19:16
  • @AaronGolden I updated my question with link to simple app. – Nico Prananta Aug 16 '13 at 02:46

3 Answers3

1

You could also simulate the user scrolling through the collection looking for the cell, by dragging the collection view until the cell becomes visible:

while (!SLWaitUntilTrue([UIAElement(lastLabel) isValidAndVisible], 1.0)) {
    [[SLWindow mainWindow] dragWithStartOffset:CGPointMake(0.5, 0.75) endOffset:CGPointMake(0.5, 0.25)];
}

Those offsets translate to dragging straight up along the middle of the collection view, from 75% down the view to 25% down the view. -isValidAndVisible lets you check for the cell's visibility without worrying about whether it exists yet (whereas -isVisible would throw an exception if the cell didn't exist). And I wrap -isValidAndVisible in SLWaitUntilTrue so that we let the collection view finish scrolling before dragging again.

In contrast to @AaronGolden's app hook solution, this approach requires you be able to identify a particular cell to scroll to. So I'd frame this approach as "scroll to a cell", whereas the app hook lets you "scroll to a position".

Jeffrey Wear
  • 1,155
  • 2
  • 12
  • 24
1

This is probably more invasive but so simple too - Go to SLUIAElement.m and add the following methods:

- (void)scrollDown {
[self waitUntilTappable:NO thenSendMessage:@"scrollDown()"];
}


- (void)scrollUp {
[self waitUntilTappable:NO thenSendMessage:@"scrollUp()"];
}

You will also have to declare those method signature in the SLUIAElement.h file to make those new methods visible to the test suite.

Then what you can do is add an accessibility identifier to a collection view, call that identifier and scroll on it. EXAMPLE:

SLElement *scrollView = [SLElement elementWithAccessibilityIdentifier:@"scrollView"];

[scrollView scrollDown];
Ray
  • 501
  • 4
  • 9
  • What really should happen is the subliminal people should just add those methods I specified to the subliminal library by default! It makes no sense to me that they would leave functionality so important as scrolling out of the library. – Ray Dec 03 '13 at 01:04
  • Hi @Ray, there are currently three ways that you can scroll: by asking an element to be scrolled to visible, by dragging the scroll view, or by using an app hook. Being able to use the higher-level `UIAScrollView` APIs like `scrollDown` or `scrollUp`, rather than dragging, would be an excellent addition to Subliminal. We're just providing interfaces to UIAutomation in bits and pieces--it's a big framework. You can help us prioritize features by filing issues on the repo--it's easy to miss comments on StackOverflow. I've filed an issue for this: https://github.com/inkling/Subliminal/issues/114. – Jeffrey Wear Jan 16 '14 at 02:03
0

The issue is that the cell you're trying to find in your test case, the one with label "This is cell 19", does not exist until the collection view has already been scrolled. So we need to make the view scroll first and then look for the cell. The easiest way to make the collection view scroll with Subliminal is through an application hook. In (for example) your view controller's viewDidLoad method, you could register the view controller to respond to a particular message from any Subliminal test case, like so:

[[SLTestController sharedTestController] registerTarget:self forAction:@selector(scrollToBottom)];

and the view controller could implement that method as:

- (void)scrollToBottom {
    [self.collectionView setContentOffset:CGPointMake(0.0, 1774.0)];
}

That 1774 is just the offset that happens to scroll the collection view in your test app all the way to the bottom. In a real application the app hook would probably be more sophisticated. (And in a real application you would want to make sure to call [[SLTestController sharedTestController] deregisterTarget:self] in your view controller's dealloc method.)

To trigger the scrollToBottom method from a Subliminal test case you can use:

[[SLTestController sharedTestController] sendAction:@selector(scrollToBottom)];

or the convenience macro:

SLAskApp(scrollToBottom);

The shared SLTestController will send the scrollToBottom message to the object that registered to receive it (your view controller).

When the sendAction or SLAskApp macro returns your cell 19 will already be visible, so you don't need to bother with the [lastLabel scrollToVisible] call anymore. Your complete test case could look like this:

- (void)testScrollingCase {
    SLElement *label1 = [SLElement elementWithAccessibilityLabel:@"This is cell 0"];
    SLAssertTrue([UIAElement(label1) isVisible], @"Cell 0 should be visible at this point");

    SLElement *label5 = [SLElement elementWithAccessibilityLabel:@"This is cell 5"];
    SLAssertFalse([UIAElement(label5) isValid], @"Cell 5 should not be visible at this point");

    // Cause the collection view to scroll to the bottom.
    SLAskApp(scrollToBottom);

    SLElement *lastLabel = [SLElement elementWithAccessibilityLabel:@"This is cell 19"];
    SLAssertTrue([UIAElement(lastLabel) isVisible], @"Last cell should be visible at this point");
}
Aaron Golden
  • 7,092
  • 1
  • 25
  • 31
  • I might suggest using `scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionBottom animated:YES` in the app hook, where `indexPath` was the path of the the last item in the last section. That way it wouldn't matter how tall the collection view's content was. – Jeffrey Wear Aug 16 '13 at 18:48
  • @AaronGolden How do I make a cell clickable though? – AlexanderN Mar 06 '14 at 16:22