Skip to content
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

Copied types from DefinitelyTyped into this repository #530

Merged
merged 12 commits into from
May 7, 2020
Merged
10 changes: 7 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.0.0-semantically-released",
"description": "Simple and complete DOM testing utilities that encourage good testing practices.",
"main": "dist/index.js",
"types": "types/index.d.ts",
"module": "dist/@testing-library/dom.esm.js",
"umd:main": "dist/@testing-library/dom.umd.js",
"source": "src/index.js",
Expand All @@ -29,20 +30,23 @@
"test": "kcd-scripts test",
"test:debug": "node --inspect-brk ./node_modules/.bin/jest --watch --runInBand",
"test:update": "npm test -- --updateSnapshot --coverage",
"validate": "kcd-scripts validate"
"validate": "npm run typecheck && kcd-scripts validate",
"typecheck": "dtslint ./types/"
},
"files": [
"dist"
"dist",
"types"
],
"dependencies": {
"@babel/runtime": "^7.9.2",
"@types/testing-library__dom": "^7.0.0",
"aria-query": "^4.0.2",
"dom-accessibility-api": "^0.4.2",
"pretty-format": "^25.1.0"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.1.1",
"conditional-type-checks": "^1.0.5",
eps1lon marked this conversation as resolved.
Show resolved Hide resolved
"dtslint": "^3.4.2",
"jest-in-case": "^1.0.2",
"jest-serializer-ansi": "^1.0.3",
"jest-watch-select-projects": "^2.0.0",
Expand Down
122 changes: 122 additions & 0 deletions types/__tests__/type-tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {
fireEvent,
isInaccessible,
queries,
screen,
waitFor,
waitForElementToBeRemoved,
} from '../index'

const {
getByText,
queryByText,
findByText,
getAllByText,
queryAllByText,
findAllByText,
queryAllByRole,
queryByRole,
findByRole,
} = queries

async function testQueries() {
// element queries
const element = document.createElement('div')
getByText(element, 'foo')
queryByText(element, 'foo')
await findByText(element, 'foo')
await findByText(element, 'foo', undefined, {timeout: 10})
getAllByText(element, 'bar')
queryAllByText(element, 'bar')
await findAllByText(element, 'bar')
await findAllByText(element, 'bar', undefined, {timeout: 10})

// screen queries
screen.getByText('foo')
screen.queryByText('foo')
await screen.findByText('foo')
await screen.findByText('foo', undefined, {timeout: 10})
screen.debug(screen.getAllByText('bar'))
screen.queryAllByText('bar')
await screen.findAllByText('bar')
await screen.findAllByText('bar', undefined, {timeout: 10})
}

async function testByRole() {
const element = document.createElement('button')
element.setAttribute('aria-hidden', 'true')

console.assert(queryByRole(element, 'button') === null)
console.assert(queryByRole(element, 'button', {hidden: true}) !== null)

console.assert(screen.queryByRole('button') === null)
console.assert(screen.queryByRole('button', {hidden: true}) !== null)

console.assert(
(await findByRole(element, 'button', undefined, {timeout: 10})) === null,
)
console.assert(
(await findByRole(element, 'button', {hidden: true}, {timeout: 10})) !==
null,
)

console.assert(
queryAllByRole(document.body, 'progressbar', {queryFallbacks: true})
.length === 1,
)

// `name` option
console.assert(queryByRole(element, 'button', {name: 'Logout'}) === null)
console.assert(queryByRole(element, 'button', {name: /^Log/}) === null)
console.assert(
queryByRole(element, 'button', {
name: (name, element) =>
name === 'Login' && element.hasAttribute('disabled'),
}) === null,
)
}

function testA11yHelper() {
const element = document.createElement('svg')
console.assert(!isInaccessible(element))
}

function eventTest() {
fireEvent.popState(window, {
location: 'http://www.example.com/?page=1',
state: {page: 1},
})

// HTMLElement
const element = document.createElement('div')
fireEvent.click(getByText(element, 'foo'))

// ChildNode
const child = document.createElement('div')
element.appendChild(child)
if (!element.firstChild) {
// Narrow Type
throw new Error(`Can't find firstChild`)
}
fireEvent.click(element.firstChild)
}

async function testWaitFors() {
const element = document.createElement('div')

await waitFor(() => getByText(element, 'apple'))
await waitFor(() => getAllByText(element, 'apple'))
const result: HTMLSpanElement = await waitFor(() =>
getByText(element, 'apple'),
)
if (!result) {
// Use value
throw new Error(`Can't find result`)
}

element.innerHTML = '<span>apple</span>'

await waitForElementToBeRemoved(() => getByText(element, 'apple'))
await waitForElementToBeRemoved(getByText(element, 'apple'))
await waitForElementToBeRemoved(getAllByText(element, 'apple'))
}
12 changes: 12 additions & 0 deletions types/config.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface Config {
testIdAttribute: string;
asyncWrapper(cb: (...args: any[]) => any): Promise<any>;
asyncUtilTimeout: number;
defaultHidden: boolean;
}

export interface ConfigFn {
(existingConfig: Config): Partial<Config>;
}

export function configure(configDelta: Partial<Config> | ConfigFn): void;
95 changes: 95 additions & 0 deletions types/events.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
export type EventType =
| 'copy'
| 'cut'
| 'paste'
| 'compositionEnd'
| 'compositionStart'
| 'compositionUpdate'
| 'keyDown'
| 'keyPress'
| 'keyUp'
| 'focus'
| 'blur'
| 'focusIn'
| 'focusOut'
| 'change'
| 'input'
| 'invalid'
| 'submit'
| 'reset'
| 'click'
| 'contextMenu'
| 'dblClick'
| 'drag'
| 'dragEnd'
| 'dragEnter'
| 'dragExit'
| 'dragLeave'
| 'dragOver'
| 'dragStart'
| 'drop'
| 'mouseDown'
| 'mouseEnter'
| 'mouseLeave'
| 'mouseMove'
| 'mouseOut'
| 'mouseOver'
| 'mouseUp'
| 'popState'
| 'select'
| 'touchCancel'
| 'touchEnd'
| 'touchMove'
| 'touchStart'
| 'scroll'
| 'wheel'
| 'abort'
| 'canPlay'
| 'canPlayThrough'
| 'durationChange'
| 'emptied'
| 'encrypted'
| 'ended'
| 'loadedData'
| 'loadedMetadata'
| 'loadStart'
| 'pause'
| 'play'
| 'playing'
| 'progress'
| 'rateChange'
| 'seeked'
| 'seeking'
| 'stalled'
| 'suspend'
| 'timeUpdate'
| 'volumeChange'
| 'waiting'
| 'load'
| 'error'
| 'animationStart'
| 'animationEnd'
| 'animationIteration'
| 'transitionEnd'
| 'doubleClick'
| 'pointerOver'
| 'pointerEnter'
| 'pointerDown'
| 'pointerMove'
| 'pointerUp'
| 'pointerCancel'
| 'pointerOut'
| 'pointerLeave'
| 'gotPointerCapture'
| 'lostPointerCapture';

export type FireFunction = (element: Document | Element | Window | Node, event: Event) => boolean;
export type FireObject = {
[K in EventType]: (element: Document | Element | Window | Node, options?: {}) => boolean;
};
export type CreateObject = {
[K in EventType]: (element: Document | Element | Window | Node, options?: {}) => Event;
};

export const createEvent: CreateObject;
export const fireEvent: FireFunction & FireObject;
1 change: 1 addition & 0 deletions types/get-node-text.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export function getNodeText(node: HTMLElement): string;
30 changes: 30 additions & 0 deletions types/get-queries-for-element.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Matcher } from './matches';
import * as queries from './queries';

