The phone gets its first witnesses — KanbanMobileUITests drive the MVP against a fixture board

The mobile app's first runtime coverage, and its first runtime, full stop: the suite launches the real app over a scratch directory seeded from rich-board.kanban via LANEWORK_LOCAL_ROOT, walks boards to lanes to cards to the card editor, retitles a card and polls the frontmatter on disk until the write lands, then taps through the Settings About section to see the changelog and license actually render. No iCloud account, no metadata query — the DEBUG override is the whole harness.

Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
2026-08-08 10:22:11 -04:00
parent 209c991030
commit ce8a446658
4 changed files with 284 additions and 0 deletions
@@ -0,0 +1,57 @@
import XCTest
/// The Settings tab's last section `SettingsTabView`'s `IndieAbout` block: version/build (which
/// doubles as the changelog link), the License document link, and the copyright line.
final class SettingsAboutUITests: XCTestCase {
@MainActor
func testSettingsAboutSection() throws {
let (app, _) = XCUIApplication.launchedWithFixtureBoard()
app.tabBars.buttons["Settings"].tap()
// The About section is last in the form (`SettingsTabView`'s own comment: "Last section
// by convention"), below the Backup section a couple of speculative swipes settle the
// list near the bottom before anything here is queried, harmless if the content already
// fit on screen.
app.swipeUp()
app.swipeUp()
// `IndieAbout`'s version line is three sibling `Text` views (prefix, the tappable
// "1.0-<build>" link, suffix) none of them wrapped in a control that would flatten them
// into one accessibility element, so the link is addressable on its own by the substring
// only it carries. `MARKETING_VERSION` for KanbanMobile is "1.0" (project.yml).
let versionLink = app.staticTexts.matching(NSPredicate(format: "label CONTAINS %@", "1.0")).firstMatch
XCTAssertTrue(
versionLink.waitForExistence(timeout: XCUIApplication.uiTimeout),
"no version label containing \"1.0\" appeared in Settings"
)
let licenseLink = app.staticTexts["License"]
XCTAssertTrue(licenseLink.waitForExistence(timeout: XCUIApplication.uiTimeout), "the License link never appeared")
let copyright = app.element(labelContaining: "2026 rzen")
XCTAssertTrue(copyright.waitForExistence(timeout: XCUIApplication.uiTimeout), "the copyright text never appeared")
// Tap the version link opens the changelog (`IndieAbout.versionLineView`'s
// `.onTapGesture`, wired to `changelogDocument: .changelog()` in `SettingsTabView`).
app.scrollUntilHittable(versionLink)
versionLink.tap()
let changelogText = app.element(labelContaining: "August 2026")
XCTAssertTrue(
changelogText.waitForExistence(timeout: XCUIApplication.uiTimeout),
"the changelog sheet never showed \"August 2026\" (KanbanMobile/CHANGELOG.md)"
)
app.navigationBars.buttons["Done"].tap()
// Tap License opens the bundled ISC license.
app.scrollUntilHittable(licenseLink)
licenseLink.tap()
let licenseText = app.element(labelContaining: "ISC License")
XCTAssertTrue(
licenseText.waitForExistence(timeout: XCUIApplication.uiTimeout),
"the license sheet never showed \"ISC License\" (LICENSE.md)"
)
app.navigationBars.buttons["Done"].tap()
}
}