Files
honeyDueKMP/iosApp/iosAppUITests/MultiUserUITests.swift
Trey t 7dce211681 wip
2025-11-08 16:02:01 -06:00

471 lines
17 KiB
Swift

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")
}
}
}
}