From ad6c5b1424d6b7a5baba17b0b98c02879b2ca594 Mon Sep 17 00:00:00 2001 From: AntoineThibi Date: Wed, 6 Sep 2023 09:20:00 +0200 Subject: [PATCH 1/4] feat: implement toBeSelected --- .../__tests__/to-be-selected.test.tsx | 73 +++++++++++++++++++ src/matchers/extend-expect.d.ts | 1 + src/matchers/extend-expect.ts | 2 + src/matchers/index.tsx | 1 + src/matchers/to-be-selected.ts | 32 ++++++++ 5 files changed, 109 insertions(+) create mode 100644 src/matchers/__tests__/to-be-selected.test.tsx create mode 100644 src/matchers/to-be-selected.ts diff --git a/src/matchers/__tests__/to-be-selected.test.tsx b/src/matchers/__tests__/to-be-selected.test.tsx new file mode 100644 index 000000000..a64a4a87f --- /dev/null +++ b/src/matchers/__tests__/to-be-selected.test.tsx @@ -0,0 +1,73 @@ +import * as React from 'react'; +import { View } from 'react-native'; +import { render, screen } from '../..'; +import '../extend-expect'; + +test('.toBeSelected() basic case', () => { + render( + + + + + + ); + + expect(screen.getByTestId('selected')).toBeSelected(); + expect(screen.getByTestId('not-selected')).not.toBeSelected(); + expect(screen.getByTestId('no-accessibilityState')).not.toBeSelected(); +}); + +test('.toBeSelected() error messages', () => { + render( + + + + + + ); + + expect(() => expect(screen.getByTestId('not-selected')).toBeSelected()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeSelected() + + Expected the element to have accessibility state selected: + + Received element is not selected: + " + `); + expect(() => expect(screen.getByTestId('selected')).not.toBeSelected()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).not.toBeSelected() + + Expected the element not to have accessibility state selected: + + Received element is selected: + " + `); + expect(() => + expect(screen.getByTestId('no-accessibilityState')).toBeSelected() + ).toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeSelected() + + Expected the element to have accessibility state selected: + + Received element is not selected: + " + `); +}); diff --git a/src/matchers/extend-expect.d.ts b/src/matchers/extend-expect.d.ts index 781db2d38..11ea4cf27 100644 --- a/src/matchers/extend-expect.d.ts +++ b/src/matchers/extend-expect.d.ts @@ -11,6 +11,7 @@ export interface JestNativeMatchers { toHaveDisplayValue(expectedValue: TextMatch, options?: TextMatchOptions): R; toHaveProp(name: string, expectedValue?: unknown): R; toHaveTextContent(expectedText: TextMatch, options?: TextMatchOptions): R; + toBeSelected(): R; } // Implicit Jest global `expect`. diff --git a/src/matchers/extend-expect.ts b/src/matchers/extend-expect.ts index 25b5d3c16..c76a2dba0 100644 --- a/src/matchers/extend-expect.ts +++ b/src/matchers/extend-expect.ts @@ -9,6 +9,7 @@ import { toBeVisible } from './to-be-visible'; import { toHaveDisplayValue } from './to-have-display-value'; import { toHaveProp } from './to-have-prop'; import { toHaveTextContent } from './to-have-text-content'; +import { toBeSelected } from './to-be-selected'; expect.extend({ toBeOnTheScreen, @@ -21,4 +22,5 @@ expect.extend({ toHaveDisplayValue, toHaveProp, toHaveTextContent, + toBeSelected, }); diff --git a/src/matchers/index.tsx b/src/matchers/index.tsx index 72718a184..16f5a6d9a 100644 --- a/src/matchers/index.tsx +++ b/src/matchers/index.tsx @@ -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'; diff --git a/src/matchers/to-be-selected.ts b/src/matchers/to-be-selected.ts new file mode 100644 index 000000000..1e6141cf7 --- /dev/null +++ b/src/matchers/to-be-selected.ts @@ -0,0 +1,32 @@ +import { ReactTestInstance } from 'react-test-renderer'; +import { matcherHint } from 'jest-matcher-utils'; +import { getAccessibilityState } from '../helpers/accessiblity'; +import { checkHostElement, formatElement, formatMessage } from './utils'; + +export function toBeSelected( + this: jest.MatcherContext, + element: ReactTestInstance +) { + checkHostElement(element, toBeSelected, this); + + return { + pass: getAccessibilityState(element)?.selected === true, + message: () => { + const is = this.isNot ? 'is' : 'is not'; + const matcher = matcherHint( + `${this.isNot ? '.not' : ''}.toBeSelected`, + 'element', + '' + ); + return formatMessage( + matcher, + `Expected the element ${ + this.isNot ? 'not to' : 'to' + } have accessibility state selected`, + '', + `Received element ${is} selected`, + formatElement(element) + ); + }, + }; +} From 80b0bb840e8a0738f910641b242c27240bc00915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 8 Sep 2023 10:16:31 +0200 Subject: [PATCH 2/4] refactor: tweaks --- src/helpers/accessiblity.ts | 7 ++++++ .../__tests__/to-be-selected.test.tsx | 12 +++------- src/matchers/to-be-selected.ts | 22 ++++++------------- 3 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/helpers/accessiblity.ts b/src/helpers/accessiblity.ts index 7a4bb0e1d..f3ac4de34 100644 --- a/src/helpers/accessiblity.ts +++ b/src/helpers/accessiblity.ts @@ -176,6 +176,13 @@ 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 { diff --git a/src/matchers/__tests__/to-be-selected.test.tsx b/src/matchers/__tests__/to-be-selected.test.tsx index a64a4a87f..bf0b20a7c 100644 --- a/src/matchers/__tests__/to-be-selected.test.tsx +++ b/src/matchers/__tests__/to-be-selected.test.tsx @@ -30,9 +30,7 @@ test('.toBeSelected() error messages', () => { .toThrowErrorMatchingInlineSnapshot(` "expect(element).toBeSelected() - Expected the element to have accessibility state selected: - - Received element is not selected: + Received element is not selected { .toThrowErrorMatchingInlineSnapshot(` "expect(element).not.toBeSelected() - Expected the element not to have accessibility state selected: - - Received element is selected: + Received element is selected { ).toThrowErrorMatchingInlineSnapshot(` "expect(element).toBeSelected() - Expected the element to have accessibility state selected: - - Received element is not selected: + Received element is not selected " diff --git a/src/matchers/to-be-selected.ts b/src/matchers/to-be-selected.ts index 1e6141cf7..3e35c4dd0 100644 --- a/src/matchers/to-be-selected.ts +++ b/src/matchers/to-be-selected.ts @@ -1,7 +1,7 @@ import { ReactTestInstance } from 'react-test-renderer'; import { matcherHint } from 'jest-matcher-utils'; -import { getAccessibilityState } from '../helpers/accessiblity'; -import { checkHostElement, formatElement, formatMessage } from './utils'; +import { getAccessibilitySelectedState } from '../helpers/accessiblity'; +import { checkHostElement, formatElement } from './utils'; export function toBeSelected( this: jest.MatcherContext, @@ -10,23 +10,15 @@ export function toBeSelected( checkHostElement(element, toBeSelected, this); return { - pass: getAccessibilityState(element)?.selected === true, + pass: getAccessibilitySelectedState(element), message: () => { const is = this.isNot ? 'is' : 'is not'; - const matcher = matcherHint( - `${this.isNot ? '.not' : ''}.toBeSelected`, - 'element', - '' - ); - return formatMessage( - matcher, - `Expected the element ${ - this.isNot ? 'not to' : 'to' - } have accessibility state selected`, + return [ + matcherHint(`${this.isNot ? '.not' : ''}.toBeSelected`, 'element', ''), '', `Received element ${is} selected`, - formatElement(element) - ); + formatElement(element), + ].join('\n'); }, }; } From f9ffcaf7a3fd49ed7906674040e21d5d05c7095f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 8 Sep 2023 10:34:44 +0200 Subject: [PATCH 3/4] refactor: tweak tests --- .../__tests__/to-be-selected.test.tsx | 67 +++++++++++++------ 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/matchers/__tests__/to-be-selected.test.tsx b/src/matchers/__tests__/to-be-selected.test.tsx index bf0b20a7c..cbf1f46cc 100644 --- a/src/matchers/__tests__/to-be-selected.test.tsx +++ b/src/matchers/__tests__/to-be-selected.test.tsx @@ -5,63 +5,92 @@ import '../extend-expect'; test('.toBeSelected() basic case', () => { render( - + <> + - - + + + ); expect(screen.getByTestId('selected')).toBeSelected(); + expect(screen.getByTestId('selected-aria')).toBeSelected(); expect(screen.getByTestId('not-selected')).not.toBeSelected(); - expect(screen.getByTestId('no-accessibilityState')).not.toBeSelected(); + expect(screen.getByTestId('not-selected-aria')).not.toBeSelected(); + expect(screen.getByTestId('default')).not.toBeSelected(); }); test('.toBeSelected() error messages', () => { render( - + <> + - - + + + ); - expect(() => expect(screen.getByTestId('not-selected')).toBeSelected()) + expect(() => expect(screen.getByTestId('selected')).not.toBeSelected()) .toThrowErrorMatchingInlineSnapshot(` - "expect(element).toBeSelected() + "expect(element).not.toBeSelected() - Received element is not selected + Received element is selected " `); - expect(() => expect(screen.getByTestId('selected')).not.toBeSelected()) + + expect(() => expect(screen.getByTestId('selected-aria')).not.toBeSelected()) .toThrowErrorMatchingInlineSnapshot(` "expect(element).not.toBeSelected() Received element is selected + " + `); + + expect(() => expect(screen.getByTestId('not-selected')).toBeSelected()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeSelected() + + Received element is not selected " `); - expect(() => - expect(screen.getByTestId('no-accessibilityState')).toBeSelected() - ).toThrowErrorMatchingInlineSnapshot(` + + expect(() => expect(screen.getByTestId('not-selected-aria')).toBeSelected()) + .toThrowErrorMatchingInlineSnapshot(` + "expect(element).toBeSelected() + + Received element is not selected + " + `); + + expect(() => expect(screen.getByTestId('default')).toBeSelected()) + .toThrowErrorMatchingInlineSnapshot(` "expect(element).toBeSelected() Received element is not selected " `); }); From 324fb1ee6a7357cc7aa7b68ec9894170686a55cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Jastrze=CC=A8bski?= Date: Fri, 8 Sep 2023 10:38:36 +0200 Subject: [PATCH 4/4] refactor: finishing touches --- src/matchers/extend-expect.d.ts | 2 +- src/matchers/extend-expect.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/matchers/extend-expect.d.ts b/src/matchers/extend-expect.d.ts index 11ea4cf27..6bc63beaf 100644 --- a/src/matchers/extend-expect.d.ts +++ b/src/matchers/extend-expect.d.ts @@ -7,11 +7,11 @@ export interface JestNativeMatchers { toBeEmptyElement(): R; toBeEnabled(): R; toBePartiallyChecked(): R; + toBeSelected(): R; toBeVisible(): R; toHaveDisplayValue(expectedValue: TextMatch, options?: TextMatchOptions): R; toHaveProp(name: string, expectedValue?: unknown): R; toHaveTextContent(expectedText: TextMatch, options?: TextMatchOptions): R; - toBeSelected(): R; } // Implicit Jest global `expect`. diff --git a/src/matchers/extend-expect.ts b/src/matchers/extend-expect.ts index c76a2dba0..87988a4a6 100644 --- a/src/matchers/extend-expect.ts +++ b/src/matchers/extend-expect.ts @@ -5,11 +5,11 @@ 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'; import { toHaveTextContent } from './to-have-text-content'; -import { toBeSelected } from './to-be-selected'; expect.extend({ toBeOnTheScreen, @@ -18,9 +18,9 @@ expect.extend({ toBeEmptyElement, toBeEnabled, toBePartiallyChecked, + toBeSelected, toBeVisible, toHaveDisplayValue, toHaveProp, toHaveTextContent, - toBeSelected, });