Skip to content

Commit

Permalink
feat!: async APIs (#790)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: APIs always return a Promise.
  • Loading branch information
ph-fritsche committed Nov 25, 2021
1 parent b754dd4 commit ca214d4
Show file tree
Hide file tree
Showing 84 changed files with 1,729 additions and 2,076 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -7,6 +7,7 @@ module.exports = {
},
},
rules: {
'no-await-in-loop': 0,
'testing-library/no-dom-import': 0,
'@typescript-eslint/non-nullable-type-assertion-style': 0,
},
Expand Down
8 changes: 0 additions & 8 deletions src/.eslintrc

This file was deleted.

58 changes: 0 additions & 58 deletions src/click.ts

This file was deleted.

29 changes: 8 additions & 21 deletions src/clipboard/copy.ts
@@ -1,24 +1,9 @@
import {fireEvent} from '@testing-library/dom'
import type {UserEvent} from '../setup'
import {Config, UserEvent} from '../setup'
import {copySelection, writeDataTransferToClipboard} from '../utils'

export interface copyOptions {
document?: Document
writeToClipboard?: boolean
}

export function copy(
this: UserEvent,
options: Omit<copyOptions, 'writeToClipboard'> & {writeToClipboard: true},
): Promise<DataTransfer>
export function copy(
this: UserEvent,
options?: Omit<copyOptions, 'writeToClipboard'> & {
writeToClipboard?: boolean
},
): DataTransfer
export function copy(this: UserEvent, options?: copyOptions) {
const doc = options?.document ?? document
export async function copy(this: UserEvent) {
const doc = this[Config].document
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body

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

return options?.writeToClipboard
? writeDataTransferToClipboard(doc, clipboardData).then(() => clipboardData)
: clipboardData
if (this[Config].writeToClipboard) {
await writeDataTransferToClipboard(doc, clipboardData)
}

return clipboardData
}
27 changes: 8 additions & 19 deletions src/clipboard/cut.ts
@@ -1,27 +1,14 @@
import {fireEvent} from '@testing-library/dom'
import type {UserEvent} from '../setup'
import {Config, UserEvent} from '../setup'
import {
copySelection,
isEditable,
prepareInput,
writeDataTransferToClipboard,
} from '../utils'

export interface cutOptions {
document?: Document
writeToClipboard?: boolean
}

export function cut(
this: UserEvent,
options: Omit<cutOptions, 'writeToClipboard'> & {writeToClipboard: true},
): Promise<DataTransfer>
export function cut(
this: UserEvent,
options?: Omit<cutOptions, 'writeToClipboard'> & {writeToClipboard?: boolean},
): DataTransfer
export function cut(this: UserEvent, options?: cutOptions) {
const doc = options?.document ?? document
export async function cut(this: UserEvent) {
const doc = this[Config].document
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body

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

return options?.writeToClipboard
? writeDataTransferToClipboard(doc, clipboardData).then(() => clipboardData)
: clipboardData
if (this[Config].writeToClipboard) {
await writeDataTransferToClipboard(doc, clipboardData)
}

return clipboardData
}
43 changes: 12 additions & 31 deletions src/clipboard/paste.ts
@@ -1,5 +1,5 @@
import {fireEvent} from '@testing-library/dom'
import type {UserEvent} from '../setup'
import {Config, UserEvent} from '../setup'
import {
createDataTransfer,
getSpaceUntilMaxLength,
Expand All @@ -8,43 +8,24 @@ import {
readDataTransferFromClipboard,
} from '../utils'

export interface pasteOptions {
document?: Document
}

export function paste(
this: UserEvent,
clipboardData?: undefined,
options?: pasteOptions,
): Promise<void>
export function paste(
this: UserEvent,
clipboardData: DataTransfer | string,
options?: pasteOptions,
): void
export function paste(
export async function paste(
this: UserEvent,
clipboardData?: DataTransfer | string,
options?: pasteOptions,
) {
const doc = options?.document ?? document
const doc = this[Config].document
const target = doc.activeElement ?? /* istanbul ignore next */ doc.body

const data: DataTransfer | undefined =
typeof clipboardData === 'string'
const data: DataTransfer =
(typeof clipboardData === 'string'
? getClipboardDataFromString(clipboardData)
: clipboardData

return data
? pasteImpl(target, data)
: readDataTransferFromClipboard(doc).then(
dt => pasteImpl(target, dt),
() => {
throw new Error(
'`userEvent.paste()` without `clipboardData` requires the `ClipboardAPI` to be available.',
)
},
: clipboardData) ??
(await readDataTransferFromClipboard(doc).catch(() => {
throw new Error(
'`userEvent.paste()` without `clipboardData` requires the `ClipboardAPI` to be available.',
)
}))

return pasteImpl(target, data)
}

function pasteImpl(target: Element, clipboardData: DataTransfer) {
Expand Down
45 changes: 45 additions & 0 deletions src/convenience/click.ts
@@ -0,0 +1,45 @@
import type {PointerInput} from '../pointer'
import {hasPointerEvents} from '../utils'
import {Config, UserEvent} from '../setup'

export async function click(this: UserEvent, element: Element): Promise<void> {
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
throw new Error(
'unable to click element as it has or inherits pointer-events set to "none".',
)
}

const pointerIn: PointerInput = []
if (!this[Config].skipHover) {
pointerIn.push({target: element})
}
pointerIn.push({keys: '[MouseLeft]', target: element})

return this.pointer(pointerIn)
}

export async function dblClick(
this: UserEvent,
element: Element,
): Promise<void> {
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
throw new Error(
'unable to double-click element as it has or inherits pointer-events set to "none".',
)
}

return this.pointer([{target: element}, '[MouseLeft][MouseLeft]'])
}

export async function tripleClick(
this: UserEvent,
element: Element,
): Promise<void> {
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
throw new Error(
'unable to triple-click element as it has or inherits pointer-events set to "none".',
)
}

return this.pointer([{target: element}, '[MouseLeft][MouseLeft][MouseLeft]'])
}
22 changes: 22 additions & 0 deletions src/convenience/hover.ts
@@ -0,0 +1,22 @@
import {Config, UserEvent} from '../setup'
import {hasPointerEvents} from '../utils'

export async function hover(this: UserEvent, element: Element) {
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
throw new Error(
'unable to hover element as it has or inherits pointer-events set to "none".',
)
}

return this.pointer({target: element})
}

export async function unhover(this: UserEvent, element: Element) {
if (!this[Config].skipPointerEventsCheck && !hasPointerEvents(element)) {
throw new Error(
'unable to unhover element as it has or inherits pointer-events set to "none".',
)
}

return this.pointer({target: element.ownerDocument.body})
}
3 changes: 3 additions & 0 deletions src/convenience/index.ts
@@ -0,0 +1,3 @@
export * from './click'
export * from './hover'
export * from './tab'
18 changes: 18 additions & 0 deletions src/convenience/tab.ts
@@ -0,0 +1,18 @@
import type {UserEvent} from '../setup'

export async function tab(
this: UserEvent,
{
shift,
}: {
shift?: boolean
} = {},
) {
return this.keyboard(
shift === true
? '{Shift>}{Tab}{/Shift}'
: shift === false
? '[/ShiftLeft][/ShiftRight]{Tab}'
: '{Tab}',
)
}
37 changes: 0 additions & 37 deletions src/hover.ts

This file was deleted.

22 changes: 2 additions & 20 deletions src/index.ts
@@ -1,21 +1,3 @@
import {userEventApis, UserEventApis, setup, UserEvent} from './setup'

const userEvent: UserEventApis & {
setup: typeof setup
} = {
...(Object.fromEntries(
Object.entries(userEventApis).map(([k, f]) => [
k,
(...a: unknown[]) =>
(f as (this: UserEvent, ...b: unknown[]) => unknown).apply(
userEvent,
a,
),
]),
) as UserEventApis),
setup,
}

export default userEvent

export {userEvent as default} from './setup'
export type {keyboardKey} from './keyboard'
export type {pointerKey} from './pointer'

0 comments on commit ca214d4

Please sign in to comment.