Skip to content

Commit

Permalink
fix: toHaveStyle nested arrays (#110)
Browse files Browse the repository at this point in the history
Co-authored-by: Maciej Jastrze台bski <mdjastrzebski@gmail.com>
  • Loading branch information
felippepuhle and mdjastrzebski committed Sep 15, 2022
1 parent e628ca0 commit 044229b
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 48 deletions.
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ React Native [0.62](https://reactnative.dev/blog/2020/03/26/version-0.62#breakin
```javascript
const { getByTestId } = render(
<View>
<Button disabled testID="button" title="submit" onPress={e => e} />
<Button disabled testID="button" title="submit" onPress={(e) => e} />
<TextInput accessibilityState={{ disabled: true }} testID="input" value="text" />
</View>,
);
Expand All @@ -151,7 +151,7 @@ Works similarly to `expect().not.toBeDisabled()`.
```javascript
const { getByTestId } = render(
<View>
<Button testID="button" title="submit" onPress={e => e} />
<Button testID="button" title="submit" onPress={(e) => e} />
<TextInput testID="input" value="text" />
</View>,
);
Expand Down Expand Up @@ -288,14 +288,17 @@ const { queryByText } = render(
</Text>,
);

expect(queryByText('Hello World')).toHaveStyle({ color: 'black', fontWeight: '600', fontSize: 16 });
expect(queryByText('Hello World')).toHaveStyle({ color: 'black' });
expect(queryByText('Hello World')).toHaveStyle({ fontWeight: '600' });
expect(queryByText('Hello World')).toHaveStyle({ fontSize: 16 });
expect(queryByText('Hello World')).toHaveStyle({ transform: [{ scale: 2 }, { rotate: '45deg' }] });
expect(queryByText('Hello World')).toHaveStyle({ transform: [{ rotate: '45deg' }] });
expect(queryByText('Hello World')).toHaveStyle([{ color: 'black' }, { fontWeight: '600' }]);
expect(queryByText('Hello World')).not.toHaveStyle({ color: 'white' });
expect(getByText('Hello World')).toHaveStyle({ color: 'black' });
expect(getByText('Hello World')).toHaveStyle({ fontWeight: '600' });
expect(getByText('Hello World')).toHaveStyle({ fontSize: 16 });
expect(getByText('Hello World')).toHaveStyle([{ fontWeight: '600' }, { color: 'black' }]);
expect(getByText('Hello World')).toHaveStyle({ color: 'black', fontWeight: '600', fontSize: 16 });
expect(getByText('Hello World')).toHaveStyle({ transform: [{ scale: 2 }, { rotate: '45deg' }] });
expect(getByText('Hello World')).not.toHaveStyle({ color: 'white' });
expect(getByText('Hello World')).not.toHaveStyle({ transform: [{ scale: 2 }] });
expect(getByText('Hello World')).not.toHaveStyle({
transform: [{ rotate: '45deg' }, { scale: 2 }],
});
```

## Inspiration
Expand Down
3 changes: 3 additions & 0 deletions src/__tests__/__snapshots__/to-have-style.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ exports[`.toHaveStyle handles negative test cases 1`] = `
{
- "scale": 1
+ "scale": 2
+ },
+ {
+ "rotate": "45deg"
}
];"
`;
Expand Down
9 changes: 6 additions & 3 deletions src/__tests__/to-have-style.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ describe('.toHaveStyle', () => {
style={[
{
backgroundColor: 'blue',
height: '100%',
height: '40%',
transform: [{ scale: 2 }, { rotate: '45deg' }],
},
[{ width: '50%' }],
[{ height: '100%' }],
[[{ width: '50%' }]],
styles.container,
]}
>
Expand All @@ -30,8 +31,8 @@ describe('.toHaveStyle', () => {
expect(container).toHaveStyle({ height: '100%' });
expect(container).toHaveStyle({ color: 'white' });
expect(container).toHaveStyle({ width: '50%' });
expect(container).toHaveStyle([[{ width: '50%' }]]);
expect(container).toHaveStyle({ transform: [{ scale: 2 }, { rotate: '45deg' }] });
expect(container).toHaveStyle({ transform: [{ rotate: '45deg' }] });
});

test('handles negative test cases', () => {
Expand All @@ -55,6 +56,8 @@ describe('.toHaveStyle', () => {
).toThrowErrorMatchingSnapshot();
expect(() => expect(container).toHaveStyle({ fontWeight: 'bold' })).toThrow();
expect(() => expect(container).not.toHaveStyle({ color: 'black' })).toThrow();
expect(container).not.toHaveStyle({ transform: [{ rotate: '45deg' }, { scale: 2 }] });
expect(container).not.toHaveStyle({ transform: [{ rotate: '45deg' }] });
});

test('handles when the style prop is undefined', () => {
Expand Down
10 changes: 1 addition & 9 deletions src/__tests__/utils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { checkReactElement, isEmpty, mergeAll } from '../utils';
import { checkReactElement, isEmpty } from '../utils';

describe('checkReactElement', () => {
test('it does not throw an error for valid native primitives', () => {
Expand All @@ -20,14 +20,6 @@ describe('checkReactElement', () => {
});
});

test('mergeAll', () => {
expect(mergeAll([{ foo: 1 }, { bar: 2 }, { baz: 3 }])).toEqual({ foo: 1, bar: 2, baz: 3 });
expect(mergeAll([{ foo: 1 }, { foo: 2 }, { bar: 2 }])).toEqual({ foo: 2, bar: 2 });
expect(mergeAll([null, { foo: 1 }, { foo: 2 }, { bar: 2 }])).toEqual({ foo: 2, bar: 2 });
expect(mergeAll([{ foo: 1 }, { foo: 2 }, { bar: 2 }, undefined])).toEqual({ foo: 2, bar: 2 });
expect(mergeAll([{ foo: 1 }, { foo: 2 }, null, { bar: 2 }])).toEqual({ foo: 2, bar: 2 });
});

test('isEmpty', () => {
expect(isEmpty(null)).toEqual(true);
expect(isEmpty(undefined)).toEqual(true);
Expand Down
28 changes: 7 additions & 21 deletions src/to-have-style.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import { StyleSheet } from 'react-native';
import { matcherHint } from 'jest-matcher-utils';
import { diff } from 'jest-diff';
import chalk from 'chalk';
import { checkReactElement, mergeAll } from './utils';

function isSubset(expected, received) {
return Object.entries(expected).every(([prop, value]) =>
Array.isArray(value)
? isSubset(mergeAll(value), mergeAll(received[prop]))
: received[prop] === value,
);
}

function mergeAllStyles(styles) {
return mergeAll(styles.flat());
}
import { checkReactElement } from './utils';

function printoutStyles(styles) {
return Object.keys(styles)
Expand All @@ -27,18 +16,15 @@ function printoutStyles(styles) {
}

/**
* Recursively narrows down the properties in received to those with counterparts in expected
* Narrows down the properties in received to those with counterparts in expected
*/
function narrow(expected, received) {
return Object.keys(received)
.filter((prop) => expected[prop])
.reduce(
(obj, prop) =>
Object.assign(obj, {
[prop]:
Array.isArray(expected[prop]) && Array.isArray(received[prop])
? expected[prop].map((_, i) => narrow(expected[prop][i], received[prop][i]))
: received[prop],
[prop]: received[prop],
}),
{},
);
Expand All @@ -59,11 +45,11 @@ export function toHaveStyle(element, style) {

const elementStyle = element.props.style ?? {};

const expected = Array.isArray(style) ? mergeAllStyles(style) : style;
const received = Array.isArray(elementStyle) ? mergeAllStyles(elementStyle) : elementStyle;
const expected = Array.isArray(style) ? StyleSheet.flatten(style) : style;
const received = Array.isArray(elementStyle) ? StyleSheet.flatten(elementStyle) : elementStyle;

return {
pass: isSubset(expected, received),
pass: Object.entries(expected).every(([prop, value]) => this.equals(received?.[prop], value)),
message: () => {
const matcher = `${this.isNot ? '.not' : ''}.toHaveStyle`;
return [matcherHint(matcher, 'element', ''), expectedDiff(expected, received)].join('\n\n');
Expand Down
5 changes: 0 additions & 5 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ function normalize(text) {
return text.replace(/\s+/g, ' ').trim();
}

function mergeAll(objects) {
return Object.assign({}, ...(objects ?? [{}]));
}

function isEmpty(value) {
if (!value) {
return true;
Expand All @@ -120,7 +116,6 @@ export {
getMessage,
matches,
normalize,
mergeAll,
isEmpty,
printElement,
};

0 comments on commit 044229b

Please sign in to comment.