Skip to content

Fix the failing fearlessTests: Japanese Welcome glyphs, bold HUD, Send pasteboard, Profile PIN race - #1322

Closed
takemiyamakoto wants to merge 6 commits into
masterfrom
hotfix/ios-test-suite-failures
Closed

takemiyamakoto wants to merge 6 commits into
masterfrom
hotfix/ios-test-suite-failures

Conversation

@takemiyamakoto

@takemiyamakoto takemiyamakoto commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes every test failure from the latest fearlessTests runs: GitHub's build job on master (dce8790cd) and on #1320, and the local full runs. None came from #1320's change. The full suite now passes locally at this branch's head: 3,599 tests, 0 failures.

Japanese Welcome text drew Chinese glyph forms (GitHub: 3 OnboardingStartTests)

  • The Welcome screen draws Japanese in the system font, and CoreText picks fallback glyphs for kanji by the device language. On a device not set to Japanese, such as GitHub's English simulator, they came out in PingFang SC, the Chinese forms. Local simulators inherit this Mac's ja-JP, so they passed.
  • FWWelcomeView and FWWelcomeActionButton now tag their text with the app language (kCTLanguageAttributeName). The reference test tags its samples the same way.

Bold Text left the HUD at its normal weight (GitHub: FWDesignSystemTests)

  • The bundled JetBrains Mono family has only Regular and Medium. withSymbolicTraits(.traitBold) returns nil, so a bold HUD fell back to Medium, which is its normal weight. Outside Japanese and Chinese, Bold Text did nothing to the HUD.
  • A bold HUD now uses the system monospaced face at Semibold, as the existing code already does when the bundled font is missing.
  • The bold check runs for explicit English and Japanese locales.

PIN change could navigate after its screen was popped (local: PinPersistenceTests, long known as "fails under load")

  • popViewController takes the PIN screen off the stack and detaches it at once. UIKit calls its viewWillDisappear, which cancels the presenter, only at the next layout pass, which I measured with a probe test. A save acknowledged in between still called showMain.
  • PinSetupViewController.willMove(toParent: nil) runs during the pop itself and now cancels the create/change presenter.
  • Results from repeated runs of the original test: 3/20, 6/50 and 7/50 failed before; 100/100 pass after.

