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

chore: deprecate some a11y queries #1226

Merged
merged 11 commits into from
Jan 28, 2023
10 changes: 10 additions & 0 deletions src/helpers/__tests__/query-name.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { getQueryPrefix } from '../query-name';

test('getQueryPrefix should return correct prefix', () => {
expect(getQueryPrefix('getByRole')).toBe('get');
expect(getQueryPrefix('getAllByText')).toEqual('getAll');
expect(getQueryPrefix('queryByTestId')).toEqual('query');
expect(getQueryPrefix('queryAllByPlaceholderText')).toEqual('queryAll');
expect(getQueryPrefix('findByHintText')).toEqual('find');
expect(getQueryPrefix('findAllByDisplayValue')).toEqual('findAll');
});
36 changes: 36 additions & 0 deletions src/helpers/deprecation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { getQueryPrefix } from './query-name';

export function deprecateQueries<Queries extends Record<string, any>>(
queriesObject: Queries,
recommendation: string
): Queries {
const result = {} as Queries;
Object.keys(queriesObject).forEach((queryName) => {
const queryFn = queriesObject[queryName];
// @ts-expect-error: generic typing is hard
result[queryName] = deprecateQuery(queryFn, queryName, recommendation);
});

return result;
}

function deprecateQuery<QueryFn extends (...args: any) => any>(
queryFn: QueryFn,
queryName: string,
recommendation: string
): QueryFn {
const formattedRecommendation = recommendation.replace(
/{queryPrefix}/g,
getQueryPrefix(queryName)
);

// @ts-expect-error: generic typing is hard
const wrapper: QueryFn = (...args: any) => {
const errorMessage = `${queryName}(...) is deprecated and will be removed in the future.\n\n${formattedRecommendation}`;
// eslint-disable-next-line no-console
console.warn(errorMessage);
return queryFn(...args);
};

return wrapper;
}
4 changes: 4 additions & 0 deletions src/helpers/query-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export function getQueryPrefix(queryName: string) {
const parts = queryName.split('By');
return parts[0];
}
101 changes: 101 additions & 0 deletions src/queries/__tests__/a11yState.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/* eslint-disable no-console */
import * as React from 'react';
import { View, Text, Pressable, TouchableOpacity } from 'react-native';
import { render } from '../..';

type ConsoleLogMock = jest.Mock<typeof console.log>;

beforeEach(() => {
jest.spyOn(console, 'warn').mockImplementation(() => {});
});

const TEXT_LABEL = 'cool text';

const Typography = ({ children, ...rest }: any) => {
Expand Down Expand Up @@ -251,3 +258,97 @@ test('byA11yState queries support hidden option', () => {
`"Unable to find an element with expanded state: false"`
);
});

