Skip to content

Commit eec3d9a

Browse files
authored
Prevent direct test failure during init if the screen is not loaded (#8)
2 parents 7f31908 + 650e4a7 commit eec3d9a

2 files changed

Lines changed: 51 additions & 12 deletions

File tree

Sources/ScreenObject/ScreenObject.swift

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import XCTest
66
// and those are obviously specific to each screen, hence should be added by each subclass.
77
open class ScreenObject {
88

9+
public enum WaitForScreenError: Equatable, Error {
10+
case timedOut
11+
}
12+
913
/// The `XCUIApplication` instance this screen is part of. This is the value passed at
1014
/// initialization time.
1115
public let app: XCUIApplication
@@ -34,17 +38,31 @@ open class ScreenObject {
3438

3539
@discardableResult
3640
func waitForScreen() throws -> Self {
37-
XCTContext.runActivity(named: "Confirm screen \(self) is loaded") { (activity) in
38-
let result = waitFor(element: expectedElement, predicate: "isEnabled == true", timeout: 20)
39-
XCTAssert(result, "Screen \(self) is not loaded.")
41+
try XCTContext.runActivity(named: "Confirm screen \(self) is loaded") { (activity) in
42+
let result = waitFor(
43+
element: expectedElement,
44+
predicate: "isEnabled == true",
45+
timeout: self.waitTimeout
46+
)
47+
48+
guard result == .completed else { throw WaitForScreenError.timedOut }
4049
}
4150
return self
4251
}
4352

44-
private func waitFor(element: XCUIElement, predicate: String, timeout: Int = 5) -> Bool {
45-
let elementPredicate = XCTNSPredicateExpectation(predicate: NSPredicate(format: predicate), object: element)
46-
let result = XCTWaiter.wait(for: [elementPredicate], timeout: TimeInterval(timeout))
47-
48-
return result == .completed
53+
private func waitFor(
54+
element: XCUIElement,
55+
predicate: String,
56+
timeout: TimeInterval
57+
) -> XCTWaiter.Result {
58+
XCTWaiter.wait(
59+
for: [
60+
XCTNSPredicateExpectation(
61+
predicate: NSPredicate(format: predicate),
62+
object: element
63+
)
64+
],
65+
timeout: timeout
66+
)
4967
}
5068
}

Tests/TestAppUITests/TestAppUITests.swift

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,26 @@ import XCTest
33

44
class TestAppUITests: XCTestCase {
55

6+
let app = XCUIApplication()
7+
68
override func setUpWithError() throws {
9+
app.launch()
710
continueAfterFailure = false
811
}
912

10-
func testExample() throws {
11-
let app = XCUIApplication()
12-
app.launch()
13-
13+
func testIsLoadedReturnsTrueWhenScreenIsLoaded() throws {
1414
let screen = try HelloWorldScreen()
1515
XCTAssertTrue(screen.isLoaded)
1616
}
17+
18+
func testScreenInitThrowsWhenScreenIsNotLoaded() throws {
19+
do {
20+
_ = try MissingScreen(app: app)
21+
XCTFail("Expected `ScreenObject` `init` to throw, but it didn't")
22+
} catch {
23+
XCTAssertEqual(error as? ScreenObject.WaitForScreenError, .timedOut)
24+
}
25+
}
1726
}
1827

1928
final class HelloWorldScreen: ScreenObject {
@@ -22,3 +31,15 @@ final class HelloWorldScreen: ScreenObject {
2231
try super.init(expectedElementGetter: { $0.staticTexts["Hello, world!"] })
2332
}
2433
}
34+
35+
/// A screen that doesn't exist. Use it to test the init failure behavior.
36+
class MissingScreen: ScreenObject {
37+
38+
init(app: XCUIApplication) throws {
39+
try super.init(
40+
expectedElementGetter: { $0.staticTexts["this screen does not exist"] },
41+
app: app,
42+
waitTimeout: 1
43+
)
44+
}
45+
}

0 commit comments

Comments
 (0)