import XCTest final class TextbookFlowUITests: XCTestCase { override func setUpWithError() throws { continueAfterFailure = false } func testTextbookFlow() throws { let app = XCUIApplication() // Skip onboarding via defaults (already set by run script, but harmless to override) app.launchArguments += ["-onboardingComplete", "YES"] app.launch() // Dashboard should be default tab. Switch to Course. let courseTab = app.tabBars.buttons["Course"] XCTAssertTrue(courseTab.waitForExistence(timeout: 5), "Course tab missing") courseTab.tap() // Attach a screenshot of the Course list attach(app, name: "01-course-list") // Tap the Textbook entry let textbookRow = app.buttons.containing(NSPredicate( format: "label CONTAINS[c] 'Complete Spanish'" )).firstMatch XCTAssertTrue(textbookRow.waitForExistence(timeout: 5), "Textbook row missing in Course") textbookRow.tap() attach(app, name: "02-textbook-chapter-list") // Tap chapter 1 — should navigate to reader let chapterOneRow = app.buttons.containing(NSPredicate( format: "label CONTAINS[c] 'Nouns, Articles'" )).firstMatch XCTAssertTrue(chapterOneRow.waitForExistence(timeout: 5), "Chapter 1 row missing") chapterOneRow.tap() attach(app, name: "03-chapter-body") // Find the first exercise link ("Exercise 1.1") let exerciseRow = app.buttons.containing(NSPredicate( format: "label CONTAINS[c] 'Exercise 1.1'" )).firstMatch XCTAssertTrue(exerciseRow.waitForExistence(timeout: 5), "Exercise 1.1 link missing") exerciseRow.tap() attach(app, name: "04-exercise-view") // Check presence of input fields: at least a few numbered prompts // Text fields use SwiftUI placeholder "Your answer" let firstField = app.textFields["Your answer"].firstMatch XCTAssertTrue(firstField.waitForExistence(timeout: 5), "No input fields rendered for exercise") firstField.tap() firstField.typeText("el") attach(app, name: "05-exercise-typed-el") // Tap Check answers let checkButton = app.buttons["Check answers"] XCTAssertTrue(checkButton.waitForExistence(timeout: 3), "Check answers button missing") checkButton.tap() attach(app, name: "06-exercise-graded") // The first answer to Exercise 1.1 is "el" — we should see the first prompt // graded correct. Iterating too deeply is fragile; just take a screenshot // and check for presence of either a checkmark-like label or "Try again". let tryAgain = app.buttons["Try again"] XCTAssertTrue(tryAgain.waitForExistence(timeout: 3), "Grading did not complete") } private func attach(_ app: XCUIApplication, name: String) { let screenshot = app.screenshot() let attachment = XCTAttachment(screenshot: screenshot) attachment.name = name attachment.lifetime = .keepAlways add(attachment) } }