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
66 lines
3.0 KiB
Swift
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)"
|
|
)
|
|
}
|
|
}
|