Skip to content

Commit

Permalink
feat: toBeBusy() matcher (#1493)
Browse files Browse the repository at this point in the history
* feat: create always passing toBeBusy() matcher

* test: prepare toBeBusy() tests

* feat: implement toBeBusy() passing condition

* feat: implement error message

* test: update error message snapshots to correct format

* refactor: use screen variable

* refactor: tweaks

* refactor: cleanup

* refactor:  clean up

* refactor: finishing touches

---------

Co-authored-by: Maciej Jastrze台bski <mdjastrzebski@gmail.com>
  • Loading branch information
hduprat and mdjastrzebski committed Sep 12, 2023
1 parent 1592d35 commit 701433c
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 11 deletions.
21 changes: 14 additions & 7 deletions src/helpers/accessiblity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,6 @@ 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 Expand Up @@ -212,3 +205,17 @@ export function getAccessibilityValue(
text: ariaValueText ?? accessibilityValue?.text,
};
}

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

export function isElementSelected(
element: ReactTestInstance
): NonNullable<AccessibilityState['selected']> {
const { accessibilityState, 'aria-selected': ariaSelected } = element.props;
return ariaSelected ?? accessibilityState?.selected ?? false;
}
96 changes: 96 additions & 0 deletions src/matchers/__tests__/to-be-busy.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('toBeBusy() basic case', () => {
render(
<>
<View testID="busy" accessibilityState={{ busy: true }} />
<View testID="busy-aria" aria-busy />
<View testID="not-busy" accessibilityState={{ busy: false }} />
<View testID="not-busy-aria" aria-busy={false} />
<View testID="default" />
</>
);

expect(screen.getByTestId('busy')).toBeBusy();
expect(screen.getByTestId('busy-aria')).toBeBusy();
expect(screen.getByTestId('not-busy')).not.toBeBusy();
expect(screen.getByTestId('not-busy-aria')).not.toBeBusy();
expect(screen.getByTestId('default')).not.toBeBusy();
});

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

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

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

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

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

expect(() => expect(screen.getByTestId('default')).toBeBusy())
.toThrowErrorMatchingInlineSnapshot(`
"expect(element).toBeBusy()
Received element is not busy:
<View
testID="default"
/>"
`);
});
4 changes: 2 additions & 2 deletions src/matchers/__tests__/to-be-selected.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { View } from 'react-native';
import { render, screen } from '../..';
import '../extend-expect';

test('.toBeSelected() basic case', () => {
test('toBeSelected() basic case', () => {
render(
<>
<View testID="selected" accessibilityState={{ selected: true }} />
Expand All @@ -21,7 +21,7 @@ test('.toBeSelected() basic case', () => {
expect(screen.getByTestId('default')).not.toBeSelected();
});

test('.toBeSelected() error messages', () => {
test('toBeSelected() error messages', () => {
render(
<>
<View testID="selected" accessibilityState={{ selected: true }} />
Expand Down
1 change: 1 addition & 0 deletions src/matchers/extend-expect.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface JestNativeMatchers<R> {
toBeOnTheScreen(): R;
toBeChecked(): R;
toBeDisabled(): R;
toBeBusy(): R;
toBeEmptyElement(): R;
toBeEnabled(): R;
toBePartiallyChecked(): 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 @@ -3,6 +3,7 @@
import { toBeOnTheScreen } from './to-be-on-the-screen';
import { toBeChecked } from './to-be-checked';
import { toBeDisabled, toBeEnabled } from './to-be-disabled';
import { toBeBusy } from './to-be-busy';
import { toBeEmptyElement } from './to-be-empty-element';
import { toBePartiallyChecked } from './to-be-partially-checked';
import { toBeSelected } from './to-be-selected';
Expand All @@ -15,6 +16,7 @@ expect.extend({
toBeOnTheScreen,
toBeChecked,
toBeDisabled,
toBeBusy,
toBeEmptyElement,
toBeEnabled,
toBePartiallyChecked,
Expand Down
1 change: 1 addition & 0 deletions src/matchers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { toBeOnTheScreen } from './to-be-on-the-screen';
export { toBeChecked } from './to-be-checked';
export { toBeDisabled, toBeEnabled } from './to-be-disabled';
export { toBeBusy } from './to-be-busy';
export { toBeEmptyElement } from './to-be-empty-element';
export { toBePartiallyChecked } from './to-be-partially-checked';
export { toBeVisible } from './to-be-visible';
Expand Down
28 changes: 28 additions & 0 deletions src/matchers/to-be-busy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
import { isElementBusy } from '../helpers/accessiblity';
import { checkHostElement, formatElement } from './utils';

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

return {
pass: isElementBusy(element),
message: () => {
const matcher = matcherHint(
`${this.isNot ? '.not' : ''}.toBeBusy`,
'element',
''
);
return [
matcher,
'',
`Received element is ${this.isNot ? '' : 'not '}busy:`,
formatElement(element),
].join('\n');
},
};
}
4 changes: 2 additions & 2 deletions src/matchers/to-be-selected.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReactTestInstance } from 'react-test-renderer';
import { matcherHint } from 'jest-matcher-utils';
import { getAccessibilitySelectedState } from '../helpers/accessiblity';
import { isElementSelected } from '../helpers/accessiblity';
import { checkHostElement, formatElement } from './utils';

export function toBeSelected(
Expand All @@ -10,7 +10,7 @@ export function toBeSelected(
checkHostElement(element, toBeSelected, this);

return {
pass: getAccessibilitySelectedState(element),
pass: isElementSelected(element),
message: () => {
const is = this.isNot ? 'is' : 'is not';
return [
Expand Down

0 comments on commit 701433c

Please sign in to comment.