- Add Suite0_OnboardingTests with fresh install and login test flows - Add accessibility identifiers to onboarding views for UI testing - Remove deprecated DataCache in favor of unified DataManager - Update API layer to support public upgrade-triggers endpoint - Improve onboarding first task view with better date handling - Update various views with accessibility identifiers for testing - Fix subscription feature comparison view layout - Update document detail view improvements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
240 lines
10 KiB
Swift
240 lines
10 KiB
Swift
import XCTest
|
|
|
|
/// Residence management tests
|
|
/// Based on working SimpleLoginTest pattern
|
|
///
|
|
/// Test Order (logical dependencies):
|
|
/// 1. View/UI tests (work with empty list)
|
|
/// 2. Navigation tests (don't create data)
|
|
/// 3. Cancel test (opens form but doesn't save)
|
|
/// 4. Creation tests (creates data)
|
|
/// 5. Tests that depend on created data (view details)
|
|
final class Suite3_ResidenceTests: XCTestCase {
|
|
var app: XCUIApplication!
|
|
|
|
override func setUpWithError() throws {
|
|
continueAfterFailure = false
|
|
app = XCUIApplication()
|
|
app.launch()
|
|
ensureLoggedIn()
|
|
}
|
|
|
|
override func tearDownWithError() throws {
|
|
app = nil
|
|
}
|
|
|
|
// MARK: - Helper Methods
|
|
|
|
private func ensureLoggedIn() {
|
|
UITestHelpers.ensureLoggedIn(app: app)
|
|
|
|
// Navigate to Residences tab
|
|
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
|
if residencesTab.exists {
|
|
residencesTab.tap()
|
|
sleep(1)
|
|
}
|
|
}
|
|
|
|
private func navigateToResidencesTab() {
|
|
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
|
if !residencesTab.isSelected {
|
|
residencesTab.tap()
|
|
sleep(1)
|
|
}
|
|
}
|
|
|
|
// MARK: - 1. View/UI Tests (work with empty list)
|
|
|
|
func test01_viewResidencesList() {
|
|
// Given: User is logged in and on Residences tab
|
|
navigateToResidencesTab()
|
|
|
|
// Then: Should see residences list header (must exist even if empty)
|
|
let residencesHeader = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Your Properties' OR label CONTAINS[c] 'My Properties' OR label CONTAINS[c] 'Residences'")).firstMatch
|
|
XCTAssertTrue(residencesHeader.waitForExistence(timeout: 5), "Residences list screen must be visible")
|
|
|
|
// Add button must exist
|
|
let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton]
|
|
XCTAssertTrue(addButton.exists, "Add residence button must exist")
|
|
}
|
|
|
|
// MARK: - 2. Navigation Tests (don't create data)
|
|
|
|
func test02_navigateToAddResidence() {
|
|
// Given: User is on Residences tab
|
|
navigateToResidencesTab()
|
|
|
|
// When: User taps add residence button (using accessibility identifier to avoid wrong button)
|
|
let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton]
|
|
XCTAssertTrue(addButton.waitForExistence(timeout: 5), "Add residence button should exist")
|
|
addButton.tap()
|
|
|
|
// Then: Should show add residence form with all required fields
|
|
sleep(2)
|
|
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Property Name' OR placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
|
XCTAssertTrue(nameField.exists, "Name field should exist in residence form")
|
|
|
|
// Verify property type picker exists
|
|
let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch
|
|
XCTAssertTrue(propertyTypePicker.exists, "Property type picker should exist in residence form")
|
|
|
|
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
|
|
XCTAssertTrue(saveButton.exists, "Save button should exist in residence form")
|
|
}
|
|
|
|
func test03_navigationBetweenTabs() {
|
|
// Given: User is on Residences tab
|
|
navigateToResidencesTab()
|
|
|
|
// When: User navigates to Tasks tab
|
|
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
|
|
XCTAssertTrue(tasksTab.exists, "Tasks tab should exist")
|
|
tasksTab.tap()
|
|
sleep(1)
|
|
|
|
// Then: Should be on Tasks tab
|
|
XCTAssertTrue(tasksTab.isSelected, "Should be on Tasks tab")
|
|
|
|
// When: User navigates back to Residences
|
|
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
|
residencesTab.tap()
|
|
sleep(1)
|
|
|
|
// Then: Should be back on Residences tab
|
|
XCTAssertTrue(residencesTab.isSelected, "Should be back on Residences tab")
|
|
}
|
|
|
|
// MARK: - 3. Cancel Test (opens form but doesn't save)
|
|
|
|
func test04_cancelResidenceCreation() {
|
|
// Given: User is on add residence form
|
|
navigateToResidencesTab()
|
|
|
|
let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton]
|
|
addButton.tap()
|
|
sleep(2)
|
|
|
|
// When: User taps cancel
|
|
let cancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Cancel'")).firstMatch
|
|
XCTAssertTrue(cancelButton.waitForExistence(timeout: 5), "Cancel button should exist")
|
|
cancelButton.tap()
|
|
|
|
// Then: Should return to residences list
|
|
sleep(1)
|
|
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
|
|
XCTAssertTrue(residencesTab.exists, "Should be back on residences list")
|
|
}
|
|
|
|
// MARK: - 4. Creation Tests
|
|
|
|
func test05_createResidenceWithMinimalData() {
|
|
// Given: User is on add residence form
|
|
navigateToResidencesTab()
|
|
|
|
// Use accessibility identifier to get the correct add button
|
|
let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton]
|
|
XCTAssertTrue(addButton.exists, "Add residence button should exist")
|
|
addButton.tap()
|
|
sleep(2)
|
|
|
|
// When: Verify form loaded correctly
|
|
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Property Name' OR placeholderValue CONTAINS[c] 'Name'")).firstMatch
|
|
XCTAssertTrue(nameField.waitForExistence(timeout: 5), "Name field should appear - form did not load correctly!")
|
|
|
|
// Fill name field
|
|
let timestamp = Int(Date().timeIntervalSince1970)
|
|
let residenceName = "UITest Home \(timestamp)"
|
|
nameField.tap()
|
|
nameField.typeText(residenceName)
|
|
|
|
// Select property type (required field)
|
|
let propertyTypePicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Property Type'")).firstMatch
|
|
if propertyTypePicker.exists {
|
|
propertyTypePicker.tap()
|
|
sleep(2)
|
|
|
|
// After tapping picker, look for any selectable option
|
|
// Try common property types as buttons
|
|
if app.buttons["House"].exists {
|
|
app.buttons["House"].tap()
|
|
} else if app.buttons["Apartment"].exists {
|
|
app.buttons["Apartment"].tap()
|
|
} else if app.buttons["Condo"].exists {
|
|
app.buttons["Condo"].tap()
|
|
} else {
|
|
// If navigation style, try cells
|
|
let cells = app.cells
|
|
if cells.count > 1 {
|
|
cells.element(boundBy: 1).tap() // Skip first which might be "Select Type"
|
|
}
|
|
}
|
|
sleep(1)
|
|
}
|
|
|
|
// Fill address fields - MUST exist for residence
|
|
let streetField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Street'")).firstMatch
|
|
XCTAssertTrue(streetField.exists, "Street field should exist in residence form")
|
|
streetField.tap()
|
|
streetField.typeText("123 Test St")
|
|
|
|
let cityField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'City'")).firstMatch
|
|
XCTAssertTrue(cityField.exists, "City field should exist in residence form")
|
|
cityField.tap()
|
|
cityField.typeText("TestCity")
|
|
|
|
let stateField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'State'")).firstMatch
|
|
XCTAssertTrue(stateField.exists, "State field should exist in residence form")
|
|
stateField.tap()
|
|
stateField.typeText("TS")
|
|
|
|
let postalField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Postal' OR placeholderValue CONTAINS[c] 'Postal'")).firstMatch
|
|
XCTAssertTrue(postalField.exists, "Postal code field should exist in residence form")
|
|
postalField.tap()
|
|
postalField.typeText("12345")
|
|
|
|
// Scroll down to see more fields
|
|
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()
|
|
|
|
// Then: Should return to residences list and verify residence was created
|
|
sleep(3) // Wait for save to complete
|
|
|
|
// First check we're back on the list
|
|
let residencesList = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'Your Properties' OR label CONTAINS 'My Properties'")).firstMatch
|
|
XCTAssertTrue(residencesList.waitForExistence(timeout: 10), "Should return to residences list after saving")
|
|
|
|
// CRITICAL: Verify the residence actually appears in the list
|
|
let newResidence = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(residenceName)'")).firstMatch
|
|
XCTAssertTrue(newResidence.waitForExistence(timeout: 10), "New residence '\(residenceName)' should appear in the list - network call may have failed!")
|
|
}
|
|
|
|
// MARK: - 5. Tests That Depend on Created Data
|
|
|
|
func test06_viewResidenceDetails() {
|
|
// Given: User is on Residences tab with at least one residence
|
|
// This test requires testCreateResidenceWithMinimalData to have run first
|
|
navigateToResidencesTab()
|
|
sleep(2)
|
|
|
|
// Find a residence card by looking for UITest Home text
|
|
let residenceCard = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'UITest Home' OR label CONTAINS 'Test'")).firstMatch
|
|
XCTAssertTrue(residenceCard.waitForExistence(timeout: 5), "At least one residence must exist - run testCreateResidenceWithMinimalData first")
|
|
|
|
// When: User taps on the residence
|
|
residenceCard.tap()
|
|
sleep(2)
|
|
|
|
// Then: Should show residence details screen with edit/delete buttons
|
|
let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch
|
|
let deleteButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Delete'")).firstMatch
|
|
|
|
XCTAssertTrue(editButton.exists || deleteButton.exists, "Residence details screen must show with edit or delete button")
|
|
}
|
|
}
|