Skip to content

Commit ca214d4

Browse files
authored
feat!: async APIs (#790)
BREAKING CHANGE: APIs always return a Promise.
1 parent b754dd4 commit ca214d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1729
-2076
lines changed

.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
},
88
},
99
rules: {
10+
'no-await-in-loop': 0,
1011
'testing-library/no-dom-import': 0,
1112
'@typescript-eslint/non-nullable-type-assertion-style': 0,
1213
},

src/.eslintrc

-8
This file was deleted.

src/click.ts

-58
This file was deleted.

src/clipboard/copy.ts

+8-21
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,9 @@
11
import {fireEvent} from '@testing-library/dom'
2-
import type {UserEvent} from '../setup'
2+
import {Config, UserEvent} from '../setup'
33
import {copySelection, writeDataTransferToClipboard} from '../utils'
44

5-
export interface copyOptions {
6-
document?: Document
7-
writeToClipboard?: boolean
8-
}
9-
10-
export function copy(
11-
this: UserEvent,
12-
options: Omit<copyOptions, 'writeToClipboard'> & {writeToClipboard: true},
13-
): Promise<DataTransfer>
14-
export function copy(
15-
this: UserEvent,
16-
options?: Omit<copyOptions, 'writeToClipboard'> & {
17-
writeToClipboard?: boolean
18-
},
19-
): DataTransfer
20-
export function copy(this: UserEvent, options?: copyOptions) {
21-
const doc = options?.document ?? document
5+
export async function copy(this: UserEvent) {
6+
const doc = this[Config].document
227
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body
238

249
const clipboardData = copySelection(target)
@@ -31,7 +16,9 @@ export function copy(this: UserEvent, options?: copyOptions) {
3116
clipboardData,
3217
})
3318

34-
return options?.writeToClipboard
35-
? writeDataTransferToClipboard(doc, clipboardData).then(() => clipboardData)
36-
: clipboardData
19+
if (this[Config].writeToClipboard) {
20+
await writeDataTransferToClipboard(doc, clipboardData)
21+
}
22+
23+
return clipboardData
3724
}

src/clipboard/cut.ts

+8-19
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,14 @@
11
import {fireEvent} from '@testing-library/dom'
2-
import type {UserEvent} from '../setup'
2+
import {Config, UserEvent} from '../setup'
33
import {
44
copySelection,
55
isEditable,
66
prepareInput,
77
writeDataTransferToClipboard,
88
} from '../utils'
99

