import XCTest /// Task management tests. /// Precondition: at least one residence must exist (task creation requires it). final class Suite5_TaskTests: AuthenticatedUITestCase { override var needsAPISession: Bool { true } override var testCredentials: (username: String, password: String) { ("testuser", "TestPass123!") } override var apiCredentials: (username: String, password: String) { ("testuser", "TestPass123!") } override func setUpWithError() throws { try super.setUpWithError() // Precondition: residence must exist for task add button ensureResidenceExists() // Dismiss any open form from previous test let cancelButton = app.buttons[AccessibilityIdentifiers.Task.formCancelButton].firstMatch if cancelButton.exists { cancelButton.tap() } navigateToTasks() // Wait for task screen to load let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch addButton.waitForExistenceOrFail(timeout: navigationTimeout, message: "Task add button should appear") } // MARK: - 1. Validation func test01_cancelTaskCreation() { let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch addButton.tap() let titleField = app.textFields[AccessibilityIdentifiers.Task.titleField].firstMatch titleField.waitForExistenceOrFail(timeout: defaultTimeout, message: "Task form should open") let cancelButton = app.buttons[AccessibilityIdentifiers.Task.formCancelButton].firstMatch cancelButton.waitForExistenceOrFail(timeout: defaultTimeout, message: "Cancel button should exist") cancelButton.tap() // Verify we're back on the task list let addButtonAgain = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch XCTAssertTrue(addButtonAgain.waitForExistence(timeout: navigationTimeout), "Should be back on tasks list after cancel") } // MARK: - 2. View/List func test02_tasksTabExists() { let tabBar = app.tabBars.firstMatch XCTAssertTrue(tabBar.exists, "Tab bar should exist") let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch XCTAssertTrue(addButton.exists, "Task add button should exist (proves we're on Tasks tab)") } func test03_viewTasksList() { // Tasks screen should show — verified by the add button existence from setUp let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch XCTAssertTrue(addButton.exists, "Tasks screen should be visible with add button") } func test04_addTaskButtonEnabled() { let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch XCTAssertTrue(addButton.isEnabled, "Task add button should be enabled when residence exists") } func test05_navigateToAddTask() { let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch addButton.tap() let titleField = app.textFields[AccessibilityIdentifiers.Task.titleField].firstMatch titleField.waitForExistenceOrFail(timeout: defaultTimeout, message: "Task title field should appear in add form") let saveButton = app.buttons[AccessibilityIdentifiers.Task.saveButton].firstMatch XCTAssertTrue(saveButton.exists, "Save button should exist in add task form") // Clean up: dismiss form let cancelButton = app.buttons[AccessibilityIdentifiers.Task.formCancelButton].firstMatch if cancelButton.exists { cancelButton.tap() } } // MARK: - 3. Creation func test06_createBasicTask() { let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch addButton.tap() let titleField = app.textFields[AccessibilityIdentifiers.Task.titleField].firstMatch titleField.waitForExistenceOrFail(timeout: defaultTimeout, message: "Task title field should appear") let timestamp = Int(Date().timeIntervalSince1970) let taskTitle = "UITest Task \(timestamp)" fillTextField(identifier: AccessibilityIdentifiers.Task.titleField, text: taskTitle) dismissKeyboard() app.swipeUp() let saveButton = app.buttons[AccessibilityIdentifiers.Task.saveButton].firstMatch saveButton.waitForExistenceOrFail(timeout: defaultTimeout, message: "Save button should exist") saveButton.tap() // Wait for form to dismiss _ = saveButton.waitForNonExistence(timeout: navigationTimeout) // Verify task was created via API (also gives the server time to process) if let items = TestAccountAPIClient.listTasks(token: session.token), let created = items.first(where: { $0.title.contains(taskTitle) }) { cleaner.trackTask(created.id) } // Navigate to tasks tab and refresh to pick up the newly created task navigateToTasks() refreshTasks() let taskListScreen = TaskListScreen(app: app) let newTask = taskListScreen.findTask(title: taskTitle) XCTAssertTrue(newTask.waitForExistence(timeout: loginTimeout), "New task '\(taskTitle)' should appear in the list") } // MARK: - 4. View Details func test07_viewTaskDetails() { // Create a task first let timestamp = Int(Date().timeIntervalSince1970) let taskTitle = "UITest Detail \(timestamp)" let addButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch addButton.tap() fillTextField(identifier: AccessibilityIdentifiers.Task.titleField, text: taskTitle) dismissKeyboard() app.swipeUp() let saveButton = app.buttons[AccessibilityIdentifiers.Task.saveButton].firstMatch saveButton.waitForExistenceOrFail(timeout: defaultTimeout) saveButton.tap() _ = saveButton.waitForNonExistence(timeout: navigationTimeout) // Verify task was created via API (also gives the server time to process) if let items = TestAccountAPIClient.listTasks(token: session.token), let created = items.first(where: { $0.title.contains(taskTitle) }) { cleaner.trackTask(created.id) } // Navigate to tasks tab and refresh to pick up the newly created task navigateToTasks() refreshTasks() let taskListScreen = TaskListScreen(app: app) let taskCard = taskListScreen.findTask(title: taskTitle) taskCard.waitForExistenceOrFail(timeout: loginTimeout, message: "Created task should appear in list") // Verify the task card is accessible and the actions menu exists // (There is no task detail screen — cards are self-contained with a context menu) let actionsMenu = app.buttons["Task actions"].firstMatch XCTAssertTrue(actionsMenu.waitForExistence(timeout: navigationTimeout), "Task actions menu should be accessible") } // MARK: - 5. Navigation func test08_navigateToContractors() { navigateToContractors() let addButton = app.buttons[AccessibilityIdentifiers.Contractor.addButton].firstMatch XCTAssertTrue(addButton.waitForExistence(timeout: navigationTimeout), "Contractors screen should load") } func test09_navigateToDocuments() { navigateToDocuments() let addButton = app.buttons[AccessibilityIdentifiers.Document.addButton].firstMatch XCTAssertTrue(addButton.waitForExistence(timeout: navigationTimeout), "Documents screen should load") } func test10_navigateBetweenTabs() { navigateToResidences() let resAddButton = app.buttons[AccessibilityIdentifiers.Residence.addButton].firstMatch XCTAssertTrue(resAddButton.waitForExistence(timeout: navigationTimeout), "Residences screen should load") navigateToTasks() let taskAddButton = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch XCTAssertTrue(taskAddButton.waitForExistence(timeout: navigationTimeout), "Tasks screen should load after navigating back") } }