Skip to content

test: cover the two keyboard paths we hand-wrote - #522

Merged
IgorShevchik merged 1 commit into
mainfrom
test/keyboard-interaction
Aug 31, 2026
Merged

test: cover the two keyboard paths we hand-wrote#522
IgorShevchik merged 1 commit into
mainfrom
test/keyboard-interaction

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Linked issue

Refs #86 — its last open workstream.

Type of change

  • Documentation (updates to the documentation or readme)
  • Bug fix (a non-breaking change that fixes an issue)
  • Enhancement (improving an existing functionality)
  • New feature (a non-breaking change that adds functionality)
  • Chore (updates to the build process or auxiliary tools and libraries)
  • Revert (undoing a merged change — retitle this PR revert(Scope): ...)
  • Breaking change (fix or feature that would cause existing functionality to change)

No src/ changes — two new spec files.

The workstream is much smaller than it reads

#86 describes it as "no arrow-key/Home/End/Escape tests for menus, tabs, accordion, palette, pagination". That sounds like a large gap. It is not one: all of that is reka-ui's roving focus and typeahead, and a test here would be testing reka-ui.

Measured instead — five places in src/runtime handle a key themselves:

spec
composables/defineShortcuts.ts ✅ has one
components/ChatPrompt.vue ✅ has one
composables/useEditorMenu.ts ✅ has one
components/CommandPalette.vue none
components/FileUpload.vue none

Those two are what this covers, and both are things a keyboard user meets directly.

CommandPalette — Backspace means two different things

With text typed it deletes a character, the ordinary meaning. With the field empty it steps back out of a group the user drilled into — the only keyboard way out of one. Confusing them is immediately visible: hitting backspace to fix a typo would throw you out of the group instead.

function onBackspace() {
  if (!searchTerm.value) {
    navigateBack()
  }
}

The second case is asserted through the placeholder, not the visible items. With text in the field the root group's items are filtered out anyway, so "Pictures is not shown" holds whether or not we stepped back — the first draft asserted exactly that and could not fail. Removing the empty-search guard left it green. The placeholder comes off the group on the history stack, which the filter does not touch.

FileUpload — a dropzone is not a native control

Everything a keyboard user needs is hand-written on it, and none of it was exercised:

  • tabindex to reach it
  • role="button" to announce it
  • Enter and Space to activate it
  • @keydown.space.prevent, so Space does not scroll the page out from under them between keydown and keyup

All four are gated on interactive and disabled.

Mutation-checked, branch by branch

mutation reddens
drop the empty-search guard leaves the group alone while there is text to delete
remove history.pop() steps back out of a group when the field is empty
drop @keydown.space.prevent swallows the Space keydown so the page does not scroll
narrow keyup.enter.space to Enter opens the file dialog on Space
pin tabindex at 0 both when it cannot be used cases
drop the interactive/disabled guards both when it cannot be used cases

One note worth carrying to other specs: vi.restoreAllMocks() runs after each FileUpload case. spyOn on a prototype method hands back the existing spy when one is already installed, so without it the click count carries between cases and "was not called" passes or fails on another test's clicks.

Gate

lint, typecheck, 340 test files / 7694 tests.

Checklist

  • I have linked an issue or discussion.
  • I have updated the documentation accordingly.

Generated by Claude Code

#86's last open workstream. It reads as "no arrow-key/Home/End/Escape tests for
menus, tabs, accordion, palette, pagination", which sounds like a large gap and
is not one: all of that is reka-ui's roving focus and typeahead, and testing it
here would be testing reka-ui.

Measured instead: five places in `src/runtime` handle a key themselves.
`defineShortcuts`, `ChatPrompt` and `useEditorMenu` already have specs. Two did
not, and both are things a keyboard user meets directly.

`CommandPalette` — Backspace means two different things depending on the caret.
With text typed it deletes a character; with the field empty it steps back out
of a group the user drilled into, which is the only keyboard way out of one.
Confusing them is immediately visible: hitting backspace to fix a typo would
throw you out of the group.

The second case is asserted through the placeholder rather than the visible
items. With text in the field the root group's items are filtered out anyway,
so "Pictures is not shown" holds whether or not we stepped back — the first
draft asserted exactly that and could not fail. The placeholder comes off the
group on the history stack, which the filter does not touch.

`FileUpload` — a drop target is not a native control, so everything a keyboard
user needs is hand-written: a `tabindex` to reach it, `role="button"` to
announce it, Enter and Space to activate it, and `@keydown.space.prevent` so
Space does not scroll the page out from under them between keydown and keyup.
All four are gated on `interactive` and `disabled`, and none was exercised.

Both specs are mutation-checked branch by branch — dropping the empty-search
guard, removing `history.pop()`, dropping `keydown.space.prevent`, narrowing
`keyup.enter.space` to Enter alone, pinning `tabindex` at 0, and removing the
`interactive`/`disabled` guards each redden a named test.

`vi.restoreAllMocks()` runs after each `FileUpload` case: `spyOn` on a
prototype method hands back the existing spy when one is already installed, so
without it the click count carries between cases and "was not called" passes or
fails on another test's clicks.

Refs #86
@IgorShevchik
IgorShevchik merged commit e731479 into main Aug 31, 2026
2 checks passed
@IgorShevchik
IgorShevchik deleted the test/keyboard-interaction branch August 31, 2026 13:58
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.

2 participants