Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ building, testing, or releasing the app.

### Developer Experience

- Keep the loading and Use Reset progress unit tests passing when the
simulator has app accessibility enabled, where the system reads progress
labels as "In progress, …". Wait for the dashboard body before checking the
loading state. ([#527](https://github.com/hemsoft-dev/codexbar-ios/issues/527))

- Split manual iPhone and iPad UI qualification into measured shards while
preserving the 90-minute worker limit and automatic PR checks. Keep touch
target assertions from rejecting 44-point controls due to floating-point noise.
Expand Down
11 changes: 9 additions & 2 deletions CodexBarIOSTests/FreeTierPresentationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,15 @@ final class FreeTierPresentationTests: XCTestCase {

func testDashboardShowsLoadingUntilInitialRefreshCompletes() throws {
try withDashboard(performsLifecycleWork: true, settles: false) { probe in
XCTAssertEqual(
probe.element(identifier: "dashboard-account-loading")?.accessibilityLabel, "Loading accounts…", "\(probe.labels)"
// The toolbar can publish before the dashboard body, so wait for the first body state.
XCTAssertTrue(probe.waitUntil {
probe.element(identifier: "dashboard-account-loading") != nil
|| probe.element(label: "Connect your first account") != nil
}, "\(probe.labels)")
XCTAssertTrue(
HostedViewProbe.isProgressLabel(
probe.element(identifier: "dashboard-account-loading")?.accessibilityLabel, "Loading accounts…"
), "\(probe.labels)"
)
XCTAssertNil(probe.element(label: "Connect your first account"))

Expand Down
19 changes: 18 additions & 1 deletion CodexBarIOSTests/ProviderUsageCardHiddenSeverityTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,15 @@ final class ProviderUsageCardHiddenSeverityTests: XCTestCase {
XCTAssertNil(lockedProbe.element(identifier: "claude-reset-cooldown"))
}

@MainActor
func testProgressLabelMatchAcceptsOnlyTheLabelOrItsInProgressForm() {
XCTAssertTrue(HostedViewProbe.isProgressLabel("Using reset…", "Using reset…"))
XCTAssertTrue(HostedViewProbe.isProgressLabel("In progress, Using reset…", "Using reset…"))
for label in [nil, "", "In progress", "Use one reset", "Using reset", "In progress, Use one reset", "Using reset…, In progress"] {
XCTAssertFalse(HostedViewProbe.isProgressLabel(label, "Using reset…"), "\(String(describing: label))")
}
}

@MainActor
func testResetInventoryShowsProgressThenFeedbackWhileUsingConfirmedReset() throws {
let now = Date()
Expand All @@ -459,7 +468,9 @@ final class ProviderUsageCardHiddenSeverityTests: XCTestCase {
XCTAssertTrue(probe.waitUntil { probe.element(label: "Use reset") != nil }, "\(probe.labels)")
XCTAssertTrue(probe.chooseAlertAction("Use reset"), "\(probe.labels)")
XCTAssertTrue(probe.waitUntil { gate.request != nil }, "\(probe.labels)")
XCTAssertTrue(probe.waitUntil { probe.labels.contains("Using reset…") }, "\(probe.labels)")
XCTAssertTrue(
probe.waitUntil { probe.labels.contains { HostedViewProbe.isProgressLabel($0, "Using reset…") } }, "\(probe.labels)"
)
XCTAssertEqual(gate.request?.grantID, grant.id)
XCTAssertEqual(gate.request?.binding, "binding")

Expand Down Expand Up @@ -624,6 +635,12 @@ final class HostedViewProbe {
elements.first { $0.accessibilityLabel?.hasPrefix(labelPrefix) == true }
}

/// SwiftUI reports a labelled ProgressView as "In progress, <label>" while the device has
/// application accessibility enabled, and as "<label>" otherwise.
static func isProgressLabel(_ label: String?, _ text: String) -> Bool {
label == text || label == "In progress, \(text)"
}

func element(identifier: String) -> NSObject? { elements(identifier: identifier).first }

func elements(identifier: String) -> [NSObject] { elements.filter { Self.identifier(of: $0) == identifier } }
Expand Down
Loading