2015-09-18 14 views
18

Mit dem neuen xcode-Update hat Apple die Art und Weise, wie wir UI-Tests durchführen, überarbeitet. In Instrumenten verwendeten wir die Java-Skriptfunktion "isVisible", um festzustellen, ob unser Zielelement sichtbar ist.Scrollen, bis Element sichtbar ist iOS UI Automation mit xcode7

Ich versuche, dies in Ziel c zu replizieren, aber ich kann nicht das Äquivalent davon finden. Ich habe eine Tabellenansicht, eine Prototypzelle mit zwei Etiketten darauf. Diese Prototypzelle wird 50 mal wiederverwendet.

Ich versuche zu scrollen, bis die letzte Zelle sichtbar ist, tat ich dies, indem Sie diese:

if (![[[[[[XCUIApplication alloc] init].tables childrenMatchingType:XCUIElementTypeCell] matchingIdentifier:@"cell"] elementBoundByIndex:49].staticTexts[@"text"] exists]) { 
     [[[[[[XCUIApplication alloc] init].tables childrenMatchingType:XCUIElementTypeCell] matchingIdentifier:@"cell"] elementBoundByIndex:0].staticTexts[@"text"] swipeUp]; 
} 

Aber das wird nicht Swipe da das Element vorhanden ist, wenn die Ansicht geladen wird. Bitte hilf mir, denn das macht mich verrückt.

Antwort

1

Sie etwas tun können:

extension XCUIElement { 
    internal func scrollToElement(element: XCUIElement) { 
     while !element.exists { 
      swipeDown() 
     } 
    } 
} 

und als scrollToElement verwendet Element

+0

kleine Korrektur: ersetzen "existiert" mit "hit table". Das hat für mich funktioniert. –

3

Leider .exists nicht bestätigen, dass ein Element zur Zeit sichtbar zu finden - so etwas wie das ist immer noch nicht perfekt aber es wird eine zuverlässigere Validierung bieten, die mit Tabellen- oder Sammlungsansichtszellen funktioniert:

extension XCUIElement { 
    var displayed: Bool { 
     guard self.exists && !CGRectIsEmpty(frame) else { return false } 
     return CGRectContainsRect(XCUIApplication().windows.elementBoundByIndex(0).frame, frame) 
    } 
} 

dann können Sie ein si schreiben mple loop like:

func scrollDownUntilVisible(element: XCUIElement) { 
    while !element.displayed { 
     swipeDown() 
    } 
} 
+1

Sie könnten Display in eine berechnete Eigenschaft drehen – Nycen

+0

Guter Anruf @nycen - aktualisiert –

26

Sie sollten die Methodenliste des XCUIElement erweitern. Die erste Methode (scrollToElement:) wird für die TableView aufgerufen, die zweite Erweiterungsmethode hilft Ihnen bei der Entscheidung, ob sich das Element im Hauptfenster befindet.

extension XCUIElement { 

    func scrollToElement(element: XCUIElement) { 
     while !element.visible() { 
      swipeUp() 
     } 
    } 

    func visible() -> Bool { 
     guard self.exists && !CGRectIsEmpty(self.frame) else { return false } 
     return CGRectContainsRect(XCUIApplication().windows.elementBoundByIndex(0).frame, self.frame) 
    } 

} 

Die Scroll-Code sollte wie folgt aussehen (zB zur letzten Zelle scrollen):

func testScrollTable() { 
    let app = XCUIApplication() 
    let table = app.tables.elementBoundByIndex(0) 
    let lastCell = table.cells.elementBoundByIndex(table.cells.count-1) 
    table.scrollToElement(lastCell) 
} 

Swift 3:

extension XCUIElement { 
    func scrollToElement(element: XCUIElement) { 
     while !element.visible() { 
      swipeUp() 
     } 
    } 

    func visible() -> Bool { 
     guard self.exists && !self.frame.isEmpty else { return false } 
     return XCUIApplication().windows.element(boundBy: 0).frame.contains(self.frame) 
    } 
} 
+0

Vielen Dank. Diese Lösung funktioniert! –

13

Alle bisherigen Antworten sind nicht zu 100% scheitern Beweis. Das Problem, mit dem ich konfrontiert war, ist, dass swipeUp() einen größeren Offset hat und ich konnte keinen Weg finden, das Scrollen zu stoppen, wenn ich das Element im View-Port habe. Manchmal wird das Element wegen des übermäßigen Scrolls weggescrollt und der Testfall schlägt daher fehl. Allerdings habe ich es geschafft, die Scroll mit dem folgenden Code zu steuern.

/** 
Scrolls to a particular element until it is rendered in the visible rect 
- Parameter elememt: the element we want to scroll to 
*/ 
func scrollToElement(element: XCUIElement) 
{ 
    while element.visible() == false 
    { 
     let app = XCUIApplication() 
     let startCoord = app.collectionViews.element.coordinateWithNormalizedOffset(CGVector(dx: 0.5, dy: 0.5)) 
     let endCoord = startCoord.coordinateWithOffset(CGVector(dx: 0.0, dy: -262)); 
     startCoord.pressForDuration(0.01, thenDragToCoordinate: endCoord) 
    } 
} 

