-
Notifications
You must be signed in to change notification settings - Fork 405
/
Copy pathto-have-style.js
75 lines (65 loc) · 2.25 KB
/
to-have-style.js
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
import chalk from 'chalk'
import {checkHtmlElement, parseCSS} from './utils'
function getStyleDeclaration(document, css) {
const styles = {}
// The next block is necessary to normalize colors
const copy = document.createElement('div')
Object.keys(css).forEach(property => {
copy.style[property] = css[property]
styles[property] = copy.style[property]
})
return styles
}
function isSubset(styles, computedStyle) {
return (
!!Object.keys(styles).length &&
Object.entries(styles).every(([prop, value]) => {
const isCustomProperty = prop.startsWith('--')
const spellingVariants = [prop]
if (!isCustomProperty) spellingVariants.push(prop.toLowerCase())
return spellingVariants.some(
name =>
computedStyle[name] === value ||
computedStyle.getPropertyValue(name) === value,
)
})
)
}
function printoutStyles(styles) {
return Object.keys(styles)
.sort()
.map(prop => `${prop}: ${styles[prop]};`)
.join('\n')
}
// Highlights only style rules that were expected but were not found in the
// received computed styles
function expectedDiff(diffFn, expected, computedStyles) {
const received = Array.from(computedStyles)
.filter(prop => expected[prop] !== undefined)
.reduce(
(obj, prop) =>
Object.assign(obj, {[prop]: computedStyles.getPropertyValue(prop)}),
{},
)
const diffOutput = diffFn(printoutStyles(expected), printoutStyles(received))
// Remove the "+ Received" annotation because this is a one-way diff
return diffOutput.replace(`${chalk.red('+ Received')}\n`, '')
}
export function toHaveStyle(htmlElement, css) {
checkHtmlElement(htmlElement, toHaveStyle, this)
const parsedCSS =
typeof css === 'object' ? css : parseCSS(css, toHaveStyle, this)
const {getComputedStyle} = htmlElement.ownerDocument.defaultView
const expected = getStyleDeclaration(htmlElement.ownerDocument, parsedCSS)
const received = getComputedStyle(htmlElement)
return {
pass: isSubset(expected, received),
message: () => {
const matcher = `${this.isNot ? '.not' : ''}.toHaveStyle`
return [
this.utils.matcherHint(matcher, 'element', ''),
expectedDiff(this.utils.diff, expected, received),
].join('\n\n')
},
}
}