import XCTest /// Comprehensive tests for residence management final class ResidenceUITests: BaseUITest { override func setUp() { super.setUp() // Login before each test login(username: "testuser", password: "TestPass123!") let residencesTab = app.tabBars.buttons["Residences"] XCTAssertTrue(residencesTab.waitForExistence(timeout: 10)) } // MARK: - List View Tests func testResidenceListDisplays() { // Given: User is on residences tab navigateToTab("Residences") // Then: Residences list should be displayed let navigationBar = app.navigationBars["Residences"] XCTAssertTrue(navigationBar.exists, "Should show residences navigation bar") } func testResidenceListShowsProperties() { // Given: User has residences navigateToTab("Residences") // Then: Residence cards should be visible let residenceCards = app.scrollViews.descendants(matching: .other).matching(NSPredicate(format: "identifier CONTAINS 'ResidenceCard'")) XCTAssertTrue(residenceCards.count > 0 || app.staticTexts["No residences yet"].exists, "Should show either residence cards or empty state") } func testEmptyStateDisplays() { // Given: User has no residences (requires test account with no data) navigateToTab("Residences") // Then: Empty state should be shown // Note: This test assumes test user has no residences let emptyStateText = app.staticTexts["No residences yet"] let addButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Add'")).firstMatch // Should show either residences or empty state with add button XCTAssertTrue(emptyStateText.exists || app.cells.count > 0, "Should show content or empty state") } // MARK: - Create Residence Tests func testCreateResidenceFlow() { // Given: User is on residences screen navigateToTab("Residences") // When: User taps add residence button let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch if !addButton.exists { // Try finding add button in other locations let fabButton = app.buttons["Add Residence"] if fabButton.exists { fabButton.tap() } else { XCTFail("Could not find add residence button") } } else { addButton.tap() } // Then: Add residence form should be displayed wait(seconds: 1) let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'name' OR label CONTAINS[c] 'Name'")).firstMatch XCTAssertTrue(nameField.exists, "Should show residence name field") // When: User fills in residence details let timestamp = Int(Date().timeIntervalSince1970) nameField.tap() nameField.typeText("Test House \(timestamp)") let addressField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'address' OR label CONTAINS[c] 'Address'")).firstMatch if addressField.exists { addressField.tap() addressField.typeText("123 Test Street") } let cityField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'city' OR label CONTAINS[c] 'City'")).firstMatch if cityField.exists { cityField.tap() cityField.typeText("Test City") } // When: User saves the residence let saveButton = app.buttons["Save"] if saveButton.exists { saveButton.tap() } // Then: User should be returned to list view // And: New residence should appear in the list wait(seconds: 2) let residenceTitle = app.staticTexts["Test House \(timestamp)"] XCTAssertTrue(residenceTitle.waitForExistence(timeout: 5) || app.navigationBars["Residences"].exists, "Should show new residence or navigate back to list") } func testCreateResidenceValidation() { // Given: User is on add residence screen navigateToTab("Residences") let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch addButton.tap() wait(seconds: 1) // When: User attempts to save without required fields let saveButton = app.buttons["Save"] if saveButton.exists { saveButton.tap() } // Then: Validation errors should be shown let errorMessages = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'required'")) XCTAssertTrue(errorMessages.count > 0 || !app.navigationBars["Residences"].exists, "Should show validation errors or prevent saving") } // MARK: - View Residence Details Tests func testViewResidenceDetails() { // Given: User has residences navigateToTab("Residences") wait(seconds: 2) // When: User taps on a residence let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() // Then: Residence details should be displayed wait(seconds: 2) let detailView = app.scrollViews.firstMatch XCTAssertTrue(detailView.exists || app.navigationBars.element(boundBy: 1).exists, "Should show residence details") } } func testResidenceDetailsShowsAllSections() { // Given: User is viewing residence details navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // Then: All sections should be visible (after scrolling) let scrollView = app.scrollViews.firstMatch if scrollView.exists { // Check for address section let addressSection = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Address'")).firstMatch // Check for tasks section scrollView.swipeUp() let tasksSection = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch XCTAssertTrue(addressSection.exists || tasksSection.exists, "Should show residence sections") } } } // MARK: - Edit Residence Tests func testEditResidenceFlow() { // Given: User is viewing residence details navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // When: User taps edit button let editButton = app.navigationBars.buttons["Edit"] if editButton.exists { editButton.tap() wait(seconds: 1) // Then: Edit form should be displayed let nameField = app.textFields.containing(NSPredicate(format: "value != nil AND value != ''")).firstMatch XCTAssertTrue(nameField.exists, "Should show edit form with current values") // When: User updates the name if nameField.exists { app.clearText(in: nameField) nameField.typeText("Updated House Name") // When: User saves changes let saveButton = app.buttons["Save"] if saveButton.exists { saveButton.tap() } // Then: Changes should be saved and details view updated wait(seconds: 2) let updatedName = app.staticTexts["Updated House Name"] XCTAssertTrue(updatedName.waitForExistence(timeout: 5) || app.navigationBars.element(boundBy: 1).exists, "Should show updated residence name or details view") } } } } func testCancelEditingResidence() { // Given: User is editing a residence navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let editButton = app.navigationBars.buttons["Edit"] if editButton.exists { editButton.tap() wait(seconds: 1) // When: User makes changes let nameField = app.textFields.firstMatch let originalValue = nameField.value as? String if nameField.exists { app.clearText(in: nameField) nameField.typeText("Temporary Change") // When: User cancels let cancelButton = app.buttons["Cancel"] if cancelButton.exists { cancelButton.tap() } // Then: Changes should be discarded wait(seconds: 1) if let original = originalValue { let originalText = app.staticTexts[original] XCTAssertTrue(originalText.exists || app.navigationBars.element(boundBy: 1).exists, "Should discard changes") } } } } } // MARK: - Delete Residence Tests func testDeleteResidence() { // Given: User has a residence to delete navigateToTab("Residences") wait(seconds: 2) let initialResidenceCount = app.cells.count // When: User swipes to delete (if supported) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.swipeLeft() let deleteButton = app.buttons["Delete"] if deleteButton.exists { deleteButton.tap() // Confirm deletion if alert appears let confirmButton = app.alerts.buttons["Delete"] if confirmButton.exists { confirmButton.tap() } // Then: Residence should be removed wait(seconds: 2) let newCount = app.cells.count XCTAssertTrue(newCount < initialResidenceCount || app.staticTexts["No residences yet"].exists, "Should remove residence from list") } } } // MARK: - Navigation Tests func testNavigateBackFromDetails() { // Given: User is viewing residence details navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // When: User taps back button navigateBack() // Then: User should return to residences list let navigationBar = app.navigationBars["Residences"] XCTAssertTrue(navigationBar.waitForExistence(timeout: 3), "Should navigate back to residences list") } } // MARK: - Search and Filter Tests (if implemented) func testSearchResidences() { // Given: User has multiple residences navigateToTab("Residences") wait(seconds: 2) // When: User searches for a residence let searchField = app.searchFields.firstMatch if searchField.exists { searchField.tap() searchField.typeText("Test") // Then: Results should be filtered wait(seconds: 1) let visibleResidences = app.cells.count XCTAssertTrue(visibleResidences >= 0, "Should show filtered results") } } // MARK: - Pull to Refresh Tests func testPullToRefreshResidences() { // Given: User is on residences list navigateToTab("Residences") wait(seconds: 2) // When: User pulls down to refresh let scrollView = app.scrollViews.firstMatch if scrollView.exists { let startPoint = scrollView.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.2)) let endPoint = scrollView.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.8)) startPoint.press(forDuration: 0.1, thenDragTo: endPoint) // Then: Loading indicator should appear let loadingIndicator = app.activityIndicators.firstMatch XCTAssertTrue(loadingIndicator.exists || scrollView.exists, "Should trigger refresh") } } }