Files
lanework/KanbanMobileUITests/BoardsNavigationUITests.swift
T
rzen 871083e5ca The tab bar retires — boards are the app, settings behind the gear, recency the default order
The boards stack becomes the root screen: Settings moves from its own
tab to a sheet behind a leading gearshape button, the sort pickers trade
their text segments for symbols (hand.draw, textformat.abc, clock) with
the words kept for accessibility, and every list now opens sorted by
most recent change. UI tests re-aimed at the gear button and Done-button
scoping fixed for the sheet-over-sheet nav bars — 4/4 green in the
simulator.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
2026-08-08 13:07:44 -04:00

66 lines
3.0 KiB
Swift

import XCTest
/// Board list → lanes → cards → card detail, then an edit that has to reach disk — the one
/// end-to-end walk of the mobile MVP's navigation stack (`BoardRoute`'s three destinations).
final class BoardsNavigationUITests: XCTestCase {
@MainActor
func testBoardsNavigationAndTitleEdit() throws {
let (app, root) = XCUIApplication.launchedWithFixtureBoard()
// Boards is the app's root screen (`BoardsTabView`), so no navigation is needed to reach
// it. The row's label is the flattened `BoardSummaryRow` — title plus the "N lanes · N
// cards · modified" subtitle `BoardIndexStore`'s first scan fills in.
let boardRow = app.element(labelContaining: RichBoard.title)
XCTAssertTrue(
boardRow.waitForExistence(timeout: XCUIApplication.uiTimeout),
"the \"\(RichBoard.title)\" row never appeared — check the fixture copy or the first scan"
)
boardRow.tap()
let laneRow = app.element(labelContaining: RichBoard.firstLane)
XCTAssertTrue(
laneRow.waitForExistence(timeout: XCUIApplication.uiTimeout),
"the \"\(RichBoard.firstLane)\" lane row never appeared"
)
laneRow.tap()
let cardRow = app.element(labelContaining: RichBoard.firstLaneFirstCard)
XCTAssertTrue(
cardRow.waitForExistence(timeout: XCUIApplication.uiTimeout),
"the \"\(RichBoard.firstLaneFirstCard)\" card row never appeared"
)
cardRow.tap()
// CardDetailScreen: the only `textField` on this screen is the title
// (`Section("Title")`) — the body is a `TextEditor`, which is a `textView`.
let titleField = app.textFields.firstMatch
XCTAssertTrue(
titleField.waitForExistence(timeout: XCUIApplication.uiTimeout),
"CardDetailScreen's title field never appeared"
)
XCTAssertEqual(
titleField.value as? String, RichBoard.firstLaneFirstCard,
"the title field did not seed with the fixture card's own title"
)
let sentinel = "Retitled by UI test"
titleField.tap()
// Select-all via a hardware-keyboard shortcut (iOS answers ⌘A the same as macOS when a
// keyboard is attached, which the Simulator always presents one as) rather than a
// backspace-per-character workaround, whose delete count only works if the tap happened
// to land the cursor at the end of the existing text.
titleField.typeKey("a", modifierFlags: .command)
titleField.typeText(sentinel)
// Commit the way the screen commits (`CardDetailScreen.body`'s `.confirmationAction`):
// the Done button folds `commitAll()` in and drops focus, without navigating back.
app.navigationBars.buttons["Done"].tap()
XCTAssertTrue(
waitForFile(under: root, containing: sentinel),
"the retitled card never landed on disk under \(root.path)"
)
}
}