-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathto-have-style.ts
76 lines (64 loc) · 2.17 KB
/
to-have-style.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import type { ImageStyle, StyleProp, TextStyle, ViewStyle } from 'react-native';
import { StyleSheet } from 'react-native';
import type { ReactTestInstance } from 'react-test-renderer';
import { diff, matcherHint } from 'jest-matcher-utils';
import { checkHostElement, formatMessage } from './utils';
export type Style = ViewStyle | TextStyle | ImageStyle;
type StyleLike = Record<string, unknown>;
export function toHaveStyle(
this: jest.MatcherContext,
element: ReactTestInstance,
style: StyleProp<Style>,
) {
checkHostElement(element, toHaveStyle, this);
const expected = (StyleSheet.flatten(style) as StyleLike) ?? {};
const received = (StyleSheet.flatten(element.props.style) as StyleLike) ?? {};
const pass = Object.keys(expected).every((key) => this.equals(expected[key], received[key]));
return {
pass,
message: () => {
const to = this.isNot ? 'not to' : 'to';
const matcher = matcherHint(`${this.isNot ? '.not' : ''}.toHaveStyle`, 'element', '');
if (pass) {
return formatMessage(
matcher,
`Expected element ${to} have style`,
formatStyles(expected),
'Received',
formatStyles(pickReceivedStyles(expected, received)),
);
} else {
return [matcher, '', expectedDiff(expected, received)].join('\n');
}
},
};
}
/**
* Generate diff between `expected` and `received` styles.
*/
function expectedDiff(expected: StyleLike, received: StyleLike) {
const receivedNarrow = pickReceivedStyles(expected, received);
return diff(formatStyles(expected), formatStyles(receivedNarrow));
}
/**
* Pick from `received` style only the keys present in `expected` style.
*/
function pickReceivedStyles(expected: StyleLike, received: StyleLike) {
const result: StyleLike = {};
Object.keys(received).forEach((key) => {
if (expected[key] !== undefined) {
result[key] = received[key];
}
});
return result;
}
function formatStyles(style: StyleLike) {
return Object.keys(style)
.sort()
.map((prop) =>
Array.isArray(style[prop])
? `${prop}: ${JSON.stringify(style[prop], null, 2)};`
: `${prop}: ${style[prop]};`,
)
.join('\n');
}