Skip to content

Adding support for extending with custom queries #573

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

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/__tests__/render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -382,3 +382,17 @@ test('renders options.wrapper around updated node', () => {
</RCTSafeAreaView>
`);
});

test('returns custom queries added', () => {
const _getByCustom = (instance: ReactTestInstance, someArg: string) => {
return `You sent: ${someArg}`;
};

const { getByCustom } = render(<View />, {
queries: {
getByCustom: _getByCustom,
},
});

expect(getByCustom('yass!!')).toBe('You sent: yass!!');
});
22 changes: 13 additions & 9 deletions src/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ import * as React from 'react';
import TestRenderer, { type ReactTestRenderer } from 'react-test-renderer'; // eslint-disable-line import/no-extraneous-dependencies
import act from './act';
import { addToCleanupQueue } from './cleanup';
import { getByAPI } from './helpers/getByAPI';
import { queryByAPI } from './helpers/queryByAPI';
import { findByAPI } from './helpers/findByAPI';
import a11yAPI from './helpers/a11yAPI';
import debugShallow from './helpers/debugShallow';
import debugDeep from './helpers/debugDeep';
import { getQueriesForElement } from './within';

type Options = {
wrapper?: React.ComponentType<any>,
createNodeMock?: (element: React.Element<any>) => any,
queries?: {
[key: string]: (instance: ReactTestInstance, ...rest: Array<any>) => any,
},
};
type TestRendererOptions = {
createNodeMock: (element: React.Element<any>) => any,
Expand All @@ -24,7 +24,7 @@ type TestRendererOptions = {
*/
export default function render<T>(
component: React.Element<T>,
{ wrapper: Wrapper, createNodeMock }: Options = {}
{ wrapper: Wrapper, createNodeMock, queries = {} }: Options = {}
) {
const wrap = (innerElement: React.Element<any>) =>
Wrapper ? <Wrapper>{innerElement}</Wrapper> : innerElement;
Expand All @@ -36,13 +36,17 @@ export default function render<T>(
const update = updateWithAct(renderer, wrap);
const instance = renderer.root;

for (let query in queries) {
queries[query] = queries[query].bind(null, instance);
}

addToCleanupQueue(renderer.unmount);

return {
...getByAPI(instance),
...queryByAPI(instance),
...findByAPI(instance),
...a11yAPI(instance),
...(queries: {
[key: $Keys<typeof queries>]: (...rest: Array<any>) => any,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Struggling a bit on how to type it better, so that custom queries are inferred without forced generics. We can improve it later though

}),
...getQueriesForElement(instance),
update,
rerender: update, // alias for `update`
unmount: renderer.unmount,
Expand Down
8 changes: 7 additions & 1 deletion typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,10 @@ interface FindByAPI {
value: string | RegExp,
waitForOptions?: WaitForOptions
) => FindReturn;
findByTestId: (testID: string | RegExp, waitForOptions?: WaitForOptions) => FindReturn;
findByTestId: (
testID: string | RegExp,
waitForOptions?: WaitForOptions
) => FindReturn;
findAllByText: (
text: string | RegExp,
waitForOptions?: WaitForOptions
Expand Down Expand Up @@ -293,6 +296,9 @@ export interface Thenable {
export interface RenderOptions {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I check RTL/DTL and they seem to have quite decent TS typings for custom queries:

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

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

Source: https://github.com/testing-library/dom-testing-library/blob/master/types/get-queries-for-element.d.ts

export type RenderResult<Q extends Queries = typeof queries> = {
  // ...
} & {[P in keyof Q]: BoundFunction<Q[P]>}

export interface RenderOptions<Q extends Queries = typeof queries> {
  // ...
  queries?: Q
}

Source: https://github.com/testing-library/react-testing-library/blob/master/types/index.d.ts

IMO we could have the same at least for TS, possibly for flow as well if possible.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that the Query type restricts return value to (Promise)(Array) Element + null + Error. IMO if we provide element queries then we should also consider similar restriction. wdyt?

wrapper?: React.ComponentType<any>;
createNodeMock?: (element: React.ReactElement<any>) => any;
queries?: {
[key: string]: (instance: ReactTestInstance, ...rest: Array<any>) => any;
};
}

type Queries = GetByAPI & QueryByAPI & FindByAPI & A11yAPI;
Expand Down