|
| 1 | +import _ from 'lodash' |
| 2 | +import postcss from 'postcss' |
| 3 | +import processPlugins from '../src/util/processPlugins' |
| 4 | + |
| 5 | +function css(nodes) { |
| 6 | + return postcss.root({ nodes }).toString() |
| 7 | +} |
| 8 | + |
| 9 | +function objectFitPlugin(variants = []) { |
| 10 | + return function ({ rule, addUtilities }) { |
| 11 | + addUtilities([ |
| 12 | + rule('.object-fill', { |
| 13 | + 'object-fit': 'fill', |
| 14 | + }), |
| 15 | + rule('.object-contain', { |
| 16 | + 'object-fit': 'contain', |
| 17 | + }), |
| 18 | + rule('.object-cover', { |
| 19 | + 'object-fit': 'cover', |
| 20 | + }), |
| 21 | + ], variants) |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +function buttonPlugin() { |
| 26 | + return function ({ rule, atRule, addComponents }) { |
| 27 | + addComponents([ |
| 28 | + rule('.btn-blue', { |
| 29 | + 'background-color': 'blue', |
| 30 | + 'color': 'white', |
| 31 | + 'padding': '.5rem 1rem', |
| 32 | + 'border-radius': '.25rem', |
| 33 | + }), |
| 34 | + rule('.btn-blue:hover', { |
| 35 | + 'background-color': 'darkblue', |
| 36 | + }), |
| 37 | + ]) |
| 38 | + } |
| 39 | +} |
| 40 | + |
| 41 | +function containerPlugin() { |
| 42 | + return function ({ rule, atRule, addComponents }) { |
| 43 | + addComponents([ |
| 44 | + rule('.container', { |
| 45 | + 'width': '100%', |
| 46 | + }), |
| 47 | + atRule('@media (min-width: 100px)', [ |
| 48 | + rule('.container', { |
| 49 | + 'max-width': '100px', |
| 50 | + }), |
| 51 | + ]), |
| 52 | + atRule('@media (min-width: 200px)', [ |
| 53 | + rule('.container', { |
| 54 | + 'max-width': '200px', |
| 55 | + }), |
| 56 | + ]), |
| 57 | + atRule('@media (min-width: 300px)', [ |
| 58 | + rule('.container', { |
| 59 | + 'max-width': '300px', |
| 60 | + }), |
| 61 | + ]) |
| 62 | + ]) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +test('plugins can create utilities', () => { |
| 67 | + const config = { |
| 68 | + plugins: [ |
| 69 | + objectFitPlugin() |
| 70 | + ] |
| 71 | + } |
| 72 | + |
| 73 | + const [components, utilities] = processPlugins(config) |
| 74 | + |
| 75 | + expect(components.length).toBe(0) |
| 76 | + expect(css(utilities)).toMatchCss(` |
| 77 | + @variants { |
| 78 | + .object-fill { |
| 79 | + object-fit: fill |
| 80 | + } |
| 81 | + .object-contain { |
| 82 | + object-fit: contain |
| 83 | + } |
| 84 | + .object-cover { |
| 85 | + object-fit: cover |
| 86 | + } |
| 87 | + } |
| 88 | + `) |
| 89 | +}) |
| 90 | + |
| 91 | +test('plugins can create utilities with variants', () => { |
| 92 | + const config = { |
| 93 | + plugins: [ |
| 94 | + objectFitPlugin(['responsive', 'hover', 'group-hover', 'focus']) |
| 95 | + ] |
| 96 | + } |
| 97 | + |
| 98 | + const [components, utilities] = processPlugins(config) |
| 99 | + |
| 100 | + expect(components.length).toBe(0) |
| 101 | + expect(css(utilities)).toMatchCss(` |
| 102 | + @variants responsive, hover, group-hover, focus { |
| 103 | + .object-fill { |
| 104 | + object-fit: fill |
| 105 | + } |
| 106 | + .object-contain { |
| 107 | + object-fit: contain |
| 108 | + } |
| 109 | + .object-cover { |
| 110 | + object-fit: cover |
| 111 | + } |
| 112 | + } |
| 113 | + `) |
| 114 | +}) |
| 115 | + |
| 116 | +test('plugins can create components', () => { |
| 117 | + const config = { |
| 118 | + plugins: [ |
| 119 | + buttonPlugin() |
| 120 | + ] |
| 121 | + } |
| 122 | + |
| 123 | + const [components, utilities] = processPlugins(config) |
| 124 | + |
| 125 | + expect(utilities.length).toBe(0) |
| 126 | + expect(css(components)).toMatchCss(` |
| 127 | + .btn-blue { |
| 128 | + background-color: blue; |
| 129 | + color: white; |
| 130 | + padding: .5rem 1rem; |
| 131 | + border-radius: .25rem |
| 132 | + } |
| 133 | + .btn-blue:hover { |
| 134 | + background-color: darkblue |
| 135 | + } |
| 136 | + `) |
| 137 | +}) |
| 138 | + |
| 139 | +test('plugins can create components with media queries', () => { |
| 140 | + const config = { |
| 141 | + plugins: [ |
| 142 | + containerPlugin() |
| 143 | + ] |
| 144 | + } |
| 145 | + |
| 146 | + const [components, utilities] = processPlugins(config) |
| 147 | + |
| 148 | + expect(utilities.length).toBe(0) |
| 149 | + expect(css(components)).toMatchCss(` |
| 150 | + .container { |
| 151 | + width: 100% |
| 152 | + } |
| 153 | + @media (min-width: 100px) { |
| 154 | + .container { |
| 155 | + max-width: 100px |
| 156 | + } |
| 157 | + } |
| 158 | + @media (min-width: 200px) { |
| 159 | + .container { |
| 160 | + max-width: 200px |
| 161 | + } |
| 162 | + } |
| 163 | + @media (min-width: 300px) { |
| 164 | + .container { |
| 165 | + max-width: 300px |
| 166 | + } |
| 167 | + } |
| 168 | + `) |
| 169 | +}) |
| 170 | + |
| 171 | +test('plugins can create rules with escaped selectors', () => { |
| 172 | + const config = { |
| 173 | + plugins: [ |
| 174 | + function ({ e, rule, addUtilities }) { |
| 175 | + addUtilities([ |
| 176 | + rule(`.${e('top-1/4')}`, { |
| 177 | + top: '25%', |
| 178 | + }) |
| 179 | + ], []) |
| 180 | + } |
| 181 | + ] |
| 182 | + } |
| 183 | + |
| 184 | + const [components, utilities] = processPlugins(config) |
| 185 | + |
| 186 | + expect(components.length).toBe(0) |
| 187 | + expect(css(utilities)).toMatchCss(` |
| 188 | + @variants { |
| 189 | + .top-1\\/4 { |
| 190 | + top: 25% |
| 191 | + } |
| 192 | + } |
| 193 | + `) |
| 194 | +}) |
| 195 | + |
| 196 | +test('plugins can access the current config', () => { |
| 197 | + const config = { |
| 198 | + screens: { |
| 199 | + 'sm': '576px', |
| 200 | + 'md': '768px', |
| 201 | + 'lg': '992px', |
| 202 | + 'xl': '1200px', |
| 203 | + }, |
| 204 | + plugins: [ |
| 205 | + function ({ rule, atRule, addComponents, config }) { |
| 206 | + const containerClasses = [ |
| 207 | + rule('.container', { |
| 208 | + 'width': '100%', |
| 209 | + }) |
| 210 | + ] |
| 211 | + |
| 212 | + _.forEach(config.screens, (breakpoint) => { |
| 213 | + const mediaQuery = atRule(`@media (min-width: ${breakpoint})`, [ |
| 214 | + rule('.container', { 'max-width': breakpoint }) |
| 215 | + ]) |
| 216 | + containerClasses.push(mediaQuery) |
| 217 | + }) |
| 218 | + |
| 219 | + addComponents(containerClasses) |
| 220 | + } |
| 221 | + ] |
| 222 | + } |
| 223 | + |
| 224 | + const [components, utilities] = processPlugins(config) |
| 225 | + |
| 226 | + expect(utilities.length).toBe(0) |
| 227 | + expect(css(components)).toMatchCss(` |
| 228 | + .container { |
| 229 | + width: 100% |
| 230 | + } |
| 231 | + @media (min-width: 576px) { |
| 232 | + .container { |
| 233 | + max-width: 576px |
| 234 | + } |
| 235 | + } |
| 236 | + @media (min-width: 768px) { |
| 237 | + .container { |
| 238 | + max-width: 768px |
| 239 | + } |
| 240 | + } |
| 241 | + @media (min-width: 992px) { |
| 242 | + .container { |
| 243 | + max-width: 992px |
| 244 | + } |
| 245 | + } |
| 246 | + @media (min-width: 1200px) { |
| 247 | + .container { |
| 248 | + max-width: 1200px |
| 249 | + } |
| 250 | + } |
| 251 | + `) |
| 252 | +}) |
0 commit comments