func visible() -> Bool 
{ 
    guard self.exists && self.hittable && !CGRectIsEmpty(self.frame) else 
    { 
     return false 
    } 

    return CGRectContainsRect(XCUIApplication().windows.elementBoundByIndex(0).frame, self.frame) 
} 

Hinweis: Bitte app.tables verwenden, wenn Ihre Ansicht Tableview

+0

** Update für swift3 ** lassen startCoord = XCUIApplication() collectionViews.element.coordinate. (WithNormalizedOffset: CGVector (dx: 0,5, dy: 0,5)) \ n lassen endCoord = startCoord.withOffset (CGVector (dx: 0.0, dy: -262)) \ n startCoord.press (forDuration: 0,01, thenDragTo: endCoord) – Stan

+0

Danke dafür. Wenn Sie eine Schaltfläche direkt in der Mitte der Ansicht haben, funktioniert eine normale Wischgeste nicht. Also musste ich die Scroll-Position ändern, wusste aber nicht wie. Diese Lösung ist sehr cool mit ein wenig, aber die Ansicht Scrollen stoppt, wenn eine kleine Menge des Rahmens sichtbar ist. Ich werde über eine Lösung für die Sichtbarkeit für den gesamten Rahmen nachdenken. Aber danke :) –

+0

genial! Ich habe so ziemlich alle Antworten hier ausprobiert und dieser war derjenige, der funktioniert hat, danke! – rgkobashi

4

Aufbauend auf @Kade's answer, in meinem Fall basierte, hatte für Tabbar in scrollToElement Rechnung zu tragen, sonst könnte eine Tabbar Taste, wenn die Ansicht geklopft bekommen unter dem Tabbar war:

func scrollToElement(element: XCUIElement) { 
     while !element.visible() { 
      swipeUp() 
     } 
     // Account for tabBar 
     let tabBar = XCUIApplication().tabBars.element(boundBy: 0) 
     if (tabBar.visible()) { 
      while element.frame.intersects(tabBar.frame) { 
       swipeUp() 
      } 
     } 
    } 
2

Lösungen swipeUp() und swipeDown() verwenden, sind nicht ideal, weil sie möglicherweise hinter dem Zielelement zu dem Impuls des Swipe aufgrund bewegen kann.Nach langem Suchen und Frustration fand ich eine magische Methode auf XCUICoordinate:

func press(forDuration duration: TimeInterval, thenDragTo otherCoordinate: XCUICoordinate) 

So können wir tun, so etwas wie:

let topCoordinate = XCUIApplication().statusBars.firstMatch.coordinate(withNormalizedOffset: .zero) 
let myElement = XCUIApplication().staticTexts["My Element"].coordinate(withNormalizedOffset: .zero) 
// drag from element to top of screen (status bar) 
myElement.press(forDuration: 0.1, thenDragTo: topCoordinate) 

Soweit die Überprüfung, ob etwas sichtbar geht, Sie isHittable verwenden möchten in Verbindung mit exists. siehe scrollDownToElement in der Verlängerung unter

Hier ist eine handliche Erweiterung, die bewegen wird, bis ein Element auf dem Bildschirm ist und dann blättern dieses Element zum oberen Rand des Bildschirms :)

extension XCUIApplication { 
    private struct Constants { 
     // Half way accross the screen and 10% from top 
     static let topOffset = CGVector(dx: 0.5, dy: 0.1) 

     // Half way accross the screen and 90% from top 
     static let bottomOffset = CGVector(dx: 0.5, dy: 0.9) 
    } 

    var screenTopCoordinate: XCUICoordinate { 
     return windows.firstMatch.coordinate(withNormalizedOffset: Constants.topOffset) 
    } 

    var screenBottomCoordinate: XCUICoordinate { 
     return windows.firstMatch.coordinate(withNormalizedOffset: Constants.bottomOffset) 
    } 

    func scrollDownToElement(element: XCUIElement, maxScrolls: Int = 5) { 
     for _ in 0..<maxScrolls { 
      if element.exists && element.isHittable { element.scrollToTop(); break } 
      scrollDown() 
     } 
    } 

    func scrollDown() { 
     screenBottomCoordinate.press(forDuration: 0.1, thenDragTo: screenTopCoordinate) 
    } 
} 

extension XCUIElement { 
    func scrollToTop() { 
     let topCoordinate = XCUIApplication().screenTopCoordinate 
     let elementCoordinate = coordinate(withNormalizedOffset: .zero) 

     // Adjust coordinate so that the drag is straight up, otherwise 
     // an embedded horizontal scrolling element will get scrolled instead 
     let delta = topCoordinate.screenPoint.x - elementCoordinate.screenPoint.x 
     let deltaVector = CGVector(dx: delta, dy: 0.0) 

     elementCoordinate.withOffset(deltaVector).press(forDuration: 0.1, thenDragTo: topCoordinate) 
    } 
} 

Gist über here mit zugesetztem scrollUp Methoden

+0

Mit xcode> = 9.1 nur funktionierende Lösung, tnx zum Teilen – ergunkocak

Verwandte Themen