import XCTest class BaseUITestCase: XCTestCase { let app = XCUIApplication() let shortTimeout: TimeInterval = 5 let defaultTimeout: TimeInterval = 15 let longTimeout: TimeInterval = 30 var includeResetStateLaunchArgument: Bool { true } var additionalLaunchArguments: [String] { [] } override func setUpWithError() throws { continueAfterFailure = false XCUIDevice.shared.orientation = .portrait var launchArguments = [ "--ui-testing", "--disable-animations" ] if includeResetStateLaunchArgument { launchArguments.append("--reset-state") } launchArguments.append(contentsOf: additionalLaunchArguments) app.launchArguments = launchArguments app.launch() app.otherElements["ui.app.ready"].waitForExistenceOrFail(timeout: defaultTimeout) } override func tearDownWithError() throws { if let run = testRun, !run.hasSucceeded { let attachment = XCTAttachment(screenshot: app.screenshot()) attachment.name = "Failure-\(name)" attachment.lifetime = .keepAlways add(attachment) } } } extension XCUIElement { @discardableResult func waitForExistenceOrFail( timeout: TimeInterval, message: String? = nil, file: StaticString = #filePath, line: UInt = #line ) -> XCUIElement { if !waitForExistence(timeout: timeout) { XCTFail(message ?? "Expected element to exist: \(self)", file: file, line: line) } return self } @discardableResult func waitUntilHittable( timeout: TimeInterval, message: String? = nil, file: StaticString = #filePath, line: UInt = #line ) -> XCUIElement { let predicate = NSPredicate(format: "exists == true AND hittable == true") let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self) let result = XCTWaiter().wait(for: [expectation], timeout: timeout) if result != .completed { XCTFail(message ?? "Expected element to become hittable: \(self)", file: file, line: line) } return self } @discardableResult func waitForNonExistence( timeout: TimeInterval, message: String? = nil, file: StaticString = #filePath, line: UInt = #line ) -> Bool { let predicate = NSPredicate(format: "exists == false") let expectation = XCTNSPredicateExpectation(predicate: predicate, object: self) let result = XCTWaiter().wait(for: [expectation], timeout: timeout) if result != .completed { XCTFail(message ?? "Expected element to disappear: \(self)", file: file, line: line) return false } return true } func scrollIntoView( in scrollView: XCUIElement, maxSwipes: Int = 8, file: StaticString = #filePath, line: UInt = #line ) { if isHittable { return } for _ in 0..