Rebrand from MyCrib to Casera
- Rename Kotlin package from com.example.mycrib to com.example.casera - Update Android app name, namespace, and application ID - Update iOS bundle identifiers and project settings - Rename iOS directories (MyCribTests -> CaseraTests, etc.) - Update deep link schemes from mycrib:// to casera:// - Update app group identifiers - Update subscription product IDs - Update all UI strings and branding 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
669
iosApp/CaseraUITests/ComprehensiveResidenceTests.swift
Normal file
669
iosApp/CaseraUITests/ComprehensiveResidenceTests.swift
Normal file
@@ -0,0 +1,669 @@
|
||||
import XCTest
|
||||
|
||||
/// Comprehensive residence testing suite covering all scenarios, edge cases, and variations
|
||||
/// This test suite is designed to be bulletproof and catch regressions early
|
||||
final class ComprehensiveResidenceTests: XCTestCase {
|
||||
var app: XCUIApplication!
|
||||
|
||||
// Test data tracking
|
||||
var createdResidenceNames: [String] = []
|
||||
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
app = XCUIApplication()
|
||||
app.launch()
|
||||
|
||||
// Ensure user is logged in
|
||||
UITestHelpers.ensureLoggedIn(app: app)
|
||||
|
||||
// Navigate to Residences tab
|
||||
navigateToResidencesTab()
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
createdResidenceNames.removeAll()
|
||||
app = nil
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
private func navigateToResidencesTab() {
|
||||
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
||||
if residencesTab.waitForExistence(timeout: 5) {
|
||||
if !residencesTab.isSelected {
|
||||
residencesTab.tap()
|
||||
sleep(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func openResidenceForm() -> Bool {
|
||||
let addButton = findAddResidenceButton()
|
||||
guard addButton.exists && addButton.isEnabled else { return false }
|
||||
addButton.tap()
|
||||
sleep(3)
|
||||
|
||||
// Verify form opened
|
||||
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
||||
return nameField.waitForExistence(timeout: 5)
|
||||
}
|
||||
|
||||
private func findAddResidenceButton() -> XCUIElement {
|
||||
sleep(2)
|
||||
|
||||
let addButtonById = app.buttons[AccessibilityIdentifiers.Residence.addButton]
|
||||
if addButtonById.exists && addButtonById.isEnabled {
|
||||
return addButtonById
|
||||
}
|
||||
|
||||
let navBarButtons = app.navigationBars.buttons
|
||||
for i in 0..<navBarButtons.count {
|
||||
let button = navBarButtons.element(boundBy: i)
|
||||
if button.label == "plus" || button.label.contains("Add") {
|
||||
if button.isEnabled {
|
||||
return button
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return addButtonById
|
||||
}
|
||||
|
||||
private func fillTextField(placeholder: String, text: String) {
|
||||
let field = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] '\(placeholder)'")).firstMatch
|
||||
if field.exists {
|
||||
field.tap()
|
||||
field.typeText(text)
|
||||
}
|
||||
}
|
||||
|
||||
private func selectPropertyType(type: String) {
|
||||
let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch
|
||||
if propertyTypePicker.exists {
|
||||
propertyTypePicker.tap()
|
||||
sleep(1)
|
||||
|
||||
// Try to find and tap the type option
|
||||
let typeButton = app.buttons[type]
|
||||
if typeButton.exists {
|
||||
typeButton.tap()
|
||||
sleep(1)
|
||||
} else {
|
||||
// Try cells if it's a navigation style picker
|
||||
let cells = app.cells
|
||||
for i in 0..<cells.count {
|
||||
let cell = cells.element(boundBy: i)
|
||||
if cell.staticTexts[type].exists {
|
||||
cell.tap()
|
||||
sleep(1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func createResidence(
|
||||
name: String,
|
||||
propertyType: String = "House",
|
||||
street: String = "123 Test St",
|
||||
city: String = "TestCity",
|
||||
state: String = "TS",
|
||||
postal: String = "12345",
|
||||
scrollBeforeAddress: Bool = true
|
||||
) -> Bool {
|
||||
guard openResidenceForm() else { return false }
|
||||
|
||||
// Fill name
|
||||
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
||||
nameField.tap()
|
||||
nameField.typeText(name)
|
||||
|
||||
// Select property type
|
||||
selectPropertyType(type: propertyType)
|
||||
|
||||
// Scroll to address section
|
||||
if scrollBeforeAddress {
|
||||
app.swipeUp()
|
||||
sleep(1)
|
||||
}
|
||||
|
||||
// Fill address fields
|
||||
fillTextField(placeholder: "Street", text: street)
|
||||
fillTextField(placeholder: "City", text: city)
|
||||
fillTextField(placeholder: "State", text: state)
|
||||
fillTextField(placeholder: "Postal", text: postal)
|
||||
|
||||
// Save
|
||||
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
|
||||
guard saveButton.exists else { return false }
|
||||
saveButton.tap()
|
||||
|
||||
sleep(4) // Wait for API call
|
||||
|
||||
// Track created residence
|
||||
createdResidenceNames.append(name)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private func findResidence(name: String) -> XCUIElement {
|
||||
return app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(name)'")).firstMatch
|
||||
}
|
||||
|
||||
// MARK: - Basic Residence Creation Tests
|
||||
|
||||
func testCreateResidenceWithMinimalData() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let residenceName = "Minimal Home \(timestamp)"
|
||||
|
||||
let success = createResidence(name: residenceName)
|
||||
XCTAssertTrue(success, "Should successfully create residence with minimal data")
|
||||
|
||||
let residenceInList = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residenceInList.waitForExistence(timeout: 10), "Residence should appear in list")
|
||||
}
|
||||
|
||||
func testCreateResidenceWithAllPropertyTypes() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let propertyTypes = ["House", "Apartment", "Condo"]
|
||||
|
||||
for (index, type) in propertyTypes.enumerated() {
|
||||
let residenceName = "\(type) Test \(timestamp)_\(index)"
|
||||
let success = createResidence(name: residenceName, propertyType: type)
|
||||
XCTAssertTrue(success, "Should create \(type) residence")
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
}
|
||||
|
||||
// Verify all residences exist
|
||||
for (index, type) in propertyTypes.enumerated() {
|
||||
let residenceName = "\(type) Test \(timestamp)_\(index)"
|
||||
let residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.exists, "\(type) residence should exist in list")
|
||||
}
|
||||
}
|
||||
|
||||
func testCreateMultipleResidencesInSequence() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
|
||||
for i in 1...3 {
|
||||
let residenceName = "Sequential Home \(i) - \(timestamp)"
|
||||
let success = createResidence(name: residenceName)
|
||||
XCTAssertTrue(success, "Should create residence \(i)")
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
}
|
||||
|
||||
// Verify all residences exist
|
||||
for i in 1...3 {
|
||||
let residenceName = "Sequential Home \(i) - \(timestamp)"
|
||||
let residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.exists, "Residence \(i) should exist in list")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Residence Editing Tests
|
||||
|
||||
func testEditResidenceName() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let originalName = "Original Name \(timestamp)"
|
||||
let newName = "Edited Name \(timestamp)"
|
||||
|
||||
// Create residence
|
||||
guard createResidence(name: originalName) else {
|
||||
XCTFail("Failed to create residence")
|
||||
return
|
||||
}
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Find and tap residence
|
||||
let residence = findResidence(name: originalName)
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 5), "Residence should exist")
|
||||
residence.tap()
|
||||
sleep(2)
|
||||
|
||||
// Tap edit button
|
||||
let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch
|
||||
if editButton.exists {
|
||||
editButton.tap()
|
||||
sleep(2)
|
||||
|
||||
// Edit name
|
||||
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
||||
if nameField.exists {
|
||||
nameField.tap()
|
||||
// Clear existing text
|
||||
nameField.tap()
|
||||
sleep(1)
|
||||
nameField.tap()
|
||||
sleep(1)
|
||||
app.menuItems["Select All"].tap()
|
||||
sleep(1)
|
||||
nameField.typeText(newName)
|
||||
|
||||
// Save
|
||||
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
|
||||
if saveButton.exists {
|
||||
saveButton.tap()
|
||||
sleep(3)
|
||||
|
||||
// Track new name
|
||||
createdResidenceNames.append(newName)
|
||||
|
||||
// Verify new name appears
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
let updatedResidence = findResidence(name: newName)
|
||||
XCTAssertTrue(updatedResidence.exists, "Residence should show updated name")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testUpdateAllResidenceFields() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let originalName = "Update All Fields \(timestamp)"
|
||||
let newName = "All Fields Updated \(timestamp)"
|
||||
let newStreet = "999 Updated Avenue"
|
||||
let newCity = "NewCity"
|
||||
let newState = "NC"
|
||||
let newPostal = "99999"
|
||||
|
||||
// Create residence with initial values
|
||||
guard createResidence(name: originalName, street: "123 Old St", city: "OldCity", state: "OC", postal: "11111") else {
|
||||
XCTFail("Failed to create residence")
|
||||
return
|
||||
}
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Find and tap residence
|
||||
let residence = findResidence(name: originalName)
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 5), "Residence should exist")
|
||||
residence.tap()
|
||||
sleep(2)
|
||||
|
||||
// Tap edit button
|
||||
let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch
|
||||
XCTAssertTrue(editButton.exists, "Edit button should exist")
|
||||
editButton.tap()
|
||||
sleep(2)
|
||||
|
||||
// Update name
|
||||
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
||||
XCTAssertTrue(nameField.exists, "Name field should exist")
|
||||
nameField.tap()
|
||||
nameField.doubleTap()
|
||||
sleep(1)
|
||||
if app.buttons["Select All"].exists {
|
||||
app.buttons["Select All"].tap()
|
||||
sleep(1)
|
||||
}
|
||||
nameField.typeText(newName)
|
||||
|
||||
// Update property type (if available)
|
||||
let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch
|
||||
if propertyTypePicker.exists {
|
||||
propertyTypePicker.tap()
|
||||
sleep(1)
|
||||
// Select Condo
|
||||
let condoOption = app.buttons["Condo"]
|
||||
if condoOption.exists {
|
||||
condoOption.tap()
|
||||
sleep(1)
|
||||
} else {
|
||||
// Try cells navigation
|
||||
let cells = app.cells
|
||||
for i in 0..<cells.count {
|
||||
let cell = cells.element(boundBy: i)
|
||||
if cell.staticTexts["Condo"].exists {
|
||||
cell.tap()
|
||||
sleep(1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to address fields
|
||||
app.swipeUp()
|
||||
sleep(1)
|
||||
|
||||
// Update street
|
||||
let streetField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Street'")).firstMatch
|
||||
if streetField.exists {
|
||||
streetField.tap()
|
||||
streetField.doubleTap()
|
||||
sleep(1)
|
||||
if app.buttons["Select All"].exists {
|
||||
app.buttons["Select All"].tap()
|
||||
sleep(1)
|
||||
}
|
||||
streetField.typeText(newStreet)
|
||||
}
|
||||
|
||||
// Update city
|
||||
let cityField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'City'")).firstMatch
|
||||
if cityField.exists {
|
||||
cityField.tap()
|
||||
cityField.doubleTap()
|
||||
sleep(1)
|
||||
if app.buttons["Select All"].exists {
|
||||
app.buttons["Select All"].tap()
|
||||
sleep(1)
|
||||
}
|
||||
cityField.typeText(newCity)
|
||||
}
|
||||
|
||||
// Update state
|
||||
let stateField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'State'")).firstMatch
|
||||
if stateField.exists {
|
||||
stateField.tap()
|
||||
stateField.doubleTap()
|
||||
sleep(1)
|
||||
if app.buttons["Select All"].exists {
|
||||
app.buttons["Select All"].tap()
|
||||
sleep(1)
|
||||
}
|
||||
stateField.typeText(newState)
|
||||
}
|
||||
|
||||
// Update postal code
|
||||
let postalField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Postal' OR placeholderValue CONTAINS[c] 'Zip'")).firstMatch
|
||||
if postalField.exists {
|
||||
postalField.tap()
|
||||
postalField.doubleTap()
|
||||
sleep(1)
|
||||
if app.buttons["Select All"].exists {
|
||||
app.buttons["Select All"].tap()
|
||||
sleep(1)
|
||||
}
|
||||
postalField.typeText(newPostal)
|
||||
}
|
||||
|
||||
// Scroll to save button
|
||||
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()
|
||||
sleep(4)
|
||||
|
||||
// Track new name
|
||||
createdResidenceNames.append(newName)
|
||||
|
||||
// Verify updated residence appears in list with new name
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
let updatedResidence = findResidence(name: newName)
|
||||
XCTAssertTrue(updatedResidence.exists, "Residence should show updated name in list")
|
||||
|
||||
// Tap on residence to verify details were updated
|
||||
updatedResidence.tap()
|
||||
sleep(2)
|
||||
|
||||
// Verify updated address appears in detail view
|
||||
let streetText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(newStreet)'")).firstMatch
|
||||
XCTAssertTrue(streetText.exists || true, "Updated street should be visible in detail view")
|
||||
|
||||
let cityText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(newCity)'")).firstMatch
|
||||
XCTAssertTrue(cityText.exists || true, "Updated city should be visible in detail view")
|
||||
|
||||
let postalText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(newPostal)'")).firstMatch
|
||||
XCTAssertTrue(postalText.exists || true, "Updated postal code should be visible in detail view")
|
||||
|
||||
// Verify property type was updated to Condo
|
||||
let condoBadge = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'Condo'")).firstMatch
|
||||
XCTAssertTrue(condoBadge.exists || true, "Updated property type should be visible (if shown in detail)")
|
||||
}
|
||||
|
||||
// MARK: - Validation & Error Handling Tests
|
||||
|
||||
func testCannotCreateResidenceWithEmptyName() {
|
||||
guard openResidenceForm() else {
|
||||
XCTFail("Failed to open residence form")
|
||||
return
|
||||
}
|
||||
|
||||
// Leave name empty, fill only address
|
||||
app.swipeUp()
|
||||
sleep(1)
|
||||
fillTextField(placeholder: "Street", text: "123 Test St")
|
||||
fillTextField(placeholder: "City", text: "TestCity")
|
||||
fillTextField(placeholder: "State", text: "TS")
|
||||
fillTextField(placeholder: "Postal", text: "12345")
|
||||
|
||||
// Scroll to save button if needed
|
||||
app.swipeUp()
|
||||
sleep(1)
|
||||
|
||||
// Save button should be disabled when name is empty
|
||||
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
|
||||
XCTAssertTrue(saveButton.exists, "Save button should exist")
|
||||
XCTAssertFalse(saveButton.isEnabled, "Save button should be disabled when name is empty")
|
||||
}
|
||||
|
||||
func testCancelResidenceCreation() {
|
||||
guard openResidenceForm() else {
|
||||
XCTFail("Failed to open residence form")
|
||||
return
|
||||
}
|
||||
|
||||
// Fill some data
|
||||
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
||||
nameField.tap()
|
||||
nameField.typeText("This will be canceled")
|
||||
|
||||
// Tap cancel
|
||||
let cancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Cancel'")).firstMatch
|
||||
XCTAssertTrue(cancelButton.exists, "Cancel button should exist")
|
||||
cancelButton.tap()
|
||||
sleep(2)
|
||||
|
||||
// Should be back on residences list
|
||||
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
||||
XCTAssertTrue(residencesTab.exists, "Should be back on residences list")
|
||||
|
||||
// Residence should not exist
|
||||
let residence = findResidence(name: "This will be canceled")
|
||||
XCTAssertFalse(residence.exists, "Canceled residence should not exist")
|
||||
}
|
||||
|
||||
// MARK: - Edge Case Tests
|
||||
|
||||
func testCreateResidenceWithVeryLongName() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let longName = "This is an extremely long residence name that goes on and on and on to test how the system handles very long text input in the name field \(timestamp)"
|
||||
|
||||
let success = createResidence(name: longName)
|
||||
XCTAssertTrue(success, "Should handle very long names")
|
||||
|
||||
// Verify it appears (may be truncated in display)
|
||||
let residence = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'extremely long residence'")).firstMatch
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 10), "Long name residence should exist")
|
||||
}
|
||||
|
||||
func testCreateResidenceWithSpecialCharacters() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let specialName = "Special !@#$%^&*() Home \(timestamp)"
|
||||
|
||||
let success = createResidence(name: specialName)
|
||||
XCTAssertTrue(success, "Should handle special characters")
|
||||
|
||||
let residence = findResidence(name: "Special")
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 10), "Residence with special chars should exist")
|
||||
}
|
||||
|
||||
func testCreateResidenceWithEmojis() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let emojiName = "Beach House 🏖️🌊 \(timestamp)"
|
||||
|
||||
let success = createResidence(name: emojiName)
|
||||
XCTAssertTrue(success, "Should handle emojis")
|
||||
|
||||
let residence = findResidence(name: "Beach House")
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 10), "Residence with emojis should exist")
|
||||
}
|
||||
|
||||
func testCreateResidenceWithInternationalCharacters() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let internationalName = "Château Montréal \(timestamp)"
|
||||
|
||||
let success = createResidence(name: internationalName)
|
||||
XCTAssertTrue(success, "Should handle international characters")
|
||||
|
||||
let residence = findResidence(name: "Château")
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 10), "Residence with international chars should exist")
|
||||
}
|
||||
|
||||
func testCreateResidenceWithVeryLongAddress() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let residenceName = "Long Address Home \(timestamp)"
|
||||
|
||||
let success = createResidence(
|
||||
name: residenceName,
|
||||
street: "123456789 Very Long Street Name That Goes On And On Boulevard Apartment Complex Unit 42B",
|
||||
city: "VeryLongCityNameThatTestsTheLimit",
|
||||
state: "CA",
|
||||
postal: "12345-6789"
|
||||
)
|
||||
XCTAssertTrue(success, "Should handle very long addresses")
|
||||
|
||||
let residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.waitForExistence(timeout: 10), "Residence with long address should exist")
|
||||
}
|
||||
|
||||
// MARK: - Navigation & List Tests
|
||||
|
||||
func testNavigateFromResidencesToOtherTabs() {
|
||||
// From Residences tab
|
||||
navigateToResidencesTab()
|
||||
|
||||
// Navigate to Tasks
|
||||
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
|
||||
XCTAssertTrue(tasksTab.exists, "Tasks tab should exist")
|
||||
tasksTab.tap()
|
||||
sleep(1)
|
||||
XCTAssertTrue(tasksTab.isSelected, "Should be on Tasks tab")
|
||||
|
||||
// Navigate back to Residences
|
||||
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
||||
residencesTab.tap()
|
||||
sleep(1)
|
||||
XCTAssertTrue(residencesTab.isSelected, "Should be back on Residences tab")
|
||||
|
||||
// Navigate to Contractors
|
||||
let contractorsTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Contractors'")).firstMatch
|
||||
XCTAssertTrue(contractorsTab.exists, "Contractors tab should exist")
|
||||
contractorsTab.tap()
|
||||
sleep(1)
|
||||
XCTAssertTrue(contractorsTab.isSelected, "Should be on Contractors tab")
|
||||
|
||||
// Back to Residences
|
||||
residencesTab.tap()
|
||||
sleep(1)
|
||||
XCTAssertTrue(residencesTab.isSelected, "Should be back on Residences tab again")
|
||||
}
|
||||
|
||||
func testRefreshResidencesList() {
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Pull to refresh (if implemented) or use refresh button
|
||||
let refreshButton = app.navigationBars.buttons.containing(NSPredicate(format: "label CONTAINS 'arrow.clockwise' OR label CONTAINS 'refresh'")).firstMatch
|
||||
if refreshButton.exists {
|
||||
refreshButton.tap()
|
||||
sleep(3)
|
||||
}
|
||||
|
||||
// Verify we're still on residences tab
|
||||
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
||||
XCTAssertTrue(residencesTab.isSelected, "Should still be on Residences tab after refresh")
|
||||
}
|
||||
|
||||
func testViewResidenceDetails() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let residenceName = "Detail View Test \(timestamp)"
|
||||
|
||||
// Create residence
|
||||
guard createResidence(name: residenceName) else {
|
||||
XCTFail("Failed to create residence")
|
||||
return
|
||||
}
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Tap on residence
|
||||
let residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.exists, "Residence should exist")
|
||||
residence.tap()
|
||||
sleep(3)
|
||||
|
||||
// Verify detail view appears with edit button or tasks section
|
||||
let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch
|
||||
let tasksSection = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks' OR label CONTAINS[c] 'Maintenance'")).firstMatch
|
||||
|
||||
XCTAssertTrue(editButton.exists || tasksSection.exists, "Detail view should show with edit button or tasks section")
|
||||
}
|
||||
|
||||
// MARK: - Data Persistence Tests
|
||||
|
||||
func testResidencePersistsAfterBackgroundingApp() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
let residenceName = "Persistence Test \(timestamp)"
|
||||
|
||||
// Create residence
|
||||
guard createResidence(name: residenceName) else {
|
||||
XCTFail("Failed to create residence")
|
||||
return
|
||||
}
|
||||
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Verify residence exists
|
||||
var residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.exists, "Residence should exist before backgrounding")
|
||||
|
||||
// Background and reactivate app
|
||||
XCUIDevice.shared.press(.home)
|
||||
sleep(2)
|
||||
app.activate()
|
||||
sleep(3)
|
||||
|
||||
// Navigate back to residences
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
|
||||
// Verify residence still exists
|
||||
residence = findResidence(name: residenceName)
|
||||
XCTAssertTrue(residence.exists, "Residence should persist after backgrounding app")
|
||||
}
|
||||
|
||||
// MARK: - Performance Tests
|
||||
|
||||
func testResidenceListPerformance() {
|
||||
measure(metrics: [XCTClockMetric(), XCTMemoryMetric()]) {
|
||||
navigateToResidencesTab()
|
||||
sleep(2)
|
||||
}
|
||||
}
|
||||
|
||||
func testResidenceCreationPerformance() {
|
||||
let timestamp = Int(Date().timeIntervalSince1970)
|
||||
|
||||
measure(metrics: [XCTClockMetric()]) {
|
||||
let residenceName = "Performance Test \(timestamp)_\(UUID().uuidString.prefix(8))"
|
||||
_ = createResidence(name: residenceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user