From a0feedf9d4e719c1146d7a96d787ffc91d26f33b Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:27:05 +0200 Subject: [PATCH 01/10] feat: create always passing toBeBusy() matcher --- src/matchers/extend-expect.d.ts | 1 + src/matchers/extend-expect.ts | 2 ++ src/matchers/index.tsx | 1 + src/matchers/to-be-busy.tsx | 11 +++++++++++ 4 files changed, 15 insertions(+) create mode 100644 src/matchers/to-be-busy.tsx diff --git a/src/matchers/extend-expect.d.ts b/src/matchers/extend-expect.d.ts index 6bc63beaf..acdb16d1d 100644 --- a/src/matchers/extend-expect.d.ts +++ b/src/matchers/extend-expect.d.ts @@ -4,6 +4,7 @@ export interface JestNativeMatchers { toBeOnTheScreen(): R; toBeChecked(): R; toBeDisabled(): R; + toBeBusy(): R; toBeEmptyElement(): R; toBeEnabled(): R; toBePartiallyChecked(): R; diff --git a/src/matchers/extend-expect.ts b/src/matchers/extend-expect.ts index 87988a4a6..730e59cbe 100644 --- a/src/matchers/extend-expect.ts +++ b/src/matchers/extend-expect.ts @@ -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'; @@ -15,6 +16,7 @@ expect.extend({ toBeOnTheScreen, toBeChecked, toBeDisabled, + toBeBusy, toBeEmptyElement, toBeEnabled, toBePartiallyChecked, diff --git a/src/matchers/index.tsx b/src/matchers/index.tsx index 16f5a6d9a..49014cc2a 100644 --- a/src/matchers/index.tsx +++ b/src/matchers/index.tsx @@ -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'; diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.tsx new file mode 100644 index 000000000..d6e8fbcd0 --- /dev/null +++ b/src/matchers/to-be-busy.tsx @@ -0,0 +1,11 @@ +import { ReactTestInstance } from 'react-test-renderer'; + +export function toBeBusy( + this: jest.MatcherContext, + element: ReactTestInstance +) { + return { + pass: true, + message: () => '', + }; +} From 3c9b633606f001ec6a3cdfa72ae715682ec4666a Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:27:28 +0200 Subject: [PATCH 02/10] test: prepare toBeBusy() tests --- src/matchers/__tests__/to-be-busy.test.tsx | 61 ++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/matchers/__tests__/to-be-busy.test.tsx diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx new file mode 100644 index 000000000..aa67a79aa --- /dev/null +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { View } from 'react-native'; +import { render } from '../..'; +import '../extend-expect'; + +test('toBeBusy() basic case with accessibilityState', () => { + const screen = render( + + + + + ); + + expect(screen.getByTestId('busy')).toBeBusy(); + expect(screen.getByTestId('not-busy')).not.toBeBusy(); +}); + +test('toBeBusy() basic case with aria-busy', () => { + const screen = render( + + + + + ); + + expect(screen.getByTestId('busy')).toBeBusy(); + expect(screen.getByTestId('not-busy')).not.toBeBusy(); +}); + +test('toBeBusy() error cases with accessibilityState', () => { + const screen = render( + + + + + ); + + expect(() => expect(screen.getByTestId('busy')).not.toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).not.toBeBusy() + + Received element is busy: + " + `); + + expect(() => expect(screen.getByTestId('not-busy')).toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeBusy() + + Received element is not busy: + " + `); +}); From a61acb56e9217abe9cc53bde076348e6cee0b9f0 Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:30:29 +0200 Subject: [PATCH 03/10] feat: implement toBeBusy() passing condition --- src/matchers/to-be-busy.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.tsx index d6e8fbcd0..c4f581393 100644 --- a/src/matchers/to-be-busy.tsx +++ b/src/matchers/to-be-busy.tsx @@ -1,11 +1,15 @@ import { ReactTestInstance } from 'react-test-renderer'; +import { matchAccessibilityState } from '../helpers/matchers/accessibilityState'; +import { checkHostElement } from './utils'; export function toBeBusy( this: jest.MatcherContext, element: ReactTestInstance ) { + checkHostElement(element, toBeBusy, this); + return { - pass: true, + pass: matchAccessibilityState(element, { busy: true }), message: () => '', }; } From f7b3ccca0993e31f608708877e7e1cc6075030ed Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:37:39 +0200 Subject: [PATCH 04/10] feat: implement error message --- src/matchers/to-be-busy.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.tsx index c4f581393..2a4a02089 100644 --- a/src/matchers/to-be-busy.tsx +++ b/src/matchers/to-be-busy.tsx @@ -1,6 +1,7 @@ import { ReactTestInstance } from 'react-test-renderer'; +import { matcherHint } from 'jest-matcher-utils'; import { matchAccessibilityState } from '../helpers/matchers/accessibilityState'; -import { checkHostElement } from './utils'; +import { checkHostElement, formatElement } from './utils'; export function toBeBusy( this: jest.MatcherContext, @@ -10,6 +11,18 @@ export function toBeBusy( return { pass: matchAccessibilityState(element, { busy: true }), - message: () => '', + message: () => { + const matcher = matcherHint( + `${this.isNot ? '.not' : ''}.toBeBusy`, + 'element', + '' + ); + return [ + matcher, + '', + `Received element is ${this.isNot ? '' : 'not '}busy:`, + formatElement(element), + ].join('\n'); + }, }; } From 9774e42fdb87551e6f6c2a687ee91a92d7cada69 Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:37:55 +0200 Subject: [PATCH 05/10] test: update error message snapshots to correct format --- src/matchers/__tests__/to-be-busy.test.tsx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx index aa67a79aa..ed04af3af 100644 --- a/src/matchers/__tests__/to-be-busy.test.tsx +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -41,8 +41,12 @@ test('toBeBusy() error cases with accessibilityState', () => { Received element is busy: " `); @@ -53,8 +57,12 @@ test('toBeBusy() error cases with accessibilityState', () => { Received element is not busy: " `); From ebb551b751e02c6202d1d9798e830b8912ce2dc5 Mon Sep 17 00:00:00 2001 From: hduprat Date: Thu, 7 Sep 2023 13:42:07 +0200 Subject: [PATCH 06/10] refactor: use screen variable --- src/matchers/__tests__/to-be-busy.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx index ed04af3af..111c72832 100644 --- a/src/matchers/__tests__/to-be-busy.test.tsx +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -1,10 +1,10 @@ import React from 'react'; import { View } from 'react-native'; -import { render } from '../..'; +import { render, screen } from '../..'; import '../extend-expect'; test('toBeBusy() basic case with accessibilityState', () => { - const screen = render( + render( @@ -16,7 +16,7 @@ test('toBeBusy() basic case with accessibilityState', () => { }); test('toBeBusy() basic case with aria-busy', () => { - const screen = render( + render( @@ -28,7 +28,7 @@ test('toBeBusy() basic case with aria-busy', () => { }); test('toBeBusy() error cases with accessibilityState', () => { - const screen = render( + render( From 96119f6d78e3635d7bb089b96d1a4e7b1f3c2290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 8 Sep 2023 12:44:26 +0200 Subject: [PATCH 07/10] refactor: tweaks --- src/helpers/accessiblity.ts | 7 ++ src/matchers/__tests__/to-be-busy.test.tsx | 77 +++++++++++++------ .../__tests__/to-be-selected.test.tsx | 4 +- src/matchers/to-be-busy.tsx | 4 +- 4 files changed, 63 insertions(+), 29 deletions(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index f3ac4de34..a5880414d 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -169,6 +169,13 @@ export function getAccessibilityState( }; } +export function getAccessibilityBusyState( + element: ReactTestInstance +): NonNullable { + const { accessibilityState, 'aria-busy': ariaBusy } = element.props; + return ariaBusy ?? accessibilityState?.busy ?? false; +} + export function getAccessibilityCheckedState( element: ReactTestInstance ): AccessibilityState['checked'] { diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx index 111c72832..235558fba 100644 --- a/src/matchers/__tests__/to-be-busy.test.tsx +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -1,38 +1,35 @@ -import React from 'react'; +import * as React from 'react'; import { View } from 'react-native'; import { render, screen } from '../..'; import '../extend-expect'; -test('toBeBusy() basic case with accessibilityState', () => { +test('toBeBusy() basic case', () => { render( - - - - + <> + + + + + + ); 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() basic case with aria-busy', () => { +test('toBeBusy() error messages', () => { render( - - - - - ); - - expect(screen.getByTestId('busy')).toBeBusy(); - expect(screen.getByTestId('not-busy')).not.toBeBusy(); -}); - -test('toBeBusy() error cases with accessibilityState', () => { - render( - - - - + <> + + + + + + ); expect(() => expect(screen.getByTestId('busy')).not.toBeBusy()) @@ -46,11 +43,21 @@ test('toBeBusy() error cases with accessibilityState', () => { "busy": true, } } - accessible={true} testID="busy" />" `); + expect(() => expect(screen.getByTestId('busy-aria')).not.toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).not.toBeBusy() + + Received element is busy: + " + `); + expect(() => expect(screen.getByTestId('not-busy')).toBeBusy()) .toThrowErrorMatchingInlineSnapshot(` "expect(element).toBeBusy() @@ -62,8 +69,28 @@ test('toBeBusy() error cases with accessibilityState', () => { "busy": false, } } - accessible={true} testID="not-busy" />" `); + + expect(() => expect(screen.getByTestId('not-busy-aria')).toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeBusy() + + Received element is not busy: + " + `); + + expect(() => expect(screen.getByTestId('default')).toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeBusy() + + Received element is not busy: + " + `); }); diff --git a/src/matchers/__tests__/to-be-selected.test.tsx b/src/matchers/__tests__/to-be-selected.test.tsx index cbf1f46cc..ba68e4936 100644 --- a/src/matchers/__tests__/to-be-selected.test.tsx +++ b/src/matchers/__tests__/to-be-selected.test.tsx @@ -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( <> @@ -21,7 +21,7 @@ test('.toBeSelected() basic case', () => { expect(screen.getByTestId('default')).not.toBeSelected(); }); -test('.toBeSelected() error messages', () => { +test('toBeSelected() error messages', () => { render( <> diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.tsx index 2a4a02089..56142afee 100644 --- a/src/matchers/to-be-busy.tsx +++ b/src/matchers/to-be-busy.tsx @@ -1,6 +1,6 @@ import { ReactTestInstance } from 'react-test-renderer'; import { matcherHint } from 'jest-matcher-utils'; -import { matchAccessibilityState } from '../helpers/matchers/accessibilityState'; +import { getAccessibilityBusyState } from '../helpers/accessiblity'; import { checkHostElement, formatElement } from './utils'; export function toBeBusy( @@ -10,7 +10,7 @@ export function toBeBusy( checkHostElement(element, toBeBusy, this); return { - pass: matchAccessibilityState(element, { busy: true }), + pass: getAccessibilityBusyState(element), message: () => { const matcher = matcherHint( `${this.isNot ? '.not' : ''}.toBeBusy`, From 7cdf2e7ec3208d7719afbe8df25808d1ea66fe10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 8 Sep 2023 16:41:17 +0200 Subject: [PATCH 08/10] refactor: cleanup --- src/helpers/accessiblity.ts | 18 +++++--- src/matchers/__tests__/to-be-busy.test.tsx | 54 ++++++++++++++++++---- src/matchers/to-be-busy.tsx | 4 +- 3 files changed, 57 insertions(+), 19 deletions(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index a5880414d..32db7cf76 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -169,13 +169,6 @@ export function getAccessibilityState( }; } -export function getAccessibilityBusyState( - element: ReactTestInstance -): NonNullable { - const { accessibilityState, 'aria-busy': ariaBusy } = element.props; - return ariaBusy ?? accessibilityState?.busy ?? false; -} - export function getAccessibilityCheckedState( element: ReactTestInstance ): AccessibilityState['checked'] { @@ -219,3 +212,14 @@ export function getAccessibilityValue( text: ariaValueText ?? accessibilityValue?.text, }; } + +export function isElementBusy( + element: ReactTestInstance +): NonNullable { + if (!isAccessibilityElement(element)) { + return false; + } + + const { accessibilityState, 'aria-busy': ariaBusy } = element.props; + return ariaBusy ?? accessibilityState?.busy ?? false; +} diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx index 235558fba..febda7b6e 100644 --- a/src/matchers/__tests__/to-be-busy.test.tsx +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -6,11 +6,11 @@ import '../extend-expect'; test('toBeBusy() basic case', () => { render( <> - - - - - + + + + + ); @@ -24,11 +24,11 @@ test('toBeBusy() basic case', () => { test('toBeBusy() error messages', () => { render( <> - - - - - + + + + + ); @@ -43,6 +43,7 @@ test('toBeBusy() error messages', () => { "busy": true, } } + accessible={true} testID="busy" />" `); @@ -53,6 +54,7 @@ test('toBeBusy() error messages', () => { Received element is busy: " @@ -69,6 +71,7 @@ test('toBeBusy() error messages', () => { "busy": false, } } + accessible={true} testID="not-busy" />" `); @@ -79,6 +82,7 @@ test('toBeBusy() error messages', () => { Received element is not busy: " @@ -90,7 +94,37 @@ test('toBeBusy() error messages', () => { Received element is not busy: " `); }); + +test('toBeBusy() requires accessibility elements', () => { + render( + <> + + + + + ); + + expect(() => expect(screen.getByTestId('busy-aria')).toBeBusy()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeBusy() + + Received element is not busy: + " + `); + + expect(() => + expect(screen.getByTestId('not-busy-aria')).not.toBeBusy() + ).toThrowErrorMatchingInlineSnapshot(); + + expect(() => + expect(screen.getByTestId('default')).not.toBeBusy() + ).toThrowErrorMatchingInlineSnapshot(); +}); diff --git a/src/matchers/to-be-busy.tsx b/src/matchers/to-be-busy.tsx index 56142afee..e8b31f554 100644 --- a/src/matchers/to-be-busy.tsx +++ b/src/matchers/to-be-busy.tsx @@ -1,6 +1,6 @@ import { ReactTestInstance } from 'react-test-renderer'; import { matcherHint } from 'jest-matcher-utils'; -import { getAccessibilityBusyState } from '../helpers/accessiblity'; +import { isElementBusy } from '../helpers/accessiblity'; import { checkHostElement, formatElement } from './utils'; export function toBeBusy( @@ -10,7 +10,7 @@ export function toBeBusy( checkHostElement(element, toBeBusy, this); return { - pass: getAccessibilityBusyState(element), + pass: isElementBusy(element), message: () => { const matcher = matcherHint( `${this.isNot ? '.not' : ''}.toBeBusy`, From 1d3831e86afeaa4bf0a23dac0cceb86d01e158f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Tue, 12 Sep 2023 10:09:41 +0200 Subject: [PATCH 09/10] refactor: clean up --- src/helpers/accessiblity.ts | 4 -- src/matchers/__tests__/to-be-busy.test.tsx | 54 ++++------------------ 2 files changed, 10 insertions(+), 48 deletions(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index 32db7cf76..67f464698 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -216,10 +216,6 @@ export function getAccessibilityValue( export function isElementBusy( element: ReactTestInstance ): NonNullable { - if (!isAccessibilityElement(element)) { - return false; - } - const { accessibilityState, 'aria-busy': ariaBusy } = element.props; return ariaBusy ?? accessibilityState?.busy ?? false; } diff --git a/src/matchers/__tests__/to-be-busy.test.tsx b/src/matchers/__tests__/to-be-busy.test.tsx index febda7b6e..235558fba 100644 --- a/src/matchers/__tests__/to-be-busy.test.tsx +++ b/src/matchers/__tests__/to-be-busy.test.tsx @@ -6,11 +6,11 @@ import '../extend-expect'; test('toBeBusy() basic case', () => { render( <> - - - - - + + + + + ); @@ -24,11 +24,11 @@ test('toBeBusy() basic case', () => { test('toBeBusy() error messages', () => { render( <> - - - - - + + + + + ); @@ -43,7 +43,6 @@ test('toBeBusy() error messages', () => { "busy": true, } } - accessible={true} testID="busy" />" `); @@ -54,7 +53,6 @@ test('toBeBusy() error messages', () => { Received element is busy: " @@ -71,7 +69,6 @@ test('toBeBusy() error messages', () => { "busy": false, } } - accessible={true} testID="not-busy" />" `); @@ -82,7 +79,6 @@ test('toBeBusy() error messages', () => { Received element is not busy: " @@ -94,37 +90,7 @@ test('toBeBusy() error messages', () => { Received element is not busy: " `); }); - -test('toBeBusy() requires accessibility elements', () => { - render( - <> - - - - - ); - - expect(() => expect(screen.getByTestId('busy-aria')).toBeBusy()) - .toThrowErrorMatchingInlineSnapshot(` - "expect(element).toBeBusy() - - Received element is not busy: - " - `); - - expect(() => - expect(screen.getByTestId('not-busy-aria')).not.toBeBusy() - ).toThrowErrorMatchingInlineSnapshot(); - - expect(() => - expect(screen.getByTestId('default')).not.toBeBusy() - ).toThrowErrorMatchingInlineSnapshot(); -}); From ecf555af5e5f4bed6b8dfaaf1c53a2a7ab173994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Tue, 12 Sep 2023 10:49:26 +0200 Subject: [PATCH 10/10] refactor: finishing touches --- src/helpers/accessiblity.ts | 14 +++++++------- src/matchers/to-be-selected.ts | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index 67f464698..ee440bc37 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -176,13 +176,6 @@ export function getAccessibilityCheckedState( return ariaChecked ?? accessibilityState?.checked; } -export function getAccessibilitySelectedState( - element: ReactTestInstance -): NonNullable { - const { accessibilityState, 'aria-selected': ariaSelected } = element.props; - return ariaSelected ?? accessibilityState?.selected ?? false; -} - export function getAccessibilityValue( element: ReactTestInstance ): AccessibilityValue | undefined { @@ -219,3 +212,10 @@ export function isElementBusy( const { accessibilityState, 'aria-busy': ariaBusy } = element.props; return ariaBusy ?? accessibilityState?.busy ?? false; } + +export function isElementSelected( + element: ReactTestInstance +): NonNullable { + const { accessibilityState, 'aria-selected': ariaSelected } = element.props; + return ariaSelected ?? accessibilityState?.selected ?? false; +} diff --git a/src/matchers/to-be-selected.ts b/src/matchers/to-be-selected.ts index 3e35c4dd0..46502cbe9 100644 --- a/src/matchers/to-be-selected.ts +++ b/src/matchers/to-be-selected.ts @@ -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( @@ -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 [