forked from testing-library/jest-native
-
Notifications
You must be signed in to change notification settings - Fork 0
/
to-have-style.ts
65 lines (57 loc) · 2.08 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
import type { ImageStyle, StyleProp, TextStyle, ViewStyle } from 'react-native';
import type { ReactTestInstance } from 'react-test-renderer';
import { StyleSheet } from 'react-native';
import { matcherHint } from 'jest-matcher-utils';
import { diff } from 'jest-diff';
import chalk from 'chalk';
import { checkReactElement } from './utils';
type Style = TextStyle | ViewStyle | ImageStyle;
type StyleLike = Record<string, unknown>;
function printoutStyles(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');
}
/**
* Narrows down the properties in received to those with counterparts in expected
*/
function narrow(expected: StyleLike, received: StyleLike) {
return Object.keys(received)
.filter((prop) => expected[prop])
.reduce(
(obj, prop) =>
Object.assign(obj, {
[prop]: received[prop],
}),
{},
);
}
// Highlights only style rules that were expected but were not found in the
// received computed styles
function expectedDiff(expected: StyleLike, received: StyleLike) {
const receivedNarrow = narrow(expected, received);
const diffOutput = diff(printoutStyles(expected), printoutStyles(receivedNarrow));
// Remove the "+ Received" annotation because this is a one-way diff
return diffOutput?.replace(`${chalk.red('+ Received')}\n`, '') ?? '';
}
export function toHaveStyle(
this: jest.MatcherContext,
element: ReactTestInstance,
style: StyleProp<Style>,
) {
checkReactElement(element, toHaveStyle, this);
const expected = (StyleSheet.flatten(style) ?? {}) as StyleLike;
const received = (StyleSheet.flatten(element.props.style) ?? {}) as StyleLike;
return {
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');
},
};
}