Skip to content

Commit

Permalink
feat: toBeDisabled matcher (#1469)
Browse files Browse the repository at this point in the history
* feat: add toBeDisabled matcher

* add tests and toBeEnabled matcher

* update logic and tests

* add test to validate toBeDisabled with parent elements

* better name

* refactor: tweaks and improvements

* chore: tweak fo

* refactor: tests

* chore: fix tests

---------

Co-authored-by: Maciej Jastrzebski <mdjastrzebski@gmail.com>
  • Loading branch information
jaworek and mdjastrzebski committed Sep 1, 2023
1 parent 3ff0afb commit 4659bba
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 70 deletions.
67 changes: 25 additions & 42 deletions src/helpers/__tests__/format-default.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import { ReactTestRendererJSON } from 'react-test-renderer';
import { defaultMapProps } from '../format-default';

const node: ReactTestRendererJSON = {
type: 'View',
props: {},
children: null,
};

describe('mapPropsForQueryError', () => {
test('preserves props that are helpful for debugging', () => {
const props = {
Expand All @@ -32,89 +25,79 @@ describe('mapPropsForQueryError', () => {
defaultValue: 'DEFAULT_VALUE',
};

const result = defaultMapProps(props, node);
const result = defaultMapProps(props);
expect(result).toStrictEqual(props);
});

test('does not preserve less helpful props', () => {
const result = defaultMapProps(
{
style: [{ flex: 1 }, { display: 'flex' }],
onPress: () => null,
key: 'foo',
},
node
);
const result = defaultMapProps({
style: [{ flex: 1 }, { flexDirection: 'row' }],
onPress: () => null,
key: 'foo',
});

expect(result).toStrictEqual({});
});

test('preserves "display: none" style but no other style', () => {
const result = defaultMapProps(
{ style: [{ flex: 1 }, { display: 'none', flex: 2 }] },
node
);
test('preserves "display: none" and "opacity: 0" styles but no other style', () => {
const result = defaultMapProps({
style: [{ flex: 1 }, { display: 'none', flex: 2 }, { opacity: 0 }],
});

expect(result).toStrictEqual({
style: { display: 'none' },
style: { display: 'none', opacity: 0 },
});
});

test('removes undefined keys from accessibilityState', () => {
const result = defaultMapProps(
{ accessibilityState: { checked: undefined, selected: false } },
node
);
const result = defaultMapProps({
accessibilityState: { checked: undefined, selected: false },
});

expect(result).toStrictEqual({
accessibilityState: { selected: false },
});
});

test('removes accessibilityState if all keys are undefined', () => {
const result = defaultMapProps(
{ accessibilityState: { checked: undefined, selected: undefined } },
node
);
const result = defaultMapProps({
accessibilityState: { checked: undefined, selected: undefined },
});

expect(result).toStrictEqual({});
});

test('does not fail if accessibilityState is a string, passes through', () => {
const result = defaultMapProps({ accessibilityState: 'foo' }, node);
const result = defaultMapProps({ accessibilityState: 'foo' });
expect(result).toStrictEqual({ accessibilityState: 'foo' });
});

test('does not fail if accessibilityState is an array, passes through', () => {
const result = defaultMapProps({ accessibilityState: [1] }, node);
const result = defaultMapProps({ accessibilityState: [1] });
expect(result).toStrictEqual({ accessibilityState: [1] });
});

test('does not fail if accessibilityState is null, passes through', () => {
const result = defaultMapProps({ accessibilityState: null }, node);
const result = defaultMapProps({ accessibilityState: null });
expect(result).toStrictEqual({ accessibilityState: null });
});

test('does not fail if accessibilityState is nested object, passes through', () => {
const accessibilityState = { 1: { 2: 3 }, 2: undefined };
const result = defaultMapProps({ accessibilityState }, node);
const result = defaultMapProps({ accessibilityState });
expect(result).toStrictEqual({ accessibilityState: { 1: { 2: 3 } } });
});

test('removes undefined keys from accessibilityValue', () => {
const result = defaultMapProps(
{ accessibilityValue: { min: 1, max: undefined } },
node
);
const result = defaultMapProps({
accessibilityValue: { min: 1, max: undefined },
});

expect(result).toStrictEqual({ accessibilityValue: { min: 1 } });
});

test('removes accessibilityValue if all keys are undefined', () => {
const result = defaultMapProps(
{ accessibilityValue: { min: undefined } },
node
);
const result = defaultMapProps({ accessibilityValue: { min: undefined } });

expect(result).toStrictEqual({});
});
Expand Down
36 changes: 27 additions & 9 deletions src/helpers/format-default.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { StyleSheet, ViewStyle } from 'react-native';
import { MapPropsFunction } from './format';

const propsToDisplay = [
'accessible',
'accessibilityElementsHidden',
'accessibilityHint',
'accessibilityLabel',
Expand All @@ -24,17 +24,20 @@ const propsToDisplay = [
'testID',
'title',
'value',
];
] as const;

/**
* Preserve props that are helpful in diagnosing test failures, while stripping rest
*/
export const defaultMapProps: MapPropsFunction = (props) => {
export function defaultMapProps(
props: Record<string, unknown>
): Record<string, unknown> {
const result: Record<string, unknown> = {};

const styles = StyleSheet.flatten(props.style as ViewStyle);
if (styles?.display === 'none') {
result.style = { display: 'none' };
const styleToDisplay = extractStyle(styles);
if (styleToDisplay !== undefined) {
result.style = styleToDisplay;
}

const accessibilityState = removeUndefinedKeys(props.accessibilityState);
Expand All @@ -54,7 +57,7 @@ export const defaultMapProps: MapPropsFunction = (props) => {
});

return result;
};
}

function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
Expand All @@ -65,17 +68,32 @@ function removeUndefinedKeys(prop: unknown) {
return prop;
}

let hasKeys = false;
const result: Record<string, unknown> = {};
Object.entries(prop).forEach(([key, value]) => {
if (value !== undefined) {
result[key] = value;
hasKeys = true;
}
});

// If object does not have any props we will ignore it.
if (Object.keys(result).length === 0) {
return hasKeys ? result : undefined;
}

function extractStyle(style: ViewStyle | undefined) {
if (style == null) {
return undefined;
}

return result;
const result: Record<string, unknown> = {};
if (style.display === 'none') {
result.display = 'none';
}

if (style.opacity === 0) {
result.opacity = 0;
}

const hasAnyKeys = Object.keys(result).length > 0;
return hasAnyKeys ? result : undefined;
}

0 comments on commit 4659bba

Please sign in to comment.