Skip to content

fix(AddressDisplay, e2e): complete clipboard a11y and harden the wallet E2E suite (#586, #571) - #642

Merged
Just-Bamford merged 1 commit into
Sorokit:mainfrom
Sam-Rytech:fix/571-586-clipboard-a11y-e2e-hardening
Sep 1, 2026
Merged

fix(AddressDisplay, e2e): complete clipboard a11y and harden the wallet E2E suite (#586, #571)#642
Just-Bamford merged 1 commit into
Sorokit:mainfrom
Sam-Rytech:fix/571-586-clipboard-a11y-e2e-hardening

Conversation

@Sam-Rytech

Copy link
Copy Markdown
Contributor

Summary

This PR closes the remaining gaps in the clipboard-copy behavior of AddressDisplay (#586) and in the wallet-flow E2E suite (#571).

The headline fixes for both issues are in place on mainb0c0165 added the execCommand fallback and the copy button's aria-label, and 59bb51f (#637) added Playwright, playwright.config.ts, e2e/wallet-flow.spec.ts, and the test:e2e script. Working through both issues end-to-end surfaced five defects those changes left behind, all inside the same code paths. This PR fixes them.

#586 — AddressDisplay

1. The reset timer leaked past unmount

clearResetTimer() was only called at the start of the next copy. Unmounting inside the 2s "Copied!" window (or the 1.5s failure window) left a pending setTimeout that fired setCopied(false) on an unmounted component.

Added a useEffect cleanup that clears the pending timeout on unmount.

2. The copy result was silent for screen readers

This is the other half of the issue's accessibility complaint. The aria-label fix means the button is now labelled, but the copy result was still conveyed only by an icon swap and a mutating aria-label — neither of which is reliably announced by assistive technology. So the original complaint, "users get no feedback that the copy failed", still held for screen-reader users in exactly the non-secure contexts the issue describes.

Added an sr-only live region that announces both outcomes:

<span role="status" aria-live="polite" className="sr-only">
  {copyFailed ? "Failed to copy address" : copied ? "Address copied to clipboard" : ""}
</span>

This mirrors the pattern already used in NetworkSwitcher.tsx:479, so it stays consistent with the codebase.

3. The execCommand fallback had two side effects

  • It raised the on-screen keyboard on mobile. The throwaway <textarea> is focused via .select() without being readOnly, so mobile browsers pop the keyboard for a fraction of a second. Now set readOnly (and aria-hidden, since it is never meant to be perceivable).
  • It destroyed the user's existing selection. textarea.select() replaces whatever the user currently has highlighted on the page, and nothing put it back. The prior Range is now captured before the copy and restored in the finally block.

#571 — E2E suite

4. e2e/ and playwright.config.ts were never type-checked

tsconfig.app.json includes only src, and tsconfig.node.json only vite.config.ts and vite.lib.config.ts. Neither covers the E2E directory, so npm run typecheck silently skipped the entire Playwright suite — a type error or a renamed selector API in a spec would only surface when the slow Playwright job ran in CI, if at all.

Added playwright.config.ts, e2e/**/*.ts, and vitest.config.ts to tsconfig.node.json's include.

5. Four acceptance criteria were asserted as one flat block

The spec covers four distinct behaviors from the issue, but a failure at "connect wallet" aborted the test and told you nothing about whether history rendering and send-payment still worked.

Wrapped each behavior in test.step(), so the reporter attributes a failure to the specific behavior that broke. This keeps one browser session and one continuous user journey — the steps are ordered and stateful by design — while making the report per-criterion.

Testing

Added 6 unit tests to src/components/AddressDisplay.test.tsx:

  • live region renders empty before any copy attempt, with aria-live="polite"
  • announces "Address copied to clipboard" on success
  • announces "Failed to copy address" when both copy paths fail
  • the pending reset timeout is cleared on unmount
  • the temporary textarea is readOnly during the copy and is removed afterwards
  • a pre-existing document selection survives the execCommand fallback

No existing test was modified, and no production behavior changed beyond the five fixes above.

Closes #586
Closes #571

…et E2E suite

Closes the gaps left by the initial fixes for Sorokit#586 (b0c0165) and Sorokit#571 (59bb51f).

AddressDisplay (Sorokit#586):
- Clear the copied/failed reset timeout on unmount. clearResetTimer() only ran
  at the start of the next copy, so unmounting inside the reset window left a
  pending timeout that fired setState on an unmounted component.
- Announce the copy result through an sr-only role="status" live region. The
  result was conveyed only by an icon swap and a mutating aria-label, neither
  of which announces reliably, so "the copy silently did nothing" still held
  for screen-reader users - the exact complaint the issue raised. Mirrors the
  live region already used in NetworkSwitcher.tsx.
- Harden the execCommand fallback: mark the throwaway textarea readOnly so
  mobile browsers do not raise the on-screen keyboard, and capture/restore the
  user's existing selection, which textarea.select() otherwise destroys.

E2E suite (Sorokit#571):
- Add playwright.config.ts and e2e/**/*.ts to tsconfig.node.json. Neither
  tsconfig covered the E2E directory, so npm run typecheck skipped the whole
  Playwright suite and breakage surfaced only in the slow CI job.
- Wrap each of the four acceptance-criteria behaviors in test.step() so a
  failure is attributed to the specific behavior that broke instead of
  aborting one flat block.

Tests: 6 new cases covering the announcements, the unmount cleanup, and the
fallback's readOnly/selection-restore behavior. AddressDisplay.test.tsx is
30 passed. Typecheck reports the same 3 pre-existing vite-config errors as
main - no new ones. eslint clean on all changed files.

Closes Sorokit#586
Closes Sorokit#571
@drips-wave

drips-wave Bot commented Aug 30, 2026

Copy link
Copy Markdown

@Sam-Rytech Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@Just-Bamford
Just-Bamford merged commit 07aa945 into Sorokit:main Sep 1, 2026
2 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants