Files
honeyDueKMP/iosApp/CaseraUITests/TaskTests.swift
Trey t c6eef720ed 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>
2025-11-28 21:10:38 -06:00

362 lines
15 KiB
Swift

import XCTest
/// Task management tests
/// Uses UITestHelpers for consistent login/logout behavior
/// IMPORTANT: Tasks require at least one residence to exist
final class TaskTests: XCTestCase {
var app: XCUIApplication!
override func setUpWithError() throws {
continueAfterFailure = false
app = XCUIApplication()
app.launch()
// Ensure user is logged in
UITestHelpers.ensureLoggedIn(app: app)
// CRITICAL: Ensure at least one residence exists
// Tasks are disabled if no residences exist
ensureResidenceExists()
// Now navigate to Tasks tab
navigateToTasksTab()
}
override func tearDownWithError() throws {
app = nil
}
// MARK: - Helper Methods
/// Ensures at least one residence exists (required for tasks to work)
private func ensureResidenceExists() {
// Navigate to Residences tab
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
if residencesTab.waitForExistence(timeout: 5) {
residencesTab.tap()
sleep(2)
// Check if we have any residences
// Look for the add button - if we see "Add a property" text or empty state, create one
let emptyStateText = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'No properties' OR label CONTAINS[c] 'No residences'")).firstMatch
if emptyStateText.exists {
// No residences exist, create a quick one
let addButton = app.buttons[AccessibilityIdentifiers.Residence.addButton]
if addButton.waitForExistence(timeout: 5) {
addButton.tap()
sleep(2)
// Fill minimal required fields
let nameField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Name'")).firstMatch
if nameField.waitForExistence(timeout: 5) {
nameField.tap()
nameField.typeText("Test Home for Tasks")
// Scroll to address fields
app.swipeUp()
sleep(1)
// Fill required address fields
let streetField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Street'")).firstMatch
if streetField.exists {
streetField.tap()
streetField.typeText("123 Test St")
}
let cityField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'City'")).firstMatch
if cityField.exists {
cityField.tap()
cityField.typeText("TestCity")
}
let stateField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'State'")).firstMatch
if stateField.exists {
stateField.tap()
stateField.typeText("TS")
}
let postalField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Postal' OR placeholderValue CONTAINS[c] 'Zip'")).firstMatch
if postalField.exists {
postalField.tap()
postalField.typeText("12345")
}
// Save
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
if saveButton.exists {
saveButton.tap()
sleep(3) // Wait for save to complete
}
}
}
}
}
}
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) // Give it time to load
}
}
}
/// Finds the Add Task button using multiple strategies
/// The button exists in two places:
/// 1. Toolbar (always visible when residences exist)
/// 2. Empty state (visible when no tasks exist)
private func findAddTaskButton() -> XCUIElement {
sleep(2) // Wait for screen to fully render
// Strategy 1: Try accessibility identifier
let addButtonById = app.buttons[AccessibilityIdentifiers.Task.addButton].firstMatch
if addButtonById.exists && addButtonById.isEnabled {
return addButtonById
}
// Strategy 2: Look for toolbar add button (navigation bar plus button)
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
}
}
}
// Strategy 3: Try finding "Add Task" button in empty state by text
let emptyStateButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Add Task'")).firstMatch
if emptyStateButton.exists && emptyStateButton.isEnabled {
return emptyStateButton
}
// Strategy 4: Look for any enabled button with a plus icon
let allButtons = app.buttons
for i in 0..<min(allButtons.count, 20) { // Check first 20 buttons
let button = allButtons.element(boundBy: i)
if button.isEnabled && (button.label.contains("plus") || button.label.contains("Add")) {
return button
}
}
// Return the identifier one as fallback (will fail assertion if doesn't exist)
return addButtonById
}
// MARK: - Tests
func testTasksTabExists() {
// Given: User is logged in
// When: User looks for Tasks tab
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
// Then: Tasks tab should exist
XCTAssertTrue(tasksTab.exists, "Tasks tab should exist in main tab bar")
XCTAssertTrue(tasksTab.isSelected, "Tasks tab should be selected after navigation")
}
func testViewTasksList() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(3)
// Then: Tasks screen should be visible
// Verify we're on the right screen by checking for the navigation title
let tasksTitle = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'All Tasks' OR label CONTAINS[c] 'Tasks'")).firstMatch
XCTAssertTrue(tasksTitle.waitForExistence(timeout: 5), "Tasks screen title should be visible")
}
func testAddTaskButtonExists() {
// Given: User is on Tasks tab with at least one residence
navigateToTasksTab()
sleep(3)
// Then: Add task button should exist and be enabled
let addButton = findAddTaskButton()
XCTAssertTrue(addButton.exists, "Add task button should exist on Tasks screen")
XCTAssertTrue(addButton.isEnabled, "Add task button should be enabled when residence exists")
}
func testNavigateToAddTask() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(3)
// When: User taps add task button
let addButton = findAddTaskButton()
XCTAssertTrue(addButton.exists, "Add task button should exist")
XCTAssertTrue(addButton.isEnabled, "Add task button should be enabled")
addButton.tap()
sleep(3)
// Then: Should show add task form with required fields
let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title' OR placeholderValue CONTAINS[c] 'Task'")).firstMatch
XCTAssertTrue(titleField.waitForExistence(timeout: 5), "Task title field should appear in add form")
let saveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Save'")).firstMatch
XCTAssertTrue(saveButton.exists, "Save button should exist in add task form")
}
func testCancelTaskCreation() {
// Given: User is on add task form
navigateToTasksTab()
sleep(3)
let addButton = findAddTaskButton()
XCTAssertTrue(addButton.exists && addButton.isEnabled, "Add task button should exist and be enabled")
addButton.tap()
sleep(3)
// Verify form opened
let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch
XCTAssertTrue(titleField.waitForExistence(timeout: 5), "Task form should open")
// When: User taps cancel
let cancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Cancel'")).firstMatch
XCTAssertTrue(cancelButton.exists, "Cancel button should exist in task form")
cancelButton.tap()
sleep(2)
// Then: Should return to tasks list
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
XCTAssertTrue(tasksTab.exists, "Should be back on tasks list after cancel")
}
func testCreateBasicTask() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(3)
// When: User taps add task button
let addButton = findAddTaskButton()
XCTAssertTrue(addButton.exists && addButton.isEnabled, "Add task button should exist and be enabled")
addButton.tap()
sleep(3)
// Verify task form loaded
let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Title'")).firstMatch
XCTAssertTrue(titleField.waitForExistence(timeout: 5), "Task title field should appear")
// Fill in task title with unique timestamp
let timestamp = Int(Date().timeIntervalSince1970)
let taskTitle = "UITest Task \(timestamp)"
titleField.tap()
titleField.typeText(taskTitle)
// Scroll down to find and fill description
app.swipeUp()
sleep(1)
let descField = app.textViews.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'Description'")).firstMatch
if descField.exists {
descField.tap()
descField.typeText("Test task")
}
// Scroll to find Save button
app.swipeUp()
sleep(1)
// When: User taps 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 tasks list
sleep(5) // Wait for API call to complete
// Verify we're back on tasks list by checking tab exists
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
XCTAssertTrue(tasksTab.exists, "Should be back on tasks list after saving")
// Verify task appears in the list (may be in kanban columns)
let newTask = app.staticTexts.containing(NSPredicate(format: "label CONTAINS '\(taskTitle)'")).firstMatch
XCTAssertTrue(newTask.waitForExistence(timeout: 10), "New task '\(taskTitle)' should appear in the list")
}
func testViewTaskDetails() {
// Given: User is on Tasks tab and at least one task exists
navigateToTasksTab()
sleep(3)
// Look for any task in the list
let taskCard = app.staticTexts.containing(NSPredicate(format: "label CONTAINS 'UITest Task' OR label CONTAINS 'Test'")).firstMatch
if !taskCard.waitForExistence(timeout: 5) {
// No task found - skip this test
print("⚠️ No tasks found - run testCreateBasicTask first")
return
}
// When: User taps on a task
taskCard.tap()
sleep(2)
// Then: Should show task details screen
let editButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Edit'")).firstMatch
let completeButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Complete' OR label CONTAINS[c] 'Mark'")).firstMatch
let backButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Back' OR label CONTAINS[c] 'Tasks'")).firstMatch
let detailScreenVisible = editButton.exists || completeButton.exists || backButton.exists
XCTAssertTrue(detailScreenVisible, "Task details screen should show with action buttons")
}
func testNavigateToContractors() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(1)
// When: User taps Contractors tab
let contractorsTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Contractors'")).firstMatch
XCTAssertTrue(contractorsTab.waitForExistence(timeout: 5), "Contractors tab should exist")
contractorsTab.tap()
sleep(1)
// Then: Should be on Contractors tab
XCTAssertTrue(contractorsTab.isSelected, "Contractors tab should be selected")
}
func testNavigateToDocuments() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(1)
// When: User taps Documents tab
let documentsTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Documents'")).firstMatch
XCTAssertTrue(documentsTab.waitForExistence(timeout: 5), "Documents tab should exist")
documentsTab.tap()
sleep(1)
// Then: Should be on Documents tab
XCTAssertTrue(documentsTab.isSelected, "Documents tab should be selected")
}
func testNavigateBetweenTabs() {
// Given: User is on Tasks tab
navigateToTasksTab()
sleep(1)
// When: User navigates to Residences tab
let residencesTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Residences'")).firstMatch
XCTAssertTrue(residencesTab.exists, "Residences tab should exist")
residencesTab.tap()
sleep(1)
// Then: Should be on Residences tab
XCTAssertTrue(residencesTab.isSelected, "Should be on Residences tab")
// When: User navigates back to Tasks
let tasksTab = app.tabBars.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Tasks'")).firstMatch
tasksTab.tap()
sleep(2)
// Then: Should be back on Tasks tab
XCTAssertTrue(tasksTab.isSelected, "Should be back on Tasks tab")
}
}