Upgrading @testing-library/user-event 12 to 13
Breaking12.8.3 → 13.5.0Breaking3Deprecated1New6Fixed26Other1
BreakingUpgrade verdict
3 breaking changes.
In plain terms
- Typing a curly brace or square bracket now has special meaning, so literal braces and brackets need escaping.
- If you do not pass a delay, type no longer returns something you can await.
- The type helper works differently inside now, so code that depended on quirks of the old version may stop working.
- A keyboard helper called specialCharMap is now marked as deprecated, so it should be avoided in new code.
Must act 4 items need code or config changes
What you must change
Breaking3
userEvent.type now treats { and [ as special characters.
userEvent.typeuserEvent.type returns no Promise when called without delay.
userEvent.typeRewrites userEvent.type with an implementation shared with userEvent.keyboard, which may break code relying on undocumented behavior.
userEvent.typeuserEvent.keyboardDeprecations to plan for
Deprecated1
Deprecates
specialCharMap in the keyboard module.specialCharMapAPI changes
Generated by DepDelta from published .d.ts files. Not mixed with prose notes.
- added:
interface Element - added:
property Element[initial]?: string - added:
property Element[onBlur]?: EventListener
- added:
function getWindowFromNode(node: Node): Window
- added:
function blur(element: Element): void
- added:
function clear(element: Element): void
- added:
function click(element: Element, init?: MouseEventInit, { skipHover, clickCount, skipPointerEventsCheck }?: clickOptions & PointerOptions): void - added:
function dblClick(element: Element, init?: MouseEventInit, { skipPointerEventsCheck }?: clickOptions & PointerOptions): void - added:
interface clickOptions - added:
property clickOptions.clickCount?: number - added:
property clickOptions.skipHover?: boolean
- added:
declare module '@testing-library/dom/dist/helpers'
- added:
function focus(element: Element): void
- added:
function hover(element: Element, init?: MouseEventInit, { skipPointerEventsCheck }?: PointerOptions): void - added:
function unhover(element: Element, init?: MouseEventInit, { skipPointerEventsCheck }?: PointerOptions): void
- added:
const userEvent: { click: typeof click; dblClick: typeof dblClick; type: typeof type; clear: typeof clear; tab: typeof tab; hover: typeof hover; unhover: typeof unhover; upload… - added:
default userEvent - added:
export { keyboardKey } from './keyboard' - added:
export { specialCharMap as specialChars }
- added:
function getKeyEventProps(keyDef: keyboardKey, state: keyboardState): { key: string | undefined; code: string | undefined; altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean; keyCode: number | undefined } - added:
function getMouseEventProps(state: keyboardState): { altKey: boolean; ctrlKey: boolean; metaKey: boolean; shiftKey: boolean }
- added:
function getNextKeyDef(text: string, options: keyboardOptions): { keyDef: keyboardKey; consumedLength: number; releasePrevious: boolean; releaseSelf: boolean; repeat: number }
- added:
export { keyboardKey } - added:
export { keyboardOptions } - added:
export { specialCharMap } from './specialCharMap' - added:
function keyboard(text: string, options: Partial<keyboardOptions & { keyboardState: keyboardState; delay: number }>): Promise<keyboardState> - added:
function keyboard(text: string, options?: Partial<keyboardOptions & { keyboardState: keyboardState; delay: 0 }>): keyboardState - added:
function keyboardImplementationWrapper(text: string, config?: Partial<keyboardOptions & { keyboardState: keyboardState }>): { promise: Promise<void>; state: keyboardState; releaseAllKeys: () => void }
- added:
const defaultKeyMap: keyboardKey[]
- added:
function keyboardImplementation(text: string, options: keyboardOptions, state: keyboardState): Promise<void> - added:
function releaseAllKeys(options: keyboardOptions, state: keyboardState): void
- added:
const keydownBehavior: behaviorPlugin[]
- added:
const keypressBehavior: behaviorPlugin[]
- added:
const keydownBehavior: behaviorPlugin[]
- added:
const keydownBehavior: behaviorPlugin[] - added:
const keypressBehavior: behaviorPlugin[] - added:
const keyupBehavior: behaviorPlugin[] - added:
const postKeyupBehavior: behaviorPlugin[] - added:
const preKeydownBehavior: behaviorPlugin[] - added:
const preKeyupBehavior: behaviorPlugin[]
- added:
const keydownBehavior: behaviorPlugin[] - added:
const keypressBehavior: behaviorPlugin[] - added:
const keyupBehavior: behaviorPlugin[] - added:
const postKeyupBehavior: behaviorPlugin[] - added:
const preKeydownBehavior: behaviorPlugin[] - added:
const preKeyupBehavior: behaviorPlugin[] - added:
const replaceBehavior: behaviorPlugin[]
- added:
function carryValue(element: Element, state: keyboardState, newValue: string): void
- added:
function fireChangeForInputTimeIfValid(el: HTMLInputElement & { type: 'time' }, prevValue: unknown, timeNewEntry: string): void
- added:
declare global - added:
function fireInputEvent(element: HTMLElement, { newValue, newSelectionStart, eventOverrides }: { newValue: string; newSelectionStart: number; eventOverrides: Partial<Parameters<typeof fireEvent>[1]> & { [k: string]: unknown } }): void
- added:
export * from './carryValue' - added:
export * from './fireChangeForInputTimeIfValid' - added:
export * from './fireInputEvent'
- added:
const specialCharMap: { readonly arrowLeft: '{arrowleft}'; readonly arrowRight: '{arrowright}'; readonly arrowDown: '{arrowdown}'; readonly arrowUp: '{arrowup}'; readonly enter: '{e…
- added:
enum DOM_KEY_LOCATION - added:
interface behaviorPlugin - added:
interface keyboardKey - added:
member DOM_KEY_LOCATION.LEFT = 1 - added:
member DOM_KEY_LOCATION.NUMPAD = 3 - added:
member DOM_KEY_LOCATION.RIGHT = 2 - added:
member DOM_KEY_LOCATION.STANDARD = 0 - added:
property behaviorPlugin.handle: (keyDef: keyboardKey, element: Element, options: keyboardOptions, state: keyboardState) => void - added:
property behaviorPlugin.matches: (keyDef: keyboardKey, element: Element, options: keyboardOptions, state: keyboardState) => boolean - added:
property keyboardKey.altGr?: boolean - added:
property keyboardKey.code?: string - added:
property keyboardKey.key?: string - added:
property keyboardKey.keyCode?: number - added:
property keyboardKey.location?: DOM_KEY_LOCATION - added:
property keyboardKey.shift?: boolean - added:
type keyboardOptions = { document: Document; delay: number; autoModify: boolean; keyboardMap: keyboardKey[] } - added:
type keyboardState = { pressed: { keyDef: keyboardKey; unpreventedDefault: boolean }[]; modifiers: { alt: boolean; caps: boolean; ctrl: boolean; meta: boolean; shift: boolean }; ac…
- added:
function paste(element: HTMLElement, text: string, init?: ClipboardEventInit, { initialSelectionStart, initialSelectionEnd }?: pasteOptions): void
- added:
const deselectOptions: (args_0: Element, args_1: string | string[] | HTMLElement | HTMLElement[], args_2?: MouseEventInit | undefined, args_3?: PointerOptions | undefined) => void - added:
const selectOptions: (args_0: Element, args_1: string | string[] | HTMLElement | HTMLElement[], args_2?: MouseEventInit | undefined, args_3?: PointerOptions | undefined) => void
- added:
function tab({ shift, focusTrap }?: tabOptions): void
- added:
function type(element: Element, text: string, options: typeOptions & { delay: number }): Promise<void> - added:
function type(element: Element, text: string, options?: typeOptions & { delay?: 0 }): void
- added:
function typeImplementation(element: Element, text: string, { delay, skipClick, skipAutoClose, initialSelectionStart, initialSelectionEnd }: typeOptions & { delay: number }): Promise<void> - added:
interface typeOptions - added:
property typeOptions.delay?: number - added:
property typeOptions.initialSelectionEnd?: number - added:
property typeOptions.initialSelectionStart?: number - added:
property typeOptions.skipAutoClose?: boolean - added:
property typeOptions.skipClick?: boolean
- added:
function upload(element: HTMLElement, fileOrFiles: File | File[], init?: uploadInit, { applyAccept }?: uploadOptions): void
- added:
function getMouseEventOptions(event: string, init?: MouseEventInit, clickCount?: number): { detail: number; buttons: number; button: number; clientX?: number | undefined; clientY?: number | undefined; movementX?: number | undefined; movementY?: number | undefined; relatedTarget?: EventTarget | null | undefined; screenX?: number | undefined; screenY?: number | undefined; altKey?: boolean | undefin…
- added:
function isClickableInput(element: Element): boolean
- added:
function buildTimeValue(value: string): string
- added:
function calculateNewValue(newEntry: string, element: HTMLElement, value?: string, selectionRange?: { selectionStart: number | null; selectionEnd: number | null }, deleteContent?: 'backward' | 'forward'): { newValue: string; newSelectionStart: number }
- added:
function isCursorAtEnd(element: Element): boolean - added:
function isCursorAtStart(element: Element): boolean
- added:
function getValue(element: Element | null): string | null
- added:
function hasUnreliableEmptyValue(element: Element): element is HTMLInputElement & { type: unreliableValueInputTypes }
- added:
function isContentEditable(element: Element): element is HTMLElement & { contenteditable: 'true' }
- added:
enum editableInputTypes - added:
function isEditable(element: Element): element is GuardedType<typeof isContentEditable> | GuardedType<typeof isEditableInput> | (HTMLTextAreaElement & { readOnly: false }) - added:
function isEditableInput(element: Element): element is HTMLInputElement & { readOnly: false; type: editableInputTypes } - added:
member editableInputTypes.'date' = 'date' - added:
member editableInputTypes.'datetime-local' = 'datetime-local' - added:
member editableInputTypes.'email' = 'email' - added:
member editableInputTypes.'month' = 'month' - added:
member editableInputTypes.'number' = 'number' - added:
member editableInputTypes.'password' = 'password' - added:
member editableInputTypes.'search' = 'search' - added:
member editableInputTypes.'tel' = 'tel' - added:
member editableInputTypes.'text' = 'text' - added:
member editableInputTypes.'time' = 'time' - added:
member editableInputTypes.'url' = 'url' - added:
member editableInputTypes.'week' = 'week'
- added:
function isValidDateValue(element: HTMLInputElement & { type: 'date' }, value: string): boolean
- added:
function isValidInputTimeValue(element: HTMLInputElement & { type: 'time' }, timeValue: string): boolean
- added:
function getSpaceUntilMaxLength(element: Element): number | undefined
- added:
function getSelectionRange(element: Element): { selectionStart: number | null; selectionEnd: number | null } - added:
function hasSelectionSupport(element: Element): element is HTMLTextAreaElement | (HTMLInputElement & { type: selectionSupportType }) - added:
function setSelectionRange(element: Element, newSelectionStart: number, newSelectionEnd: number): void
- added:
function getActiveElement(document: Document | ShadowRoot): Element | null
- added:
function isFocusable(element: Element): element is HTMLElement
- added:
const FOCUSABLE_SELECTOR: string
- added:
export * from './click/getMouseEventOptions' - added:
export * from './click/isClickableInput' - added:
export * from './edit/buildTimeValue' - added:
export * from './edit/calculateNewValue' - added:
export * from './edit/cursorPosition' - added:
export * from './edit/getValue' - added:
export * from './edit/hasUnreliableEmptyValue' - added:
export * from './edit/isContentEditable' - added:
export * from './edit/isEditable' - added:
export * from './edit/isValidDateValue' - added:
export * from './edit/isValidInputTimeValue' - added:
export * from './edit/maxLength' - added:
export * from './edit/selectionRange' - added:
export * from './focus/getActiveElement' - added:
export * from './focus/isFocusable' - added:
export * from './focus/selector' - added:
export * from './misc/eventWrapper' - added:
export * from './misc/hasFormSubmit' - added:
export * from './misc/hasPointerEvents' - added:
export * from './misc/isDisabled' - added:
export * from './misc/isDocument' - added:
export * from './misc/isElementType' - added:
export * from './misc/isLabelWithInternallyDisabledControl' - added:
export * from './misc/isVisible' - added:
export * from './misc/wait'
- added:
function eventWrapper<T>(cb: () => T): T | undefined
- added:
const hasFormSubmit: (form: HTMLFormElement | null) => form is HTMLFormElement
- added:
function hasPointerEvents(element: Element): boolean - added:
interface PointerOptions - added:
property PointerOptions.skipPointerEventsCheck?: boolean
- added:
function isDisabled(element: Element | null): boolean
- added:
function isDocument(el: Document | Element): el is Document
- added:
function isElementType<T extends tag, P extends { [k: string]: unknown } | undefined = undefined>(element: Element, tag: T | T[], props?: P): element is P extends undefined ? HTMLElementTagNameMap[T] : HTMLElementTagNameMap[T] & P
- added:
function isLabelWithInternallyDisabledControl(element: Element): boolean
- added:
function isVisible(element: Element): boolean
- added:
function wait(time?: number): Promise<void>
- removed:
const userEvent: { clear: (element: TargetElement) => void; click: (element: TargetElement, init?: MouseEventInit, options?: IClickOptions) => void; dblClick: (element: TargetE… - removed:
default userEvent - removed:
enum specialChars - removed:
interface IClickOptions - removed:
interface ITabUserOptions - removed:
interface ITypeOpts - removed:
interface IUploadOptions - removed:
member specialChars.arrowDown = '{arrowdown}' - removed:
member specialChars.arrowLeft = '{arrowleft}' - removed:
member specialChars.arrowRight = '{arrowright}' - removed:
member specialChars.arrowUp = '{arrowup}' - removed:
member specialChars.backspace = '{backspace}' - removed:
member specialChars.delete = '{del}' - removed:
member specialChars.end = '{end}' - removed:
member specialChars.enter = '{enter}' - removed:
member specialChars.escape = '{esc}' - removed:
member specialChars.home = '{home}' - removed:
member specialChars.selectAll = '{selectall}' - removed:
member specialChars.space = '{space}' - removed:
member specialChars.whitespace = ' ' - removed:
property IClickOptions.clickCount?: number - removed:
property IClickOptions.skipHover?: boolean - removed:
property ITabUserOptions.focusTrap?: Document | Element - removed:
property ITabUserOptions.shift?: boolean - removed:
property ITypeOpts.delay?: number - removed:
property ITypeOpts.initialSelectionEnd?: number - removed:
property ITypeOpts.initialSelectionStart?: number - removed:
property ITypeOpts.skipAutoClose?: boolean - removed:
property ITypeOpts.skipClick?: boolean - removed:
property IUploadOptions.applyAccept?: boolean - removed:
type FilesArgument = File | File[] - removed:
type TargetElement = Element | Window - removed:
type UploadInitArgument = { clickInit?: MouseEventInit; changeInit?: Event }