feat(reader): 增强阅读器功能与 UI 测试支持
- 新增字体选择(系统/宋体/圆体/等宽)与暗色图片柔化配置 - 文本选择改为自定义手势+操作栏(拷贝/高亮/批注) - 添加 accessibilityIdentifier 支持自动化 UI 测试 - 新增 UITests 覆盖阅读器打开/关闭、工具栏、设置面板、批注等 - 添加 Demo 测试用 EPUB 书源(宝山辽墓材料与释读) - 新增文档:UI 自动化测试、功能开发计划、阅读器规划
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
import Foundation
|
||||
|
||||
enum IDs {
|
||||
static let demoStatus = "demo.status"
|
||||
static let demoBooksTable = "demo.books.table"
|
||||
static func demoBook(_ index: Int) -> String { "demo.book.\(index)" }
|
||||
static let demoReaderState = "demo.reader.state"
|
||||
|
||||
static let readerBack = "epub.reader.back"
|
||||
static let readerTitle = "epub.reader.title"
|
||||
static let readerTopToolbar = "epub.reader.topToolbar"
|
||||
static let readerBottomToolbar = "epub.reader.bottomToolbar"
|
||||
static let readerContent = "epub.reader.content"
|
||||
static let readerPaging = "epub.reader.paging"
|
||||
static let readerSettings = "epub.reader.settings"
|
||||
static let readerSelectionText = "epub.reader.selection.text"
|
||||
static let readerSelectionHighlight = "epub.reader.selection.高亮"
|
||||
|
||||
static let settingsScroll = "epub.reader.settings.scroll"
|
||||
static let settingsFontIncrease = "epub.reader.settings.font.increase"
|
||||
static let settingsFontDecrease = "epub.reader.settings.font.decrease"
|
||||
static let settingsFontValue = "epub.reader.settings.font.value"
|
||||
static let settingsFontChoice = "epub.reader.settings.font.choice"
|
||||
static let settingsDone = "epub.reader.settings.done"
|
||||
static func settingsTheme(_ index: Int) -> String { "epub.reader.settings.theme.\(index)" }
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
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 : "<missing>"
|
||||
XCTFail("阅读器状态未包含 \(expectedText),当前:\(currentLabel)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user