import XCTest extension XCUIApplication { func launchAndOpenSampleBook(displayType: String? = nil, pageNumber: Int? = nil) { var args = ["--demo-book-title", "回归验证样本"] if let displayType { args += ["--demo-display-type", displayType] } if let pageNumber { args += ["--demo-page", "\(pageNumber)"] } launchArguments = args launch() } @discardableResult func waitForReader(timeout: TimeInterval = 12) -> XCUIElement { let state = staticTexts[IDs.demoReaderState] XCTAssertTrue(state.waitForExistence(timeout: timeout), "阅读器状态标签未出现") XCTAssertTrue(state.label.contains("reader=opened"), "阅读器未进入 opened 状态:\(state.label)") return state } func showReaderChromeIfNeeded() { if buttons[IDs.readerBack].exists && buttons[IDs.readerSettings].exists { return } let content = otherElements[IDs.readerContent] if content.waitForExistence(timeout: 3) { content.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } else { windows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0.5, dy: 0.5)).tap() } } func waitForReaderState(containing expectedText: String, timeout: TimeInterval = 8) { let state = staticTexts[IDs.demoReaderState] let deadline = Date().addingTimeInterval(timeout) while Date() < deadline { if state.exists && state.label.contains(expectedText) { return } RunLoop.current.run(until: Date().addingTimeInterval(0.1)) } let currentLabel = state.exists ? state.label : "" XCTFail("阅读器状态未包含 \(expectedText),当前:\(currentLabel)") } }