stop the disconnected-history alert from blocking scrolling
- Skip older-history loads silently while the connection is down: the trigger previously failed with "not connected", popped the global alert over the timeline and froze scrolling until dismissed. - Accept fast reply-swipe flicks whose end state is clearly leftward even without an intermediate horizontal lock, while scroll-owned touches still never activate the swipe. - Add a seeded-chat UI test mode (launch argument), accessibility identifiers and a LumaUITests target with timeline scroll and reply swipe tests; guard the fix in verify.sh.
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
import XCTest
|
||||
|
||||
final class TimelineUITests: XCTestCase {
|
||||
override func setUpWithError() throws {
|
||||
continueAfterFailure = false
|
||||
}
|
||||
|
||||
private func launchApp() -> XCUIApplication {
|
||||
let app = XCUIApplication()
|
||||
app.launchArguments = ["-luma-ui-test-chat"]
|
||||
app.launch()
|
||||
return app
|
||||
}
|
||||
|
||||
private func bubble(_ id: String, in app: XCUIApplication) -> XCUIElement {
|
||||
app.descendants(matching: .any).matching(identifier: "bubble-\(id)").firstMatch
|
||||
}
|
||||
|
||||
private func openChat(_ app: XCUIApplication) {
|
||||
let chatRow = app.staticTexts["uitest-peer"]
|
||||
XCTAssertTrue(chatRow.waitForExistence(timeout: 15))
|
||||
chatRow.tap()
|
||||
XCTAssertTrue(
|
||||
app.descendants(matching: .any).matching(identifier: "chat-timeline").firstMatch
|
||||
.waitForExistence(timeout: 15)
|
||||
)
|
||||
XCTAssertTrue(bubble("uitest-msg-60", in: app).waitForExistence(timeout: 15))
|
||||
}
|
||||
|
||||
func testTimelineVerticalScrollWorks() throws {
|
||||
let app = launchApp()
|
||||
openChat(app)
|
||||
|
||||
for _ in 0..<7 {
|
||||
app.swipeDown()
|
||||
}
|
||||
XCTAssertTrue(bubble("uitest-msg-1", in: app).waitForExistence(timeout: 10))
|
||||
|
||||
for _ in 0..<9 {
|
||||
app.swipeUp()
|
||||
}
|
||||
XCTAssertTrue(bubble("uitest-msg-60", in: app).waitForExistence(timeout: 10))
|
||||
}
|
||||
|
||||
func testReplySwipeShowsPlateAndScrollStillWorks() throws {
|
||||
let app = launchApp()
|
||||
openChat(app)
|
||||
|
||||
// Message 60 can sit partially behind the composer, so drag on a
|
||||
// bubble that is reliably visible and hittable in the bottom area.
|
||||
let target = bubble("uitest-msg-55", in: app)
|
||||
XCTAssertTrue(target.waitForExistence(timeout: 10))
|
||||
XCTAssertTrue(target.isHittable, "The swipe target must be hittable")
|
||||
// A controlled right-to-left drag: the stock swipeLeft() flicks too
|
||||
// fast for the gesture's horizontal lock to engage reliably.
|
||||
let start = target.coordinate(withNormalizedOffset: CGVector(dx: 0.9, dy: 0.5))
|
||||
start.press(forDuration: 0.15, thenDragTo: start.withOffset(CGVector(dx: -200, dy: 0)))
|
||||
let attachment = XCTAttachment(screenshot: app.screenshot())
|
||||
attachment.name = "after-drag"
|
||||
attachment.lifetime = .keepAlways
|
||||
add(attachment)
|
||||
XCTAssertTrue(
|
||||
app.descendants(matching: .any).matching(identifier: "reply-banner").firstMatch
|
||||
.waitForExistence(timeout: 5),
|
||||
"A left swipe must open the reply plate"
|
||||
)
|
||||
|
||||
app.buttons["Отменить ответ"].tap()
|
||||
for _ in 0..<7 {
|
||||
app.swipeDown()
|
||||
}
|
||||
XCTAssertTrue(bubble("uitest-msg-1", in: app).waitForExistence(timeout: 10))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user