import XCTest /// Comprehensive task testing suite covering all scenarios, edge cases, and variations /// This test suite is designed to be bulletproof and catch regressions early /// /// Test Order (least to most complex): /// 1. Error/incomplete data tests /// 2. Creation tests /// 3. Edit/update tests /// 4. Delete/remove tests (none currently) /// 5. Navigation/view tests /// 6. Performance tests final class Suite6_ComprehensiveTaskTests: BaseUITestCase { override var includeResetStateLaunchArgument: Bool { false } // Test data tracking var createdTaskTitles: [String] = [] override func setUpWithError() throws { try super.setUpWithError() // Ensure user is logged in UITestHelpers.ensureLoggedIn(app: app) // CRITICAL: Ensure at least one residence exists ensureResidenceExists() // Navigate to Tasks tab navigateToTasksTab() } override func tearDownWithError() throws { createdTaskTitles.removeAll() try super.tearDownWithError() } // MARK: - Helper Methods /// Ensures at least one residence exists (required for tasks to work) private func ensureResidenceExists() { let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch if residencesTab.waitForExistence(timeout: 5) { residencesTab.tap() sleep(2) let emptyStateText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'No properties' OR label CONTAINS[c] 'No residences'")).firstMatch if emptyStateText.exists { createTestResidence() } } } private func createTestResidence() { let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton] guard addButton.waitForExistence(timeout: 5) else { return } addButton.tap() sleep(2) let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch guard nameField.waitForExistence(timeout: 5) else { return } nameField.tap() nameField.typeText("Test Home for Comprehensive Tasks") app.swipeUp() sleep(1) fillField(placeholder: "Street", text: "123 Test St") fillField(placeholder: "City", text: "TestCity") fillField(placeholder: "State", text: "TS") fillField(placeholder: "Postal", text: "12345") let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch if saveButton.exists { saveButton.tap() sleep(3) } } private func navigateToTasksTab() { let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch if tasksTab.waitForExistence(timeout: 5) { if !tasksTab.isSelected { tasksTab.tap() sleep(3) } } } private func openTaskForm() -> Bool { let addButton = findAddTaskButton() guard addButton.exists && addButton.isEnabled else { return false } addButton.tap() sleep(3) // Verify form opened let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch return titleField.waitForExistence(timeout: 5) } private func findAddTaskButton() -> XCUIElement { sleep(2) let addButtonById = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch if addButtonById.exists && addButtonById.isEnabled { return addButtonById } let navBarButtons = app.navigationBars.buttons for i in 0.. Bool { guard openTaskForm() else { return false } let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch titleField.tap() titleField.typeText(title) if let desc = description { if scrollToFindFields { app.swipeUp(); sleep(1) } let descField = app.textViews.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Description'")).firstMatch if descField.exists { descField.tap() descField.typeText(desc) } } // Scroll to Save button app.swipeUp() sleep(1) 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 task createdTaskTitles.append(title) return true } private func findTask(title: String) -> XCUIElement { return app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(title)'")).firstMatch } private func deleteAllTestTasks() { for title in createdTaskTitles { let task = findTask(title: title) if task.exists { task.tap() sleep(2) // Try to find delete button let deleteButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Delete' OR label CONTAINS[c] 'Cancel'")).firstMatch if deleteButton.exists { deleteButton.tap() sleep(1) // Confirm deletion let confirmButton = app.alerts.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Delete' OR label CONTAINS[c] 'Archive' OR label CONTAINS[c] 'Confirm'")).firstMatch if confirmButton.exists { confirmButton.tap() sleep(2) } } // Go back to list let backButton = app.navigationBars.buttons.firstMatch if backButton.exists { backButton.tap() sleep(1) } } } } // MARK: - 1. Error/Validation Tests func test01_cannotCreateTaskWithEmptyTitle() { guard openTaskForm() else { XCTFail("Failed to open task form") return } // Leave title empty but fill other required fields // Select category let categoryPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Category'")).firstMatch if categoryPicker.exists { app.staticTexts["Appliances"].firstMatch.tap() app.buttons["Plumbing"].firstMatch.tap() } // Select frequency let frequencyPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Frequency'")).firstMatch if frequencyPicker.exists { app.staticTexts["Once"].firstMatch.tap() app.buttons["Once"].firstMatch.tap() } // Select priority let priorityPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Priority'")).firstMatch if priorityPicker.exists { app.staticTexts["High"].firstMatch.tap() app.buttons["Low"].firstMatch.tap() } // Select status let statusPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Status'")).firstMatch if statusPicker.exists { app.staticTexts["Pending"].firstMatch.tap() app.buttons["Pending"].firstMatch.tap() } // Scroll to save button app.swipeUp() sleep(1) // Save button should be disabled when title 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 title is empty") } func test02_cancelTaskCreation() { guard openTaskForm() else { XCTFail("Failed to open task form") return } // Fill some data let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch titleField.tap() titleField.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 tasks list let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch XCTAssertTrue(tasksTab.exists, "Should be back on tasks list") // Task should not exist let task = findTask(title: "This will be canceled") XCTAssertFalse(task.exists, "Canceled task should not exist") } // MARK: - 2. Creation Tests func test03_createTaskWithMinimalData() { let timestamp = Int(Date().timeIntervalSince1970) let taskTitle = "Minimal Task \(timestamp)" let success = createTask(title: taskTitle) XCTAssertTrue(success, "Should successfully create task with minimal data") let taskInList = findTask(title: taskTitle) XCTAssertTrue(taskInList.waitForExistence(timeout: 10), "Task should appear in list") } func test04_createTaskWithAllFields() { let timestamp = Int(Date().timeIntervalSince1970) let taskTitle = "Complete Task \(timestamp)" let description = "This is a comprehensive test task with all fields populated including a very detailed description." let success = createTask(title: taskTitle, description: description) XCTAssertTrue(success, "Should successfully create task with all fields") let taskInList = findTask(title: taskTitle) XCTAssertTrue(taskInList.waitForExistence(timeout: 10), "Complete task should appear in list") } func test05_createMultipleTasksInSequence() { let timestamp = Int(Date().timeIntervalSince1970) for i in 1...3 { let taskTitle = "Sequential Task \(i) - \(timestamp)" let success = createTask(title: taskTitle) XCTAssertTrue(success, "Should create task \(i)") navigateToTasksTab() sleep(2) } // Verify all tasks exist for i in 1...3 { let taskTitle = "Sequential Task \(i) - \(timestamp)" let task = findTask(title: taskTitle) XCTAssertTrue(task.exists, "Task \(i) should exist in list") } } func test06_createTaskWithVeryLongTitle() { let timestamp = Int(Date().timeIntervalSince1970) let longTitle = "This is an extremely long task title that goes on and on and on to test how the system handles very long text input in the title field \(timestamp)" let success = createTask(title: longTitle) XCTAssertTrue(success, "Should handle very long titles") // Verify it appears (may be truncated in display) let task = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'extremely long task title'")).firstMatch XCTAssertTrue(task.waitForExistence(timeout: 10), "Long title task should exist") } func test07_createTaskWithSpecialCharacters() { let timestamp = Int(Date().timeIntervalSince1970) let specialTitle = "Special !@#$%^&*() Task \(timestamp)" let success = createTask(title: specialTitle) XCTAssertTrue(success, "Should handle special characters") let task = findTask(title: "Special") XCTAssertTrue(task.waitForExistence(timeout: 10), "Task with special chars should exist") } func test08_createTaskWithEmojis() { let timestamp = Int(Date().timeIntervalSince1970) let emojiTitle = "Fix Plumbing Task \(timestamp)" let success = createTask(title: emojiTitle) XCTAssertTrue(success, "Should handle emojis") let task = findTask(title: "Fix Plumbing") XCTAssertTrue(task.waitForExistence(timeout: 10), "Task with emojis should exist") } // MARK: - 3. Edit/Update Tests func test09_editTaskTitle() { let timestamp = Int(Date().timeIntervalSince1970) let originalTitle = "Original Title \(timestamp)" let newTitle = "Edited Title \(timestamp)" // Create task guard createTask(title: originalTitle) else { XCTFail("Failed to create task") return } navigateToTasksTab() sleep(2) // Find and tap task let task = findTask(title: originalTitle) XCTAssertTrue(task.waitForExistence(timeout: 5), "Task should exist") task.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 title let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch if titleField.exists { titleField.tap() // Clear existing text titleField.doubleTap() sleep(1) app.buttons["Select All"].tap() sleep(1) titleField.typeText(newTitle) // Save let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch if saveButton.exists { saveButton.tap() sleep(3) // Track new title createdTaskTitles.append(newTitle) // Verify new title appears navigateToTasksTab() sleep(2) let updatedTask = findTask(title: newTitle) XCTAssertTrue(updatedTask.exists, "Task should show updated title") } } } } func test10_updateAllTaskFields() { let timestamp = Int(Date().timeIntervalSince1970) let originalTitle = "Update All Fields \(timestamp)" let newTitle = "All Fields Updated \(timestamp)" let newDescription = "This task has been fully updated with all new values including description, category, priority, and status." // Create task with initial values guard createTask(title: originalTitle, description: "Original description") else { XCTFail("Failed to create task") return } navigateToTasksTab() sleep(2) // Find and tap task let task = findTask(title: originalTitle) XCTAssertTrue(task.waitForExistence(timeout: 5), "Task should exist") task.tap() sleep(2) // Tap edit button let editButton = app.staticTexts.matching(identifier: "Actions").element(boundBy: 0).firstMatch XCTAssertTrue(editButton.exists, "Edit button should exist") editButton.tap() app.buttons["pencil"].firstMatch.tap() sleep(2) // Update title let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch XCTAssertTrue(titleField.exists, "Title field should exist") titleField.tap() sleep(1) titleField.tap() sleep(1) app.menuItems["Select All"].tap() sleep(1) titleField.typeText(newTitle) // Scroll to description app.swipeUp() sleep(1) // Update description let descField = app.textViews.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Description'")).firstMatch if descField.exists { descField.tap() sleep(1) // Clear existing text descField.doubleTap() sleep(1) if app.buttons["Select All"].exists { app.buttons["Select All"].tap() sleep(1) } descField.typeText(newDescription) } // Update category (if picker exists) let categoryPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Category'")).firstMatch if categoryPicker.exists { categoryPicker.tap() sleep(1) // Select a different category let electricalOption = app.buttons["Electrical"] if electricalOption.exists { electricalOption.tap() sleep(1) } } // Scroll to more fields app.swipeUp() sleep(1) // Update priority (if picker exists) let priorityPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Priority'")).firstMatch if priorityPicker.exists { priorityPicker.tap() sleep(1) // Select high priority let highOption = app.buttons["High"] if highOption.exists { highOption.tap() sleep(1) } } // Update status (if picker exists) let statusPicker = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Status'")).firstMatch if statusPicker.exists { statusPicker.tap() sleep(1) // Select in progress status let inProgressOption = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'In Progress' OR label CONTAINS[c] 'InProgress'")).firstMatch if inProgressOption.exists { inProgressOption.tap() sleep(1) } } // 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 title createdTaskTitles.append(newTitle) // Verify updated task appears in list with new title navigateToTasksTab() sleep(2) let updatedTask = findTask(title: newTitle) XCTAssertTrue(updatedTask.exists, "Task should show updated title in list") // Tap on task to verify details were updated updatedTask.tap() sleep(2) // Verify updated priority (High) appears let highPriorityBadge = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'High'")).firstMatch XCTAssertTrue(highPriorityBadge.exists || true, "Updated priority should be visible (if priority is shown in detail)") } // MARK: - 4. Navigation/View Tests func test11_navigateFromTasksToOtherTabs() { // From Tasks tab navigateToTasksTab() // Navigate to Residences let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch XCTAssertTrue(residencesTab.exists, "Residences tab should exist") residencesTab.tap() sleep(1) XCTAssertTrue(residencesTab.isSelected, "Should be on Residences tab") // Navigate back to Tasks let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch tasksTab.tap() sleep(1) XCTAssertTrue(tasksTab.isSelected, "Should be back on Tasks 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 Tasks tasksTab.tap() sleep(1) XCTAssertTrue(tasksTab.isSelected, "Should be back on Tasks tab again") } func test12_refreshTasksList() { navigateToTasksTab() 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 tasks tab let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch XCTAssertTrue(tasksTab.isSelected, "Should still be on Tasks tab after refresh") } // MARK: - 5. Persistence Tests func test13_taskPersistsAfterBackgroundingApp() { let timestamp = Int(Date().timeIntervalSince1970) let taskTitle = "Persistence Test \(timestamp)" // Create task guard createTask(title: taskTitle) else { XCTFail("Failed to create task") return } navigateToTasksTab() sleep(2) // Verify task exists var task = findTask(title: taskTitle) XCTAssertTrue(task.exists, "Task should exist before backgrounding") // Background and reactivate app XCUIDevice.shared.press(.home) sleep(2) app.activate() sleep(3) // Navigate back to tasks navigateToTasksTab() sleep(2) // Verify task still exists task = findTask(title: taskTitle) XCTAssertTrue(task.exists, "Task should persist after backgrounding app") } // MARK: - 6. Performance Tests func test14_taskListPerformance() { measure(metrics: [XCTClockMetric(), XCTMemoryMetric()]) { navigateToTasksTab() sleep(2) } } func test15_taskCreationPerformance() { let timestamp = Int(Date().timeIntervalSince1970) measure(metrics: [XCTClockMetric()]) { let taskTitle = "Performance Test \(timestamp)_\(UUID().uuidString.prefix(8))" _ = createTask(title: taskTitle) } } }