-
Notifications
You must be signed in to change notification settings - Fork 250
Rework type #581
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rework type #581
Changes from all commits
66d80e3
153aca8
fb61f97
423595d
492493e
9863138
d078392
7dcd1a5
2b9ec50
3944223
421afee
8497533
18f48c3
a7cc548
a28f1c7
61631a1
defe327
eb8280b
eec73dd
b22dc33
3c94d7b
294409c
2308fd7
4fbfae6
a389ccc
e77dfb3
514e0d2
362c105
7f7bd62
7cc8460
a1c78bc
810c9a2
b8a78c8
ab8461d
c528645
39b1d08
3d76f0f
3fae3bc
781e0d6
b409062
64ffb17
db00fe1
f6c533e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module.exports = { | ||
extends: './node_modules/kcd-scripts/eslint.js', | ||
settings: { | ||
'import/resolver': { | ||
node: { | ||
extensions: ['.js', '.ts'], | ||
}, | ||
}, | ||
}, | ||
rules: { | ||
'testing-library/no-dom-import': 0, | ||
'@typescript-eslint/non-nullable-type-assertion-style': 0, | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import cases from 'jest-in-case' | ||
import {getNextKeyDef} from 'keyboard/getNextKeyDef' | ||
ph-fritsche marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import {defaultKeyMap} from 'keyboard/keyMap' | ||
import {keyboardKey, keyboardOptions} from 'keyboard/types' | ||
|
||
const options: keyboardOptions = { | ||
document, | ||
keyboardMap: defaultKeyMap, | ||
autoModify: false, | ||
delay: 123, | ||
} | ||
|
||
cases( | ||
'reference key per', | ||
({text, key, code}) => { | ||
expect(getNextKeyDef(`${text}foo`, options)).toEqual( | ||
expect.objectContaining({ | ||
keyDef: expect.objectContaining({ | ||
key, | ||
code, | ||
}) as keyboardKey, | ||
}), | ||
) | ||
}, | ||
{ | ||
code: {text: '[ControlLeft]', key: 'Control', code: 'ControlLeft'}, | ||
'unimplemented code': {text: '[Foo]', key: 'Unknown', code: 'Foo'}, | ||
key: {text: '{Control}', key: 'Control', code: 'ControlLeft'}, | ||
'unimplemented key': {text: '{Foo}', key: 'Foo', code: 'Unknown'}, | ||
'legacy modifier': {text: '{ctrl}', key: 'Control', code: 'ControlLeft'}, | ||
'printable character': {text: 'a', key: 'a', code: 'KeyA'}, | ||
'{ as printable': {text: '{{', key: '{', code: 'Unknown'}, | ||
'[ as printable': {text: '[[', key: '[', code: 'Unknown'}, | ||
}, | ||
) | ||
|
||
cases( | ||
'modifiers', | ||
({text, modifiers}) => { | ||
expect(getNextKeyDef(`${text}foo`, options)).toEqual( | ||
expect.objectContaining(modifiers), | ||
) | ||
}, | ||
{ | ||
'no releasePrevious': { | ||
text: '{Control}', | ||
modifiers: {releasePrevious: false}, | ||
}, | ||
'releasePrevious per key': { | ||
text: '{/Control}', | ||
modifiers: {releasePrevious: true}, | ||
}, | ||
'releasePrevious per code': { | ||
text: '[/ControlLeft]', | ||
modifiers: {releasePrevious: true}, | ||
}, | ||
'default releaseSelf': { | ||
text: '{Control}', | ||
modifiers: {releaseSelf: true}, | ||
}, | ||
'keep key pressed per key': { | ||
text: '{Control>}', | ||
modifiers: {releaseSelf: false}, | ||
}, | ||
'keep key pressed per code': { | ||
text: '[Control>]', | ||
modifiers: {releaseSelf: false}, | ||
}, | ||
'no releaseSelf on legacy modifier': { | ||
text: '{ctrl}', | ||
modifiers: {releaseSelf: false}, | ||
}, | ||
'release legacy modifier': { | ||
text: '{ctrl/}', | ||
modifiers: {releaseSelf: true}, | ||
}, | ||
}, | ||
) |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,137 @@ | ||||||||
import userEvent from '../../index' | ||||||||
import {addListeners, setup} from '../helpers/utils' | ||||||||
|
||||||||
it('type without focus', () => { | ||||||||
const {element} = setup('<input/>') | ||||||||
const {getEventSnapshot} = addListeners(document.body) | ||||||||
|
||||||||
userEvent.keyboard('foo') | ||||||||
|
||||||||
expect(element).toHaveValue('') | ||||||||
expect(getEventSnapshot()).toMatchInlineSnapshot(` | ||||||||
Events fired on: body | ||||||||
|
||||||||
body - keydown: f (102) | ||||||||
body - keypress: f (102) | ||||||||
body - keyup: f (102) | ||||||||
body - keydown: o (111) | ||||||||
body - keypress: o (111) | ||||||||
body - keyup: o (111) | ||||||||
body - keydown: o (111) | ||||||||
body - keypress: o (111) | ||||||||
body - keyup: o (111) | ||||||||
`) | ||||||||
}) | ||||||||
|
||||||||
it('type with focus', () => { | ||||||||
const {element} = setup('<input/>') | ||||||||
const {getEventSnapshot} = addListeners(document.body) | ||||||||
Comment on lines
+27
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Curious why this isn't:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same for other tests in this file. Not sure why we care about the events fired on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, yeah, that makes sense 👍 |
||||||||
;(element as HTMLInputElement).focus() | ||||||||
|
||||||||
userEvent.keyboard('foo') | ||||||||
|
||||||||
expect(element).toHaveValue('foo') | ||||||||
expect(getEventSnapshot()).toMatchInlineSnapshot(` | ||||||||
Events fired on: body | ||||||||
|
||||||||
input[value=""] - focusin | ||||||||
input[value=""] - keydown: f (102) | ||||||||
input[value=""] - keypress: f (102) | ||||||||
input[value="f"] - input | ||||||||
input[value="f"] - keyup: f (102) | ||||||||
input[value="f"] - keydown: o (111) | ||||||||
input[value="f"] - keypress: o (111) | ||||||||
input[value="fo"] - input | ||||||||
input[value="fo"] - keyup: o (111) | ||||||||
input[value="fo"] - keydown: o (111) | ||||||||
input[value="fo"] - keypress: o (111) | ||||||||
input[value="foo"] - input | ||||||||
input[value="foo"] - keyup: o (111) | ||||||||
`) | ||||||||
}) | ||||||||
|
||||||||
it('type asynchronous', async () => { | ||||||||
const {element} = setup('<input/>') | ||||||||
const {getEventSnapshot} = addListeners(document.body) | ||||||||
;(element as HTMLInputElement).focus() | ||||||||
|
||||||||
// eslint-disable-next-line testing-library/no-await-sync-events | ||||||||
await userEvent.keyboard('foo', {delay: 1}) | ||||||||
|
||||||||
expect(element).toHaveValue('foo') | ||||||||
expect(getEventSnapshot()).toMatchInlineSnapshot(` | ||||||||
Events fired on: body | ||||||||
|
||||||||
input[value=""] - focusin | ||||||||
input[value=""] - keydown: f (102) | ||||||||
input[value=""] - keypress: f (102) | ||||||||
input[value="f"] - input | ||||||||
input[value="f"] - keyup: f (102) | ||||||||
input[value="f"] - keydown: o (111) | ||||||||
input[value="f"] - keypress: o (111) | ||||||||
input[value="fo"] - input | ||||||||
input[value="fo"] - keyup: o (111) | ||||||||
input[value="fo"] - keydown: o (111) | ||||||||
input[value="fo"] - keypress: o (111) | ||||||||
input[value="foo"] - input | ||||||||
input[value="foo"] - keyup: o (111) | ||||||||
`) | ||||||||
}) | ||||||||
|
||||||||
describe('error', () => { | ||||||||
afterEach(() => { | ||||||||
;(console.error as jest.MockedFunction<typeof console.error>).mockClear() | ||||||||
}) | ||||||||
|
||||||||
it('error in sync', async () => { | ||||||||
const err = jest.spyOn(console, 'error') | ||||||||
err.mockImplementation(() => {}) | ||||||||
|
||||||||
userEvent.keyboard('{!') | ||||||||
|
||||||||
// the catch will be asynchronous | ||||||||
await Promise.resolve() | ||||||||
|
||||||||
expect(err).toHaveBeenCalledWith(expect.any(Error)) | ||||||||
expect(err.mock.calls[0][0]).toHaveProperty( | ||||||||
'message', | ||||||||
'Expected key descriptor but found "!" in "{!"', | ||||||||
) | ||||||||
}) | ||||||||
|
||||||||
it('error in async', async () => { | ||||||||
const promise = userEvent.keyboard('{!', {delay: 1}) | ||||||||
|
||||||||
return expect(promise).rejects.toThrowError( | ||||||||
'Expected key descriptor but found "!" in "{!"', | ||||||||
) | ||||||||
}) | ||||||||
}) | ||||||||
|
||||||||
it('continue typing with state', () => { | ||||||||
const {element, getEventSnapshot, clearEventCalls} = setup('<input/>') | ||||||||
;(element as HTMLInputElement).focus() | ||||||||
clearEventCalls() | ||||||||
|
||||||||
const state = userEvent.keyboard('[ShiftRight>]') | ||||||||
|
||||||||
expect(getEventSnapshot()).toMatchInlineSnapshot(` | ||||||||
Events fired on: input[value=""] | ||||||||
|
||||||||
input[value=""] - keydown: Shift (16) {shift} | ||||||||
`) | ||||||||
clearEventCalls() | ||||||||
|
||||||||
userEvent.keyboard('F[/ShiftRight]', {keyboardState: state}) | ||||||||
|
||||||||
expect(getEventSnapshot()).toMatchInlineSnapshot(` | ||||||||
Events fired on: input[value="F"] | ||||||||
|
||||||||
input[value=""] - keydown: F (70) {shift} | ||||||||
input[value=""] - keypress: F (70) {shift} | ||||||||
input[value="F"] - input | ||||||||
"{CURSOR}" -> "F{CURSOR}" | ||||||||
input[value="F"] - keyup: F (70) {shift} | ||||||||
input[value="F"] - keyup: Shift (16) | ||||||||
`) | ||||||||
}) |
Uh oh!
There was an error while loading. Please reload this page.