diff --git a/Project.yml b/Project.yml index 975d104..2043396 100644 --- a/Project.yml +++ b/Project.yml @@ -43,3 +43,17 @@ targets: product: VNCCore - package: VNCUI product: VNCUI + + ScreensUITests: + type: bundle.ui-testing + platform: iOS + deploymentTarget: "18.0" + sources: + - path: ScreensUITests + settings: + base: + PRODUCT_BUNDLE_IDENTIFIER: com.tt.screens.uitests + TEST_TARGET_NAME: Screens + GENERATE_INFOPLIST_FILE: YES + dependencies: + - target: Screens diff --git a/ScreensUITests/ScreensUITests.swift b/ScreensUITests/ScreensUITests.swift new file mode 100644 index 0000000..2fed11c --- /dev/null +++ b/ScreensUITests/ScreensUITests.swift @@ -0,0 +1,63 @@ +import XCTest + +final class ScreensUITests: XCTestCase { + override func setUp() { + continueAfterFailure = false + } + + @MainActor + func testLayoutFillsScreenAndCoreFlows() { + let app = XCUIApplication() + app.launch() + + // ---- Top chrome is present and flush with the safe area top. + let title = app.staticTexts["Screens"] + XCTAssertTrue(title.waitForExistence(timeout: 5), "Title should appear") + + let screenFrame = app.windows.firstMatch.frame + let titleY = title.frame.midY + XCTAssertLessThan(titleY, screenFrame.height * 0.25, + "Title should sit in the top 25% of the screen; actual Y \(titleY) in screen \(screenFrame.height)") + + // ---- Tap + to open Add Connection sheet. + let addButton = app.buttons["Add connection"] + XCTAssertTrue(addButton.exists, "Add button should exist") + addButton.tap() + + let displayNameField = app.textFields["Display name"] + XCTAssertTrue(displayNameField.waitForExistence(timeout: 2), + "Add Connection sheet should present and show Display name field") + + app.buttons["Cancel"].tap() + XCTAssertFalse(displayNameField.waitForExistence(timeout: 1), + "Add sheet should dismiss on Cancel") + + // ---- Settings gear opens Settings sheet. + app.buttons["Settings"].tap() + let settingsTitle = app.navigationBars.staticTexts["Settings"] + XCTAssertTrue(settingsTitle.waitForExistence(timeout: 2), + "Settings sheet should present") + app.buttons["Done"].tap() + + // ---- Search field accepts input and clears. + let search = app.textFields.matching(NSPredicate(format: "placeholderValue == %@", "Search connections")).firstMatch + XCTAssertTrue(search.waitForExistence(timeout: 2), "Search field should exist") + search.tap() + search.typeText("mini") + XCTAssertEqual(search.value as? String, "mini", + "Search text should round-trip") + // Title should still be visible (top chrome does not scroll off) + XCTAssertTrue(title.isHittable, "Title should remain on screen during search") + + // ---- Empty-state CTA routes to Add Connection. + let emptyCTA = app.buttons["Add a computer"] + if emptyCTA.waitForExistence(timeout: 1) { + // clear search first + app.buttons["Clear search"].tap() + emptyCTA.tap() + XCTAssertTrue(displayNameField.waitForExistence(timeout: 2), + "Empty-state CTA should present Add Connection sheet") + app.buttons["Cancel"].tap() + } + } +}