test(swift-sdk): add testnet identity-discovery UI test#3560
test(swift-sdk): add testnet identity-discovery UI test#3560llbartekll wants to merge 9 commits intov3.1-devfrom
Conversation
Extract Identifier enum, XCUIElement helpers, and the create/delete wallet flow into Support/ for cross-class reuse. Rewrite the existing testCreateGeneratedWalletFlow on top of the extracted helpers; behavior is unchanged. Add WalletPersistenceTests with two SDK-backed integration tests: - testWalletPersistsAcrossRelaunch validates loadFromPersistor() after a cold restart (SwiftData rehydration + Keychain read). - testWalletDeletionCleanupSurvivesRelaunch guards atomic SwiftData + Keychain mnemonic cleanup; the orphan-mnemonic recovery prompt fires on relaunch if either side leaks. Both new tests use addTeardownBlock + MainActor.assumeIsolated for best-effort wallet cleanup if assertions halt mid-flow. Extend swift-example-app-ui-smoke.yml -only-testing list to include the two new tests; -parallel-testing-enabled NO and -maximum-concurrent-test-simulator-destinations 1 retained. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Imports a wallet from `UI_TEST_TESTNET_MNEMONIC`, runs DIP-9 identity discovery, and asserts the registered identity surfaces with a non-zero balance. Skipped when the env var is unset. Test is scaffolded under CreditTransferTest so the credit-transfer assertion can be re-added as a sibling method (helpers for that flow are already in WalletFlow). Adds accessibility identifiers across the views the test traverses (wallet creation, identities tab, search-wallets sheet, identity detail, options/network picker, transition form) and one accessibilityValue on the balance label so the raw credit count is parseable from XCUITest. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds deterministic accessibility identifiers across the SwiftExampleApp UI, centralizes test identifier constants and XCUI helper utilities, implements extensive UI-test flow helpers and new UI test suites (wallet persistence and credit transfer), updates network-switch state handling in AppState, and extends the CI workflow to run the UI smoke tests. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 0/1 reviews remaining, refill in 3 minutes and 5 seconds.Comment |
|
🕓 Ready for review (commit 3823ee4) |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/OptionsView.swift`:
- Around line 88-110: The status label incorrectly shows "Connected" whenever
appState.sdk != nil even while a network switch is in progress; change the logic
so isSwitchingNetwork remains true until the async switch completes (or derive
connected state from a network-specific readiness signal on the SDK) so that the
UI only shows "Connected" when the new network is actually ready; update the
state transitions in switchAppNetworkToTestnet (and any reset helpers) to
set/clear isSwitchingNetwork around the full async completion and use that
combined with appState.sdk (or a new appState.sdk.isReady flag) to drive the
Label bound to accessibilityIdentifier "options.networkStatusLabel".
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swift`:
- Around line 96-101: The test is asserting a live testnet funding floor
(XCTAssertGreaterThan(balance, 0)); instead assert only that a readable balance
was returned: call readIdentityBalanceCredits(in:) and replace the
XCTAssertGreaterThan check with an assertion that the read succeeded (if the
function returns an Optional use XCTAssertNotNil(balance, "..."), or if it
returns an Int use XCTAssertGreaterThanOrEqual(balance, 0, "...") to allow
zero). Update the failure message to say the balance should be readable rather
than non-zero and keep the test focused on discovery/readability rather than
funding.
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift`:
- Around line 933-969: The negative branch in assertWalletRowVisible(true/false)
can false-pass because it never scrolls and queries app-wide button/text rows
that may be off-screen; change the exists == false path to reuse
scrollToWalletRow(named:in:) to bring the specific wallet row into the viewport
(or obtain the per-wallet XCUIElement) and then assert non-existence against
that element (e.g. wait for row.exists == false or use an
XCTNSPredicateExpectation on the returned row) instead of the current app-level
buttonRow/textRow checks so off-screen elements can't make the assertion pass
incorrectly.
- Around line 492-518: The test currently assumes the picker auto-selects the
imported wallet (walletPicker / Identifier.SearchWallets.walletPicker) which is
flaky; instead explicitly drive selection to walletName: after
walletPicker.waitForExistence, open the picker UI and locate the row/button/cell
whose label equals walletName (or the table cell in
SearchWalletsForIdentitiesView) and tap it to select that wallet, then assert
the selection; alternatively, if simpler, add a deterministic cleanup step
(delete competing wallets) before importing so only walletName remains—reference
walletPicker, walletName, and SearchWalletsForIdentitiesView when updating the
helper.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 655844a1-5da6-46a1-acaf-193e6c0801cd
📒 Files selected for processing (16)
.github/workflows/swift-example-app-ui-smoke.ymlpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/ContentView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/CreateWalletView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Core/Views/IdentitiesContentView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/IdentitiesView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/IdentityDetailView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/OptionsView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/SearchWalletsForIdentitiesView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionDetailView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/TransitionInputView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/Identifiers.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/XCUIElement+Helpers.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/SwiftExampleAppUITests.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/WalletPersistenceTests.swift
|
✅ DashSDKFFI.xcframework built for this PR.
SwiftPM (host the zip at a stable URL, then use): .binaryTarget(
name: "DashSDKFFI",
url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
checksum: "ff27351f1cc521742a7be124e9ebc864b4e8d297884c979eeef0a9680d7d69dc"
)Xcode manual integration:
|
thepastaclaw
left a comment
There was a problem hiding this comment.
Code Review
Test-only PR that adds accessibility identifiers and a new XCUITest (CreditTransferTest.testImportWalletAndDiscoverIdentity) plus shared helpers extracted from the existing test class. No app-side logic or consensus-critical code is touched. The main concerns are about test reliability: a verifiable race in switchAppNetworkToTestnet (the Connected label can be true via the stale SDK throughout the switch), brittle assumptions about picker default state, and ~200 lines of unused credit-transfer scaffolding likely to rot before the follow-up lands.
Reviewed commit: b3c85a2
🔴 1 blocking | 🟡 4 suggestion(s) | 💬 2 nitpick(s)
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift`:
- [BLOCKING] lines 375-439: switchAppNetworkToTestnet can return while the app is still on the previous network
`switchAppNetworkToTestnet` waits for `options.networkStatusLabel` to contain `Connected` as proof the switch finished, but the app provides no such guarantee. In `OptionsView` (lines 27-50), tapping the segmented control sets `appState.currentNetwork` and clears `isSwitchingNetwork` once the local resets finish; the actual SDK rebuild runs separately on the `currentNetwork.didSet` task in `AppState` (lines 12-17, 105-126). The status label renders `Connected` whenever `appState.sdk != nil`, and `switchNetwork` never nils the old SDK before constructing the new one (`sdk = newSDK` only after `try SDK(network:)` succeeds). On a simulator left on a non-testnet network from a previous run, the helper can therefore observe `Connected` against the stale SDK and return before testnet DAPI is bound — the discovery step then runs against the wrong backend and the test result is nondeterministic. Gate on a stronger signal: e.g. an SDK-level state transition published from `AppState` or a test-only flag flipped after `switchNetwork` completes, rather than the always-green status label.
- [SUGGESTION] lines 492-519: runIdentityDiscovery relies on "only one wallet exists" without enforcing it
`runIdentityDiscovery` trusts the picker's default-first auto-selection and only sanity-checks `walletPicker.label.contains(walletName)`. The invariant is never enforced: `SearchWalletsForIdentitiesView` queries `@Query(sort: \PersistentWallet.createdAt) hdWallets` unfiltered, and `CreditTransferTest` only deletes the row matching `expectedSenderWalletIdHex` (lines 69-76 of `CreditTransferTest.swift`). Any other persisted wallet from prior local runs still appears in the picker and, being older, becomes the default — the picker-label assertion will then fail loudly even though import and discovery are themselves working. The comment in the helper acknowledges this assumption but the test does not enforce it. Either reset `PersistentWallet` rows for unrelated wallets before discovery (e.g. a `cleanupWalletsByPrefix`-style sweep on entry, or a full SwiftData reset), or drive the picker to explicitly select `walletName` instead of trusting the default.
- [SUGGESTION] lines 624-833: Credit-transfer helpers (~200 lines) are added but unused
`navigateToIdentityCreditTransferForm`, `executeCreditTransfer`, `waitForCreditTransferSuccess`, and `cleanupWalletsByPrefix` are defined but have no callers anywhere in the test suite — grep confirms only the definitions exist. Carrying ~200 lines of unexecuted UI test helpers is risky: the most fragile string matching in the file lives here (`label CONTAINS[c] "manage identities"`, the `"💳 Manually Enter Recipient"` literal, the `transition.input.toIdentityId` identifier, the `"State Transitions"` cell label), and none of it is exercised, so it will silently rot against UI changes until the follow-up tries to use it. Note also that `executeCreditTransfer` calls `app.swipeDown()` after typing the amount — `importWallet` explicitly warns that `swipeDown` can dismiss sheets; the Transfer Credits screen is push-navigated rather than presented so it may not bite, but the inconsistency is worth verifying before the helper is wired in. Either land these helpers together with the test that uses them, or trim to what the discovery test actually needs and re-add the rest in the follow-up PR.
- [SUGGESTION] lines 466-490: Identity-discovery retry loop can close an already-open menu
The retry loop binds `for attempt in 1...3 where !sheetOpened` purely as a counter and then has to do `_ = attempt` to silence the unused-variable warning — that's a tell that the index shouldn't be bound at all (`for _ in 1...3 where !sheetOpened` is clearer). More substantively, every iteration unconditionally calls `addMenu.tap()` again. If the previous attempt actually opened the SwiftUI Menu but the search-item lookup transiently failed, the next `addMenu.tap()` will *close* the menu, putting the retry into a worse state than the first attempt. Probe the search item or the menu's selected state before re-tapping, e.g. only call `addMenu.tap()` when neither `searchMenuItem.exists` nor `addMenu.isSelected`.
In `packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swift`:
- [SUGGESTION] lines 53-59: Recovery-prompt guard runs before the network switch
`failIfRecoveryPromptVisible(in: app, timeout: 2)` runs immediately after `app.launch()`, then `switchAppNetworkToTestnet` runs. A wallet left over from a previous testnet run, when the simulator boots on a different default network (regtest, etc.), only triggers the orphan-mnemonic recovery prompt *after* the network switch rebinds the wallet-scoped services. In that scenario the guard runs against a state where the prompt has not yet appeared and misses it. Re-run the guard after `switchAppNetworkToTestnet`, or move the existing call to right after the switch so the prompt is detected on whichever network the test actually executes against.
Network-switch race (BLOCKING from both reviewers): lift `isSwitchingNetwork` from OptionsView's local @State to AppState. The flag now spans the full async cycle (currentNetwork.didSet → Task → switchNetwork → sdk = newSDK), so the network status label and test-side `Connected` predicate stop reading the previous network's SDK as a successful switch. Test reliability: - runIdentityDiscovery drives the wallet picker explicitly instead of trusting default-first auto-selection, so unrelated wallets on the simulator no longer hijack discovery. - assertWalletRowVisible(exists: false) scrolls to the top and sweeps down before declaring absent, closing a false-pass on long lists where SwiftUI's lazy List could leave a still-persisted row outside the accessibility tree. - CreditTransferTest drops the `balance > 0` floor (couples to live testnet funding state); readIdentityBalanceCredits already XCFails on parse error, so reaching the next line is the readability signal. - Re-run failIfRecoveryPromptVisible after switchAppNetworkToTestnet — a leftover testnet wallet on a simulator booted to a different default network only triggers the orphan-mnemonic prompt after the network switch rebinds wallet-scoped services. - cleanupWalletsByPrefix("ImportTransfer-") on entry sweeps random- suffixed wallets from prior failed runs (the deterministic walletId-based check missed them). - Discovery retry loop only re-taps the Add menu when its menu item isn't still visible from a prior attempt — re-tapping while the menu is open closes it. Trim: - Delete unused credit-transfer helpers (navigateToIdentityCreditTransferForm, executeCreditTransfer, waitForCreditTransferSuccess) and Identifier.Transition. They will return alongside the credit-transfer test in a follow-up; the corresponding app-side .accessibilityIdentifier calls on TransitionDetailView/TransitionInputView are kept (harmless). CI: - Wire CreditTransferTest into the smoke workflow with -only-testing. Self-skips when UI_TEST_TESTNET_MNEMONIC is unset, so the new line is a no-op for forks/PRs without the secret while still exercising the build path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift (1)
528-532: Wait for picker selection to propagate before asserting label text.The assertion on Line 528 can race right after
walletOption.tap(). A short predicate wait onwalletPicker.labelcontainingwalletNamewill make this less flaky on slower simulators.Proposed stabilization
- XCTAssertTrue( - walletPicker.label.contains(walletName), - "Picker shows \"\(walletPicker.label)\" but the test imported \(walletName).", - file: file, line: line - ) + let selectedWalletPredicate = NSPredicate { object, _ in + guard let element = object as? XCUIElement, element.exists else { return false } + return element.label.contains(walletName) + } + let selectedWalletResult = XCTWaiter.wait( + for: [XCTNSPredicateExpectation(predicate: selectedWalletPredicate, object: walletPicker)], + timeout: 5 + ) + XCTAssertEqual( + selectedWalletResult, + .completed, + "Picker shows \"\(walletPicker.label)\" but the test imported \(walletName).", + file: file, line: line + )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift` around lines 528 - 532, The assertion on walletPicker.label can race immediately after walletOption.tap(); add an explicit predicate wait that walletPicker.label contains walletName (e.g., create an NSPredicate "label CONTAINS %@", use expectation(for:evaluatedWith:handler:) or XCTNSPredicateExpectation, then wait(for:timeout:)) before calling XCTAssertTrue so the picker selection has time to propagate; update the flow around walletOption.tap(), walletPicker and the XCTAssertTrue to perform the predicate wait first and then assert.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AppState.swift`:
- Around line 24-28: The isSwitchingNetwork flag is being cleared
unconditionally by each spawned Task after awaiting switchNetwork(to:), which
allows an earlier task to flip it false while a later switch is still running;
fix by introducing a request token/version (e.g., an Int or UUID property like
networkSwitchRequestID) that you increment/assign before creating the Task,
capture that token inside the Task, and only set isSwitchingNetwork = false if
the captured token matches the current networkSwitchRequestID after await
switchNetwork(to:); apply this change to both places that spawn the Task so
completions are serialized/guarded and stale tasks cannot clear readiness.
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swift`:
- Around line 5-8: Update the stale header comment at the top of
CreditTransferTest.swift (the file-level comment in the CreditTransferTest test)
to reflect the current assertions: change the phrase that claims the test
asserts a "non-zero balance" to state it only verifies that the identity's
balance is readable/accessible (and keep or clarify that the actual
credit-transfer assertion is deferred). Edit the header comment block above the
test implementation to match the test's scope (balance readability) and remove
or adjust any misleading wording about asserting a non-zero balance.
---
Nitpick comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift`:
- Around line 528-532: The assertion on walletPicker.label can race immediately
after walletOption.tap(); add an explicit predicate wait that walletPicker.label
contains walletName (e.g., create an NSPredicate "label CONTAINS %@", use
expectation(for:evaluatedWith:handler:) or XCTNSPredicateExpectation, then
wait(for:timeout:)) before calling XCTAssertTrue so the picker selection has
time to propagate; update the flow around walletOption.tap(), walletPicker and
the XCTAssertTrue to perform the predicate wait first and then assert.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fed7c149-4bb2-4a06-b438-e518503b44eb
📒 Files selected for processing (6)
.github/workflows/swift-example-app-ui-smoke.ymlpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AppState.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/OptionsView.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/Identifiers.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift
🚧 Files skipped from review as they are similar to previous changes (2)
- .github/workflows/swift-example-app-ui-smoke.yml
- packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/OptionsView.swift
Three findings from coderabbit's re-review of 7c0ae94: - AppState: overlapping network switches could cause an earlier task to clear `isSwitchingNetwork` while a later switch was still running. Add a monotonic `networkSwitchRequestID`; each spawned task captures its id at start and only clears the flag when its id still matches. - CreditTransferTest header: aligned the file-level comment with the current scope (balance readability, not non-zero balance). - WalletFlow `runIdentityDiscovery`: replaced the bare label-contains assertion after `walletOption.tap()` with an `XCTNSPredicateExpectation` wait so the picker has time to propagate the selection on slower simulators. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Renames the testnet mnemonic env var the XCUITest reads to `UI_TEST_MNEMONIC` and forwards it from a GitHub secret of the same name into the xcodebuild step as `TEST_RUNNER_UI_TEST_MNEMONIC` (the prefix is required — xcodebuild strips it before handing the env to the XCUITest runner process). Empty on fork PRs (GitHub withholds secrets there), at which point the test self-skips. Once a repository secret named `UI_TEST_MNEMONIC` is set, `testImportWalletAndDiscoverIdentity` runs end-to-end against testnet on every push to a non-fork branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a 23:00 UTC daily cron to the smoke workflow, alongside the existing manual `workflow_dispatch` trigger. Mirrors the repo's nightly pattern (separate workflow with its own cron, like `tests-rs-nightly-long-running.yml`). Also adds a concurrency block so a manual dispatch and a cron run don't fight over the single self-hosted macOS ARM64 runner — the older run is cancelled in favor of the newer one. The cron only takes effect once this lands on the default branch (`v3.1-dev`); GitHub Actions schedules run against the default branch's workflow file. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the operational gotchas that took multiple sessions to re-discover: - `TEST_RUNNER_` prefix gate when passing `UI_TEST_MNEMONIC` via `xcodebuild test ENV=`. - `simctl erase` is the only way to clear stale Keychain entries between runs (uninstall alone leaves orphan mnemonics that trip the recovery prompt). - SwiftData migration failures from leftover stores manifest as a "Expected root tab bar" timeout, not an obvious crash. - The CI nightly cron's reliance on the self-hosted Mac being online. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift (1)
407-434:⚠️ Potential issue | 🟠 MajorWait for Testnet selection to latch before accepting “Connected”.
Right now the helper can still pass if the app remains connected on the previous network and the segmented-control tap doesn’t take effect. Add an explicit wait that
testnetButton.isSelected == truebefore asserting connection status.Suggested patch
@@ - if testnetButton.isSelected { - // Already on Testnet; status should already be Connected. - } else { + if !testnetButton.isSelected { testnetButton.tap() } + + let selectedResult = XCTWaiter.wait( + for: [ + XCTNSPredicateExpectation( + predicate: NSPredicate(format: "isSelected == true"), + object: testnetButton + ), + ], + timeout: 10 + ) + XCTAssertEqual( + selectedResult, + .completed, + "Expected Testnet segment to be selected before waiting for connected status.", + file: file, line: line + ) @@ let result = XCTWaiter.wait( for: [XCTNSPredicateExpectation(predicate: connectedPredicate, object: statusLabel)], timeout: timeout )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift` around lines 407 - 434, The helper can report "Connected" for the previous network if the segmented control tap hasn't latched; fix by waiting for the Testnet segment selection to take effect before checking network status: after tapping testnetButton (or the existing isSelected check) add an explicit wait using an NSPredicate/XCTNSPredicateExpectation that verifies testnetButton.isSelected == true (with a reasonable timeout) and assert the wait completes successfully, then proceed to build statusLabel and wait for the "Connected" predicate (retain connectedPredicate, statusLabel, and the existing XCTWaiter usage).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift`:
- Around line 518-520: The NSPredicate used to find walletOption is too
permissive and can match prefixes; update the predicate in the walletOption
construction (the app.buttons.matching(...) call) to require a trailing space
after the walletName token (e.g., use "label BEGINSWITH %@ " with walletName as
the argument) so it only matches the exact name token rather than any prefix;
keep the rest of the selector (firstMatch) unchanged.
- Around line 653-667: cleanupWalletsByPrefix is only checking visible buttons
and can miss off-screen wallets; change it to iterate over the full query (use
app.buttons.matching(predicate).allElementsBoundByIndex) or repeatedly scroll
the wallets list (element(Identifier.walletsScreen)) while locating elements
matching the predicate so every persisted wallet is discovered, and call
bestEffortDeleteWallet(named:in:) for each found name until none remain; ensure
the loop continues until the full query is empty rather than stopping when no
visible match is found.
---
Duplicate comments:
In
`@packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift`:
- Around line 407-434: The helper can report "Connected" for the previous
network if the segmented control tap hasn't latched; fix by waiting for the
Testnet segment selection to take effect before checking network status: after
tapping testnetButton (or the existing isSelected check) add an explicit wait
using an NSPredicate/XCTNSPredicateExpectation that verifies
testnetButton.isSelected == true (with a reasonable timeout) and assert the wait
completes successfully, then proceed to build statusLabel and wait for the
"Connected" predicate (retain connectedPredicate, statusLabel, and the existing
XCTWaiter usage).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 032ec7d6-0160-4c45-b81b-78633330445e
📒 Files selected for processing (5)
.github/workflows/swift-example-app-ui-smoke.ymlpackages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AppState.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swiftpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/README.mdpackages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/Support/WalletFlow.swift
✅ Files skipped from review due to trivial changes (1)
- packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/README.md
🚧 Files skipped from review as they are similar to previous changes (3)
- .github/workflows/swift-example-app-ui-smoke.yml
- packages/swift-sdk/SwiftExampleApp/SwiftExampleAppUITests/CreditTransferTest.swift
- packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/AppState.swift
Three findings from coderabbit's re-review: - `switchAppNetworkToTestnet`: wait for the testnet segment's `isSelected == true` before trusting the "Connected" predicate. The AppState fix already covers the rebind-in-progress race; this closes the missed-tap window where the picker setter never fires and the previous network's "Connected" still satisfies the wait. - `runIdentityDiscovery`: anchor the wallet-option predicate with a trailing space (`BEGINSWITH "<walletName> "`) so a longer wallet name sharing a prefix can't win firstMatch. - `cleanupWalletsByPrefix`: scroll-and-sweep the full wallets list instead of bailing when no matching row is visible in the current viewport. Resets to top, then up to 10 delete+reset cycles + 10 scroll passes per call. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-reviewed 296d9661.
The follow-up fixes address the reliability issues from my earlier pass: the network-status signal now stays honest across the full SDK rebind, overlapping switches no longer clear readiness early, the discovery flow explicitly selects the imported wallet, the recovery-prompt guard runs after the testnet hop, and the unused transfer scaffolding is trimmed back out. The workflow/docs wiring for UI_TEST_MNEMONIC also makes the new smoke path much easier to understand and run.
Looks good to me.
Issue being fixed or feature implemented
Extends the SwiftExampleApp UI test suite with an end-to-end test that exercises the SDK paths the existing local-only wallet tests don't touch: importing a wallet from a known mnemonic, DIP-9 identity discovery, and reading the discovered identity's balance from Platform.
This is one regression check across roughly half the SDK —
PlatformWallet.fromMnemonic,platform_wallet_discover_identities, DIP-9 TRANSFER key derivation, DAPI lookup, balance refresh.What was done?
CreditTransferTest.testImportWalletAndDiscoverIdentity— imports a testnet wallet fromUI_TEST_TESTNET_MNEMONIC, runs identity discovery, asserts the expected identity ID surfaces with a non-zero balance. Skipped when the env var is unset, so the rest of the suite continues to run locally without test-network credentials.accessibilityValueon the balance label so the raw credit count is parseable from XCUITest (the displayed%.8f DASHrounding hides amounts below 1000 credits).WalletFlow.swiftfor testnet flows: import-with-mnemonic, network switch, identity discovery, balance read, plus credit-transfer form navigation/execution scaffolding kept in place for the follow-up that re-adds the transfer assertion.The class and file are named
CreditTransferTestso the deferred transfer assertion can be re-added as a sibling method — helpers are already wired up.How Has This Been Tested?
UI_TEST_TESTNET_MNEMONICexported through Xcode's scheme env vars (note:xcodebuild test ENV=...does not propagate env vars to the XCUITest runner — use theTEST_RUNNER_<NAME>prefix from the command line, see the file's leading comment).3ou98WEERy6ExmmHWYWsFtyhgW8rmr1giceZYTFqdAAAwith a non-zero balance.testCreateGeneratedWalletFlow,testWalletPersistsAcrossRelaunch,testWalletDeletionCleanupSurvivesRelaunch) still pass.Breaking Changes
None — accessibility identifiers and
accessibilityValueare additive; no app-side logic changed.Checklist:
For repository code-owners and collaborators only
Summary by CodeRabbit
Tests
Accessibility
UI
Documentation