import XCTest /// Comprehensive tests for multi-user residence features final class MultiUserUITests: BaseUITest { override func setUp() { super.setUp() // Login as primary owner login(username: "testowner", password: "TestPass123!") let residencesTab = app.tabBars.buttons["Residences"] XCTAssertTrue(residencesTab.waitForExistence(timeout: 10)) } // MARK: - Manage Users Tests func testManageUsersButtonVisibleForOwner() { // Given: User owns a residence navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // Then: Manage users button should be visible let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch XCTAssertTrue(manageUsersButton.exists, "Owner should see manage users button") } } func testManageUsersButtonHiddenForSharedUser() { // Given: User is a shared user (not owner) logout() login(username: "shareduser", password: "TestPass123!") navigateToTab("Residences") wait(seconds: 2) // Find a shared residence let sharedResidence = app.cells.firstMatch if sharedResidence.exists { sharedResidence.tap() wait(seconds: 2) // Then: Manage users button should NOT be visible let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch XCTAssertFalse(manageUsersButton.exists, "Shared user should not see manage users button") } } func testOpenManageUsersScreen() { // Given: Owner is viewing a residence navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // When: Owner taps manage users button let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Then: Manage users screen should be displayed let manageUsersTitle = app.navigationBars["Manage Users"] XCTAssertTrue(manageUsersTitle.waitForExistence(timeout: 3), "Should show manage users screen") // And: User list should be visible let usersList = app.scrollViews.firstMatch XCTAssertTrue(usersList.exists, "Should show users list") } } } // MARK: - Share Code Tests func testShareCodeInitiallyBlank() { // Given: Owner opens manage users screen navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Then: Share code should be blank initially let noActiveCode = app.staticTexts["No active code"] XCTAssertTrue(noActiveCode.exists, "Share code should start blank") } } } func testGenerateShareCode() { // Given: Owner is on manage users screen navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // When: Owner taps generate code button let generateButton = app.buttons["Generate"] if !generateButton.exists { // Button might say "New Code" if there's an existing code let newCodeButton = app.buttons["New Code"] if newCodeButton.exists { newCodeButton.tap() } } else { generateButton.tap() } // Then: Share code should be generated and displayed wait(seconds: 2) let shareCodeTexts = app.staticTexts.matching(NSPredicate(format: "label.length == 6 AND label MATCHES %@", "[A-Z0-9]{6}")) XCTAssertTrue(shareCodeTexts.count > 0, "Should display 6-character share code") } } } func testRegenerateShareCode() { // Given: Owner has generated a share code navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Generate first code let generateButton = app.buttons["Generate"] if generateButton.exists { generateButton.tap() wait(seconds: 2) let firstCode = app.staticTexts.matching(NSPredicate(format: "label.length == 6 AND label MATCHES %@", "[A-Z0-9]{6}")).firstMatch.label // When: Owner generates new code let newCodeButton = app.buttons["New Code"] if newCodeButton.exists { newCodeButton.tap() wait(seconds: 2) // Then: A different code should be generated let secondCode = app.staticTexts.matching(NSPredicate(format: "label.length == 6 AND label MATCHES %@", "[A-Z0-9]{6}")).firstMatch.label XCTAssertNotEqual(firstCode, secondCode, "New code should be different") } } } } } // MARK: - Join Residence Tests func testJoinResidenceWithValidCode() { // This test requires coordination between two accounts // Given: Owner generates a share code var shareCode: String = "" navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) let generateButton = app.buttons["Generate"] if generateButton.exists { generateButton.tap() wait(seconds: 2) shareCode = app.staticTexts.matching(NSPredicate(format: "label.length == 6 AND label MATCHES %@", "[A-Z0-9]{6}")).firstMatch.label } // Close manage users screen let closeButton = app.buttons["Close"] if closeButton.exists { closeButton.tap() } } } // When: Different user joins with code if !shareCode.isEmpty { logout() login(username: "newuser", password: "TestPass123!") navigateToTab("Residences") wait(seconds: 1) // Find join residence button let joinButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Join'")).firstMatch if joinButton.exists { joinButton.tap() wait(seconds: 1) // Enter share code let codeField = app.textFields.firstMatch if codeField.exists { codeField.tap() codeField.typeText(shareCode) // Submit let submitButton = app.buttons["Join"] if submitButton.exists { submitButton.tap() wait(seconds: 2) // Then: User should be added to residence let successMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Successfully joined'")) XCTAssertTrue(successMessage.firstMatch.exists || app.cells.count > 0, "Should join residence successfully") } } } } } func testJoinResidenceWithInvalidCode() { // Given: User is on join residence screen navigateToTab("Residences") let joinButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Join'")).firstMatch if joinButton.exists { joinButton.tap() wait(seconds: 1) // When: User enters invalid code let codeField = app.textFields.firstMatch if codeField.exists { codeField.tap() codeField.typeText("INVALID") let submitButton = app.buttons["Join"] if submitButton.exists { submitButton.tap() wait(seconds: 2) // Then: Error message should be shown let errorMessage = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Invalid' OR label CONTAINS[c] 'not found'")) XCTAssertTrue(errorMessage.firstMatch.exists, "Should show invalid code error") } } } } // MARK: - User List Tests func testUserListShowsAllUsers() { // Given: Residence has multiple users navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Then: User count should be displayed let userCountLabel = app.staticTexts.matching(NSPredicate(format: "label CONTAINS[c] 'Users'")) XCTAssertTrue(userCountLabel.count > 0, "Should show user count") // And: Individual users should be listed let usersList = app.scrollViews.firstMatch XCTAssertTrue(usersList.exists, "Should show users list") } } } func testOwnerLabelDisplayed() { // Given: Owner is viewing manage users screen navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Then: Owner badge should be visible next to owner's name let ownerBadge = app.staticTexts["Owner"] XCTAssertTrue(ownerBadge.exists, "Should show Owner badge") } } } // MARK: - Remove User Tests func testRemoveUserAsOwner() { // Given: Owner has residence with multiple users navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // When: Owner taps remove button on a user let removeButtons = app.buttons.matching(identifier: "trash") if removeButtons.count > 0 { let initialUserCount = removeButtons.count removeButtons.firstMatch.tap() // Confirm removal if prompted let confirmButton = app.alerts.buttons["Remove"] if confirmButton.exists { confirmButton.tap() } // Then: User should be removed wait(seconds: 2) let newUserCount = app.buttons.matching(identifier: "trash").count XCTAssertTrue(newUserCount < initialUserCount, "Should remove user") } } } } func testCannotRemoveOwner() { // Given: Owner is viewing manage users navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) // Then: Owner row should NOT have remove button let ownerLabel = app.staticTexts["Owner"] if ownerLabel.exists { // Check if there's a remove button in the same container // Owner should not have a remove button next to their name } } } } // MARK: - Shared User Access Tests func testSharedUserCanViewResidence() { // Given: User is a shared user logout() login(username: "shareduser", password: "TestPass123!") // Then: Shared residences should appear in list navigateToTab("Residences") wait(seconds: 2) let residencesList = app.cells.count XCTAssertTrue(residencesList > 0, "Shared user should see shared residences") } func testSharedUserCanCreateTasks() { // Given: Shared user is viewing a shared residence logout() login(username: "shareduser", password: "TestPass123!") navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // When: Shared user tries to create a task let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch XCTAssertTrue(addButton.exists, "Shared user should be able to add tasks") if addButton.exists { addButton.tap() wait(seconds: 1) // Then: Add task form should be displayed let titleField = app.textFields.firstMatch XCTAssertTrue(titleField.exists, "Shared user should be able to create tasks") } } } func testSharedUserCanEditTasks() { // Given: Shared user is viewing tasks logout() login(username: "shareduser", password: "TestPass123!") navigateToTab("Tasks") wait(seconds: 2) // When: Shared user tries to edit a task let editButtons = app.buttons.matching(identifier: "pencil") if editButtons.count > 0 { // Then: Edit buttons should be available XCTAssertTrue(editButtons.firstMatch.exists, "Shared user should be able to edit tasks") } } func testUserCountDisplayed() { // Given: Owner is viewing a residence navigateToTab("Residences") wait(seconds: 2) let firstResidence = app.cells.firstMatch if firstResidence.exists { firstResidence.tap() wait(seconds: 2) // Then: User count should be visible somewhere on the screen // This depends on your UI design - adjust as needed let manageUsersButton = app.navigationBars.buttons.matching(identifier: "person.2").firstMatch if manageUsersButton.exists { manageUsersButton.tap() wait(seconds: 1) let userCountText = app.staticTexts.matching(NSPredicate(format: "label CONTAINS[c] 'Users'")) XCTAssertTrue(userCountText.count > 0, "Should display user count") } } } }