Skip to content

Add alias to hidden in query options #1220

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

Merged
merged 15 commits into from
Nov 15, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
coverage
*.log
.eslintcache
build
Expand Down
17 changes: 15 additions & 2 deletions src/__tests__/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ beforeEach(() => {

test('getConfig() returns existing configuration', () => {
expect(getConfig().asyncUtilTimeout).toEqual(1000);
expect(getConfig().defaultIncludeHiddenElements).toEqual(true);
});

test('configure() overrides existing config values', () => {
Expand All @@ -14,14 +15,26 @@ test('configure() overrides existing config values', () => {
expect(getConfig()).toEqual({
asyncUtilTimeout: 5000,
defaultDebugOptions: { message: 'debug message' },
defaultHidden: true,
defaultIncludeHiddenElements: true,
});
});

test('resetToDefaults() resets config to defaults', () => {
configure({ asyncUtilTimeout: 5000 });
configure({
asyncUtilTimeout: 5000,
defaultIncludeHiddenElements: false,
});
expect(getConfig().asyncUtilTimeout).toEqual(5000);
expect(getConfig().defaultIncludeHiddenElements).toEqual(false);

resetToDefaults();
expect(getConfig().asyncUtilTimeout).toEqual(1000);
expect(getConfig().defaultIncludeHiddenElements).toEqual(true);
});

test('configure handles alias option defaultHidden', () => {
expect(getConfig().defaultIncludeHiddenElements).toEqual(true);

configure({ defaultHidden: false });
expect(getConfig().defaultIncludeHiddenElements).toEqual(false);
});
23 changes: 18 additions & 5 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,37 @@ export type Config = {
/** Default timeout, in ms, for `waitFor` and `findBy*` queries. */
asyncUtilTimeout: number;

/** Default hidden value for all queries */
defaultHidden: boolean;
/** Default value for `includeHiddenElements` query option. */
defaultIncludeHiddenElements: boolean;

/** Default options for `debug` helper. */
defaultDebugOptions?: Partial<DebugOptions>;
};

export type ConfigAliasOptions = {
/** RTL-compatibility alias to `defaultIncludeHiddenElements` */
defaultHidden: boolean;
};

const defaultConfig: Config = {
asyncUtilTimeout: 1000,
defaultHidden: true,
defaultIncludeHiddenElements: true,
};

let config = { ...defaultConfig };

export function configure(options: Partial<Config>) {
export function configure(options: Partial<Config & ConfigAliasOptions>) {
const { defaultHidden, ...restOptions } = options;

const defaultIncludeHiddenElements =
restOptions.defaultIncludeHiddenElements ??
defaultHidden ??
config.defaultIncludeHiddenElements;

config = {
...config,
...options,
...restOptions,
defaultIncludeHiddenElements,
};
}

Expand Down
8 changes: 7 additions & 1 deletion src/helpers/__tests__/component-tree.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ describe('getHostParent()', () => {
expect(getHostParent(hostGrandparent)).toBe(null);
});

it('returns host parent for null', () => {
expect(getHostParent(null)).toBe(null);
});

it('returns host parent for composite component', () => {
const view = render(
<View testID="parent">
Expand All @@ -65,7 +69,7 @@ describe('getHostChildren()', () => {
<View testID="grandparent">
<View testID="parent">
<View testID="subject" />
<View testID="sibling" />
<Text testID="sibling">Hello</Text>
</View>
</View>
);
Expand All @@ -74,6 +78,8 @@ describe('getHostChildren()', () => {
expect(getHostChildren(hostSubject)).toEqual([]);

const hostSibling = view.getByTestId('sibling');
expect(getHostChildren(hostSibling)).toEqual([]);

const hostParent = view.getByTestId('parent');
expect(getHostChildren(hostParent)).toEqual([hostSubject, hostSibling]);

Expand Down
39 changes: 39 additions & 0 deletions src/helpers/__tests__/includeHiddenElements.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { View } from 'react-native';
import { configure, render, screen } from '../..';

test('includeHiddenElements query option takes priority over hidden option and global config', () => {
configure({ defaultHidden: true, defaultIncludeHiddenElements: true });
render(<View testID="view" style={{ display: 'none' }} />);
expect(
screen.queryByTestId('view', { includeHiddenElements: false, hidden: true })
).toBeFalsy();
});

test('hidden option takes priority over global config when includeHiddenElements is not defined', () => {
configure({ defaultHidden: true, defaultIncludeHiddenElements: true });
render(<View testID="view" style={{ display: 'none' }} />);
expect(screen.queryByTestId('view', { hidden: false })).toBeFalsy();
});

test('global config defaultIncludeElements option takes priority over defaultHidden when set at the same time', () => {
configure({ defaultHidden: false, defaultIncludeHiddenElements: true });
render(<View testID="view" style={{ display: 'none' }} />);
expect(screen.getByTestId('view')).toBeTruthy();
});

test('defaultHidden takes priority when it was set last', () => {
// also simulates the case when defaultIncludeHiddenElements is true by default in the config
configure({ defaultIncludeHiddenElements: true });
configure({ defaultHidden: false });
render(<View testID="view" style={{ display: 'none' }} />);
expect(screen.queryByTestId('view')).toBeFalsy();
});

test('defaultIncludeHiddenElements takes priority when it was set last', () => {
// also simulates the case when defaultHidden is true by default in the config
configure({ defaultHidden: true });
configure({ defaultIncludeHiddenElements: false });
render(<View testID="view" style={{ display: 'none' }} />);
expect(screen.queryByTestId('view')).toBeFalsy();
});
10 changes: 8 additions & 2 deletions src/helpers/findAll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { getConfig } from '../config';
import { isHiddenFromAccessibility } from './accessiblity';

interface FindAllOptions {
includeHiddenElements?: boolean;
/** RTL-compatible alias to `includeHiddenElements` */
hidden?: boolean;
}

Expand All @@ -13,8 +15,12 @@ export function findAll(
) {
const results = root.findAll(predicate);

const hidden = options?.hidden ?? getConfig().defaultHidden;
if (hidden) {
const includeHiddenElements =
options?.includeHiddenElements ??
options?.hidden ??
getConfig()?.defaultIncludeHiddenElements;

if (includeHiddenElements) {
return results;
}

Expand Down
14 changes: 10 additions & 4 deletions src/queries/__tests__/a11yState.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -238,10 +238,16 @@ test('byA11yState queries support hidden option', () => {
);

expect(getByA11yState({ expanded: false })).toBeTruthy();
expect(getByA11yState({ expanded: false }, { hidden: true })).toBeTruthy();
expect(
Copy link
Member

Choose a reason for hiding this comment

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

style: in our tests (also in other test files) I think it would be enough to use recommended includeHiddenElements option name and avoid polluting them with hidden all the time. We might want to have some few separate tests that would check that hidden alias is also used.

Copy link
Member

Choose a reason for hiding this comment

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

Or in case you find it useful the current way, just put the includeHiddenElements first as the recommended option.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

extracting them in another test file sounds good :) (helped me find a bug in the process)

getByA11yState({ expanded: false }, { includeHiddenElements: true })
).toBeTruthy();

expect(queryByA11yState({ expanded: false }, { hidden: false })).toBeFalsy();
expect(
queryByA11yState({ expanded: false }, { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByA11yState({ expanded: false }, { hidden: false })
).toThrow();
getByA11yState({ expanded: false }, { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with expanded state: false"`
);
});
16 changes: 12 additions & 4 deletions src/queries/__tests__/a11yValue.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,16 @@ test('byA11yValue queries support hidden option', () => {
);

expect(getByA11yValue({ max: 10 })).toBeTruthy();
expect(getByA11yValue({ max: 10 }, { hidden: true })).toBeTruthy();

expect(queryByA11yValue({ max: 10 }, { hidden: false })).toBeFalsy();
expect(() => getByA11yValue({ max: 10 }, { hidden: false })).toThrow();
expect(
getByA11yValue({ max: 10 }, { includeHiddenElements: true })
).toBeTruthy();

expect(
queryByA11yValue({ max: 10 }, { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByA11yValue({ max: 10 }, { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with accessibilityValue: {"max":10}"`
);
});
16 changes: 12 additions & 4 deletions src/queries/__tests__/displayValue.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,16 @@ test('byDisplayValue queries support hidden option', () => {
);

expect(getByDisplayValue('hidden')).toBeTruthy();
expect(getByDisplayValue('hidden', { hidden: true })).toBeTruthy();

expect(queryByDisplayValue('hidden', { hidden: false })).toBeFalsy();
expect(() => getByDisplayValue('hidden', { hidden: false })).toThrow();
expect(
getByDisplayValue('hidden', { includeHiddenElements: true })
).toBeTruthy();

expect(
queryByDisplayValue('hidden', { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByDisplayValue('hidden', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with displayValue: hidden"`
);
});
14 changes: 10 additions & 4 deletions src/queries/__tests__/hintText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,14 @@ test('byHintText queries support hidden option', () => {
);

expect(getByHintText('hidden')).toBeTruthy();
expect(getByHintText('hidden', { hidden: true })).toBeTruthy();

expect(queryByHintText('hidden', { hidden: false })).toBeFalsy();
expect(() => getByHintText('hidden', { hidden: false })).toThrow();
expect(getByHintText('hidden', { includeHiddenElements: true })).toBeTruthy();

expect(
queryByHintText('hidden', { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByHintText('hidden', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with accessibilityHint: hidden"`
);
});
16 changes: 12 additions & 4 deletions src/queries/__tests__/labelText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,16 @@ test('byLabelText queries support hidden option', () => {
);

expect(getByLabelText('hidden')).toBeTruthy();
expect(getByLabelText('hidden', { hidden: true })).toBeTruthy();

expect(queryByLabelText('hidden', { hidden: false })).toBeFalsy();
expect(() => getByLabelText('hidden', { hidden: false })).toThrow();
expect(
getByLabelText('hidden', { includeHiddenElements: true })
).toBeTruthy();

expect(
queryByLabelText('hidden', { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByLabelText('hidden', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with accessibilityLabel: hidden"`
);
});
14 changes: 11 additions & 3 deletions src/queries/__tests__/placeholderText.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,16 @@ test('byPlaceholderText queries support hidden option', () => {
);

expect(getByPlaceholderText('hidden')).toBeTruthy();
expect(getByPlaceholderText('hidden', { hidden: true })).toBeTruthy();
expect(
getByPlaceholderText('hidden', { includeHiddenElements: true })
).toBeTruthy();

expect(queryByPlaceholderText('hidden', { hidden: false })).toBeFalsy();
expect(() => getByPlaceholderText('hidden', { hidden: false })).toThrow();
expect(
queryByPlaceholderText('hidden', { includeHiddenElements: false })
).toBeFalsy();
expect(() =>
getByPlaceholderText('hidden', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with placeholder: hidden"`
);
});
10 changes: 7 additions & 3 deletions src/queries/__tests__/role.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -706,8 +706,12 @@ test('byRole queries support hidden option', () => {
);

expect(getByRole('button')).toBeTruthy();
expect(getByRole('button', { hidden: true })).toBeTruthy();
expect(getByRole('button', { includeHiddenElements: true })).toBeTruthy();

expect(queryByRole('button', { hidden: false })).toBeFalsy();
expect(() => getByRole('button', { hidden: false })).toThrow();
expect(queryByRole('button', { includeHiddenElements: false })).toBeFalsy();
expect(() =>
getByRole('button', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with role: "button""`
);
});
10 changes: 7 additions & 3 deletions src/queries/__tests__/testId.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,12 @@ test('byTestId queries support hidden option', () => {
);

expect(getByTestId('hidden')).toBeTruthy();
expect(getByTestId('hidden', { hidden: true })).toBeTruthy();
expect(getByTestId('hidden', { includeHiddenElements: true })).toBeTruthy();

expect(queryByTestId('hidden', { hidden: false })).toBeFalsy();
expect(() => getByTestId('hidden', { hidden: false })).toThrow();
expect(queryByTestId('hidden', { includeHiddenElements: false })).toBeFalsy();
expect(() =>
getByTestId('hidden', { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with testID: hidden"`
);
});
10 changes: 7 additions & 3 deletions src/queries/__tests__/text.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,12 @@ test('byText support hidden option', () => {
);

expect(getByText(/hidden/i)).toBeTruthy();
expect(getByText(/hidden/i, { hidden: true })).toBeTruthy();
expect(getByText(/hidden/i, { includeHiddenElements: true })).toBeTruthy();

expect(queryByText(/hidden/i, { hidden: false })).toBeFalsy();
expect(() => getByText(/hidden/i, { hidden: false })).toThrow();
expect(queryByText(/hidden/i, { includeHiddenElements: false })).toBeFalsy();
expect(() =>
getByText(/hidden/i, { includeHiddenElements: false })
).toThrowErrorMatchingInlineSnapshot(
`"Unable to find an element with text: /hidden/i"`
);
});
8 changes: 7 additions & 1 deletion src/queries/options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { NormalizerFn } from '../matches';

export type CommonQueryOptions = { hidden?: boolean };
export type CommonQueryOptions = {
/** Should query include elements hidden from accessibility. */
includeHiddenElements?: boolean;

/** RTL-compatibile alias to `includeHiddenElements`. */
hidden?: boolean;
};

export type TextMatchOptions = {
exact?: boolean;
Expand Down
15 changes: 13 additions & 2 deletions typings/index.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ type QueryAllReturn = Array<ReactTestInstance> | [];
type FindReturn = Promise<ReactTestInstance>;
type FindAllReturn = Promise<ReactTestInstance[]>;

type CommonQueryOptions = { hidden?: boolean };
type CommonQueryOptions = {
includeHiddenElements?: boolean,
hidden?: boolean,
};
type TextMatch = string | RegExp;

declare type NormalizerFn = (textToNormalize: string) => string;
Expand Down Expand Up @@ -463,10 +466,18 @@ declare module '@testing-library/react-native' {

declare interface Config {
asyncUtilTimeout: number;
defaultIncludeHiddenElements: boolean;
defaultDebugOptions?: $Shape<DebugOptions>;
}

declare export var configure: (options: $Shape<Config>) => void;
declare interface ConfigAliasOptions {
/** Alias to `defaultIncludeHiddenElements` for RTL compatibility */
defaultHidden: boolean;
}

declare export var configure: (
options: $Shape<Config & ConfigAliasOptions>
) => void;
declare export var resetToDefaults: () => void;

declare export var act: (callback: () => void) => Thenable;
Expand Down
Loading