test('*ByA11yState deprecation warnings', () => {
const mockCalls = (console.warn as ConsoleLogMock).mock.calls;
const view = render(<View accessibilityState={{ disabled: true }} />);

view.getByA11yState({ disabled: true });
expect(mockCalls[0][0]).toMatchInlineSnapshot(`
"getByA11yState(...) is deprecated and will be removed in the future.

Use getByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.getAllByA11yState({ disabled: true });
expect(mockCalls[1][0]).toMatchInlineSnapshot(`
"getAllByA11yState(...) is deprecated and will be removed in the future.

Use getAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.queryByA11yState({ disabled: true });
expect(mockCalls[2][0]).toMatchInlineSnapshot(`
"queryByA11yState(...) is deprecated and will be removed in the future.

Use queryByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.queryAllByA11yState({ disabled: true });
expect(mockCalls[3][0]).toMatchInlineSnapshot(`
"queryAllByA11yState(...) is deprecated and will be removed in the future.

Use queryAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.findByA11yState({ disabled: true });
expect(mockCalls[4][0]).toMatchInlineSnapshot(`
"findByA11yState(...) is deprecated and will be removed in the future.

Use findByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.findAllByA11yState({ disabled: true });
expect(mockCalls[5][0]).toMatchInlineSnapshot(`
"findAllByA11yState(...) is deprecated and will be removed in the future.

Use findAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);
});

test('*ByAccessibilityState deprecation warnings', () => {
const mockCalls = (console.warn as ConsoleLogMock).mock.calls;
const view = render(<View accessibilityState={{ disabled: true }} />);

view.getByAccessibilityState({ disabled: true });
expect(mockCalls[0][0]).toMatchInlineSnapshot(`
"getByAccessibilityState(...) is deprecated and will be removed in the future.

Use getByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.getAllByAccessibilityState({ disabled: true });
expect(mockCalls[1][0]).toMatchInlineSnapshot(`
"getAllByAccessibilityState(...) is deprecated and will be removed in the future.

Use getAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.queryByAccessibilityState({ disabled: true });
expect(mockCalls[2][0]).toMatchInlineSnapshot(`
"queryByAccessibilityState(...) is deprecated and will be removed in the future.

Use queryByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.queryAllByAccessibilityState({ disabled: true });
expect(mockCalls[3][0]).toMatchInlineSnapshot(`
"queryAllByAccessibilityState(...) is deprecated and will be removed in the future.

Use queryAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.findByAccessibilityState({ disabled: true });
expect(mockCalls[4][0]).toMatchInlineSnapshot(`
"findByAccessibilityState(...) is deprecated and will be removed in the future.

Use findByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);

view.findAllByAccessibilityState({ disabled: true });
expect(mockCalls[5][0]).toMatchInlineSnapshot(`
"findAllByAccessibilityState(...) is deprecated and will be removed in the future.

Use findAllByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead."
`);
});
101 changes: 101 additions & 0 deletions src/queries/__tests__/a11yValue.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
/* eslint-disable no-console */
import * as React from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import { render } from '../..';

type ConsoleLogMock = jest.Mock<typeof console.log>;

beforeEach(() => {
jest.spyOn(console, 'warn').mockImplementation(() => {});
});

const TEXT_LABEL = 'cool text';

const Typography = ({ children, ...rest }: any) => {
Expand Down Expand Up @@ -130,3 +137,97 @@ test('byA11yValue error messages', () => {
`"Unable to find an element with min value: 1, max value: 2, now value: 3, text value: /foo/i"`
);
});

test('*ByA11yValue deprecation warnings', () => {
const mockCalls = (console.warn as ConsoleLogMock).mock.calls;
const view = render(<View accessibilityValue={{ min: 10 }} />);

view.getByA11yValue({ min: 10 });
expect(mockCalls[0][0]).toMatchInlineSnapshot(`
"getByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or getByRole(role, { value: ... }) query instead."
`);

view.getAllByA11yValue({ min: 10 });
expect(mockCalls[1][0]).toMatchInlineSnapshot(`
"getAllByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or getAllByRole(role, { value: ... }) query instead."
`);

view.queryByA11yValue({ min: 10 });
expect(mockCalls[2][0]).toMatchInlineSnapshot(`
"queryByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or queryByRole(role, { value: ... }) query instead."
`);

view.queryAllByA11yValue({ min: 10 });
expect(mockCalls[3][0]).toMatchInlineSnapshot(`
"queryAllByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or queryAllByRole(role, { value: ... }) query instead."
`);

view.findByA11yValue({ min: 10 });
expect(mockCalls[4][0]).toMatchInlineSnapshot(`
"findByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or findByRole(role, { value: ... }) query instead."
`);

view.findAllByA11yValue({ min: 10 });
expect(mockCalls[5][0]).toMatchInlineSnapshot(`
"findAllByA11yValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or findAllByRole(role, { value: ... }) query instead."
`);
});

test('*ByAccessibilityValue deprecation warnings', () => {
const mockCalls = (console.warn as ConsoleLogMock).mock.calls;
const view = render(<View accessibilityValue={{ min: 10 }} />);

view.getByAccessibilityValue({ min: 10 });
expect(mockCalls[0][0]).toMatchInlineSnapshot(`
"getByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or getByRole(role, { value: ... }) query instead."
`);

view.getAllByAccessibilityValue({ min: 10 });
expect(mockCalls[1][0]).toMatchInlineSnapshot(`
"getAllByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or getAllByRole(role, { value: ... }) query instead."
`);

view.queryByAccessibilityValue({ min: 10 });
expect(mockCalls[2][0]).toMatchInlineSnapshot(`
"queryByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or queryByRole(role, { value: ... }) query instead."
`);

view.queryAllByAccessibilityValue({ min: 10 });
expect(mockCalls[3][0]).toMatchInlineSnapshot(`
"queryAllByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or queryAllByRole(role, { value: ... }) query instead."
`);

view.findByAccessibilityValue({ min: 10 });
expect(mockCalls[4][0]).toMatchInlineSnapshot(`
"findByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or findByRole(role, { value: ... }) query instead."
`);

view.findAllByAccessibilityValue({ min: 10 });
expect(mockCalls[5][0]).toMatchInlineSnapshot(`
"findAllByAccessibilityValue(...) is deprecated and will be removed in the future.

Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or findAllByRole(role, { value: ... }) query instead."
`);
});
31 changes: 18 additions & 13 deletions src/queries/a11yState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { AccessibilityState } from 'react-native';
import { accessibilityStateKeys } from '../helpers/accessiblity';
import { deprecateQueries } from '../helpers/deprecation';
import { findAll } from '../helpers/findAll';
import { matchAccessibilityState } from '../helpers/matchers/accessibilityState';
import { makeQueries } from './makeQueries';
Expand Down Expand Up @@ -92,18 +93,22 @@ export const bindByA11yStateQueries = (
const findAllByA11yState = findAllBy(instance);

return {
getByA11yState,
getAllByA11yState,
queryByA11yState,
queryAllByA11yState,
findByA11yState,
findAllByA11yState,

getByAccessibilityState: getByA11yState,
getAllByAccessibilityState: getAllByA11yState,
queryByAccessibilityState: queryByA11yState,
queryAllByAccessibilityState: queryAllByA11yState,
findByAccessibilityState: findByA11yState,
findAllByAccessibilityState: findAllByA11yState,
...deprecateQueries(
{
getByA11yState,
getAllByA11yState,
queryByA11yState,
queryAllByA11yState,
findByA11yState,
findAllByA11yState,
getByAccessibilityState: getByA11yState,
getAllByAccessibilityState: getAllByA11yState,
queryByAccessibilityState: queryByA11yState,
queryAllByAccessibilityState: queryAllByA11yState,
findByAccessibilityState: findByA11yState,
findAllByAccessibilityState: findAllByA11yState,
},
'Use {queryPrefix}ByRole(role, { disabled, selected, checked, busy, expanded }) query or expect(...).toHaveAccessibilityState(...) matcher from "@testing-library/jest-native" package instead.'
),
};
};
31 changes: 18 additions & 13 deletions src/queries/a11yValue.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ReactTestInstance } from 'react-test-renderer';
import { accessiblityValueKeys } from '../helpers/accessiblity';
import { deprecateQueries } from '../helpers/deprecation';
import { findAll } from '../helpers/findAll';
import {
AccessibilityValueMatcher,
Expand Down Expand Up @@ -109,18 +110,22 @@ export const bindByA11yValueQueries = (
const findAllByA11yValue = findAllBy(instance);

return {
getByA11yValue,
getAllByA11yValue,
queryByA11yValue,
queryAllByA11yValue,
findByA11yValue,
findAllByA11yValue,

getByAccessibilityValue: getByA11yValue,
getAllByAccessibilityValue: getAllByA11yValue,
queryByAccessibilityValue: queryByA11yValue,
queryAllByAccessibilityValue: queryAllByA11yValue,
findByAccessibilityValue: findByA11yValue,
findAllByAccessibilityValue: findAllByA11yValue,
...deprecateQueries(
{
getByA11yValue,
getAllByA11yValue,
queryByA11yValue,
queryAllByA11yValue,
findByA11yValue,
findAllByA11yValue,
getByAccessibilityValue: getByA11yValue,
getAllByAccessibilityValue: getAllByA11yValue,
queryByAccessibilityValue: queryByA11yValue,
queryAllByAccessibilityValue: queryAllByA11yValue,
findByAccessibilityValue: findByA11yValue,
findAllByAccessibilityValue: findAllByA11yValue,
},
'Use expect(...).toHaveAccessibilityValue(...) matcher from "@testing-library/jest-native" package or {queryPrefix}ByRole(role, { value: ... }) query instead.'
),
};
};
4 changes: 2 additions & 2 deletions website/docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ Use cases for scoped queries include:

## `query` APIs

Each of the get APIs listed in the render section above have a complimentary query API. The get APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the query API instead:
Each of the `getBy` APIs listed in the render section above have a complimentary `queryBy` API. The `getBy` APIs will throw errors if a proper node cannot be found. This is normally the desired effect. However, if you want to make an assertion that an element is not present in the hierarchy, then you can use the `queryBy` API instead:

```jsx
import { render, screen } from '@testing-library/react-native';
Expand All @@ -697,7 +697,7 @@ expect(submitButton).not.toBeOnTheScreen(); // it doesn't exist

## `queryAll` APIs

Each of the query APIs have a corresponding queryAll version that always returns an Array of matching nodes. getAll is the same but throws when the array has a length of 0.
Each of the query APIs have a corresponding `queryAll` version that always returns an array of matching nodes. `getAll` is the same but throws when the array has a length of 0.

```jsx
import { render } from '@testing-library/react-native';
Expand Down
Loading