import XCTest /// Residence management tests /// Based on working SimpleLoginTest pattern /// /// Test Order (logical dependencies): /// 1. View/UI tests (work with empty list) /// 2. Navigation tests (don't create data) /// 3. Cancel test (opens form but doesn't save) /// 4. Creation tests (creates data) /// 5. Tests that depend on created data (view details) final class Suite3_ResidenceTests: XCTestCase { var app: XCUIApplication! override func setUpWithError() throws { continueAfterFailure = false app = XCUIApplication() app.launch() ensureLoggedIn() } override func tearDownWithError() throws { app = nil } // MARK: - Helper Methods private func ensureLoggedIn() { UITestHelpers.ensureLoggedIn(app: app) // Navigate to Residences tab let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch if residencesTab.exists { residencesTab.tap() sleep(1) } } private func navigateToResidencesTab() { let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch if !residencesTab.isSelected { residencesTab.tap() sleep(1) } } // MARK: - 1. View/UI Tests (work with empty list) func test01_viewResidencesList() { // Given: User is logged in and on Residences tab navigateToResidencesTab() // Then: Should see residences list header (must exist even if empty) let residencesHeader = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Your Properties' OR label CONTAINS[c] 'My Properties' OR label CONTAINS[c] 'Residences'")).firstMatch XCTAssertTrue(residencesHeader.waitForExistence(timeout: 5), "Residences list screen must be visible") // Add button must exist let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton] XCTAssertTrue(addButton.exists, "Add residence button must exist") } // MARK: - 2. Navigation Tests (don't create data) func test02_navigateToAddResidence() { // Given: User is on Residences tab navigateToResidencesTab() // When: User taps add residence button (using accessibility identifier to avoid wrong button) let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton] XCTAssertTrue(addButton.waitForExistence(timeout: 5), "Add residence button should exist") addButton.tap() // Then: Should show add residence form with all required fields sleep(2) let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Property Name' OR placeholderValue CONTAINS[c] 'Name'")).firstMatch XCTAssertTrue(nameField.exists, "Name field should exist in residence form") // Verify property type picker exists let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch XCTAssertTrue(propertyTypePicker.exists, "Property type picker should exist in residence form") let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch XCTAssertTrue(saveButton.exists, "Save button should exist in residence form") } func test03_navigationBetweenTabs() { // Given: User is on Residences tab navigateToResidencesTab() // When: User navigates to Tasks tab let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch XCTAssertTrue(tasksTab.exists, "Tasks tab should exist") tasksTab.tap() sleep(1) // Then: Should be on Tasks tab XCTAssertTrue(tasksTab.isSelected, "Should be on Tasks tab") // When: User navigates back to Residences let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch residencesTab.tap() sleep(1) // Then: Should be back on Residences tab XCTAssertTrue(residencesTab.isSelected, "Should be back on Residences tab") } // MARK: - 3. Cancel Test (opens form but doesn't save) func test04_cancelResidenceCreation() { // Given: User is on add residence form navigateToResidencesTab() let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton] addButton.tap() sleep(2) // When: User taps cancel let cancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Cancel'")).firstMatch XCTAssertTrue(cancelButton.waitForExistence(timeout: 5), "Cancel button should exist") cancelButton.tap() // Then: Should return to residences list sleep(1) let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch XCTAssertTrue(residencesTab.exists, "Should be back on residences list") } // MARK: - 4. Creation Tests func test05_createResidenceWithMinimalData() { // Given: User is on add residence form navigateToResidencesTab() // Use accessibility identifier to get the correct add button let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton] XCTAssertTrue(addButton.exists, "Add residence button should exist") addButton.tap() sleep(2) // When: Verify form loaded correctly let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Property Name' OR placeholderValue CONTAINS[c] 'Name'")).firstMatch XCTAssertTrue(nameField.waitForExistence(timeout: 5), "Name field should appear - form did not load correctly!") // Fill name field let timestamp = Int(Date().timeIntervalSince1970) let residenceName = "UITest Home \(timestamp)" nameField.tap() nameField.typeText(residenceName) // Select property type (required field) let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch if propertyTypePicker.exists { propertyTypePicker.tap() sleep(2) // After tapping picker, look for any selectable option // Try common property types as buttons if app.buttons["House"].exists { app.buttons["House"].tap() } else if app.buttons["Apartment"].exists { app.buttons["Apartment"].tap() } else if app.buttons["Condo"].exists { app.buttons["Condo"].tap() } else { // If navigation style, try cells let cells = app.cells if cells.count > 1 { cells.element(boundBy: 1).tap() // Skip first which might be "Select Type" } } sleep(1) } // Fill address fields - MUST exist for residence let streetField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Street'")).firstMatch XCTAssertTrue(streetField.exists, "Street field should exist in residence form") streetField.tap() streetField.typeText("123 Test St") let cityField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'City'")).firstMatch XCTAssertTrue(cityField.exists, "City field should exist in residence form") cityField.tap() cityField.typeText("TestCity") let stateField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'State'")).firstMatch XCTAssertTrue(stateField.exists, "State field should exist in residence form") stateField.tap() stateField.typeText("TS") let postalField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Postal' OR placeholderValue CONTAINS[c] 'Postal'")).firstMatch XCTAssertTrue(postalField.exists, "Postal code field should exist in residence form") postalField.tap() postalField.typeText("12345") // Scroll down to see more fields app.swipeUp() sleep(1) // Save let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch XCTAssertTrue(saveButton.exists, "Save button should exist") saveButton.tap() // Then: Should return to residences list and verify residence was created sleep(3) // Wait for save to complete // First check we're back on the list let residencesList = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'Your Properties' OR label CONTAINS 'My Properties'")).firstMatch XCTAssertTrue(residencesList.waitForExistence(timeout: 10), "Should return to residences list after saving") // CRITICAL: Verify the residence actually appears in the list let newResidence = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(residenceName)'")).firstMatch XCTAssertTrue(newResidence.waitForExistence(timeout: 10), "New residence '\(residenceName)' should appear in the list - network call may have failed!") } // MARK: - 5. Tests That Depend on Created Data func test06_viewResidenceDetails() { // Given: User is on Residences tab with at least one residence // This test requires testCreateResidenceWithMinimalData to have run first navigateToResidencesTab() sleep(2) // Find a residence card by looking for UITest Home text let residenceCard = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'UITest Home' OR label CONTAINS 'Test'")).firstMatch XCTAssertTrue(residenceCard.waitForExistence(timeout: 5), "At least one residence must exist - run testCreateResidenceWithMinimalData first") // When: User taps on the residence residenceCard.tap() sleep(2) // Then: Should show residence details screen with edit/delete buttons let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch let deleteButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Delete'")).firstMatch XCTAssertTrue(editButton.exists || deleteButton.exists, "Residence details screen must show with edit or delete button") } }