import React from 'react' import { render } from '@testing-library/react' import { type, shift, Keys } from './interactions' type Events = 'onKeyDown' | 'onKeyUp' | 'onKeyPress' | 'onClick' | 'onBlur' | 'onFocus' let events: Events[] = ['onKeyDown', 'onKeyUp', 'onKeyPress', 'onClick', 'onBlur', 'onFocus'] type Args = [ string | Partial, (string | Partial)[], Set ] function key(input: string | Partial): Partial { if (typeof input === 'string') return { key: input } return input } function event( input: string | Partial, target?: string ): Partial { let e = typeof input === 'string' ? { type: input } : input if (target) { Object.defineProperty(e, 'target', { configurable: false, enumerable: true, get() { return document.getElementById(target!) }, }) } return e } describe('Keyboard', () => { describe('type', () => { it.each([ // Default - no cancellation ['a', ['keydown', 'keypress', 'keyup'], new Set()], [Keys.Space, ['keydown', 'keypress', 'keyup', 'click'], new Set()], [Keys.Enter, ['keydown', 'keypress', 'click', 'keyup'], new Set()], [ Keys.Tab, [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'after'), event('keyup', 'after'), ], new Set(), ], [ shift(Keys.Tab), [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'before'), event('keyup', 'before'), ], new Set(), ], // Canceling keydown ['a', ['keydown', 'keyup'], new Set(['onKeyDown'])], [Keys.Space, ['keydown', 'keyup'], new Set(['onKeyDown'])], [Keys.Enter, ['keydown', 'keyup'], new Set(['onKeyDown'])], [Keys.Tab, ['keydown', 'keyup'], new Set(['onKeyDown'])], [shift(Keys.Tab), ['keydown', 'keyup'], new Set(['onKeyDown'])], // Canceling keypress ['a', ['keydown', 'keypress', 'keyup'], new Set(['onKeyPress'])], [Keys.Space, ['keydown', 'keypress', 'keyup', 'click'], new Set(['onKeyPress'])], [Keys.Enter, ['keydown', 'keypress', 'keyup'], new Set(['onKeyPress'])], [ Keys.Tab, [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'after'), event('keyup', 'after'), ], new Set(['onKeyPress']), ], [ shift(Keys.Tab), [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'before'), event('keyup', 'before'), ], new Set(['onKeyPress']), ], // Canceling keyup ['a', ['keydown', 'keypress', 'keyup'], new Set(['onKeyUp'])], [Keys.Space, ['keydown', 'keypress', 'keyup'], new Set(['onKeyUp'])], [Keys.Enter, ['keydown', 'keypress', 'click', 'keyup'], new Set(['onKeyUp'])], [ Keys.Tab, [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'after'), event('keyup', 'after'), ], new Set(['onKeyUp']), ], [ shift(Keys.Tab), [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'before'), event('keyup', 'before'), ], new Set(['onKeyUp']), ], // Cancelling blur [ Keys.Tab, [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'after'), event('keyup', 'after'), ], new Set(['onBlur']), ], [ shift(Keys.Tab), [ event('keydown', 'trigger'), event('blur', 'trigger'), event('focus', 'before'), event('keyup', 'before'), ], new Set(['onBlur']), ], ])('should fire the correct events %#', async (input, result, prevents) => { let fired: (KeyboardEvent | MouseEvent)[] = [] let state = { readyToCapture: false } function createProps(id: string) { return events.reduce( (props: React.ComponentProps<'button'>, name) => { props[name] = (event: any) => { if (!state.readyToCapture) return if (prevents.has(name)) event.preventDefault() fired.push(event.nativeEvent) } return props }, { id } ) } render( <> ) let trigger = document.getElementById('trigger') trigger?.focus() state.readyToCapture = true await type([key(input)]) let expected = result.map(e => event(e)) expect(fired.length).toEqual(result.length) for (let [idx, event] of fired.entries()) { for (let key in expected[idx]) { let _key = key as keyof (KeyboardEvent | MouseEvent) expect(event[_key]).toBe(expected[idx][_key]) } } }) }) })