Skip to content

test: add unit tests for keyboard shortcut hook confirming it does not fire when focus is in a form element (#626) - #711

Closed
abimbolaalabi wants to merge 173 commits into
accesslayerorg:mainfrom
abimbolaalabi:fix/issue-626-keyboard-shortcut-form-tests
Closed

test: add unit tests for keyboard shortcut hook confirming it does not fire when focus is in a form element (#626)#711
abimbolaalabi wants to merge 173 commits into
accesslayerorg:mainfrom
abimbolaalabi:fix/issue-626-keyboard-shortcut-form-tests

Conversation

@abimbolaalabi

Copy link
Copy Markdown

Overview

This PR adds unit tests for the \T\ keyboard shortcut hook in \LandingPage, confirming the handler correctly fires when focus is on the document body and is suppressed when focus is on form elements (\input, \ extarea, \select).

Related Issue

Closes #626

Changes

Keyboard Shortcut Tests

  • [ADD] \src/pages/tests/LandingPage.tradeShortcut.test.tsx\
    • Simulates \T\ keydown with focus on \document.body\ and asserts the handler fires (dialog opens)
    • Simulates \T\ keydown with focus on <input>\ and asserts the handler does not fire
    • Simulates \T\ keydown with focus on <textarea>\ and asserts the handler does not fire
    • Simulates \T\ keydown with focus on <select>\ and asserts the handler does not fire

Verification Results

\
pnpm vitest run src/pages/tests/LandingPage.tradeShortcut.test.tsx
✅ 4/4 passed
\\

Acceptance Criteria Status
Handler fires when focus is on the document body ✅ Passed
Handler suppressed when focus is on an input ✅ Passed
Handler suppressed when focus is on a textarea ✅ Passed
Handler suppressed when focus is on a select ✅ Passed

T-kesh and others added 30 commits June 23, 2026 23:26
- Rewrite .env.example with a one-line description for every variable
  and remove duplicate entries; group into required vs optional
- Add an 'Environment variables' section to CONTRIBUTING.md covering
  required vs optional vars and where to source testnet RPC URLs
Verifies that the GitHub and Telegram community links render with
the correct href values, open in a new tab, and carry the expected
rel="noopener noreferrer" attribute so a future refactor cannot
silently break these URLs.

Closes accesslayerorg#428
…on-test

 Add integration tests for MarketingPage community links
…-add-helper-for-formatting-key-price-display-in-xlm-with-correct-decimal-places

feat: accesslayerorg#420 Add helper for formatting key price display in XLM with co…
- Add computePriceChange(current: bigint, previous: bigint) in src/utils/priceChange.utils.ts
- Returns { percent: number, direction: 'up' | 'down' | 'flat' }
- Returns flat when previous is zero or current equals previous
- 7 unit tests covering: price up, price down, no change, zero previous, both zero

Closes accesslayerorg#429
…rorg#444 accesslayerorg#445

- Add copy-to-clipboard button to ConnectWalletButton with 2s feedback and screen-reader announcement (accesslayerorg#442)
- Add src/lib/queryKeys.ts factory-style React Query key constants with unit tests (accesslayerorg#443)
- Add LandingPage.holdings.test.tsx integration tests asserting portfolio totals and per-holding values (accesslayerorg#444)
- Add docs/api-layer.md documenting service conventions, error handling, and a worked end-to-end example (accesslayerorg#445)
…cesslayerorg#437

- Add ledgerToTimestamp helper for converting Stellar ledger sequence numbers to estimated timestamps
- Add transaction status badge legend tooltip for user-friendly status explanations
- Add creator card keyboard shortcut hint (press 'B' to quick buy) with desktop-only display
- Add integration test for creator card price update on snapshot data change
…elper-tx-tooltip-keyboard-shortcut-price-test

Add ledger timestamp helper, transaction status tooltip, keyboard shortcuts, and price update tests
…-address

feat: add shortenAddress helper for wallet address display — Close accesslayerorg#423
Closes accesslayerorg#438 by formatting counts under 1K as plain strings and larger values with one-decimal K/M suffixes, with unit tests for each range and boundary values.

Co-authored-by: Cursor <cursoragent@cursor.com>
Documents the standard pattern contributors should follow when writing
new useQuery and useMutation hooks — covering the onError callback
convention, when to show a toast vs inline error vs error boundary,
how to distinguish 4xx client errors from 5xx server errors and network
failures, and a worked example hook that handles all three cases.

Closes accesslayerorg#460
…-holder-count

Add formatHolderCount helper for compact holder display.
closes accesslayerorg#460 - docs: add error handling guide for React Query hooks
Closes accesslayerorg#424

Add a React error boundary scoped to creator detail pages so a render
error shows a fallback UI instead of crashing the whole app to a blank
screen. Follows the existing SectionErrorBoundary class pattern.

- Fallback shows a short message and a "Back to creators" link (/creators)
- Logs the error to console only in development (import.meta.env.DEV)
- Add tests covering normal render, fallback on error, and the list link
…d layout

- Add new CreatorCardSkeleton component that mirrors CreatorCard's
  dimensions (avatar, name + verified/change/supply/recent-activity
  badges, handle, bio, sparkline placeholder, 3 mini stat chips, 3
  meta rows, social links, action row, helper text) so it acts as a
  layout-stable placeholder while the creator list is fetching.
- Use the existing dark-theme .skeleton-shimmer animation and
  CREATOR_CARD_MEDIA_RADIUS_CLASS token so the skeleton visually
  matches the rest of the marketplace.
- Respect prefers-reduced-motion via the shared CSS rule and a
  disableShimmer prop, matching CreatorSkeleton's API.
- Add a CreatorCardGridSkeleton helper that defaults to count = 6
  to satisfy the acceptance criterion.
- Wire CreatorCardGridSkeleton into LandingPage's initial-loading
  branch so the marketplace shows 6 stable skeleton cards instead of
  the generic grid skeleton.
- Cover the new component with vitest tests asserting role/aria
  coverage, 6-by-default grid, disableShimmer propagation, className
  merging, and shimmer-vs-static block toggling.
Closes accesslayerorg#426.

Adds docs/adding-page-routes.md covering where routes are registered in src/App.tsx, the file naming convention for page components, the recommended pattern for auth-protected routes (with a RequireAuth wrapper example), and a four-step worked example adding a public AboutPage at /about. Adds a one-line pointer in CONTRIBUTING.md under Frontend conventions so contributors can find the guide.
…ice-change

feat: add computePriceChange helper for key price percentage change
…imestamp-test

test: add integration test for ledgerToTimestamp (accesslayerorg#461)
…rage-preferences

feat: add generic localStorage preference helpers (accesslayerorg#458)
…-component

Feat/error boundary component
…e-contributing-folder-structure

docs: update CONTRIBUTING.md with folder structure and conventions
Chucks1093 and others added 27 commits July 27, 2026 09:00
…tion/test

test: add integration test for trade panel submit button disabled while transaction is in flight (accesslayerorg#622)
…onnectionLogger (accesslayerorg#599)

Adds a debug-level structured log emitted the moment a wallet
connection succeeds, so developers can trace wallet session activity
without relying on browser extension logs.

- New useWalletConnectionLogger hook watches wagmi's useAccount state
  and logs truncated_address (first 4 + last 4), connection_method
  (from the active connector), and connected_at once per connection
  event, deduped on the connected address so re-renders and cache
  updates never re-log.
- Mounted once at the Web3Provider boundary so the log fires exactly
  once app-wide regardless of which UI (connect button, reconnect
  banner) initiated the connection.
- Suppressed in the test environment by default, matching the
  cache-invalidation logging convention already used in useWallet.ts.
- Full wallet address is never logged under any field name.
…eview fetch failure with creator and quantity context
…og-for-trade-panel-price-preview-fetch-failure-with-creator-and-quantity-context

Add structured log for trade panel price preview fetch failure
…tion-log

feat(observability): log successful wallet connections via useWalletConnectionLogger (accesslayerorg#599)
…60-accesslayer

test(wallet): cover creator 404, activity ordering, holdings total updates, and disconnect session logging
…verage

- accesslayerorg#639: integration test for creator list page/scroll restoration after
  navigating to a profile and back. Also fixes a real bug found while
  writing it: visibleCount (infinite-scroll load-more progress) had no
  sessionStorage persistence, and two mount-time effects unconditionally
  reset page/visibleCount to defaults on every mount, clobbering the
  restored values. Both are now guarded to skip their first run.
- accesslayerorg#642: end-to-end buy flow test (quantity input -> success toast ->
  holdings cache update), mirroring the existing sell-flow (accesslayerorg#644)
  pattern. Trading in this app is scoped to a single featured-creator
  panel with no per-card or profile-page trade UI, so the test targets
  the real buy surface instead of the issue's literal "profile page"
  wording.
- accesslayerorg#643: coverage for CreatorCardSkeleton's no-layout-shift properties
  (pulse class on every region, no real content rendered, root sizing
  constraints) against its current design, which already exceeds the
  issue's minimal 4-region ask (it mirrors all ~10+ CreatorCard regions,
  per accesslayerorg#421). Redesigning down to 4 regions would regress the accesslayerorg#421 suite.
- accesslayerorg#646: extends the existing holdings empty-state coverage (accesslayerorg#539) with
  the one assertion it didn't have: skeleton placeholders visible during
  loading, not just "empty state absent".

closes accesslayerorg#639
closes accesslayerorg#642
closes accesslayerorg#643
closes accesslayerorg#646
…aniel/feat/623-empty-state-unit-tests

feat(components): add unit tests and CTA/message support for EmptySta…
…alidation

- Add integration test for creator discovery list card rendering
- Add contributing guide for new pages and data fetching
- Add structured logging for failed wallet transactions
- Add unit tests for trade panel quantity input validation
…roll-restore-buy-flow-skeleton-empty-state-639-642-643-646

Add scroll/page restore, buy flow, skeleton, and empty-state test coverage
…ue-batch-1

feat: Add integration tests, contributing guide, transaction logs, and quantity validation
…e-integration-629

test: add creator profile page integration test
…yerorg#677)

Adds the supporting infrastructure for a paginated wallet activity feed
and the integration test that verifies it loads older trades as the user
scrolls.

* src/services/walletActivity.service.ts (NEW): exposes
  fetchWalletActivityPage so React Query useInfiniteQuery can fetch
  per-page activity for a wallet address; cacheManager-backed.
* src/hooks/useWallet.ts (MODIFIED): useWalletActivity now uses
  useInfiniteQuery with initialPageParam=1 and getNextPageParam wired
  to lastPage.nextPage. Query key (queryKeys.wallet.activity(address))
  is unchanged so the existing queryKeyIntegration.test.tsx continues to
  pass.
* src/components/common/WalletActivityFeed.tsx (NEW): aggregates
  useInfiniteQuery pages, deduplicates trades by id, renders existing
  TransactionHistory with the accumulated list, and drives a sentinel
  via useInfiniteScroll to trigger fetchNextPage when the bottom of the
  feed scrolls into view.
* src/components/common/__tests__/WalletActivityFeed.infiniteScroll.
  integration.test.tsx (NEW): four integration tests covering acceptance
  criteria - page 1 visible on initial load, scroll triggers next page
  fetch, page 2 appended below page 1, no duplicate trades when pages
  overlap.
Implements accesslayerorg#686. Two of the four assigned issues describe components that
do not exist in this repository — see the note below and the PR body.

The nav bar's CTA was a bare "Connect Wallet" link that stayed there
whether or not a wallet was connected, so there was no persistent
indication of which account or which network was active.

WalletStatusChip replaces it:

- Truncated address via the existing shortenAddress, which already
  formats first-4/last-4 exactly as the issue specifies.
- Network badge, green for mainnet and yellow for testnet.
- Dropdown with the full address, copy, and disconnect.
- The same Connect link rendered from inside the component when no wallet
  is connected, so the nav slot is never empty and Header does not need to
  branch.

The chip reads useAccount and useChainId directly rather than taking
props. Passing the address down would leave it stale until whatever owns
that prop happened to re-render; reading wagmi state means a network
switch in the extension updates the badge immediately, which is one of
the acceptance criteria.

describeNetwork is a separate module so the classification is testable
without rendering. Anything that is not Ethereum mainnet is treated as a
testnet, and an unrecognised chain gets its own "unsupported" state
rather than being shown as a testnet — labelling a chain the app cannot
talk to as "testnet" implies the app works there. That default also means
a chain added to supportedChains later shows yellow until someone
deliberately promotes it, instead of silently rendering a green
"you are on mainnet".

Copy keeps the menu open so the copied-state tick is visible, and reverts
after 2s so the confirmation is unambiguous rather than permanent.

Verified: tsc -b --noEmit clean, 7 tests passing.

Not implemented — the underlying features are absent:

- accesslayerorg#687 asks for an optimistic update in a useFollowCreator mutation.
  There is no follow feature anywhere in src: no hook, no service call,
  no isFollowing state, no button.
- accesslayerorg#689 asks for tests of a transaction history filter with a type
  dropdown, date range and Reset. TransactionHistory.tsx renders a list
  from props and has no filter controls at all.

Both need the feature built first, which is a different change from the
one they describe.
…ptimistic-skeletons-tests

feat(nav): wallet status chip with address and network badge
… sell validation tests, trade-shortcut unmount test

Fixes four Stellar Wave issues in one batch:

accesslayerorg#684 test: bonding curve price preview component
- computeBuyCost() (bonding curve total-cost-for-N-keys math) already had
  full unit test coverage as a pure function, but was never actually wired
  into any React component -- TradeDialog's buy side only ever showed a
  flat per-unit price, not a quantity-aware total. Added a new, small,
  standalone BuyPriceEstimate component that uses computeBuyCost to render
  the real total XLM cost for the entered quantity, with a debounced
  "Calculating price..." loading state and no buy button at quantity 0.
  New BuyPriceEstimate.test.tsx covers quantity 1/0/100, price updates on
  quantity change, the loading state, and asserts computeBuyCost is called
  with the correct (currentSupply, quantity, params) arguments (mocked via
  vi.spyOn on the module namespace).
- Scoping note: this does not modify the existing, heavily-tested
  TradeDialog/LandingPage buy flow (~30 existing test files depend on its
  current behavior) -- wiring BuyPriceEstimate into that live flow is a
  reasonable follow-up once it can be done with test coverage run to
  confirm nothing regresses.

accesslayerorg#685 feat: infinite scroll for the creator key marketplace
- The marketplace listing (LandingPage) already had an "infinite scroll"
  mode, but it was client-side only: courseService.getCourses() fetches
  every creator up front and the "infinite scroll" just reveals more of
  the already-fully-loaded array -- it doesn't reduce initial page weight
  at all, which is exactly the problem the issue describes.
- Added courseService.getCoursesPage(page, params): a real cursor(page-
  number)-paginated fetch reading has_more/hasMore from the response
  (falling back to "page was full" when the backend doesn't send it).
- Added useInfiniteCreatorMarketplace(): wraps getCoursesPage in
  @tanstack/react-query's useInfiniteQuery (initialPageParam/
  getNextPageParam), de-duplicating creators across pages by id.
- Added CreatorMarketplaceInfiniteList: wires the existing
  useInfiniteScroll (IntersectionObserver) hook's sentinel to
  fetchNextPage, shows the existing CreatorGridSkeleton while the first
  page and subsequent pages load, and stops rendering the sentinel once
  hasMore is false.
- New tests for both the hook (first-page-only fetch, next-page fetch +
  de-dup, stops at hasMore: false, params passed through) and the
  component (initial skeleton, rendering, next-page skeleton, sentinel
  wiring, disabling the observer while a fetch is in flight).
- Scoping note: same as accesslayerorg#684 -- built and tested as a new, standalone unit
  rather than swapping LandingPage's existing pagination live, to avoid
  risking its ~30 existing test files without being able to run them.

accesslayerorg#657 test: sell quantity exceeds-holding validation
- TradeDialog's validationError logic already correctly rejects a sell
  quantity greater than availableHoldings, and already has a distinct
  "Amount must be greater than zero" message for quantity 0 -- this was a
  pure test-writing task. New TradeDialog.sellQuantityValidation.test.tsx
  covers: exceeds-holding error shown/cleared, distinct zero-quantity
  error, quantity equal to holding accepted, quantity 1 accepted, and the
  confirm button disabled while the error is present.

accesslayerorg#654 test: T trade-shortcut listener cleanup on unmount
- The keydown effect that opens the trade dialog on "T" (LandingPage --
  its own comment already calls this "the creator profile page") already
  correctly returns a cleanup function removing the listener. New
  LandingPage.tradeShortcutUnmount.integration.test.tsx confirms the full
  cycle end-to-end: T opens the dialog while mounted, unmounting (in place
  of a stand-in "creator discovery list" page) makes T inert with no
  console errors, and remounting makes T work again.

No install/build/test run was performed for this PR (current task scope).
Every new hook/component was written against this repo's real, existing
conventions (useInfiniteScroll, CreatorGridSkeleton, the useInfiniteQuery/
QueryClientProvider test pattern from tradeCacheInvalidation.test.ts, the
TradeDialog.clamp.integration.test.tsx render helper, and the LandingPage
mock block from LandingPage.keyboard.test.tsx) to minimize the risk of
something not compiling/working as written.

Closes accesslayerorg#684
Closes accesslayerorg#685
Closes accesslayerorg#657
Closes accesslayerorg#654
…ave-batch-684-685-657-654

feat(marketplace),test: bonding curve price preview, infinite scroll, sell validation tests, trade-shortcut unmount test
…ponent-unit-tests-628

feat: add toast component unit tests
…llet-activity-infinite-scroll

feat(wallet): add infinite-scroll activity feed + integration test (accesslayerorg#677)
@netlify

netlify Bot commented Jul 28, 2026

Copy link
Copy Markdown

Deploy Preview for accesslayer ready!

Name Link
🔨 Latest commit 4b8096b
🔍 Latest deploy log https://app.netlify.com/projects/accesslayer/deploys/6a688db3c0ea650008116a09
😎 Deploy Preview https://deploy-preview-711--accesslayer.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions

Copy link
Copy Markdown

👋 Hey @abimbolaalabi, thanks for your contribution!

This PR is targeting main directly. We use main for stable releases only — all contributions should be opened against the dev branch instead.

Please close this PR and reopen it with dev as the base branch. If you're unsure how to do that, you can change the base branch using the Edit button at the top of this PR page.

Closing this PR automatically. See you in dev! 🚀

@github-actions github-actions Bot closed this Jul 28, 2026
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.