diff --git a/.all-contributorsrc b/.all-contributorsrc index d1af374a..22c26d55 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -273,6 +273,15 @@ "name": "Jean Chung", "avatar_url": "https://avatars0.githubusercontent.com/u/10778036?v=4", "profile": "https://github.com/jeanchung", + "contributions": [ + "code", + "test" + ], + { + "login": "CarlaTeo", + "name": "CarlaTeo", + "avatar_url": "https://avatars3.githubusercontent.com/u/9220147?v=4", + "profile": "https://github.com/CarlaTeo", "contributions": [ "code", "test" diff --git a/README.md b/README.md index 616969e9..9e7baf61 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ [![version][version-badge]][package] [![downloads][downloads-badge]][npmtrends] [![MIT License][license-badge]][license] -[![All Contributors](https://img.shields.io/badge/all_contributors-27-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-28-orange.svg?style=flat-square)](#contributors-) [![PRs Welcome][prs-badge]][prs] [![Code of Conduct][coc-badge]][coc] [![Watch on GitHub][github-watch-badge]][github-watch] @@ -1075,6 +1075,7 @@ Thanks goes to these people ([emoji key][emojis]): Jaga Santagostino
Jaga Santagostino

🐛 ⚠️ 📖 + Carla Teodoro
Carla Teodoro

💻 ⚠️ diff --git a/src/__tests__/to-have-style.js b/src/__tests__/to-have-style.js index 95949958..35b77256 100644 --- a/src/__tests__/to-have-style.js +++ b/src/__tests__/to-have-style.js @@ -15,6 +15,7 @@ describe('.toHaveStyle', () => { background-color: black; color: white; float: left; + transition: opacity 0.2s ease-out, top 0.3s cubic-bezier(1.175, 0.885, 0.32, 1.275); } ` document.body.appendChild(style) @@ -30,6 +31,11 @@ describe('.toHaveStyle', () => { background-color: blue; color: white; `) + + expect(container.querySelector('.label')).toHaveStyle( + 'transition: opacity 0.2s ease-out, top 0.3s cubic-bezier(1.175, 0.885, 0.32, 1.275)', + ) + expect(container.querySelector('.label')).toHaveStyle( 'background-color:blue;color:white', ) @@ -53,6 +59,7 @@ describe('.toHaveStyle', () => { background-color: black; color: white; float: left; + transition: opacity 0.2s ease-out, top 0.3s cubic-bezier(1.175, 0.885, 0.32, 1.275); } ` document.body.appendChild(style) @@ -63,16 +70,24 @@ describe('.toHaveStyle', () => { 'font-weight: bold', ), ).toThrowError() + expect(() => expect(container.querySelector('.label')).not.toHaveStyle('color: white'), ).toThrowError() + expect(() => + expect(container.querySelector('.label')).toHaveStyle( + 'transition: all 0.7s ease, width 1.0s cubic-bezier(3, 4, 5, 6);', + ), + ).toThrowError() + // Make sure the test fails if the css syntax is not valid expect(() => expect(container.querySelector('.label')).not.toHaveStyle( 'font-weight bold', ), ).toThrowError() + expect(() => expect(container.querySelector('.label')).toHaveStyle('color white'), ).toThrowError() @@ -96,4 +111,27 @@ describe('.toHaveStyle', () => { `) expect(queryByTestId('color-example')).toHaveStyle('border: 1px solid #fff') }) + + test('handles different color declaration formats', () => { + const {queryByTestId} = render(` + Hello World + `) + + expect(queryByTestId('color-example')).toHaveStyle('color: #000000') + expect(queryByTestId('color-example')).toHaveStyle( + 'background-color: rgba(0, 0, 0, 1)', + ) + }) + + test('handles nonexistent styles', () => { + const {container} = render(` +
+ Hello World +
+ `) + + expect(container.querySelector('.label')).not.toHaveStyle( + 'whatever: anything', + ) + }) }) diff --git a/src/to-have-style.js b/src/to-have-style.js index d3c6966a..6552f67e 100644 --- a/src/to-have-style.js +++ b/src/to-have-style.js @@ -1,17 +1,19 @@ import {matcherHint} from 'jest-matcher-utils' import jestDiff from 'jest-diff' import chalk from 'chalk' -import {checkHtmlElement, checkValidCSS} from './utils' +import {checkHtmlElement, parseCSS} from './utils' function getStyleDeclaration(document, css) { + const styles = {} + + // The next block is necessary to normalize colors const copy = document.createElement('div') - copy.style = css - const styles = copy.style + Object.keys(css).forEach(property => { + copy.style[property] = css[property] + styles[property] = copy.style[property] + }) - return Array.from(styles).reduce( - (acc, name) => ({...acc, [name]: styles[name]}), - {}, - ) + return styles } function isSubset(styles, computedStyle) { @@ -47,10 +49,10 @@ function expectedDiff(expected, computedStyles) { export function toHaveStyle(htmlElement, css) { checkHtmlElement(htmlElement, toHaveStyle, this) - checkValidCSS(css, toHaveStyle, this) + const parsedCSS = parseCSS(css, toHaveStyle, this) const {getComputedStyle} = htmlElement.ownerDocument.defaultView - const expected = getStyleDeclaration(htmlElement.ownerDocument, css) + const expected = getStyleDeclaration(htmlElement.ownerDocument, parsedCSS) const received = getComputedStyle(htmlElement) return { diff --git a/src/utils.js b/src/utils.js index 99c37907..1647fd29 100644 --- a/src/utils.js +++ b/src/utils.js @@ -79,7 +79,7 @@ class InvalidCSSError extends Error { } } -function checkValidCSS(css, ...args) { +function parseCSS(css, ...args) { const ast = parse(`selector { ${css} }`, {silent: true}).stylesheet if (ast.parsingErrors && ast.parsingErrors.length > 0) { @@ -93,6 +93,14 @@ function checkValidCSS(css, ...args) { ...args, ) } + + const parsedRules = ast.rules[0].declarations + .filter(d => d.type === 'declaration') + .reduce( + (obj, {property, value}) => Object.assign(obj, {[property]: value}), + {}, + ) + return parsedRules } function display(value) { @@ -187,7 +195,7 @@ function compareArraysAsSet(a, b) { export { HtmlElementTypeError, checkHtmlElement, - checkValidCSS, + parseCSS, deprecate, getMessage, matches,