Skip to content

feat(investment-form): make the token purchase form accessible and cover it with unit tests - #1309

Merged
nanaf6203-bit merged 1 commit into
MettaChain:mainfrom
rozemary2026-a11y:feat/investment-form-a11y-and-tests
Oct 21, 2026
Merged

nanaf6203-bit merged 1 commit into
MettaChain:mainfrom
rozemary2026-a11y:feat/investment-form-a11y-and-tests

Conversation

@rozemary2026-a11y

Copy link
Copy Markdown
Contributor

Summary

The token purchase form (PurchaseTokenForm) had no accessible name, did not mark the fields that have to be filled in, and left the user hunting for the reason a submission was refused. It also had no unit tests of its own — only a single accessibility assertion.

This PR makes the form accessible and covers it with unit tests.

Closes #1268
Closes #1271

Changes

Accessibility (#1268)

What Before After
The name of the form The form had no accessible name aria-labelledby points at the heading, so the form is announced as "Purchase Tokens"
The description of the form The property the tokens are bought for was only visible aria-describedby points at the introduction
The required fields Nothing said that a field had to be filled in The inputs carry the required attribute
The terms checkbox A wrapping label, no hint A FormLabel linked to the control, with a hint of its own
The help and the error message of a field The ids were set by hand on every field The form primitives own the ids, so the help and the message are always referenced by the field itself
A refused submission The focus stayed on the submit button and the user had to look for the reason The errors are collected in an error summary that takes the focus, and every entry in it moves the focus to the field it belongs to

The error summary follows the pattern that is used for this kind of form elsewhere: a role="alert" region named "There is a problem", which lists every refused value and links it to its field. The hidden propertyId field is listed without a link, because it has no control to focus.

The redundant second validation pass (the schema was parsed a second time inside the submit handler, after the resolver had already validated the values) is gone — the resolver is the single source of truth.

Validation messages

purchaseTokenSchema was written against the zod 3 API (invalid_type_error and errorMap), which zod 4 ignores. The form therefore showed "Invalid input: expected true" instead of "You must agree to the terms before purchasing.", and "Invalid input: expected number" instead of "Token amount must be a number.". The schema now uses the zod 4 API, so the messages reach the user. This also removes three type errors that the old API produced.

Tests

  • src/components/forms/__tests__/PurchaseTokenForm.test.tsx (new): the rendering, the validation rules (empty form, a token amount that is not a whole number, a token amount above the maximum, a max price of zero, terms that were not accepted) and the submission (a market order, a bid order, the removal of the error summary).
  • src/components/forms/__tests__/PurchaseTokenForm.a11y.test.tsx: extended with the name and the description of the form, the required fields, the error summary and the focus management. The existing assertion now reads the message the input points at with aria-describedby instead of matching any text in the document, which stays unambiguous now that the errors appear twice.

Documentation

  • docs/investment-form.md describes the fields, the validation rules, the accessibility contract and the tests, and is linked from the README.

How it was verified

npx jest src/components/forms/__tests__/PurchaseTokenForm
npm run typecheck
npx eslint src/components/forms src/lib/formSchemas.ts

The 20 tests of the two suites pass. The type check reports three findings less than the base commit, and the lint report is unchanged.

…vered

The token purchase form had no accessible name, did not mark the fields that
have to be filled in, and left the user hunting for the reason a submission
was refused. It also had no unit tests of its own.

- name the form after its heading and describe it with its introduction, so
  a screen reader announces what the form is and which property it is for
- mark the required fields with the `required` attribute and give the terms
  checkbox a hint of its own
- collect the errors of a refused submission in an error summary that takes
  the focus, and link every entry to the field it belongs to
- let the form primitives own the ids of the fields and their messages, so
  the help and the error message of a field are always referenced by the
  field itself
- use the zod 4 API in `purchaseTokenSchema`, so the validation messages
  reach the user instead of "Invalid input: expected true"
- cover the rendering, the validation rules and the submission with unit
  tests, and document the behaviour in docs/investment-form.md

Closes MettaChain#1268
Closes MettaChain#1271
@drips-wave

drips-wave Bot commented Oct 20, 2026

Copy link
Copy Markdown

@rozemary2026-a11y 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

@nanaf6203-bit nanaf6203-bit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the accessibility focus on the token purchase form plus the unit tests to back it up. Approved ✅

@nanaf6203-bit
nanaf6203-bit merged commit 5bc2bab into MettaChain:main Oct 21, 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.

Write unit tests for InvestmentForm Improve accessibility (a11y) of InvestmentForm

2 participants