Stop scrolling on UITableView at last during XCUI TestCase
Asked Answered
G

1

5

In my one of UITableView have more then 10 rows. I want to scroll till last row while UITestCase running.

I have written below code to scroll till last row.

-(void)scrollToElement:(XCUIElement *)element application:(XCUIApplication *)app{
    while ([self visible:element withApplication:app]) {
        XCUIElement *searchResultTableView = app.tables[@"searchResultView"];
        XCUICoordinate *startCoord = [searchResultTableView coordinateWithNormalizedOffset:CGVectorMake(0.5, 0.5)];
        XCUICoordinate *endCoord = [startCoord coordinateWithOffset:CGVectorMake(0.0, -262)];
        [startCoord pressForDuration:0.01 thenDragToCoordinate:endCoord];
    }
}
-(BOOL)visible:(XCUIElement *)element withApplication:(XCUIApplication *)app{
    if (element.exists && !CGRectIsEmpty(element.frame) && element.isHittable) {
        return CGRectContainsRect([app.windows elementBoundByIndex:0].frame, element.frame);
    } else {
        return FALSE;
    }
}

An i have called above method in my one of UITestCase method by below code

XCUIElement *searchResultTableView = app.tables[@"searchResultView"];
[self waitForElementToAppear:searchResultTableView withTimeout:30];


XCUIElement *table = [app.tables elementBoundByIndex:0];
XCUIElement *lastCell = [table.cells elementBoundByIndex:table.cells.count - 1];
[self scrollToElement:lastCell application:app];

By this code i can scroll to last row but after reaching last row, it continue doing scroll means can't stop scrolling.

Please help me to scroll to only last row and then it should stop to scroll so that i can perform next action event.

I have refer StackOverFlow answer but none of them meet my requirement.

Thanks in advance.

Grubbs answered 24/1, 2018 at 9:24 Comment(2)
It should be enough for the implementation of visible to just return the result of element.exists && element.isHittable... does that work for you?Phosphate
Thanks @Phosphate for your replay. I have tried with element.exists && element.isHittable, but still not working.Grubbs
M
8

I faced similar issue in one of my project. In that I wanted to test "Load More" feature by TestKit framework.

Here is some workaround to achieve the same scenario.

//app           : is your current instance of appliaction
//listTable     : is a Table which you've found via accessibility identifier
//loadMoreTest  : is a parameter to determine whether code should perform test for loadmore feature or not

- (void)testScrollableTableForApplication:(XCUIApplication *)app
                                 forTable:(XCUIElement *)listTable
                         withLoadMoreTest:(BOOL)loadMoreTest {

    [listTable accessibilityScroll:UIAccessibilityScrollDirectionUp];
    [listTable swipeUp];

    if (loadMoreTest) {
        __block BOOL isLoadMoreCalled;
        __block XCUIElement *lastCell;
        __block __weak void (^load_more)();
        void (^loadMoreCall)();
        load_more = loadMoreCall = ^() {
            XCUIElementQuery *tablesQuery = app.tables;
            XCUIElementQuery *cellQuery = [tablesQuery.cells containingType:XCUIElementTypeCell identifier:@"LoadMoreCell"];
            lastCell = cellQuery.element;
            if ([lastCell elementIsWithinWindowForApplication:app]) {
                [self waitForElementToAppear:lastCell withTimeout:2];
                [lastCell tap];
                isLoadMoreCalled = true;
                [self wait:2];
            }
            [listTable swipeUp];
            if (!isLoadMoreCalled) {
                load_more();
            }
        };
        loadMoreCall();
    }
}


- (void)waitForElementToAppear:(XCUIElement *)element withTimeout:(NSTimeInterval)timeout
{
    NSUInteger line = __LINE__;
    NSString *file = [NSString stringWithUTF8String:__FILE__];

    NSPredicate *existsPredicate = [NSPredicate predicateWithFormat:@"exists == 1"];
    [self expectationForPredicate:existsPredicate evaluatedWithObject:element handler:nil];

    [self waitForExpectationsWithTimeout:timeout handler:^(NSError * _Nullable error) {
        if (error != nil) {
            NSString *message = [NSString stringWithFormat:@"Failed to find %@ after %f seconds",element,timeout];
            [self recordFailureWithDescription:message inFile:file atLine:line expected:YES];
        }
    }];
}

create one category for XCUIElement XCUIElement+Helper.m and import it into your respective Test class.

#import <XCTest/XCTest.h>

@interface XCUIElement (Helper)

/// Check whether current XCUIElement is within current window or not
- (BOOL)elementIsWithinWindowForApplication:(XCUIApplication *)app ;

@end

@implementation XCUIElement (Helper)

/// Check whether current XCUIElement is within current window or not
/*
@description: we need to check particular element's frame and window's frame is intersecting or not, to get perfectly outcome whether element is currently visible on screen or not, because if element has not yet appeared on screen then also the flag frame, exists and hittable can become true
*/
- (BOOL)elementIsWithinWindowForApplication:(XCUIApplication *)app {
    if (self.exists && !CGRectIsEmpty(self.frame) && self.hittable)
        return CGRectContainsRect(app.windows.allElementsBoundByIndex[0].frame, self.frame);
    else
        return false;
}

@end

To get the "Load More" cell, i've given the

cell.accessibilityIdentifier = @"LoadMoreCell";

Rest of the code is, recursive function in testScrollableTableForApplication to make Tableview scroll to reach to bottom so i can have the access of load more cell(in your case last cell). Then i am performing the action Tap to fetch new records from server. Then again i am scrolling the Table to verify if the new records has been fetched from server or not.

Tip : you can replace recursive function with do while or while loop to achieve the same.

Hope this helps!

Happy Coding!!

Marplot answered 2/2, 2018 at 7:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.