Package limn.testing.a11y


@NullMarked package limn.testing.a11y
What a widget of each accessibility shape owes a screen reader, as named cases a test runs.

Each shape has a contract and a subject: ToggleContract over a ToggleSubject, ValueContract over a ValueSubject, and the same for text, rows, grids, menus, a leaf action and a popup owner. The subject builds the widget fresh for every case and answers through the widget's API what the published tree cannot say; the contract's cases returns ContractCases, each a name and a check, which a test turns into its framework's dynamic tests in one line. The toolkit's own components are held to these same contracts.

  • Class
    Description
    One named check of a per-shape contract: a rule the shape holds every widget of that shape to, with the decision it comes from in its name, run over a fresh widget each time.
    The check; it throws AssertionError when the rule does not hold.
    What every widget of the GRID shape owes a reader beyond what its rows do, as named cases over a GridSubject: the container is of the GRID shape and carries a TableFacet whose column count is the header's; the four invariants hold, unfocused and focused; the header cells sit at row −1, one per column, in order, each carrying the direction its column is sorted in and PRESS exactly where the column sorts; PRESS on a sortable header sorts by it and the facet says so, and a second press changes the direction the facet reports; a data cell is a CELL at a row and a column inside the counts; FOCUS on a cell that offers it moves the cursor onto that cell, which is then the one active node, and selects nothing; a header cell keeps its id across a sort.
    A widget of the GRID shape as GridContract drives it: a table or a calendar, whose container carries a TableFacet, whose header cells sit at row −1 and whose data cells carry their place.
    What every widget of the LEAF_ACTION shape owes a reader, as named cases over a LeafActionSubject: it is a leaf that offers PRESS; the verb reaches the widget's own handler exactly once; a disabled leaf withdraws the verb and a press reaches nothing; and the node keeps its id across a press.
    A widget of the LEAF_ACTION shape as the leaf contract sees it: a pressable leaf the contract can build fresh and count the presses of through the widget's own handler.
    What every widget of the MENU shape owes a reader, as named cases over a MenuSubject: a menu bar and a popup menu under the same rules, which until this were tested in each widget's own file.
    A widget of the MENU shape as MenuContract drives it: a menu bar, whose rows are its titles, or a popup menu, whose rows are the root column's.
    What a row is, which decides the verbs the contract expects on it.
    What every widget of the POPUP_OWNER shape owes a reader, as named cases over a PopupOwnerSubject: it says HAS_POPUP before anything has happened (a disclosure, which opens in place, says it nowhere); its open state is the facet's and the API's; closed, it offers EXPAND and not COLLAPSE; EXPAND opens it and something appears in the tree, described where it lives; open, it never offers EXPAND, and offers COLLAPSE unless a layer above owns the input, in which case it offers nothing; a second EXPAND changes nothing; closing through the API brings EXPAND back; and the node keeps its id across the round trip.
    A widget of the POPUP_OWNER shape as the popup-owner contract sees it: something that opens a popup, which the contract can build fresh, closed, and read the open state of through the widget's own API.
    What every widget of the ROWS shape owes a reader, as named cases over a RowsSubject.
    A widget of the ROWS shape as the rows contract sees it: something that publishes a selection and members of it, which the contract can build fresh, read the selection and the cursor of through the widget's own API, and ask three things about that the published tree cannot say.
    How the widget reaches a row outside its box.
    What every widget of the TEXT shape owes a reader, as named cases over a TextSubject: the facet's string is the API's; SET_TEXT with a text replaces it and with anything else changes nothing; SET_CARET with a collapsed range moves the caret and SET_SELECTION with a range selects it, each read back off the facet; and the node keeps its id as the text changes.
    A widget of the TEXT shape as the text contract sees it: an editable text the contract can build fresh, holding a short string, and read back through the widget's own API.
    What every widget of the TOGGLE shape owes a reader, as named cases over a ToggleSubject: the facet is the API's state and the verb is offered exactly where the flip is; TOGGLE flips it, heard once by the widget's own listener and announced, where announced, from the user, and flips it back; a disabled toggle withdraws the verb and moves for nothing; and the node keeps its id as it flips.
    A widget of the TOGGLE shape as the toggle contract sees it: something that publishes one node that is on or off, which the contract can build fresh, read the state of through the widget's own API, and ask whether the flip is on offer.
    What every widget of the VALUE shape owes a reader, as named cases over a ValueSubject: the number, its bounds and its step are the API's; INCREMENT and DECREMENT move by the step the facet names, clamped at the bounds, each heard once by the widget's own listener and announced, where announced, from the user; SET_VALUE takes a finite number and moves nothing for anything else; a read-only value offers no verb and moves for none; a disabled one withdraws its verbs and moves for none; and the node keeps its id as the number moves.
    A widget of the VALUE shape as the value contract sees it: something that publishes one number in a range, which the contract can build fresh, read the number of through the widget's own API, and ask whether the number can be set at all.