10-
export interface cutOptions {
11-
document?: Document
12-
writeToClipboard?: boolean
13-
}
14-
15-
export function cut(
16-
this: UserEvent,
17-
options: Omit<cutOptions, 'writeToClipboard'> & {writeToClipboard: true},
18-
): Promise<DataTransfer>
19-
export function cut(
20-
this: UserEvent,
21-
options?: Omit<cutOptions, 'writeToClipboard'> & {writeToClipboard?: boolean},
22-
): DataTransfer
23-
export function cut(this: UserEvent, options?: cutOptions) {
24-
const doc = options?.document ?? document
10+
export async function cut(this: UserEvent) {
11+
const doc = this[Config].document
2512
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body
2613

2714
const clipboardData = copySelection(target)
@@ -38,7 +25,9 @@ export function cut(this: UserEvent, options?: cutOptions) {
3825
prepareInput('', target, 'deleteByCut')?.commit()
3926
}
4027

41-
return options?.writeToClipboard
42-
? writeDataTransferToClipboard(doc, clipboardData).then(() => clipboardData)
43-
: clipboardData
28+
if (this[Config].writeToClipboard) {
29+
await writeDataTransferToClipboard(doc, clipboardData)
30+
}
31+
32+
return clipboardData
4433
}

src/clipboard/paste.ts

+12-31
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {fireEvent} from '@testing-library/dom'
2-
import type {UserEvent} from '../setup'
2+
import {Config, UserEvent} from '../setup'
33
import {
44
createDataTransfer,
55
getSpaceUntilMaxLength,
@@ -8,43 +8,24 @@ import {
88
readDataTransferFromClipboard,
99
} from '../utils'
1010

11-
export interface pasteOptions {
12-
document?: Document
13-
}
14-
15-
export function paste(
16-
this: UserEvent,
17-
clipboardData?: undefined,
18-
options?: pasteOptions,
19-
): Promise<void>
20-
export function paste(
21-
this: UserEvent,
22-
clipboardData: DataTransfer | string,
23-
options?: pasteOptions,
24-
): void
25-
export function paste(
11+
export async function paste(
2612
this: UserEvent,
2713
clipboardData?: DataTransfer | string,
28-
options?: pasteOptions,
2914
) {
30-
const doc = options?.document ?? document
15+
const doc = this[Config].document
3116
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body
3217

33-
const data: DataTransfer | undefined =
34-
typeof clipboardData === 'string'
18+
const data: DataTransfer =
19+
(typeof clipboardData === 'string'
3520
? getClipboardDataFromString(clipboardData)
36-
: clipboardData
37-
38-
return data
39-
? pasteImpl(target, data)
40-
: readDataTransferFromClipboard(doc).then(
41-
dt => pasteImpl(target, dt),
42-
() => {
43-
throw new Error(
44-
'`userEvent.paste()` without `clipboardData` requires the `ClipboardAPI` to be available.',
45-
)
46-
},
21+
: clipboardData) ??
22+
(await readDataTransferFromClipboard(doc).catch(() => {
23+
throw new Error(
24+
'`userEvent.paste()` without `clipboardData` requires the `ClipboardAPI` to be available.',
4725
)
26+
}))
27+
28+
return pasteImpl(target, data)
4829
}
4930

5031
function pasteImpl(target: Element, clipboardData: DataTransfer) {

src/convenience/click.ts

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type {PointerInput} from '../pointer'
2+
import {hasPointerEvents} from '../utils'
3+
import {Config, UserEvent} from '../setup'
4+
5+
export async function click(this: UserEvent, element: Element): Promise<void> {
6+
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
7+
throw new Error(
8+
'unable to click element as it has or inherits pointer-events set to "none".',
9+
)
10+
}
11+
12+
const pointerIn: PointerInput = []
13+
if (!this[Config].skipHover) {
14+
pointerIn.push({target: element})
15+
}
16+
pointerIn.push({keys: '[MouseLeft]', target: element})
17+
18+
return this.pointer(pointerIn)
19+
}
20+
21+
export async function dblClick(
22+
this: UserEvent,
23+
element: Element,
24+
): Promise<void> {
25+
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
26+
throw new Error(
27+
'unable to double-click element as it has or inherits pointer-events set to "none".',
28+
)
29+
}
30+
31+
return this.pointer([{target: element}, '[MouseLeft][MouseLeft]'])
32+
}
33+
34+
export async function tripleClick(
35+
this: UserEvent,
36+
element: Element,
37+
): Promise<void> {
38+
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
39+
throw new Error(
40+
'unable to triple-click element as it has or inherits pointer-events set to "none".',
41+
)
42+
}
43+
44+
return this.pointer([{target: element}, '[MouseLeft][MouseLeft][MouseLeft]'])
45+
}

src/convenience/hover.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {Config, UserEvent} from '../setup'
2+
import {hasPointerEvents} from '../utils'
3+
4+
export async function hover(this: UserEvent, element: Element) {
5+
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
6+
throw new Error(
7+
'unable to hover element as it has or inherits pointer-events set to "none".',
8+
)
9+
}
10+
11+
return this.pointer({target: element})
12+
}
13+
14+
export async function unhover(this: UserEvent, element: Element) {
15+
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
16+
throw new Error(
17+
'unable to unhover element as it has or inherits pointer-events set to "none".',
18+
)
19+
}
20+
21+
return this.pointer({target: element.ownerDocument.body})
22+
}

src/convenience/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './click'
2+
export * from './hover'
3+
export * from './tab'

src/convenience/tab.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type {UserEvent} from '../setup'
2+
3+
export async function tab(
4+
this: UserEvent,
5+
{
6+
shift,
7+
}: {
8+
shift?: boolean
9+
} = {},
10+
) {
11+
return this.keyboard(
12+
shift === true
13+
? '{Shift>}{Tab}{/Shift}'
14+
: shift === false
15+
? '[/ShiftLeft][/ShiftRight]{Tab}'
16+
: '{Tab}',
17+
)
18+
}

src/hover.ts

-37
This file was deleted.

src/index.ts

+2-20
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,3 @@
1-
import {userEventApis, UserEventApis, setup, UserEvent} from './setup'
2-
3-
const userEvent: UserEventApis & {
4-
setup: typeof setup
5-
} = {
6-
...(Object.fromEntries(
7-
Object.entries(userEventApis).map(([k, f]) => [
8-
k,
9-
(...a: unknown[]) =>
10-
(f as (this: UserEvent, ...b: unknown[]) => unknown).apply(
11-
userEvent,
12-
a,
13-
),
14-
]),
15-
) as UserEventApis),
16-
setup,
17-
}
18-
19-
export default userEvent
20-
1+
export {userEvent as default} from './setup'
212
export type {keyboardKey} from './keyboard'
3+
export type {pointerKey} from './pointer'

0 commit comments

Comments
 (0)