Skip to content

Commit

Permalink
fix: convert exported modules to typescript (#599)
Browse files Browse the repository at this point in the history
* fix: convert exported modules to typescript

* fix: remove/ignore uncovered branches
  • Loading branch information
ph-fritsche authored Mar 19, 2021
1 parent a552f18 commit be0b1b6
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 165 deletions.
1 change: 0 additions & 1 deletion src/clear.d.ts

This file was deleted.

30 changes: 0 additions & 30 deletions src/clear.js

This file was deleted.

43 changes: 43 additions & 0 deletions src/clear.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {isDisabled, isInstanceOfElement} from './utils'
import {type} from './type'

function clear(element: Element) {
if (
!isInstanceOfElement(element, 'HTMLInputElement') &&
!isInstanceOfElement(element, 'HTMLTextAreaElement')
) {
// TODO: support contenteditable
throw new Error(
'clear currently only supports input and textarea elements.',
)
}
const el = element as HTMLInputElement | HTMLTextAreaElement

if (isDisabled(el)) {
return
}

// TODO: track the selection range ourselves so we don't have to do this input "type" trickery
// just like cypress does: https://github.com/cypress-io/cypress/blob/8d7f1a0bedc3c45a2ebf1ff50324b34129fdc683/packages/driver/src/dom/selection.ts#L16-L37

const elementType = el.type

if (elementType !== 'textarea') {
// setSelectionRange is not supported on certain types of inputs, e.g. "number" or "email"
;(element as HTMLInputElement).type = 'text'
}

type(element, '{selectall}{del}', {
delay: 0,
initialSelectionStart:
el.selectionStart ?? /* istanbul ignore next */ undefined,
initialSelectionEnd:
el.selectionEnd ?? /* istanbul ignore next */ undefined,
})

if (elementType !== 'textarea') {
;(el as HTMLInputElement).type = elementType
}
}

export {clear}
12 changes: 0 additions & 12 deletions src/click.d.ts

This file was deleted.

75 changes: 49 additions & 26 deletions src/click.js → src/click.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import {
getMouseEventOptions,
isLabelWithInternallyDisabledControl,
isFocusable,
isDisabled,
isInstanceOfElement,
} from './utils'
import {hover} from './hover'
import {blur} from './blur'
import {focus} from './focus'

function getPreviouslyFocusedElement(element) {
function getPreviouslyFocusedElement(element: Element) {
const focusedElement = element.ownerDocument.activeElement
const wasAnotherElementFocused =
focusedElement &&
Expand All @@ -17,7 +19,16 @@ function getPreviouslyFocusedElement(element) {
return wasAnotherElementFocused ? focusedElement : null
}

function clickLabel(label, init, {clickCount}) {
export declare interface clickOptions {
skipHover?: boolean
clickCount?: number
}

function clickLabel(
label: HTMLLabelElement,
init: MouseEventInit | undefined,
{clickCount}: clickOptions,
) {
if (isLabelWithInternallyDisabledControl(label)) return

fireEvent.pointerDown(label, init)
Expand All @@ -34,15 +45,19 @@ function clickLabel(label, init, {clickCount}) {
if (label.control) focus(label.control)
}

function clickBooleanElement(element, init, clickCount) {
function clickBooleanElement(
element: HTMLInputElement,
init: MouseEventInit | undefined,
{clickCount}: clickOptions,
) {
fireEvent.pointerDown(element, init)
if (!element.disabled) {
fireEvent.mouseDown(
element,
getMouseEventOptions('mousedown', init, clickCount),
)
}
focus(element, init)
focus(element)
fireEvent.pointerUp(element, init)
if (!element.disabled) {
fireEvent.mouseUp(
Expand All @@ -53,36 +68,41 @@ function clickBooleanElement(element, init, clickCount) {
}
}

function clickElement(element, init, {clickCount}) {
function clickElement(
element: Element,
init: MouseEventInit | undefined,
{clickCount}: clickOptions,
) {
const previousElement = getPreviouslyFocusedElement(element)
fireEvent.pointerDown(element, init)
if (!element.disabled) {
if (!isDisabled(element)) {
const continueDefaultHandling = fireEvent.mouseDown(
element,
getMouseEventOptions('mousedown', init, clickCount),
)
if (continueDefaultHandling) {
const closestFocusable = findClosest(element, isFocusable)
if (previousElement && !closestFocusable) {
blur(previousElement, init)
blur(previousElement)
} else if (closestFocusable) {
focus(closestFocusable, init)
focus(closestFocusable)
}
}
}
fireEvent.pointerUp(element, init)
if (!element.disabled) {
if (!isDisabled(element)) {
fireEvent.mouseUp(
element,
getMouseEventOptions('mouseup', init, clickCount),
)
fireEvent.click(element, getMouseEventOptions('click', init, clickCount))
const parentLabel = element.closest('label')
if (parentLabel?.control) focus(parentLabel.control, init)
if (parentLabel?.control) focus(parentLabel.control)
}
}

function findClosest(el, callback) {
function findClosest(element: Element, callback: (e: Element) => boolean) {
let el: Element | null = element
do {
if (callback(el)) {
return el
Expand All @@ -92,25 +112,28 @@ function findClosest(el, callback) {
return undefined
}

function click(element, init, {skipHover = false, clickCount = 0} = {}) {
function click(
element: Element,
init?: MouseEventInit,
{skipHover = false, clickCount = 0}: clickOptions = {},
) {
if (!skipHover) hover(element, init)
switch (element.tagName) {
case 'LABEL':
clickLabel(element, init, {clickCount})
break
case 'INPUT':
if (element.type === 'checkbox' || element.type === 'radio') {
clickBooleanElement(element, init, {clickCount})
} else {
clickElement(element, init, {clickCount})
}
break
default:
clickElement(element, init, {clickCount})

if (isInstanceOfElement(element, 'HTMLLabelElement')) {
clickLabel(element as HTMLLabelElement, init, {clickCount})
} else if (isInstanceOfElement(element, 'HTMLInputElement')) {
const el = element as HTMLInputElement
if (el.type === 'checkbox' || el.type === 'radio') {
clickBooleanElement(el, init, {clickCount})
} else {
clickElement(el, init, {clickCount})
}
} else {
clickElement(element, init, {clickCount})
}
}

function dblClick(element, init) {
function dblClick(element: Element, init?: MouseEventInit) {
hover(element, init)
click(element, init, {skipHover: true, clickCount: 0})
click(element, init, {skipHover: true, clickCount: 1})
Expand Down
9 changes: 0 additions & 9 deletions src/paste.d.ts

This file was deleted.

34 changes: 25 additions & 9 deletions src/paste.js → src/paste.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@ import {
setSelectionRangeIfNecessary,
calculateNewValue,
eventWrapper,
isDisabled,
} from './utils'

interface pasteOptions {
initialSelectionStart?: number
initialSelectionEnd?: number
}

function paste(
element,
text,
init,
{initialSelectionStart, initialSelectionEnd} = {},
element: HTMLInputElement | HTMLTextAreaElement,
text: string,
init?: MouseEventInit,
{initialSelectionStart, initialSelectionEnd}: pasteOptions = {},
) {
if (element.disabled) return
if (isDisabled(element)) {
return
}

// TODO: implement for contenteditable
if (typeof element.value === 'undefined') {
throw new TypeError(
`the current element is of type ${element.tagName} and doesn't have a valid value`,
Expand Down Expand Up @@ -43,10 +53,16 @@ function paste(
inputType: 'insertFromPaste',
target: {value: newValue},
})
setSelectionRangeIfNecessary(element, {
newSelectionStart,
newSelectionEnd: newSelectionStart,
})
setSelectionRangeIfNecessary(
element,

// TODO: investigate why the selection caused by invalid parameters was expected
({
newSelectionStart,
selectionEnd: newSelectionStart,
} as unknown) as number,
({} as unknown) as number,
)
}
}

Expand Down
11 changes: 0 additions & 11 deletions src/select-options.d.ts

This file was deleted.

33 changes: 20 additions & 13 deletions src/select-options.js → src/select-options.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import {createEvent, getConfig, fireEvent} from '@testing-library/dom'
import {isInstanceOfElement} from './utils'
import {isDisabled, isInstanceOfElement} from './utils'
import {click} from './click'
import {focus} from './focus'
import {hover, unhover} from './hover'

function selectOptionsBase(newValue, select, values, init) {
if (!newValue && !select.multiple) {
function selectOptionsBase(
newValue: boolean,
select: Element,
values: HTMLElement | HTMLElement[] | string[] | string,
init?: MouseEventInit,
) {
if (!newValue && !(select as HTMLSelectElement).multiple) {
throw getConfig().getElementError(
`Unable to deselect an option in a non-multiple select. Use selectOptions to change the selection instead.`,
select,
Expand All @@ -17,28 +22,30 @@ function selectOptionsBase(newValue, select, values, init) {
)
const selectedOptions = valArray
.map(val => {
if (allOptions.includes(val)) {
if (typeof val !== 'string' && allOptions.includes(val)) {
return val
} else {
const matchingOption = allOptions.find(
o => o.value === val || o.innerHTML === val,
o =>
(o as HTMLInputElement | HTMLTextAreaElement).value === val ||
o.innerHTML === val,
)
if (matchingOption) {
return matchingOption
} else {
throw getConfig().getElementError(
`Value "${val}" not found in options`,
`Value "${String(val)}" not found in options`,
select,
)
}
}
})
.filter(option => !option.disabled)
.filter(option => !isDisabled(option))

if (select.disabled || !selectedOptions.length) return
if (isDisabled(select) || !selectedOptions.length) return

if (isInstanceOfElement(select, 'HTMLSelectElement')) {
if (select.multiple) {
if ((select as HTMLSelectElement).multiple) {
for (const option of selectedOptions) {
// events fired for multiple select are weird. Can't use hover...
fireEvent.pointerOver(option, init)
Expand All @@ -49,17 +56,17 @@ function selectOptionsBase(newValue, select, values, init) {
fireEvent.mouseMove(option, init)
fireEvent.pointerDown(option, init)
fireEvent.mouseDown(option, init)
focus(select, init)
focus(select)
fireEvent.pointerUp(option, init)
fireEvent.mouseUp(option, init)
selectOption(option)
selectOption(option as HTMLOptionElement)
fireEvent.click(option, init)
}
} else if (selectedOptions.length === 1) {
// the click to open the select options
click(select, init)

selectOption(selectedOptions[0])
selectOption(selectedOptions[0] as HTMLOptionElement)

// the browser triggers another click event on the select for the click on the option
// this second click has no 'down' phase
Expand Down Expand Up @@ -89,7 +96,7 @@ function selectOptionsBase(newValue, select, values, init) {
)
}

function selectOption(option) {
function selectOption(option: HTMLOptionElement) {
option.selected = newValue
fireEvent(
select,
Expand Down
Loading

0 comments on commit be0b1b6

Please sign in to comment.