diff --git a/README.md b/README.md index 9ac0a4f..aa5efe5 100644 --- a/README.md +++ b/README.md @@ -164,8 +164,8 @@ let myButton = try eventGenerator.viewWithIdentifier("my_button", ofType: UIButt You will often need to wait for the simulator to finish displaying something on the screen or for an animation to end. Hammer provides multiple methods to wait until a view is visible on screen or if a control is hittable ```swift -try eventGenerator.wait(untilVisible: "myLabel", timeout: 1) -try eventGenerator.wait(untilHittable: "myButton", timeout: 1) +try eventGenerator.waitUntilVisible("my_label", timeout: 1) +try eventGenerator.waitUntilHittable("my_button", timeout: 1) ``` ## Troubleshooting diff --git a/Sources/Hammer/EventGenerator/EventGenerator.swift b/Sources/Hammer/EventGenerator/EventGenerator.swift index 1e0eceb..fe691b3 100644 --- a/Sources/Hammer/EventGenerator/EventGenerator.swift +++ b/Sources/Hammer/EventGenerator/EventGenerator.swift @@ -98,7 +98,7 @@ public final class EventGenerator { /// - parameter timeout: The maximum time to wait for the window to be ready. public func waitUntilWindowIsReady(timeout: TimeInterval = 2) throws { do { - try self.wait(until: self.isWindowReady, timeout: timeout) + try self.waitUntil(self.isWindowReady, timeout: timeout) } catch { throw HammerError.windowIsNotReadyForInteraction } diff --git a/Sources/Hammer/Utilties/Subviews.swift b/Sources/Hammer/Utilties/Subviews.swift index 66d7c5e..05ca985 100644 --- a/Sources/Hammer/Utilties/Subviews.swift +++ b/Sources/Hammer/Utilties/Subviews.swift @@ -81,7 +81,7 @@ extension EventGenerator { checkInterval: TimeInterval = 0.1) throws -> UIView { do { - return try self.wait(until: { + return try self.waitUntilExists({ do { return try self.viewWithIdentifier(accessibilityIdentifier) } catch HammerError.unableToFindView { @@ -115,7 +115,7 @@ extension EventGenerator { checkInterval: TimeInterval = 0.1) throws -> T { do { - return try self.wait(until: { + return try self.waitUntilExists({ do { return try self.viewWithIdentifier(accessibilityIdentifier, ofType: type) } catch HammerError.unableToFindView { diff --git a/Sources/Hammer/Utilties/Waiting.swift b/Sources/Hammer/Utilties/Waiting.swift index 6428994..3e475a8 100644 --- a/Sources/Hammer/Utilties/Waiting.swift +++ b/Sources/Hammer/Utilties/Waiting.swift @@ -18,8 +18,8 @@ extension EventGenerator { /// - parameter checkInterval: How often should the condition be checked. /// /// - throws: An error if the condition did not return true within the specified time. - public func wait(until condition: @autoclosure @escaping () throws -> Bool, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntil(_ condition: @autoclosure @escaping () throws -> Bool, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { let startTime = Date().timeIntervalSinceReferenceDate while try !condition() { @@ -41,8 +41,8 @@ extension EventGenerator { /// /// - returns: The non-nil object. @discardableResult - public func wait(until exists: @autoclosure @escaping () throws -> T?, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws -> T + public func waitUntilExists(_ exists: @autoclosure @escaping () throws -> T?, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws -> T { let startTime = Date().timeIntervalSinceReferenceDate while true { @@ -65,10 +65,10 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the view does not exist after the specified time. - public func wait(untilExists accessibilityIdentifier: String, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilExists(_ accessibilityIdentifier: String, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.viewWithIdentifier(accessibilityIdentifier), + try self.waitUntilExists(self.viewWithIdentifier(accessibilityIdentifier), timeout: timeout, checkInterval: checkInterval) } @@ -80,11 +80,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the view does not exist after the specified time. - public func wait(untilVisible accessibilityIdentifier: String, visibility: Visibility = .partial, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilVisible(_ accessibilityIdentifier: String, visibility: Visibility = .partial, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.viewIsVisible(accessibilityIdentifier, visibility: visibility), - timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.viewIsVisible(accessibilityIdentifier, visibility: visibility), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a view with the specified identifier to be visible within the specified time. @@ -95,11 +95,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the view does not exist after the specified time. - public func wait(untilVisible view: UIView, visibility: Visibility = .partial, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilVisible(_ view: UIView, visibility: Visibility = .partial, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.viewIsVisible(view, visibility: visibility), - timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.viewIsVisible(view, visibility: visibility), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a rect to be visible on screen within the specified time. @@ -110,11 +110,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the rect is not visible within the specified time. - public func wait(untilVisible rect: CGRect, visibility: Visibility = .partial, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilVisible(_ rect: CGRect, visibility: Visibility = .partial, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.rectIsVisible(rect, visibility: visibility), - timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.rectIsVisible(rect, visibility: visibility), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a point to be visible on screen within the specified time. @@ -124,11 +124,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the point is not visible within the specified time. - public func wait(untilVisible point: CGPoint, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilVisible(_ point: CGPoint, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.pointIsVisible(point), - timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.pointIsVisible(point), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a view with the specified identifier to be hittable within the specified time. @@ -138,11 +138,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the view does not exist after the specified time. - public func wait(untilHittable accessibilityIdentifier: String, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilHittable(_ accessibilityIdentifier: String, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.viewIsHittable(accessibilityIdentifier), - timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.viewIsHittable(accessibilityIdentifier), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a view with the specified identifier to be hittable within the specified time. @@ -152,10 +152,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the view does not exist after the specified time. - public func wait(untilHittable view: UIView, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilHittable(_ view: UIView, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.viewIsHittable(view), timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.viewIsHittable(view), + timeout: timeout, checkInterval: checkInterval) } /// Waits for a point to be visible and hittable on screen within the specified time. @@ -165,10 +166,11 @@ extension EventGenerator { /// - parameter checkInterval: How often should the view be checked. /// /// - throws: An error if the point is not hittable within the specified time. - public func wait(untilHittable point: CGPoint, - timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws + public func waitUntilHittable(_ point: CGPoint, + timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.pointIsHittable(point), timeout: timeout, checkInterval: checkInterval) + try self.waitUntil(self.pointIsHittable(point), + timeout: timeout, checkInterval: checkInterval) } /// Waits for the default touch location to be visible and hittable on screen within the specified time. @@ -178,6 +180,7 @@ extension EventGenerator { /// /// - throws: An error if the point is not hittable within the specified time. public func waitUntilHittable(timeout: TimeInterval, checkInterval: TimeInterval = 0.1) throws { - try self.wait(until: self.defaultTouchLocation, timeout: timeout, checkInterval: checkInterval) + try self.waitUntilExists(self.defaultTouchLocation, + timeout: timeout, checkInterval: checkInterval) } } diff --git a/Tests/HammerTests/ViewControllerTests.swift b/Tests/HammerTests/ViewControllerTests.swift index 678725a..a281066 100644 --- a/Tests/HammerTests/ViewControllerTests.swift +++ b/Tests/HammerTests/ViewControllerTests.swift @@ -8,7 +8,7 @@ final class ViewControllerTests: XCTestCase { let viewController = TestSignInViewController() let navigationController = UINavigationController(rootViewController: viewController) let eventGenerator = try EventGenerator(viewController: navigationController) - try eventGenerator.wait(untilHittable: "username_field", timeout: 1) + try eventGenerator.waitUntilHittable("username_field", timeout: 1) let usernameTextField = try eventGenerator.viewWithIdentifier("username_field", ofType: UITextField.self) @@ -29,7 +29,7 @@ final class ViewControllerTests: XCTestCase { XCTAssertTrue(signInButton.isEnabled) try eventGenerator.keyPress(.returnOrEnter) - try eventGenerator.wait(untilExists: "username_label", timeout: 1) + try eventGenerator.waitUntilExists("username_label", timeout: 1) let usernameLabel = try eventGenerator.viewWithIdentifier("username_label", ofType: UILabel.self) XCTAssertEqual(usernameLabel.text, "Hello GabrielUsername123") diff --git a/Tests/HammerTests/WaitingTests.swift b/Tests/HammerTests/WaitingTests.swift index 863e1a9..055093a 100644 --- a/Tests/HammerTests/WaitingTests.swift +++ b/Tests/HammerTests/WaitingTests.swift @@ -1,5 +1,4 @@ import CoreGraphics -import Dispatch import Hammer import UIKit import XCTest @@ -16,13 +15,14 @@ final class WaitingTests: XCTestCase { try eventGenerator.waitUntilHittable(timeout: 1) view.isHidden = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) { + let timer = Timer.scheduledTimer(withTimeInterval: 0.02, repeats: false) { _ in view.isHidden = false } XCTAssertFalse(eventGenerator.viewIsVisible("my_button")) - try eventGenerator.wait(untilVisible: "my_button", timeout: 1) + try eventGenerator.waitUntilVisible("my_button", timeout: 1) XCTAssertTrue(eventGenerator.viewIsVisible("my_button")) + timer.invalidate() } func testWaitUntilVisible() throws { @@ -36,13 +36,14 @@ final class WaitingTests: XCTestCase { try eventGenerator.waitUntilHittable(timeout: 1) view.isHidden = true - DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) { + let timer = Timer.scheduledTimer(withTimeInterval: 0.02, repeats: false) { _ in view.isHidden = false } XCTAssertFalse(eventGenerator.viewIsVisible(view)) - try eventGenerator.wait(untilVisible: view, timeout: 1) + try eventGenerator.waitUntilVisible(view, timeout: 1) XCTAssertTrue(eventGenerator.viewIsVisible(view)) + timer.invalidate() } func testWaitUntilVisibleMove() throws { @@ -58,13 +59,14 @@ final class WaitingTests: XCTestCase { let eventGenerator = try EventGenerator(view: scrollView) try eventGenerator.waitUntilHittable(timeout: 1) - DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + let timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in scrollView.scrollRectToVisible(view.frame, animated: false) } XCTAssertFalse(eventGenerator.viewIsVisible("my_button")) - try eventGenerator.wait(untilVisible: "my_button", timeout: 1) + try eventGenerator.waitUntilVisible("my_button", timeout: 1) XCTAssertTrue(eventGenerator.viewIsVisible("my_button")) + timer.invalidate() } func testWaitUntilHittableWithIdentifier() throws { @@ -78,13 +80,14 @@ final class WaitingTests: XCTestCase { try eventGenerator.waitUntilHittable(timeout: 1) view.isUserInteractionEnabled = false - DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) { + let timer = Timer.scheduledTimer(withTimeInterval: 0.02, repeats: false) { _ in view.isUserInteractionEnabled = true } XCTAssertFalse(eventGenerator.viewIsHittable("my_button")) - try eventGenerator.wait(untilHittable: "my_button", timeout: 1) + try eventGenerator.waitUntilHittable("my_button", timeout: 1) XCTAssertTrue(eventGenerator.viewIsHittable("my_button")) + timer.invalidate() } func testViewForIdentifierWithTimeout() throws {