|
1 |
| -const { getCSS, matcherTest, buildReturnMessage } = require('./utils') |
| 1 | +const { getCSS, matcherTest, buildReturnMessage } = require('./utils'); |
2 | 2 |
|
3 |
| -const shouldDive = node => |
4 |
| - typeof node.dive === 'function' && typeof node.type() !== 'string' |
| 3 | +const shouldDive = node => typeof node.dive === 'function' && typeof node.type() !== 'string'; |
5 | 4 |
|
6 |
| -const isTagWithClassName = node => |
7 |
| - node.exists() && node.prop('className') && typeof node.type() === 'string' |
| 5 | +const isTagWithClassName = node => node.exists() && node.prop('className') && typeof node.type() === 'string'; |
8 | 6 |
|
9 | 7 | const getClassNames = received => {
|
10 |
| - let className |
| 8 | + let className; |
11 | 9 |
|
12 | 10 | if (received) {
|
13 | 11 | if (received.$$typeof === Symbol.for('react.test.json')) {
|
14 |
| - className = received.props.className || received.props.class |
| 12 | + className = received.props.className || received.props.class; |
15 | 13 | } else if (typeof received.exists === 'function' && received.exists()) {
|
16 |
| - const tree = shouldDive(received) ? received.dive() : received |
17 |
| - const components = tree.findWhere(isTagWithClassName) |
| 14 | + const tree = shouldDive(received) ? received.dive() : received; |
| 15 | + const components = tree.findWhere(isTagWithClassName); |
18 | 16 | if (components.length) {
|
19 |
| - className = components.first().prop('className') |
| 17 | + className = components.first().prop('className'); |
20 | 18 | }
|
21 | 19 | } else if (global.Element && received instanceof global.Element) {
|
22 |
| - className = Array.from(received.classList).join(' ') |
| 20 | + className = Array.from(received.classList).join(' '); |
23 | 21 | }
|
24 | 22 | }
|
25 | 23 |
|
26 |
| - return className ? className.split(/\s/) : [] |
27 |
| -} |
| 24 | + return className ? className.split(/\s/) : []; |
| 25 | +}; |
28 | 26 |
|
29 |
| -const hasAtRule = options => |
30 |
| - Object.keys(options).some(option => ['media', 'supports'].includes(option)) |
| 27 | +const hasAtRule = options => Object.keys(options).some(option => ['media', 'supports'].includes(option)); |
31 | 28 |
|
32 | 29 | const getAtRules = (ast, options) => {
|
33 |
| - const mediaRegex = /(\([a-z-]+:)\s?([a-z0-9.]+\))/g |
| 30 | + const mediaRegex = /(\([a-z-]+:)\s?([a-z0-9.]+\))/g; |
34 | 31 |
|
35 | 32 | return Object.keys(options)
|
36 | 33 | .map(option =>
|
37 | 34 | ast.stylesheet.rules
|
38 |
| - .filter( |
39 |
| - rule => |
40 |
| - rule.type === option && |
41 |
| - rule[option] === options[option].replace(mediaRegex, '$1$2') |
42 |
| - ) |
| 35 | + .filter(rule => rule.type === option && rule[option] === options[option].replace(mediaRegex, '$1$2')) |
43 | 36 | .map(rule => rule.rules)
|
44 | 37 | .reduce((acc, rules) => acc.concat(rules), [])
|
45 | 38 | )
|
46 |
| - .reduce((acc, rules) => acc.concat(rules), []) |
47 |
| -} |
| 39 | + .reduce((acc, rules) => acc.concat(rules), []); |
| 40 | +}; |
48 | 41 |
|
49 | 42 | const getModifiedClassName = (className, modifier = '') => {
|
50 |
| - const classNameSelector = `.${className}` |
51 |
| - let prefix = '' |
| 43 | + const classNameSelector = `.${className}`; |
| 44 | + let prefix = ''; |
52 | 45 |
|
53 |
| - modifier = modifier.trim() |
| 46 | + modifier = modifier.trim(); |
54 | 47 | if (modifier.includes('&')) {
|
55 |
| - modifier = modifier.replace(/&/g, classNameSelector) |
| 48 | + modifier = modifier.replace(/&/g, classNameSelector); |
56 | 49 | } else {
|
57 |
| - prefix += classNameSelector |
| 50 | + prefix += classNameSelector; |
58 | 51 | }
|
59 |
| - const first = modifier[0] |
| 52 | + const first = modifier[0]; |
60 | 53 | if (first !== ':' && first !== '[') {
|
61 |
| - prefix += ' ' |
| 54 | + prefix += ' '; |
62 | 55 | }
|
63 | 56 |
|
64 |
| - return `${prefix}${modifier}`.trim() |
65 |
| -} |
| 57 | + return `${prefix}${modifier}`.trim(); |
| 58 | +}; |
66 | 59 |
|
67 | 60 | const hasClassNames = (classNames, selectors, options) =>
|
68 |
| - classNames.some(className => |
69 |
| - selectors.includes(getModifiedClassName(className, options.modifier)) |
70 |
| - ) |
| 61 | + classNames.some(className => selectors.includes(getModifiedClassName(className, options.modifier))); |
71 | 62 |
|
72 | 63 | const getRules = (ast, classNames, options) => {
|
73 |
| - const rules = hasAtRule(options) |
74 |
| - ? getAtRules(ast, options) |
75 |
| - : ast.stylesheet.rules |
76 |
| - |
77 |
| - return rules.filter( |
78 |
| - rule => |
79 |
| - rule.type === 'rule' && hasClassNames(classNames, rule.selectors, options) |
80 |
| - ) |
81 |
| -} |
| 64 | + const rules = hasAtRule(options) ? getAtRules(ast, options) : ast.stylesheet.rules; |
| 65 | + |
| 66 | + return rules.filter(rule => rule.type === 'rule' && hasClassNames(classNames, rule.selectors, options)); |
| 67 | +}; |
82 | 68 |
|
83 | 69 | const handleMissingRules = options => ({
|
84 | 70 | pass: false,
|
85 | 71 | message: () =>
|
86 | 72 | `No style rules found on passed Component${
|
87 |
| - Object.keys(options).length |
88 |
| - ? ` using options:\n${JSON.stringify(options)}` |
89 |
| - : '' |
| 73 | + Object.keys(options).length ? ` using options:\n${JSON.stringify(options)}` : '' |
90 | 74 | }`,
|
91 |
| -}) |
| 75 | +}); |
92 | 76 |
|
93 | 77 | const getDeclaration = (rule, property) =>
|
94 | 78 | rule.declarations
|
95 |
| - .filter( |
96 |
| - declaration => |
97 |
| - declaration.type === 'declaration' && declaration.property === property |
98 |
| - ) |
99 |
| - .pop() |
| 79 | + .filter(declaration => declaration.type === 'declaration' && declaration.property === property) |
| 80 | + .pop(); |
100 | 81 |
|
101 |
| -const getDeclarations = (rules, property) => |
102 |
| - rules.map(rule => getDeclaration(rule, property)).filter(Boolean) |
| 82 | +const getDeclarations = (rules, property) => rules.map(rule => getDeclaration(rule, property)).filter(Boolean); |
103 | 83 |
|
104 | 84 | const normalizeOptions = options =>
|
105 | 85 | options.modifier
|
106 | 86 | ? Object.assign({}, options, {
|
107 |
| - modifier: Array.isArray(options.modifier) |
108 |
| - ? options.modifier.join('') |
109 |
| - : options.modifier, |
| 87 | + modifier: Array.isArray(options.modifier) ? options.modifier.join('') : options.modifier, |
110 | 88 | })
|
111 |
| - : options |
| 89 | + : options; |
112 | 90 |
|
113 | 91 | function toHaveStyleRule(component, property, expected, options = {}) {
|
114 |
| - const classNames = getClassNames(component) |
115 |
| - const ast = getCSS() |
116 |
| - const normalizedOptions = normalizeOptions(options) |
117 |
| - const rules = getRules(ast, classNames, normalizedOptions) |
| 92 | + const classNames = getClassNames(component); |
| 93 | + const ast = getCSS(); |
| 94 | + const normalizedOptions = normalizeOptions(options); |
| 95 | + const rules = getRules(ast, classNames, normalizedOptions); |
118 | 96 |
|
119 | 97 | if (!rules.length) {
|
120 |
| - return handleMissingRules(normalizedOptions) |
| 98 | + return handleMissingRules(normalizedOptions); |
121 | 99 | }
|
122 | 100 |
|
123 |
| - const declarations = getDeclarations(rules, property) |
124 |
| - const declaration = declarations.pop() || {} |
125 |
| - const received = declaration.value |
126 |
| - const pass = |
127 |
| - !received && !expected && this.isNot |
128 |
| - ? false |
129 |
| - : matcherTest(received, expected) |
| 101 | + const declarations = getDeclarations(rules, property); |
| 102 | + const declaration = declarations.pop() || {}; |
| 103 | + const received = declaration.value; |
| 104 | + const pass = !received && !expected && this.isNot ? false : matcherTest(received, expected); |
130 | 105 |
|
131 | 106 | return {
|
132 | 107 | pass,
|
133 | 108 | message: buildReturnMessage(this.utils, pass, property, received, expected),
|
134 |
| - } |
| 109 | + }; |
135 | 110 | }
|
136 | 111 |
|
137 |
| -module.exports = toHaveStyleRule |
| 112 | +module.exports = toHaveStyleRule; |
0 commit comments