testing-library / testing-library/user-event
Support keyboard composition sessions
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 2.3k
- Forks
- 258
- PR merge metrics
- No merged PRs in 30d
Description
Problem description
I am testing input in a non-english keyboard environment and need to test behaviour differences between non-composed and composed keyboard input.
A reduced use-case would be some thing like this:
- User types into a
contentEditablecontainer. - When an
inputevent occurs:- Selection is saved.
- The content is syntax highlighted.
- Selection is restored.
Except, if the input isComposing, manipulation must not happen as touching the selection/DOM breaks the composition session.
On my native language keyboard layout (Icelandic), when typing á: I would first press the ´ key, then press a. On my system Chrome emits this sequence of events:
// pressing: ´
{ type: 'keydown', key: 'Dead', code: 'Quote', isComposing: false }
{ type: 'compositionstart' }
{ type: 'beforeinput', isComposing: true }
{ type: 'compositionupdate' }
{ type: 'input', isComposing: true } // content has become ´
{ type: 'selectionchange' }
{ type: 'keyup', key: 'Dead', code: 'Quote', isComposing: true }
// pressing: a
{ type: 'keydown', key: 'á', code: 'KeyA', isComposing: true }
{ type: 'beforeinput', isComposing: true }
{ type: 'compositionupdate' }
{ type: 'input', isComposing: true } // content has changed to á
{ type: 'compositionend' }
{ type: 'selectionchange' }
{ type: 'keyup', key: 'a', code: 'KeyA', isComposing: false}
If, however, the selection or DOM is manipulated during the sequence, the composition session terminates prematurely and the second key is sent normally and content ends up as ´a.
Suggested solution
It would obviously be great to be able to do userEvent.type('óráð') and have the accented characters broken down and sent in parts as they would be typed normally. However, a lower level solution for this would probably be sufficient for most users who need things this nuanced. The fact that ´ is sent as { key: 'Dead', code: 'Quote' } also causes complications with keyboard maps.
In my case it would be a sufficient interface to be able to tag a key as a "composition starter" under a custom keyboardMap and then call keyboard('{Quote}{o}{r}{Quote}{a}{ð}')
Of course, this still requires data on what following characters may be composed and an implementation of a composition session which interacts with mutations in DOM and selections. But without them, composed character input is pretty much impossible to test without a significant amount of code. It would be a much easier job to write around this using fireEvent if there was access to lower level methods that insert/delete characters.
Additional context
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue names userEvent.type, keyboard, custom keyboardMap, and fireEvent as relevant entry points; start by tracing those APIs alongside the compositionstart, beforeinput, input, and compositionend sequence described. Done means tests can represent a composition session without DOM or selection manipulation terminating it, including the proposed lower-level keyboard path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- frontend, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100