Profile PIN prompt race (GitHub, on #1320 only: ProfileAuthorizationLifecycleTests)

  • After an authorization screen leaves, the wireframe releases its pending request a moment later. By design, it ignores a Change PIN tap until then, and the test tapped as soon as the screen had gone.
  • Every open in that class now waits for the release. That wait still fails a test whose dismissed request is never released.

Clipboard hang and a relaunched, inactive test host (local: 4 SendDependencyErrorSurfacingTests)

  • A read of the system pasteboard blocked the host's main thread for 2 minutes; the spindump shows -[_UIConcretePasteboard items] in a semaphore wait. Content another app wrote, such as the Mac clipboard that Simulator syncs, waits for a paste-permission answer.
  • XCTest then relaunched the host, and the next Send form tests ran before its scene was active.
  • SendPresenter and WalletSendConfirmPresenter now take a PasteboardStringAccessing, which defaults to UIPasteboard.general. The tests pass an in-memory one, and the Solana fixtures wait for an active scene.

Run configuration only (local: 13 tests, no code change)

  • 11 keychain and app-group tests fail when CODE_SIGNING_ALLOWED=NO drops the simulator entitlements. GitHub's job and scripts/test-matrix.sh build signed, and so do the runs below.
  • 2 AccountConfirmPresentationTests cases take about 127 s at this Mac's load, past a 2-minute allowance an earlier run set. The runs below allow 5 minutes.
  • AGENTS.md notes these traps, how to match GitHub's English runs (-testLanguage en -testRegion US), and system-pasteboard reads in tests.

Transaction-builder audit (GitHub: the build job stopped at this pre-build gate on this branch)

  • scripts/audit-transaction-builder-tests.sh required the literal UIPasteboard.general.string = recovery.messageHashHex, which the pasteboard injection changed.
  • It now requires pasteboard.string = recovery.messageHashHex and the UIPasteboard.general default.
  • Its harness has a 141st destructive fixture, which fails a presenter whose default is redirected.

Evidence

A CoreText probe run inside the simulators gives the same result on iOS 18.4, 26.2 and 26.5:

  • Untagged 新しいウォレットを作成 in the system font gives .HiraKakuInterface-W6 under ja-JP. Under English it gives .PingFangUIDisplaySC-Semibold and .CJKSymbolsFallbackSC-Semibold, the names in GitHub's failure messages.
  • Tagged ja, it gives Hiragino under both languages.
  • JetBrainsMono-Medium with .traitBold is nil.

On master's code the font tests fail as GitHub shows: run 41823644385 (master push) and run 42376841255 (#1320), on iOS 26.2 in English.

Tests

All runs are local, with a signed simulator build and a 300 s per-test allowance. No hosted CI is required.

Run Commit Simulator Language Result
Full fearlessTests 1a2437833 (head's app and test code; 893c7b9fd only changes scripts/) iOS 26.5 iPhone 17 ja-JP 3,599 tests: 3,525 passed, 74 skipped, 0 failed
The changed classes plus the PIN classes 1a2437833 iOS 26.2 iPhone 16e (GitHub's runtime) -testLanguage en -testRegion US 234/234 passed
testActualNavigationPopFencesPendingPinChangeCompletion ×100 1a2437833 iOS 26.5 ja-JP 100/100 passed
GitHub's 26 audit and contract steps (scripts/*-audit*.sh, remote config, native source, XCM boundary) 893c7b9fd (head) — — all pass
11 keychain/app-group tests + AccountConfirmPresentationTests + the changed classes d09ce3f2c content iOS 26.5 ja-JP 236/236 passed

Not covered:

  • The iOS 18.x check that AGENTS.md asks for UIKit text changes could not run. This Mac's Xcode 27.2 Debug build doesn't launch below iOS 26 (dyld: Library not loaded: /usr/lib/swift/libswiftWebKit.dylib; see below). The CoreText probe above did run on iOS 18.4.
  • The iOS-native Authorized RPC contract suite and the Iroha SDK download check were not rerun: this branch doesn't touch Native/, and the download check needs the network.
  • Two full-suite attempts were cut short by this Mac's CoreSimulatorService, which was restarted at 04:34 and sent SIGTERM at 06:03, neither by this session. The suite was rerun from the start each time.

Not in this PR

  • Other screens don't tag their text, so their Japanese kanji still follow the device language.
  • Other test classes still read the system pasteboard; ExactTonMnemonicExportTests does so on purpose.
  • The Xcode 27.2 Debug build declares iOS 15.0 as its minimum, yet its debug dylib strongly links /usr/lib/swift/libswiftWebKit.dylib and @rpath/libswiftCompatibilitySpan.dylib, and the app embeds neither. Release archives were not checked.

Risk and rollback

  • Welcome text gets a language attribute.
  • Bold HUD text changes face only when Bold Text is on and the language is neither Japanese nor Chinese.
  • The PIN create/change screen cancels at pop time instead of one layout pass later. Authorization mode is unchanged.
  • The pasteboard parameter defaults to the system pasteboard.
  • Rollback: revert the commits.

🤖 Generated with Claude Code

takemiyamakoto and others added 4 commits November 8, 2026 05:02
CoreText picks fallback glyphs for kanji by the device language, so the
Welcome screen's Japanese text came out in Chinese forms (PingFang SC) on a
device not set to Japanese, which is how GitHub's English iOS 26.2 simulator
failed three OnboardingStartTests. Welcome labels and buttons now tag their
text with the app language (kCTLanguageAttributeName), and the reference test
tags its samples the same way.

The bundled JetBrains Mono family has only Regular and Medium, so
withSymbolicTraits(.traitBold) returns nil and a bold HUD fell back to Medium,
its normal weight: Bold Text did nothing to the HUD outside Japanese and
Chinese. It now takes the heavier system monospaced face, as the existing
fallback does when the bundled font is missing. The bold check runs for an
explicit English and Japanese locale instead of the device's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e scene

A read of UIPasteboard.general blocked a test host's main thread for two
minutes (-[_UIConcretePasteboard items] waiting on a semaphore): reading content
another app wrote, such as the Mac clipboard that Simulator syncs, waits for a
paste-permission answer. XCTest then relaunched the host, and the next Send form
tests ran before its scene was active, where the Solana form refuses to continue
by design.

SendPresenter and WalletSendConfirmPresenter take a PasteboardStringAccessing,
UIPasteboard.general by default, and SendDependencyErrorSurfacingTests hands
them an in-memory one. The Solana fixtures wait for an active scene first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ased

After an authorization screen leaves, its presenter releases the wireframe's
pending request a moment later, and the wireframe ignores a Change PIN tap until
then by design. The Profile lifecycle tests tapped as soon as the screen had
left, so on GitHub's runner one tap was ignored and
testActualProfileExternalAnimatedDismissalRejectsReplyDuringTransition failed.
Each open now waits for the release itself, which still fails a test whose
dismissed request is never released.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unsigned builds fail 11 keychain and app-group tests, a new simulator takes the
Mac's language (GitHub's runs are English), and system pasteboard reads in tests
can wait for a paste-permission answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
takemiyamakoto and others added 2 commits November 8, 2026 07:24
popViewController takes the PIN screen off the stack and detaches it at
once, but UIKit calls its viewWillDisappear, which cancels the presenter,
only at the next layout pass. A save acknowledged in between still called
showMain, so PinPersistenceTests.testActualNavigationPopFencesPendingPinChangeCompletion
failed now and then under load (3 of 20, 6 of 50 and 7 of 50 repeated runs
here). willMove(toParent: nil), which UIKit calls during the pop itself,
now cancels the create/change presenter; 100 of 100 repeated runs pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The audit required the literal UIPasteboard.general.string assignment for the
TON unknown-outcome copy action. WalletSendConfirmPresenter now copies through
its injected pasteboard, so the audit requires that assignment plus the
system-pasteboard default, and a new destructive fixture (141) fails a
presenter whose default is redirected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Nov 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.55556% with 2 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (master@dce8790). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...WalletSend/SendDependencyErrorSurfacingTests.swift 92.59% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #1322   +/-   ##
=========================================
  Coverage          ?   78.19%           
=========================================
  Files             ?      285           
  Lines             ?   142070           
  Branches          ?        0           
=========================================
  Hits              ?   111088           
  Misses            ?    30982           
  Partials          ?        0           
Files with missing lines Coverage Δ
...lessTests/Common/Helpers/FWDesignSystemTests.swift 100.00% <100.00%> (ø)
...Modules/OnboardingStart/OnboardingStartTests.swift 98.59% <100.00%> (ø)
...lessTests/Modules/Pincode/PinContinuityTests.swift 95.25% <100.00%> (ø)
...WalletSend/SendDependencyErrorSurfacingTests.swift 97.71% <92.59%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@takemiyamakoto

Copy link
Copy Markdown
Contributor Author

Folded into #1326, which brings every open iOS PR into master in one change, so one code-owner approval covers it. This PR's branch is kept.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant