Skip to content

Commit

Permalink
feat: implement toBeSelected matcher (#1488)
Browse files Browse the repository at this point in the history
* feat: implement toBeSelected

* refactor: tweaks

* refactor: tweak tests

* refactor: finishing touches

---------

Co-authored-by: Maciej Jastrze台bski <mdjastrzebski@gmail.com>
  • Loading branch information
AntoineThibi and mdjastrzebski committed Sep 8, 2023
1 parent 8373d6a commit 1592d35
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/helpers/accessiblity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ export function getAccessibilityCheckedState(
return ariaChecked ?? accessibilityState?.checked;
}

export function getAccessibilitySelectedState(
element: ReactTestInstance
): NonNullable<AccessibilityState['selected']> {
const { accessibilityState, 'aria-selected': ariaSelected } = element.props;
return ariaSelected ?? accessibilityState?.selected ?? false;
}

export function getAccessibilityValue(
element: ReactTestInstance
): AccessibilityValue | undefined {
Expand Down
96 changes: 96 additions & 0 deletions src/matchers/__tests__/to-be-selected.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as React from 'react';
import { View } from 'react-native';
import { render, screen } from '../..';
import '../extend-expect';

test('.toBeSelected() basic case', () => {
render(
<>
<View testID="selected" accessibilityState={{ selected: true }} />
<View testID="selected-aria" aria-selected />
<View testID="not-selected" accessibilityState={{ selected: false }} />
<View testID="not-selected-aria" aria-selected={false} />
<View testID="default" />
</>
);

expect(screen.getByTestId('selected')).toBeSelected();
expect(screen.getByTestId('selected-aria')).toBeSelected();
expect(screen.getByTestId('not-selected')).not.toBeSelected();
expect(screen.getByTestId('not-selected-aria')).not.toBeSelected();
expect(screen.getByTestId('default')).not.toBeSelected();
});

test('.toBeSelected() error messages', () => {
render(
<>
<View testID="selected" accessibilityState={{ selected: true }} />
<View testID="selected-aria" aria-selected />
<View testID="not-selected" accessibilityState={{ selected: false }} />
<View testID="not-selected-aria" aria-selected={false} />
<View testID="default" />
</>
);

expect(() => expect(screen.getByTestId('selected')).not.toBeSelected())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).not.toBeSelected()
Received element is selected
<View
accessibilityState={
{
"selected": true,
}
}
testID="selected"
/>"
`);

expect(() => expect(screen.getByTestId('selected-aria')).not.toBeSelected())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).not.toBeSelected()
Received element is selected
<View
aria-selected={true}
testID="selected-aria"
/>"
`);

expect(() => expect(screen.getByTestId('not-selected')).toBeSelected())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).toBeSelected()
Received element is not selected
<View
accessibilityState={
{
"selected": false,
}
}
testID="not-selected"
/>"
`);

expect(() => expect(screen.getByTestId('not-selected-aria')).toBeSelected())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).toBeSelected()
Received element is not selected
<View
aria-selected={false}
testID="not-selected-aria"
/>"
`);

expect(() => expect(screen.getByTestId('default')).toBeSelected())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).toBeSelected()
Received element is not selected
<View
testID="default"
/>"
`);
});
1 change: 1 addition & 0 deletions src/matchers/extend-expect.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface JestNativeMatchers<R> {
toBeEmptyElement(): R;
toBeEnabled(): R;
toBePartiallyChecked(): R;
toBeSelected(): R;
toBeVisible(): R;
toHaveDisplayValue(expectedValue: TextMatch, options?: TextMatchOptions): R;
toHaveProp(name: string, expectedValue?: unknown): R;
Expand Down
2 changes: 2 additions & 0 deletions src/matchers/extend-expect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { toBeChecked } from './to-be-checked';
import { toBeDisabled, toBeEnabled } from './to-be-disabled';
import { toBeEmptyElement } from './to-be-empty-element';
import { toBePartiallyChecked } from './to-be-partially-checked';
import { toBeSelected } from './to-be-selected';
import { toBeVisible } from './to-be-visible';
import { toHaveDisplayValue } from './to-have-display-value';
import { toHaveProp } from './to-have-prop';
Expand All @@ -17,6 +18,7 @@ expect.extend({
toBeEmptyElement,
toBeEnabled,
toBePartiallyChecked,
toBeSelected,
toBeVisible,
toHaveDisplayValue,
toHaveProp,
Expand Down
1 change: 1 addition & 0 deletions src/matchers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { toBeVisible } from './to-be-visible';
export { toHaveDisplayValue } from './to-have-display-value';
export { toHaveProp } from './to-have-prop';
export { toHaveTextContent } from './to-have-text-content';
export { toBeSelected } from './to-be-selected';
24 changes: 24 additions & 0 deletions src/matchers/to-be-selected.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
import { getAccessibilitySelectedState } from '../helpers/accessiblity';
import { checkHostElement, formatElement } from './utils';

export function toBeSelected(
this: jest.MatcherContext,
element: ReactTestInstance
) {
checkHostElement(element, toBeSelected, this);

return {
pass: getAccessibilitySelectedState(element),
message: () => {
const is = this.isNot ? 'is' : 'is not';
return [
matcherHint(`${this.isNot ? '.not' : ''}.toBeSelected`, 'element', ''),
'',
`Received element ${is} selected`,
formatElement(element),
].join('\n');
},
};
}

0 comments on commit 1592d35

Please sign in to comment.