export type BoundFunction<T> = T extends (
attribute: string,
element: HTMLElement,
text: infer P,
options: infer Q,
) => infer R
? (text: P, options?: Q) => R
: T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer W) => infer R
? (text: P, options?: Q, waitForElementOptions?: W) => R
: T extends (a1: any, text: infer P, options: infer Q) => infer R
? (text: P, options?: Q) => R
: never;
export type BoundFunctions<T> = { [P in keyof T]: BoundFunction<T[P]> };

export type Query = (
container: HTMLElement,
...args: any[]
) => Error | Promise<HTMLElement[]> | Promise<HTMLElement> | HTMLElement[] | HTMLElement | null;

export interface Queries {
[T: string]: Query;
}

export function getQueriesForElement<T extends Queries = typeof queries>(
element: HTMLElement,
queriesToBind?: T,
): BoundFunctions<T>;
24 changes: 24 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// TypeScript Version: 3.1

import { getQueriesForElement } from './get-queries-for-element';
import * as queries from './queries';
import * as queryHelpers from './query-helpers';

declare const within: typeof getQueriesForElement;
export { queries, queryHelpers, within };

export * from './queries';
export * from './query-helpers';
export * from './screen';
export * from './wait';
export * from './wait-for';
export * from './wait-for-dom-change';
export * from './wait-for-element';
export * from './wait-for-element-to-be-removed';
export * from './matches';
export * from './get-node-text';
export * from './events';
export * from './get-queries-for-element';
export * from './pretty-dom';
export * from './role-helpers';
export * from './config';
29 changes: 29 additions & 0 deletions types/matches.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export type MatcherFunction = (content: string, element: HTMLElement) => boolean;
export type Matcher = string | RegExp | MatcherFunction;

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

export interface MatcherOptions {
exact?: boolean;
/** Use normalizer with getDefaultNormalizer instead */
trim?: boolean;
/** Use normalizer with getDefaultNormalizer instead */
collapseWhitespace?: boolean;
normalizer?: NormalizerFn;
}

export type Match = (
textToMatch: string,
node: HTMLElement | null,
matcher: Matcher,
options?: MatcherOptions,
) => boolean;

export interface DefaultNormalizerOptions {
trim?: boolean;
collapseWhitespace?: boolean;
}

export function getDefaultNormalizer(options?: DefaultNormalizerOptions): NormalizerFn;

// N.B. Don't expose fuzzyMatches + matches here: they're not public API
4 changes: 4 additions & 0 deletions types/pretty-dom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { OptionsReceived } from 'pretty-format';

export function prettyDOM(dom?: Element | HTMLDocument, maxLength?: number, options?: OptionsReceived): string | false;
export function logDOM(dom?: Element | HTMLDocument, maxLength?: number, options?: OptionsReceived): void;
Loading