Files
Luma/UITests/TimelineUITests.swift
wt 6ed5cb3ce9
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
fix app lock hanging on macOS and blocking the photo picker
- Lock only when the scene really backgrounds: transient inactive
  states (system photo picker, app switcher) no longer swap in the
  lock screen and break gallery selection on iOS.
- Cache biometric availability once per session off the main thread
  instead of calling LAContext.canEvaluatePolicy in view bodies,
  which froze the macOS lock screen, and auto-prompt biometrics on
  iOS only.
- Keep UI tests as an opt-in target and guard both fixes in
  verify.sh.
2026-08-30 01:14:23 +07:00

82 lines
3.0 KiB
Swift

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: 30))
chatRow.tap()
XCTAssertTrue(
app.descendants(matching: .any).matching(identifier: "chat-timeline").firstMatch
.waitForExistence(timeout: 30)
)
XCTAssertTrue(bubble("uitest-msg-60", in: app).waitForExistence(timeout: 30))
}
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)
// The initial scroll position varies slightly between runs, so pick
// the first hittable bubble from the bottom area of the timeline.
let candidates = [60, 59, 58, 55, 50, 45].map {
bubble("uitest-msg-\($0)", in: app)
}
// A controlled right-to-left drag: the stock swipeLeft() flicks too
// fast for the gesture's horizontal lock to engage reliably. The drag
// itself can occasionally be swallowed, so retry on the next hittable
// bubble until the reply plate appears.
let banner = app.descendants(matching: .any).matching(identifier: "reply-banner").firstMatch
var bannerAppeared = false
for _ in 0..<3 where !bannerAppeared {
guard let target = candidates.first(where: { $0.exists && $0.isHittable }) else {
break
}
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)))
bannerAppeared = banner.waitForExistence(timeout: 2)
}
let attachment = XCTAttachment(screenshot: app.screenshot())
attachment.name = "after-drag"
attachment.lifetime = .keepAlways
add(attachment)
XCTAssertTrue(bannerAppeared, "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))
}
}