Files
divkit/client/ios/DivKitTests/Extensions/XCTestCase+ViewVisibilityCallCount.swift
T
denlvovich afb34a0bf9 Fixed call to 'passVisibleBoundsChanged' on iOS26
commit_hash:0c2df2ccca3cf75f92c594ef124a0dcdbfcc9899
2025-11-19 16:03:04 +03:00

109 lines
2.6 KiB
Swift

import LayoutKit
import VGSL
import XCTest
extension XCTestCase {
@MainActor
func getViewVisibilityCallCount(
view: BlockView,
rect: CGRect,
visibilityRect: CGRect? = nil,
timerScheduler: TestTimerScheduler
) async throws -> Int {
let performer = UIActionEventPerformerMock()
performer.addSubview(view)
try await changeViewVisibility(
view: view,
rect: rect,
visibilityRect: visibilityRect,
timerScheduler: timerScheduler
)
return performer.callCount
}
}
final class UIActionEventPerformerMock: UIView, UIActionEventPerforming {
var callCount: Int = 0
var receivedEvents: [UIActionEvent] = []
func perform(uiActionEvent: UIActionEvent, from _: AnyObject) {
callCount += 1
receivedEvents.append(uiActionEvent)
}
}
final class VisibilityTester {
let view: BlockView
let timer: TestTimerScheduler
let performer = UIActionEventPerformerMock()
var callsCount: Int { performer.callCount }
init(block: Block, timer: TestTimerScheduler) {
self.view = block.makeBlockView()
self.timer = timer
performer.addSubview(view)
}
func setViewVisibleAndDisappear(repeatCount: Int) async throws {
for _ in 0..<repeatCount {
try await setViewAppear()
try await setViewDisappear()
}
}
func setViewAppear() async throws {
try await updateViewVisibility(isVisible: true)
}
func setViewDisappear() async throws {
try await updateViewVisibility(isVisible: false)
}
func callsCount(type: VisibilityActionType, url: URL? = nil) -> Int {
performer.receivedEvents.filter {
$0.type == type && (url == nil || $0.payload.divActionParams?.url == url)
}.count
}
private func updateViewVisibility(isVisible: Bool) async throws {
let rect = CGRect(origin: .zero, size: CGSize(squareDimension: 20))
try await changeViewVisibility(
view: view,
rect: rect,
visibilityRect: isVisible ? rect : .zero,
timerScheduler: timer
)
}
}
extension UIActionEvent {
fileprivate var type: VisibilityActionType {
VisibilityActionType(
rawValue: uiAction.path.parent?.leaf ?? ""
)!
}
}
@MainActor
func changeViewVisibility(
view: BlockView,
rect: CGRect,
visibilityRect: CGRect? = nil,
timerScheduler: TestTimerScheduler
) async throws {
view.frame = rect
view.layoutIfNeeded()
view.onVisibleBoundsChanged(from: rect, to: visibilityRect ?? rect)
await skipMainRunLoopCycles(view.visibilityHierarchyDepth())
for timer in timerScheduler.timers {
guard timer.isValid else { continue }
timer.fire()
}
}