Skip to content

fix(components-native): Tie Toast a11y announcement to render lifecycle#3099

Draft
edison-cy-yang wants to merge 1 commit into
masterfrom
edi-fix-toast-test-flake
Draft

fix(components-native): Tie Toast a11y announcement to render lifecycle#3099
edison-cy-yang wants to merge 1 commit into
masterfrom
edi-fix-toast-test-flake

Conversation

@edison-cy-yang
Copy link
Copy Markdown
Contributor

Why Is This Changing?

AccessibilityInfo.announceForAccessibility was being called inside the onShow
animation callback of react-native-toast-message, behind a 100ms setTimeout.
This created a two-step async chain (animation callback → timer) that was
unreliable under CI load, causing intermittent failures:

Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)
Expected: "Notify message"
Number of calls: 0

The root cause: onShow is called synchronously before React flushes the
setIsVisible(true) state update, so the timer is scheduled at an earlier,
less predictable point relative to the test's waitFor polling window. On
slower CI machines, the timer races against waitFor's timeout.

What Is Changing?

  • Toast.tsx: Moves announceForAccessibility from showToast's onShow
    callback into a useEffect inside DefaultToast. The component mounting is
    the correct signal that the toast is visible — no animation callback required.
    The 100ms delay is preserved to avoid conflicting with the entrance animation
    on device.

Consumer Impact

  • Impact: None — internal implementation change only, no public API affected.
  • Action required: None.
  • Breaking change: No.

Validation

  • I tried adding a regression test that strips onShow from Toast.show to simulate the race
    condition. It would fail on the original code (Number of calls: 0) and passes
    with the fix. It is not included in the diff since it was only used to confirm the root cause of the flake.
  • Existing tests continue to pass.

Reviewer Notes

The key insight is that tying the announcement to useEffect (React's render
lifecycle) rather than an animation callback makes RNTL's waitFor/findByText
the right tool — both respond to the same render flush, so there's no longer a
hidden async dependency that the test framework can't see.

Changes can be
tested via Pre-release


In Atlantis we use Github's built in pull request reviews.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying atlantis with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1572823
Status: ✅  Deploy successful!
Preview URL: https://8d48eea4.atlantis.pages.dev
Branch Preview URL: https://edi-fix-toast-test-flake.atlantis.pages.dev

View logs

@github-actions
Copy link
Copy Markdown

Published Pre-release for 1572823 with versions:

  - @jobber/components-native@0.101.4-edi-fix-to-1572823.15+157282326

To install the new version(s) for Mobile run:

npm install @jobber/components-native@0.101.4-edi-fix-to-1572823.15+157282326

@edison-cy-yang
Copy link
Copy Markdown
Contributor Author

I tested this change on device and somehow the voiceover isn't working

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