parseObjectStyles.test.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. import parseObjectStyles from '../src/util/parseObjectStyles'
  2. import postcss from 'postcss'
  3. function css(nodes) {
  4. return postcss.root({ nodes }).toString()
  5. }
  6. test('it parses simple single class definitions', () => {
  7. const result = parseObjectStyles({
  8. '.foobar': {
  9. backgroundColor: 'red',
  10. color: 'white',
  11. padding: '1rem',
  12. },
  13. })
  14. expect(css(result)).toMatchCss(`
  15. .foobar {
  16. background-color: red;
  17. color: white;
  18. padding: 1rem
  19. }
  20. `)
  21. })
  22. test('it parses multiple class definitions', () => {
  23. const result = parseObjectStyles({
  24. '.foo': {
  25. backgroundColor: 'red',
  26. color: 'white',
  27. padding: '1rem',
  28. },
  29. '.bar': {
  30. width: '200px',
  31. height: '100px',
  32. },
  33. })
  34. expect(css(result)).toMatchCss(`
  35. .foo {
  36. background-color: red;
  37. color: white;
  38. padding: 1rem
  39. }
  40. .bar {
  41. width: 200px;
  42. height: 100px
  43. }
  44. `)
  45. })
  46. test('it parses nested pseudo-selectors', () => {
  47. const result = parseObjectStyles({
  48. '.foo': {
  49. backgroundColor: 'red',
  50. color: 'white',
  51. padding: '1rem',
  52. ':hover': {
  53. backgroundColor: 'orange',
  54. },
  55. ':focus': {
  56. backgroundColor: 'blue',
  57. },
  58. },
  59. })
  60. expect(css(result)).toMatchCss(`
  61. .foo {
  62. background-color: red;
  63. color: white;
  64. padding: 1rem;
  65. }
  66. .foo:hover {
  67. background-color: orange;
  68. }
  69. .foo:focus {
  70. background-color: blue;
  71. }
  72. `)
  73. })
  74. test('it parses top-level media queries', () => {
  75. const result = parseObjectStyles({
  76. '@media (min-width: 200px)': {
  77. '.foo': {
  78. backgroundColor: 'orange',
  79. },
  80. },
  81. })
  82. expect(css(result)).toMatchCss(`
  83. @media (min-width: 200px) {
  84. .foo {
  85. background-color: orange
  86. }
  87. }
  88. `)
  89. })
  90. test('it parses nested media queries', () => {
  91. const result = parseObjectStyles({
  92. '.foo': {
  93. backgroundColor: 'red',
  94. color: 'white',
  95. padding: '1rem',
  96. '@media (min-width: 200px)': {
  97. backgroundColor: 'orange',
  98. },
  99. },
  100. })
  101. expect(css(result)).toMatchCss(`
  102. .foo {
  103. background-color: red;
  104. color: white;
  105. padding: 1rem;
  106. }
  107. @media (min-width: 200px) {
  108. .foo {
  109. background-color: orange;
  110. }
  111. }
  112. `)
  113. })
  114. test('it bubbles nested screen rules', () => {
  115. const result = parseObjectStyles({
  116. '.foo': {
  117. backgroundColor: 'red',
  118. color: 'white',
  119. padding: '1rem',
  120. '@screen sm': {
  121. backgroundColor: 'orange',
  122. },
  123. },
  124. })
  125. expect(css(result)).toMatchCss(`
  126. .foo {
  127. background-color: red;
  128. color: white;
  129. padding: 1rem;
  130. }
  131. @screen sm {
  132. .foo {
  133. background-color: orange;
  134. }
  135. }
  136. `)
  137. })
  138. test('it parses pseudo-selectors in nested media queries', () => {
  139. const result = parseObjectStyles({
  140. '.foo': {
  141. backgroundColor: 'red',
  142. color: 'white',
  143. padding: '1rem',
  144. ':hover': {
  145. '@media (min-width: 200px)': {
  146. backgroundColor: 'orange',
  147. },
  148. },
  149. },
  150. })
  151. expect(css(result)).toMatchCss(`
  152. .foo {
  153. background-color: red;
  154. color: white;
  155. padding: 1rem;
  156. }
  157. @media (min-width: 200px) {
  158. .foo:hover {
  159. background-color: orange;
  160. }
  161. }
  162. `)
  163. })
  164. test('it parses descendant selectors', () => {
  165. const result = parseObjectStyles({
  166. '.foo': {
  167. backgroundColor: 'red',
  168. color: 'white',
  169. padding: '1rem',
  170. '.bar': {
  171. backgroundColor: 'orange',
  172. },
  173. },
  174. })
  175. expect(css(result)).toMatchCss(`
  176. .foo {
  177. background-color: red;
  178. color: white;
  179. padding: 1rem;
  180. }
  181. .foo .bar {
  182. background-color: orange;
  183. }
  184. `)
  185. })
  186. test('it parses nested multi-class selectors', () => {
  187. const result = parseObjectStyles({
  188. '.foo': {
  189. backgroundColor: 'red',
  190. color: 'white',
  191. padding: '1rem',
  192. '&.bar': {
  193. backgroundColor: 'orange',
  194. },
  195. },
  196. })
  197. expect(css(result)).toMatchCss(`
  198. .foo {
  199. background-color: red;
  200. color: white;
  201. padding: 1rem;
  202. }
  203. .foo.bar {
  204. background-color: orange;
  205. }
  206. `)
  207. })
  208. test('it parses nested multi-class selectors in media queries', () => {
  209. const result = parseObjectStyles({
  210. '.foo': {
  211. backgroundColor: 'red',
  212. color: 'white',
  213. padding: '1rem',
  214. '@media (min-width: 200px)': {
  215. '&.bar': {
  216. backgroundColor: 'orange',
  217. },
  218. },
  219. },
  220. })
  221. expect(css(result)).toMatchCss(`
  222. .foo {
  223. background-color: red;
  224. color: white;
  225. padding: 1rem;
  226. }
  227. @media (min-width: 200px) {
  228. .foo.bar {
  229. background-color: orange;
  230. }
  231. }
  232. `)
  233. })
  234. test('it strips empty selectors when nesting', () => {
  235. const result = parseObjectStyles({
  236. '.foo': {
  237. '.bar': {
  238. backgroundColor: 'orange',
  239. },
  240. },
  241. })
  242. expect(css(result)).toMatchCss(`
  243. .foo .bar {
  244. background-color: orange
  245. }
  246. `)
  247. })
  248. test('it can parse an array of styles', () => {
  249. const result = parseObjectStyles([
  250. {
  251. '.foo': {
  252. backgroundColor: 'orange',
  253. },
  254. },
  255. {
  256. '.bar': {
  257. backgroundColor: 'red',
  258. },
  259. },
  260. {
  261. '.foo': {
  262. backgroundColor: 'blue',
  263. },
  264. },
  265. ])
  266. expect(css(result)).toMatchCss(`
  267. .foo {
  268. background-color: orange
  269. }
  270. .bar {
  271. background-color: red
  272. }
  273. .foo {
  274. background-color: blue
  275. }
  276. `)
  277. })
  278. test('custom properties preserve their case', () => {
  279. const result = parseObjectStyles({
  280. ':root': {
  281. '--colors-aColor-500': '0',
  282. },
  283. })
  284. expect(css(result)).toMatchCss(`
  285. :root {
  286. --colors-aColor-500: 0;
  287. }
  288. `)
  289. })