347 lines
13 KiB
Swift
347 lines
13 KiB
Swift
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")
|
|
}
|
|
}
|
|
}
|