testing-library / testing-library/user-event

Support keyboard composition sessions

Open
#1,097 4 comments 5 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
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:

  1. User types into a contentEditable container.
  2. When an input event occurs:
    1. Selection is saved.
    2. The content is syntax highlighted.
    3. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.