diff --git a/__tests__/focusableAtRule.test.js b/__tests__/focusableAtRule.test.js index 2241105cf770..ea8749f5e3eb 100644 --- a/__tests__/focusableAtRule.test.js +++ b/__tests__/focusableAtRule.test.js @@ -14,12 +14,14 @@ test('it adds a focusable variant to each nested class definition', () => { ` const output = ` - .banana, .focus\\:banana:focus { color: yellow; } - .chocolate, .focus\\:chocolate:focus { color: brown; } + .banana { color: yellow; } + .chocolate { color: brown; } + .focus\\:banana:focus { color: yellow; } + .focus\\:chocolate:focus { color: brown; } ` return run(input).then(result => { - expect(result.css).toEqual(output) + expect(result.css).toMatchCss(output) expect(result.warnings().length).toBe(0) }) }) diff --git a/jest/customMatchers.js b/jest/customMatchers.js new file mode 100644 index 000000000000..9d2b7af6e836 --- /dev/null +++ b/jest/customMatchers.js @@ -0,0 +1,22 @@ +expect.extend({ + // Compare two CSS strings with all whitespace removed + // This is probably naive but it's fast and works well enough. + toMatchCss(received, argument) { + function stripped(str) { + return str.replace(/\s/g, '') + } + + if (stripped(received) == stripped(argument)) { + return { + message: () => + `expected ${received} not to match CSS ${argument}`, + pass: true, + }; + } else { + return { + message: () => `expected ${received} to match CSS ${argument}`, + pass: false, + }; + } + } +}) diff --git a/package.json b/package.json index f5f6969bbc83..02ea20d3a68a 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,9 @@ "react" ] }, + "jest": { + "setupTestFrameworkScriptFile": "/jest/customMatchers.js" + }, "engines": { "node": ">=6.9.0" } diff --git a/src/lib/substituteFocusableAtRules.js b/src/lib/substituteFocusableAtRules.js index 5fe48c825fe2..8d4cb25d0b6a 100644 --- a/src/lib/substituteFocusableAtRules.js +++ b/src/lib/substituteFocusableAtRules.js @@ -1,15 +1,16 @@ -import cloneNodes from '../util/cloneNodes' - export default function() { return function(css) { css.walkAtRules('focusable', atRule => { - atRule.walkRules(rule => { + const clonedRule = atRule.clone() + + clonedRule.walkRules(rule => { // Might be wise to error if the rule has multiple selectors, // or weird compound selectors like .bg-blue>p>h1 - rule.selectors = [rule.selector, `.focus\\:${rule.selector.slice(1)}:focus`] + rule.selector = `.focus\\:${rule.selector.slice(1)}:focus` }) - atRule.before(cloneNodes(atRule.nodes)) + atRule.before(atRule.clone().nodes) + atRule.after(clonedRule.nodes) atRule.remove() })