432 lines
15 KiB
Swift
432 lines
15 KiB
Swift
import XCTest
|
|
|
|
/// Comprehensive tests for task management
|
|
final class TaskUITests: BaseUITest {
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
// Login before each test
|
|
login(username: "testuser", password: "TestPass123!")
|
|
let residencesTab = app.tabBars.buttons["Residences"]
|
|
XCTAssertTrue(residencesTab.waitForExistence(timeout: 10))
|
|
}
|
|
|
|
// MARK: - Task List Tests
|
|
|
|
func testTasksTabDisplays() {
|
|
// When: User navigates to tasks tab
|
|
navigateToTab("Tasks")
|
|
|
|
// Then: Tasks screen should be displayed
|
|
let navigationBar = app.navigationBars["All Tasks"]
|
|
XCTAssertTrue(navigationBar.waitForExistence(timeout: 5), "Should show tasks navigation bar")
|
|
}
|
|
|
|
func testTaskColumnsDisplay() {
|
|
// Given: User is on tasks tab
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// Then: Task columns should be visible
|
|
let upcomingLabel = app.staticTexts["Upcoming"]
|
|
let inProgressLabel = app.staticTexts["In Progress"]
|
|
let doneLabel = app.staticTexts["Done"]
|
|
|
|
XCTAssertTrue(upcomingLabel.exists || inProgressLabel.exists || doneLabel.exists ||
|
|
app.staticTexts["No tasks yet"].exists,
|
|
"Should show task columns or empty state")
|
|
}
|
|
|
|
func testEmptyTasksState() {
|
|
// Given: User has no tasks (requires account with no tasks)
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// Then: Empty state should be shown
|
|
let emptyState = app.staticTexts["No tasks yet"]
|
|
let addButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Add Task'")).firstMatch
|
|
|
|
// Should show either tasks or empty state
|
|
XCTAssertTrue(emptyState.exists || app.scrollViews.firstMatch.exists,
|
|
"Should show content or empty state")
|
|
}
|
|
|
|
// MARK: - Create Task Tests
|
|
|
|
func testCreateTaskFromTasksTab() {
|
|
// Given: User is on tasks tab
|
|
navigateToTab("Tasks")
|
|
|
|
// When: User taps add task button
|
|
let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch
|
|
if addButton.exists {
|
|
addButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// Then: Add task form should be displayed
|
|
let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'title' OR label CONTAINS[c] 'Title'")).firstMatch
|
|
XCTAssertTrue(titleField.exists, "Should show add task form")
|
|
|
|
// When: User fills in task details
|
|
let timestamp = Int(Date().timeIntervalSince1970)
|
|
titleField.tap()
|
|
titleField.typeText("Test Task \(timestamp)")
|
|
|
|
let descriptionField = app.textViews.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'description' OR label CONTAINS[c] 'Description'")).firstMatch
|
|
if descriptionField.exists {
|
|
descriptionField.tap()
|
|
descriptionField.typeText("Test task description")
|
|
}
|
|
|
|
// When: User saves the task
|
|
let saveButton = app.buttons["Save"]
|
|
if saveButton.exists {
|
|
saveButton.tap()
|
|
}
|
|
|
|
// Then: Task should be created and user returned to tasks list
|
|
wait(seconds: 2)
|
|
XCTAssertTrue(app.navigationBars["All Tasks"].exists || app.staticTexts["Test Task \(timestamp)"].exists,
|
|
"Should create task and return to list")
|
|
}
|
|
}
|
|
|
|
func testCreateTaskFromResidenceDetails() {
|
|
// Given: User is viewing a residence
|
|
navigateToTab("Residences")
|
|
wait(seconds: 2)
|
|
|
|
let firstResidence = app.cells.firstMatch
|
|
if firstResidence.exists {
|
|
firstResidence.tap()
|
|
wait(seconds: 2)
|
|
|
|
// When: User taps add task button
|
|
let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch
|
|
if addButton.exists {
|
|
addButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// Then: Add task form should be displayed
|
|
let titleField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'title' OR label CONTAINS[c] 'Title'")).firstMatch
|
|
XCTAssertTrue(titleField.exists, "Should show add task form from residence")
|
|
|
|
// When: User creates the task
|
|
let timestamp = Int(Date().timeIntervalSince1970)
|
|
titleField.tap()
|
|
titleField.typeText("Residence Task \(timestamp)")
|
|
|
|
let saveButton = app.buttons["Save"]
|
|
if saveButton.exists {
|
|
saveButton.tap()
|
|
}
|
|
|
|
// Then: Task should be created
|
|
wait(seconds: 2)
|
|
XCTAssertTrue(app.staticTexts["Residence Task \(timestamp)"].exists || app.navigationBars.element(boundBy: 1).exists,
|
|
"Should create task for residence")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testCreateTaskValidation() {
|
|
// Given: User is on add task form
|
|
navigateToTab("Tasks")
|
|
let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch
|
|
if addButton.exists {
|
|
addButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// When: User tries to save without required fields
|
|
let saveButton = app.buttons["Save"]
|
|
if saveButton.exists {
|
|
saveButton.tap()
|
|
}
|
|
|
|
// Then: Validation errors should be shown
|
|
let errorMessages = app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'required'"))
|
|
XCTAssertTrue(errorMessages.count > 0 || !app.navigationBars["All Tasks"].exists,
|
|
"Should show validation errors")
|
|
}
|
|
}
|
|
|
|
// MARK: - View Task Details Tests
|
|
|
|
func testViewTaskDetails() {
|
|
// Given: User has tasks
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User taps on a task card
|
|
let taskCard = app.otherElements.containing(NSPredicate(format: "identifier CONTAINS 'TaskCard'")).firstMatch
|
|
if !taskCard.exists {
|
|
// Try finding by task title
|
|
let taskTitle = app.staticTexts.matching(NSPredicate(format: "label CONTAINS[c] 'task'")).firstMatch
|
|
if taskTitle.exists {
|
|
taskTitle.tap()
|
|
}
|
|
} else {
|
|
taskCard.tap()
|
|
}
|
|
|
|
// Note: Depending on implementation, tapping a task might show details or edit form
|
|
wait(seconds: 1)
|
|
// Verify some form of task interaction occurred
|
|
}
|
|
|
|
// MARK: - Edit Task Tests
|
|
|
|
func testEditTaskFlow() {
|
|
// Given: User is viewing/editing a task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// Find and tap edit button on a task
|
|
let editButtons = app.buttons.matching(identifier: "pencil")
|
|
if editButtons.count > 0 {
|
|
editButtons.firstMatch.tap()
|
|
wait(seconds: 1)
|
|
|
|
// When: User modifies task details
|
|
let titleField = app.textFields.containing(NSPredicate(format: "value != nil AND value != ''")).firstMatch
|
|
if titleField.exists {
|
|
app.clearText(in: titleField)
|
|
titleField.typeText("Updated Task Title")
|
|
|
|
// When: User saves changes
|
|
let saveButton = app.buttons["Save"]
|
|
if saveButton.exists {
|
|
saveButton.tap()
|
|
}
|
|
|
|
// Then: Changes should be saved
|
|
wait(seconds: 2)
|
|
let updatedTitle = app.staticTexts["Updated Task Title"]
|
|
XCTAssertTrue(updatedTitle.waitForExistence(timeout: 5) || app.navigationBars["All Tasks"].exists,
|
|
"Should save task changes")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Complete Task Tests
|
|
|
|
func testCompleteTaskFlow() {
|
|
// Given: User has an incomplete task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User taps complete button on a task
|
|
let completeButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Complete'")).firstMatch
|
|
if completeButton.exists {
|
|
completeButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// Then: Complete task dialog should be shown
|
|
let completionDialog = app.sheets.firstMatch
|
|
XCTAssertTrue(completionDialog.exists || app.staticTexts.containing(NSPredicate(format: "label CONTAINS[c] 'Complete'")).firstMatch.exists,
|
|
"Should show completion dialog")
|
|
|
|
// When: User confirms completion
|
|
let confirmButton = app.buttons["Complete"]
|
|
if confirmButton.exists {
|
|
confirmButton.tap()
|
|
}
|
|
|
|
// Then: Task should be marked as complete
|
|
wait(seconds: 2)
|
|
// Task should move to completed column or show completion status
|
|
}
|
|
}
|
|
|
|
func testCompleteTaskWithDetails() {
|
|
// Given: User is completing a task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
let completeButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Complete'")).firstMatch
|
|
if completeButton.exists {
|
|
completeButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// When: User adds completion details
|
|
let notesField = app.textViews.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'notes' OR label CONTAINS[c] 'Notes'")).firstMatch
|
|
if notesField.exists {
|
|
notesField.tap()
|
|
notesField.typeText("Task completed successfully")
|
|
}
|
|
|
|
let costField = app.textFields.containing(NSPredicate(format: "placeholderValue CONTAINS[c] 'cost' OR label CONTAINS[c] 'Cost'")).firstMatch
|
|
if costField.exists {
|
|
costField.tap()
|
|
costField.typeText("100")
|
|
}
|
|
|
|
// When: User saves completion
|
|
let saveButton = app.buttons["Save"]
|
|
if saveButton.exists {
|
|
saveButton.tap()
|
|
}
|
|
|
|
// Then: Task should be completed with details
|
|
wait(seconds: 2)
|
|
}
|
|
}
|
|
|
|
// MARK: - Task Status Changes Tests
|
|
|
|
func testMarkTaskInProgress() {
|
|
// Given: User has a pending task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User marks task as in progress
|
|
let inProgressButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'In Progress'")).firstMatch
|
|
if inProgressButton.exists {
|
|
inProgressButton.tap()
|
|
wait(seconds: 2)
|
|
|
|
// Then: Task should move to In Progress column
|
|
let inProgressColumn = app.staticTexts["In Progress"]
|
|
XCTAssertTrue(inProgressColumn.exists, "Should have In Progress column")
|
|
}
|
|
}
|
|
|
|
func testCancelTask() {
|
|
// Given: User has an active task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User cancels a task
|
|
let cancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Cancel'")).firstMatch
|
|
if cancelButton.exists {
|
|
cancelButton.tap()
|
|
|
|
// Confirm cancellation if prompted
|
|
let confirmButton = app.alerts.buttons["Cancel Task"]
|
|
if confirmButton.exists {
|
|
confirmButton.tap()
|
|
}
|
|
|
|
// Then: Task should be cancelled
|
|
wait(seconds: 2)
|
|
}
|
|
}
|
|
|
|
func testUncancelTask() {
|
|
// Given: User has a cancelled task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User uncancels a task
|
|
let uncancelButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Uncancel' OR label CONTAINS[c] 'Restore'")).firstMatch
|
|
if uncancelButton.exists {
|
|
uncancelButton.tap()
|
|
wait(seconds: 2)
|
|
|
|
// Then: Task should be restored
|
|
}
|
|
}
|
|
|
|
// MARK: - Archive Task Tests
|
|
|
|
func testArchiveTask() {
|
|
// Given: User has a completed task
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// When: User archives a task
|
|
let archiveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Archive'")).firstMatch
|
|
if archiveButton.exists {
|
|
archiveButton.tap()
|
|
wait(seconds: 2)
|
|
|
|
// Then: Task should be archived (moved to archived column or hidden)
|
|
let archivedColumn = app.staticTexts["Archived"]
|
|
// Task may be in archived column or removed from view
|
|
}
|
|
}
|
|
|
|
func testUnarchiveTask() {
|
|
// Given: User has archived tasks
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
// Scroll to archived column if it exists
|
|
let scrollView = app.scrollViews.firstMatch
|
|
if scrollView.exists {
|
|
scrollView.swipeLeft()
|
|
scrollView.swipeLeft()
|
|
}
|
|
|
|
// When: User unarchives a task
|
|
let unarchiveButton = app.buttons.containing(NSPredicate(format: "label CONTAINS[c] 'Unarchive'")).firstMatch
|
|
if unarchiveButton.exists {
|
|
unarchiveButton.tap()
|
|
wait(seconds: 2)
|
|
|
|
// Then: Task should be restored from archive
|
|
}
|
|
}
|
|
|
|
// MARK: - Task Filtering and Viewing Tests
|
|
|
|
func testSwipeBetweenTaskColumns() {
|
|
// Given: User is viewing tasks
|
|
navigateToTab("Tasks")
|
|
wait(seconds: 2)
|
|
|
|
let scrollView = app.scrollViews.firstMatch
|
|
if scrollView.exists {
|
|
// When: User swipes to view different columns
|
|
scrollView.swipeLeft()
|
|
wait(seconds: 0.5)
|
|
|
|
// Then: Next column should be visible
|
|
scrollView.swipeLeft()
|
|
wait(seconds: 0.5)
|
|
|
|
// User can navigate between columns
|
|
scrollView.swipeRight()
|
|
wait(seconds: 0.5)
|
|
}
|
|
}
|
|
|
|
func testTasksByResidence() {
|
|
// Given: User is viewing a residence
|
|
navigateToTab("Residences")
|
|
wait(seconds: 2)
|
|
|
|
let firstResidence = app.cells.firstMatch
|
|
if firstResidence.exists {
|
|
firstResidence.tap()
|
|
wait(seconds: 2)
|
|
|
|
// Then: Tasks for that residence should be shown
|
|
let tasksSection = app.staticTexts["Tasks"]
|
|
XCTAssertTrue(tasksSection.exists || app.scrollViews.firstMatch.exists,
|
|
"Should show tasks section in residence details")
|
|
}
|
|
}
|
|
|
|
// MARK: - Task Recurrence Tests
|
|
|
|
func testCreateRecurringTask() {
|
|
// Given: User is creating a new task
|
|
navigateToTab("Tasks")
|
|
let addButton = app.navigationBars.buttons.matching(identifier: "plus").firstMatch
|
|
|
|
if addButton.exists {
|
|
addButton.tap()
|
|
wait(seconds: 1)
|
|
|
|
// When: User selects recurring frequency
|
|
let frequencyPicker = app.pickers.firstMatch
|
|
if frequencyPicker.exists {
|
|
// Select a frequency (e.g., Monthly)
|
|
let monthlyOption = app.pickerWheels.element.adjust(toPickerWheelValue: "Monthly")
|
|
// Task creation with recurrence
|
|
}
|
|
}
|
|
}
|
|
}
|