Skip to content

Commit

Permalink
feat: migrate some files to typescript (#848)
Browse files Browse the repository at this point in the history
Co-authored-by: eps1lon <silbermann.sebastian@gmail.com>
  • Loading branch information
marcosvega91 and eps1lon authored Dec 11, 2020
1 parent f753c8a commit accb6cc
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 39 deletions.
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"node": ">=10"
},
"scripts": {
"build": "kcd-scripts build --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --bundle --no-clean",
"build": "kcd-scripts build --no-ts-defs --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --no-ts-defs --bundle --no-clean",
"lint": "kcd-scripts lint",
"setup": "npm install && npm run validate -s",
"test": "kcd-scripts test",
Expand Down Expand Up @@ -53,11 +53,14 @@
"jest-serializer-ansi": "^1.0.3",
"jest-watch-select-projects": "^2.0.0",
"jsdom": "^16.4.0",
"kcd-scripts": "^7.5.1",
"kcd-scripts": "^7.5.3",
"typescript": "^4.1.2"
},
"eslintConfig": {
"extends": "./node_modules/kcd-scripts/eslint.js",
"extends": [
"./node_modules/kcd-scripts/eslint.js",
"plugin:import/typescript"
],
"rules": {
"import/prefer-default-export": "off",
"import/no-unassigned-import": "off",
Expand Down
14 changes: 11 additions & 3 deletions src/config.js → src/config.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import {Config, ConfigFn} from '../types/config'
import {prettyDOM} from './pretty-dom'

type Callback<T> = () => T
interface InternalConfig extends Config {
_disableExpensiveErrorDiagnostics: boolean
}

// It would be cleaner for this to live inside './queries', but
// other parts of the code assume that all exports from
// './queries' are query functions.
let config = {
let config: InternalConfig = {
testIdAttribute: 'data-testid',
asyncUtilTimeout: 1000,
// this is to support React's async `act` function.
Expand Down Expand Up @@ -36,7 +42,9 @@ let config = {
}

export const DEFAULT_IGNORE_TAGS = 'script, style'
export function runWithExpensiveErrorDiagnosticsDisabled(callback) {
export function runWithExpensiveErrorDiagnosticsDisabled<T>(
callback: Callback<T>,
) {
try {
config._disableExpensiveErrorDiagnostics = true
return callback()
Expand All @@ -45,7 +53,7 @@ export function runWithExpensiveErrorDiagnosticsDisabled(callback) {
}
}

export function configure(newConfig) {
export function configure(newConfig: Partial<Config> | ConfigFn) {
if (typeof newConfig === 'function') {
// Pass the existing config out to the provided function
// and accept a delta in return
Expand Down
15 changes: 9 additions & 6 deletions src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,15 @@ function createEvent(
/* istanbul ignore if */
if (typeof window.DataTransfer === 'function') {
Object.defineProperty(event, dataTransferKey, {
value: Object
.getOwnPropertyNames(dataTransferValue)
.reduce((acc, propName) => {
Object.defineProperty(acc, propName, {value: dataTransferValue[propName]});
return acc;
}, new window.DataTransfer())
value: Object.getOwnPropertyNames(dataTransferValue).reduce(
(acc, propName) => {
Object.defineProperty(acc, propName, {
value: dataTransferValue[propName],
})
return acc
},
new window.DataTransfer(),
),
})
} else {
Object.defineProperty(event, dataTransferKey, {
Expand Down
37 changes: 22 additions & 15 deletions src/label-helpers.js → src/label-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ const labelledNodeNames = [
'input',
]

function getTextContent(node) {
function getTextContent(
node: Node | Element | HTMLInputElement,
): string | null {
if (labelledNodeNames.includes(node.nodeName.toLowerCase())) {
return ''
}
Expand All @@ -22,37 +24,43 @@ function getTextContent(node) {
.join('')
}

function getLabelContent(node) {
let textContent
if (node.tagName.toLowerCase() === 'label') {
textContent = getTextContent(node)
function getLabelContent(element: Element): string | null {
let textContent: string | null
if (element.tagName.toLowerCase() === 'label') {
textContent = getTextContent(element)
} else {
textContent = node.value || node.textContent
textContent = (element as HTMLInputElement).value || element.textContent
}
return textContent
}

// Based on https://github.com/eps1lon/dom-accessibility-api/pull/352
function getRealLabels(element) {
if (element.labels !== undefined) return element.labels ?? []
function getRealLabels(element: Element) {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- types are not aware of older browsers that don't implement `labels`
if ((element as HTMLInputElement).labels !== undefined) {
return (element as HTMLInputElement).labels ?? []
}

if (!isLabelable(element)) return []

const labels = element.ownerDocument.querySelectorAll('label')
return Array.from(labels).filter(label => label.control === element)
}

function isLabelable(element) {
function isLabelable(element: Element) {
return (
element.tagName.match(/BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/) ||
/BUTTON|METER|OUTPUT|PROGRESS|SELECT|TEXTAREA/.test(element.tagName) ||
(element.tagName === 'INPUT' && element.getAttribute('type') !== 'hidden')
)
}

function getLabels(container, element, {selector = '*'} = {}) {
const labelsId = element.getAttribute('aria-labelledby')
? element.getAttribute('aria-labelledby').split(' ')
: []
function getLabels(
container: Element,
element: Element,
{selector = '*'} = {},
) {
const ariaLabelledBy = element.getAttribute('aria-labelledby')
const labelsId = ariaLabelledBy ? ariaLabelledBy.split(' ') : []
return labelsId.length
? labelsId.map(labelId => {
const labellingElement = container.querySelector(`[id="${labelId}"]`)
Expand All @@ -67,7 +75,6 @@ function getLabels(container, element, {selector = '*'} = {}) {
const labelledFormControl = Array.from(
label.querySelectorAll(formControlSelector),
).filter(formControlElement => formControlElement.matches(selector))[0]

return {content: textToMatch, formControl: labelledFormControl}
})
}
Expand Down
44 changes: 37 additions & 7 deletions src/matches.js → src/matches.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
function assertNotNullOrUndefined(matcher) {
if (matcher == null) {
import {
Matcher,
NormalizerFn,
NormalizerOptions,
DefaultNormalizerOptions,
} from '../types'

type Nullish<T> = T | null | undefined

function assertNotNullOrUndefined<T>(
matcher: T,
): asserts matcher is NonNullable<T> {
if (matcher === null || matcher === undefined) {
throw new Error(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- implicitly converting `T` to `string`
`It looks like ${matcher} was passed instead of a matcher. Did you do something like getByText(${matcher})?`,
)
}
}

function fuzzyMatches(textToMatch, node, matcher, normalizer) {
function fuzzyMatches(
textToMatch: Nullish<string>,
node: Nullish<Element>,
matcher: Nullish<Matcher>,
normalizer: NormalizerFn,
) {
if (typeof textToMatch !== 'string') {
return false
}

assertNotNullOrUndefined(matcher)

const normalizedText = normalizer(textToMatch)

if (typeof matcher === 'string') {
return normalizedText.toLowerCase().includes(matcher.toLowerCase())
} else if (typeof matcher === 'function') {
Expand All @@ -23,7 +40,12 @@ function fuzzyMatches(textToMatch, node, matcher, normalizer) {
}
}

function matches(textToMatch, node, matcher, normalizer) {
function matches(
textToMatch: Nullish<string>,
node: Nullish<Element>,
matcher: Nullish<Matcher>,
normalizer: NormalizerFn,
) {
if (typeof textToMatch !== 'string') {
return false
}
Expand All @@ -40,7 +62,10 @@ function matches(textToMatch, node, matcher, normalizer) {
}
}

function getDefaultNormalizer({trim = true, collapseWhitespace = true} = {}) {
function getDefaultNormalizer({
trim = true,
collapseWhitespace = true,
}: DefaultNormalizerOptions = {}): NormalizerFn {
return text => {
let normalizedText = text
normalizedText = trim ? normalizedText.trim() : normalizedText
Expand All @@ -60,7 +85,12 @@ function getDefaultNormalizer({trim = true, collapseWhitespace = true} = {}) {
* @param {Function|undefined} normalizer The user-specified normalizer
* @returns {Function} A normalizer
*/
function makeNormalizer({trim, collapseWhitespace, normalizer}) {

function makeNormalizer({
trim,
collapseWhitespace,
normalizer,
}: NormalizerOptions) {
if (normalizer) {
// User has specified a custom normalizer
if (
Expand Down
7 changes: 7 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
"compilerOptions": {
"allowJs": true
},
"include": ["./src", "./types"]
}
4 changes: 3 additions & 1 deletion types/config.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
export interface Config {
testIdAttribute: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
asyncWrapper(cb: (...args: any[]) => any): Promise<any>
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventWrapper(cb: (...args: any[]) => any): void
asyncUtilTimeout: number
computedStyleSupportsPseudoElements: boolean
defaultHidden: boolean
showOriginalStackTrace: boolean
throwSuggestions: boolean
getElementError: (message: string, container: HTMLElement) => Error
getElementError: (message: string | null, container: Element) => Error
}

export interface ConfigFn {
Expand Down
13 changes: 11 additions & 2 deletions types/matches.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import {ARIARole} from 'aria-query'

export type MatcherFunction = (content: string, element: HTMLElement) => boolean
export type Matcher = MatcherFunction | {}
type Nullish<T> = T | null | undefined

export type MatcherFunction = (
content: string,
element: Nullish<Element>,
) => boolean
export type Matcher = MatcherFunction | RegExp | string

// Get autocomplete for ARIARole union types, while still supporting another string
// Ref: https://github.com/microsoft/TypeScript/issues/29729#issuecomment-505826972
export type ByRoleMatcher = ARIARole | MatcherFunction | {}

export type NormalizerFn = (text: string) => string

export interface NormalizerOptions extends DefaultNormalizerOptions {
normalizer?: NormalizerFn
}

export interface MatcherOptions {
exact?: boolean
/** Use normalizer with getDefaultNormalizer instead */
Expand Down
3 changes: 1 addition & 2 deletions types/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"extends": "../node_modules/kcd-scripts/shared-tsconfig.json",
"include": ["."]
"extends": "../tsconfig.json"
}

0 comments on commit accb6cc

Please sign in to comment.