mirror of
https://github.com/callstack/agent-device.git
synced 2026-09-14 20:06:34 +08:00
5676d5ff8a
* refactor(apple): drop dead runner code and collapse duplicated helpers Removes declarations with no consumers (findScopeElement, interactiveTypes, two unused PresentedNode convenience inits) and collapses copy-pasted logic: DataPayload now relies on the synthesized memberwise init, TvRemoteButton is String-raw-valued, point-hit sorting shares smallestElementFirst, command-id trim-or-nil lives once on RunnerCommandJournal, scroll/desktopScroll share direction and durationMs validators, and the seven inline NSError refusals use unsupportedOperationError. elementTypeName reads a table pinned by the visibility-fold parity test. The packager now skips files whose unit-test blocks were their whole body, so 10 test-only files stop shipping (and stop compiling on user machines) as empty translation units. Packaged Swift: 432.3 kB -> 427.8 kB; 56 files instead of 66. Net -144 lines. * test(apple): pin skeleton-file exclusion in the packaging guard The strip fixture always kept runtime content, so reverting the skeleton-skip branch left every guard green. The new fixture's whole body is unit-test blocks; the packaged path must be absent while a non-skeleton sibling still ships. Observed red with the skip branch disabled before re-enabling it. * refactor(apple): tighten runner cleanup boundaries
159 lines
7.3 KiB
Swift
159 lines
7.3 KiB
Swift
#if AGENT_DEVICE_RUNNER_UNIT_TESTS
|
|
import XCTest
|
|
|
|
extension RunnerTests {
|
|
private static func foldNode(
|
|
_ index: Int,
|
|
type: String,
|
|
label: String? = nil,
|
|
rect: SnapshotRect,
|
|
depth: Int,
|
|
parentIndex: Int?
|
|
) -> RawAXNode {
|
|
RawAXNode(
|
|
index: index, type: type, label: label, identifier: nil, value: nil, rect: rect,
|
|
enabled: true, focused: nil, selected: nil, hittable: false, depth: depth,
|
|
parentIndex: parentIndex, hiddenContentAbove: nil, hiddenContentBelow: nil
|
|
)
|
|
}
|
|
|
|
private static func folded(
|
|
_ nodes: [RawAXNode],
|
|
viewport: CGRect,
|
|
interactiveOnly: Bool = false,
|
|
policy: SnapshotVisibilityFold.Policy = .cursorProjected
|
|
) -> [SnapshotPresentationNode] {
|
|
SnapshotVisibilityFold.fold(
|
|
nodes, viewport: viewport, interactiveOnly: interactiveOnly, policy: policy)
|
|
}
|
|
|
|
func testRegularFoldClipsScrollOverflowReparentsAndBooksHints() {
|
|
let nodes = [
|
|
Self.foldNode(0, type: "Application", label: "App",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 402, height: 874), depth: 0, parentIndex: nil),
|
|
Self.foldNode(1, type: "ScrollView",
|
|
rect: SnapshotRect(x: 0, y: 96, width: 402, height: 700), depth: 1, parentIndex: 0),
|
|
Self.foldNode(2, type: "Cell", label: "Visible row",
|
|
rect: SnapshotRect(x: 0, y: 120, width: 402, height: 52),
|
|
depth: 2, parentIndex: 1),
|
|
Self.foldNode(3, type: "StaticText", label: "Detail",
|
|
rect: SnapshotRect(x: 16, y: 130, width: 200, height: 20), depth: 3, parentIndex: 2),
|
|
Self.foldNode(4, type: "Cell", label: "Offscreen row",
|
|
rect: SnapshotRect(x: 0, y: 900, width: 402, height: 52),
|
|
depth: 2, parentIndex: 1),
|
|
Self.foldNode(5, type: "StaticText", label: "Clamped child",
|
|
rect: SnapshotRect(x: 16, y: 96, width: 100, height: 20), depth: 3, parentIndex: 4),
|
|
// An offscreen generic wrapper does not own visibility; its visible overlay survives and is
|
|
// reparented to the scroll container.
|
|
Self.foldNode(6, type: "Other",
|
|
rect: SnapshotRect(x: 0, y: 900, width: 402, height: 52), depth: 2, parentIndex: 1),
|
|
Self.foldNode(7, type: "StaticText", label: "Visible overlay",
|
|
rect: SnapshotRect(x: 16, y: 200, width: 100, height: 20), depth: 3, parentIndex: 6),
|
|
]
|
|
let folded = Self.folded(nodes, viewport: CGRect(x: 0, y: 0, width: 402, height: 874))
|
|
|
|
XCTAssertEqual(
|
|
folded.map { $0.raw.type },
|
|
["Application", "ScrollView", "Cell", "StaticText", "StaticText"])
|
|
XCTAssertEqual(
|
|
folded.compactMap { $0.raw.label },
|
|
["App", "Visible row", "Detail", "Visible overlay"])
|
|
XCTAssertEqual(folded.map { $0.raw.depth }, [0, 1, 2, 3, 2])
|
|
XCTAssertEqual(folded.map { $0.raw.parentIndex }, [nil, 0, 1, 2, 1])
|
|
XCTAssertEqual(folded.first { $0.raw.type == "ScrollView" }?.raw.hiddenContentBelow, true)
|
|
}
|
|
|
|
func testRegularFoldKeepsWindowCarriersButNeverHittableOutsideClip() {
|
|
let nodes = [
|
|
Self.foldNode(0, type: "Application", label: "App",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 402, height: 874), depth: 0, parentIndex: nil),
|
|
Self.foldNode(1, type: "Window", label: "Second screen",
|
|
rect: SnapshotRect(x: 402, y: 0, width: 402, height: 874),
|
|
depth: 1, parentIndex: 0),
|
|
Self.foldNode(2, type: "Button", label: "Gone",
|
|
rect: SnapshotRect(x: 500, y: 100, width: 100, height: 44),
|
|
depth: 2, parentIndex: 1),
|
|
]
|
|
let folded = Self.folded(nodes, viewport: CGRect(x: 0, y: 0, width: 402, height: 874))
|
|
|
|
XCTAssertEqual(folded.map { $0.raw.type }, ["Application", "Window"])
|
|
XCTAssertEqual(folded.last?.raw.hittable, false)
|
|
XCTAssertEqual(folded.last?.effectiveRect.x, 402)
|
|
XCTAssertEqual(folded.last?.effectiveRect.y, 0)
|
|
XCTAssertEqual(folded.last?.effectiveRect.width, 0)
|
|
XCTAssertEqual(folded.last?.effectiveRect.height, 0)
|
|
XCTAssertFalse(folded.contains { $0.raw.label == "Gone" })
|
|
}
|
|
|
|
func testRegularFoldDropsSubPixelContentlessDecorationOnEveryBackend() {
|
|
let nodes = [
|
|
Self.foldNode(0, type: "Application", label: "App",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 402, height: 874), depth: 0, parentIndex: nil),
|
|
Self.foldNode(1, type: "Button",
|
|
rect: SnapshotRect(x: 0, y: 100, width: 402, height: 1),
|
|
depth: 1, parentIndex: 0),
|
|
Self.foldNode(2, type: "StaticText", label: "Hairline caption",
|
|
rect: SnapshotRect(x: 0, y: 200, width: 402, height: 1), depth: 1, parentIndex: 0),
|
|
Self.foldNode(3, type: "StaticText", label: "Frameless semantics",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 0, height: 0),
|
|
depth: 1, parentIndex: 0),
|
|
]
|
|
let folded = Self.folded(nodes, viewport: CGRect(x: 0, y: 0, width: 402, height: 874))
|
|
|
|
XCTAssertEqual(
|
|
folded.compactMap { $0.raw.label },
|
|
["App", "Hairline caption", "Frameless semantics"])
|
|
XCTAssertFalse(folded.contains { $0.raw.type == "Button" })
|
|
XCTAssertEqual(folded.first { $0.raw.label == "Frameless semantics" }?.raw.hittable, false)
|
|
}
|
|
|
|
func testPlainViewportPolicyFoldsWithoutAncestorCursor() {
|
|
let nodes = [
|
|
Self.foldNode(0, type: "Application", label: "App",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 800, height: 600), depth: 0, parentIndex: nil),
|
|
Self.foldNode(1, type: "Window", label: "Offscreen window",
|
|
rect: SnapshotRect(x: 900, y: 0, width: 800, height: 600), depth: 1, parentIndex: 0),
|
|
Self.foldNode(2, type: "Cell", label: "Offscreen row",
|
|
rect: SnapshotRect(x: 0, y: 900, width: 800, height: 52), depth: 1, parentIndex: 0),
|
|
Self.foldNode(3, type: "StaticText", label: "Clamped child",
|
|
rect: SnapshotRect(x: 16, y: 100, width: 100, height: 20), depth: 2, parentIndex: 2),
|
|
]
|
|
let viewport = CGRect(x: 0, y: 0, width: 800, height: 600)
|
|
|
|
let regular = Self.folded(nodes, viewport: viewport, policy: .plainViewport)
|
|
XCTAssertEqual(
|
|
regular.compactMap { $0.raw.label }, ["App", "Offscreen window", "Clamped child"])
|
|
|
|
let interactive = Self.folded(
|
|
nodes, viewport: viewport, interactiveOnly: true, policy: .plainViewport)
|
|
XCTAssertFalse(interactive.contains { $0.raw.label == "Offscreen window" })
|
|
}
|
|
|
|
func testPlainViewportPolicyDoesNotClipToScrollAncestor() {
|
|
let nodes = [
|
|
Self.foldNode(0, type: "Application", label: "App",
|
|
rect: SnapshotRect(x: 0, y: 0, width: 800, height: 600), depth: 0, parentIndex: nil),
|
|
Self.foldNode(1, type: "ScrollView", label: "Scroll",
|
|
rect: SnapshotRect(x: 0, y: 100, width: 800, height: 100), depth: 1, parentIndex: 0),
|
|
Self.foldNode(2, type: "StaticText", label: "Outside scroll clip",
|
|
rect: SnapshotRect(x: 16, y: 240, width: 100, height: 20), depth: 2, parentIndex: 1),
|
|
]
|
|
let viewport = CGRect(x: 0, y: 0, width: 800, height: 600)
|
|
|
|
let plain = Self.folded(nodes, viewport: viewport, policy: .plainViewport)
|
|
XCTAssertTrue(plain.contains { $0.raw.label == "Outside scroll clip" })
|
|
|
|
let cursorProjected = Self.folded(nodes, viewport: viewport, policy: .cursorProjected)
|
|
XCTAssertFalse(cursorProjected.contains { $0.raw.label == "Outside scroll clip" })
|
|
}
|
|
|
|
func testScrollContainerTypeNamesMatchElementTypeSet() {
|
|
XCTAssertEqual(
|
|
SnapshotVisibilityFold.scrollContainerTypeNames,
|
|
Set(Self.scrollContainerTypes.map(elementTypeName))
|
|
)
|
|
XCTAssertEqual(elementTypeName(.cell), "Cell")
|
|
}
|
|
}
|
|
#endif
|