pxtorem-spec.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. // Jasmine unit tests
  2. // To run tests, run these commands from the project root:
  3. // 1. `npm install -g jasmine-node`
  4. // 2. `jasmine-node spec`
  5. /* global describe, it, expect */
  6. "use strict";
  7. var postcss = require("postcss");
  8. var pxtorem = require("..");
  9. var basicCSS = ".rule { font-size: 15px }";
  10. var filterPropList = require("../lib/filter-prop-list");
  11. describe("pxtorem", function() {
  12. it("should work on the readme example", function() {
  13. var input =
  14. "h1 { margin: 0 0 20px; font-size: 32px; line-height: 1.2; letter-spacing: 1px; }";
  15. var output =
  16. "h1 { margin: 0 0 20px; font-size: 2rem; line-height: 1.2; letter-spacing: 0.0625rem; }";
  17. var processed = postcss(pxtorem()).process(input).css;
  18. expect(processed).toBe(output);
  19. });
  20. it("should replace the px unit with rem", function() {
  21. var processed = postcss(pxtorem()).process(basicCSS).css;
  22. var expected = ".rule { font-size: 0.9375rem }";
  23. expect(processed).toBe(expected);
  24. });
  25. it("should ignore non px properties", function() {
  26. var expected = ".rule { font-size: 2em }";
  27. var processed = postcss(pxtorem()).process(expected).css;
  28. expect(processed).toBe(expected);
  29. });
  30. it("should handle < 1 values and values without a leading 0 - legacy", function() {
  31. var rules = ".rule { margin: 0.5rem .5px -0.2px -.2em }";
  32. var expected = ".rule { margin: 0.5rem 0.03125rem -0.0125rem -.2em }";
  33. var options = {
  34. propWhiteList: ["margin"]
  35. };
  36. var processed = postcss(pxtorem(options)).process(rules).css;
  37. expect(processed).toBe(expected);
  38. });
  39. it("should handle < 1 values and values without a leading 0", function() {
  40. var rules = ".rule { margin: 0.5rem .5px -0.2px -.2em }";
  41. var expected = ".rule { margin: 0.5rem 0.03125rem -0.0125rem -.2em }";
  42. var options = {
  43. propList: ["margin"]
  44. };
  45. var processed = postcss(pxtorem(options)).process(rules).css;
  46. expect(processed).toBe(expected);
  47. });
  48. it("should not add properties that already exist", function() {
  49. var expected = ".rule { font-size: 16px; font-size: 1rem; }";
  50. var processed = postcss(pxtorem()).process(expected).css;
  51. expect(processed).toBe(expected);
  52. });
  53. it("should remain unitless if 0", function() {
  54. var expected = ".rule { font-size: 0px; font-size: 0; }";
  55. var processed = postcss(pxtorem()).process(expected).css;
  56. expect(processed).toBe(expected);
  57. });
  58. });
  59. describe("value parsing", function() {
  60. it("should not replace values in double quotes or single quotes - legacy", function() {
  61. var options = {
  62. propWhiteList: []
  63. };
  64. var rules =
  65. ".rule { content: '16px'; font-family: \"16px\"; font-size: 16px; }";
  66. var expected =
  67. ".rule { content: '16px'; font-family: \"16px\"; font-size: 1rem; }";
  68. var processed = postcss(pxtorem(options)).process(rules).css;
  69. expect(processed).toBe(expected);
  70. });
  71. it("should not replace values in double quotes or single quotes", function() {
  72. var options = {
  73. propList: ["*"]
  74. };
  75. var rules =
  76. ".rule { content: '16px'; font-family: \"16px\"; font-size: 16px; }";
  77. var expected =
  78. ".rule { content: '16px'; font-family: \"16px\"; font-size: 1rem; }";
  79. var processed = postcss(pxtorem(options)).process(rules).css;
  80. expect(processed).toBe(expected);
  81. });
  82. it("should not replace values in `url()` - legacy", function() {
  83. var options = {
  84. propWhiteList: []
  85. };
  86. var rules = ".rule { background: url(16px.jpg); font-size: 16px; }";
  87. var expected = ".rule { background: url(16px.jpg); font-size: 1rem; }";
  88. var processed = postcss(pxtorem(options)).process(rules).css;
  89. expect(processed).toBe(expected);
  90. });
  91. it("should not replace values in `url()`", function() {
  92. var options = {
  93. propList: ["*"]
  94. };
  95. var rules = ".rule { background: url(16px.jpg); font-size: 16px; }";
  96. var expected = ".rule { background: url(16px.jpg); font-size: 1rem; }";
  97. var processed = postcss(pxtorem(options)).process(rules).css;
  98. expect(processed).toBe(expected);
  99. });
  100. it("should not replace values with an uppercase P or X", function() {
  101. var options = {
  102. propList: ["*"]
  103. };
  104. var rules =
  105. ".rule { margin: 12px calc(100% - 14PX); height: calc(100% - 20px); font-size: 12Px; line-height: 16px; }";
  106. var expected =
  107. ".rule { margin: 0.75rem calc(100% - 14PX); height: calc(100% - 1.25rem); font-size: 12Px; line-height: 1rem; }";
  108. var processed = postcss(pxtorem(options)).process(rules).css;
  109. expect(processed).toBe(expected);
  110. });
  111. });
  112. describe("rootValue", function() {
  113. // Deprecate
  114. it("should replace using a root value of 10 - legacy", function() {
  115. var expected = ".rule { font-size: 1.5rem }";
  116. var options = {
  117. root_value: 10
  118. };
  119. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  120. expect(processed).toBe(expected);
  121. });
  122. it("should replace using a root value of 10", function() {
  123. var expected = ".rule { font-size: 1.5rem }";
  124. var options = {
  125. rootValue: 10
  126. };
  127. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  128. expect(processed).toBe(expected);
  129. });
  130. it("should replace using different root values with different files", function() {
  131. var css2 = ".rule { font-size: 20px }";
  132. var expected = ".rule { font-size: 1rem }";
  133. var options = {
  134. rootValue: function(input) {
  135. if (input.from.indexOf("basic.css") !== -1) {
  136. return 15;
  137. }
  138. return 20;
  139. }
  140. };
  141. var processed1 = postcss(pxtorem(options)).process(basicCSS, {
  142. from: "/tmp/basic.css"
  143. }).css;
  144. var processed2 = postcss(pxtorem(options)).process(css2, {
  145. from: "/tmp/whatever.css"
  146. }).css;
  147. expect(processed1).toBe(expected);
  148. expect(processed2).toBe(expected);
  149. });
  150. });
  151. describe("unitPrecision", function() {
  152. // Deprecate
  153. it("should replace using a decimal of 2 places - legacy", function() {
  154. var expected = ".rule { font-size: 0.94rem }";
  155. var options = {
  156. unit_precision: 2
  157. };
  158. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  159. expect(processed).toBe(expected);
  160. });
  161. it("should replace using a decimal of 2 places", function() {
  162. var expected = ".rule { font-size: 0.94rem }";
  163. var options = {
  164. unitPrecision: 2
  165. };
  166. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  167. expect(processed).toBe(expected);
  168. });
  169. });
  170. describe("propWhiteList", function() {
  171. // Deprecate
  172. it("should only replace properties in the white list - legacy", function() {
  173. var expected = ".rule { font-size: 15px }";
  174. var options = {
  175. prop_white_list: ["font"]
  176. };
  177. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  178. expect(processed).toBe(expected);
  179. });
  180. it("should only replace properties in the white list - legacy", function() {
  181. var expected = ".rule { font-size: 15px }";
  182. var options = {
  183. propWhiteList: ["font"]
  184. };
  185. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  186. expect(processed).toBe(expected);
  187. });
  188. it("should only replace properties in the white list - legacy", function() {
  189. var css = ".rule { margin: 16px; margin-left: 10px }";
  190. var expected = ".rule { margin: 1rem; margin-left: 10px }";
  191. var options = {
  192. propWhiteList: ["margin"]
  193. };
  194. var processed = postcss(pxtorem(options)).process(css).css;
  195. expect(processed).toBe(expected);
  196. });
  197. it("should only replace properties in the prop list", function() {
  198. var css =
  199. ".rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }";
  200. var expected =
  201. ".rule { font-size: 1rem; margin: 1rem; margin-left: 5px; padding: 5px; padding-right: 1rem }";
  202. var options = {
  203. propWhiteList: ["*font*", "margin*", "!margin-left", "*-right", "pad"]
  204. };
  205. var processed = postcss(pxtorem(options)).process(css).css;
  206. expect(processed).toBe(expected);
  207. });
  208. it("should only replace properties in the prop list with wildcard", function() {
  209. var css =
  210. ".rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }";
  211. var expected =
  212. ".rule { font-size: 16px; margin: 1rem; margin-left: 5px; padding: 5px; padding-right: 16px }";
  213. var options = {
  214. propWhiteList: ["*", "!margin-left", "!*padding*", "!font*"]
  215. };
  216. var processed = postcss(pxtorem(options)).process(css).css;
  217. expect(processed).toBe(expected);
  218. });
  219. it("should replace all properties when white list is empty", function() {
  220. var rules = ".rule { margin: 16px; font-size: 15px }";
  221. var expected = ".rule { margin: 1rem; font-size: 0.9375rem }";
  222. var options = {
  223. propWhiteList: []
  224. };
  225. var processed = postcss(pxtorem(options)).process(rules).css;
  226. expect(processed).toBe(expected);
  227. });
  228. });
  229. describe("selectorBlackList", function() {
  230. // Deprecate
  231. it("should ignore selectors in the selector black list - legacy", function() {
  232. var rules = ".rule { font-size: 15px } .rule2 { font-size: 15px }";
  233. var expected = ".rule { font-size: 0.9375rem } .rule2 { font-size: 15px }";
  234. var options = {
  235. selector_black_list: [".rule2"]
  236. };
  237. var processed = postcss(pxtorem(options)).process(rules).css;
  238. expect(processed).toBe(expected);
  239. });
  240. it("should ignore selectors in the selector black list", function() {
  241. var rules = ".rule { font-size: 15px } .rule2 { font-size: 15px }";
  242. var expected = ".rule { font-size: 0.9375rem } .rule2 { font-size: 15px }";
  243. var options = {
  244. selectorBlackList: [".rule2"]
  245. };
  246. var processed = postcss(pxtorem(options)).process(rules).css;
  247. expect(processed).toBe(expected);
  248. });
  249. it("should ignore every selector with `body$`", function() {
  250. var rules =
  251. "body { font-size: 16px; } .class-body$ { font-size: 16px; } .simple-class { font-size: 16px; }";
  252. var expected =
  253. "body { font-size: 1rem; } .class-body$ { font-size: 16px; } .simple-class { font-size: 1rem; }";
  254. var options = {
  255. selectorBlackList: ["body$"]
  256. };
  257. var processed = postcss(pxtorem(options)).process(rules).css;
  258. expect(processed).toBe(expected);
  259. });
  260. it("should only ignore exactly `body`", function() {
  261. var rules =
  262. "body { font-size: 16px; } .class-body { font-size: 16px; } .simple-class { font-size: 16px; }";
  263. var expected =
  264. "body { font-size: 16px; } .class-body { font-size: 1rem; } .simple-class { font-size: 1rem; }";
  265. var options = {
  266. selectorBlackList: [/^body$/]
  267. };
  268. var processed = postcss(pxtorem(options)).process(rules).css;
  269. expect(processed).toBe(expected);
  270. });
  271. });
  272. describe("replace", function() {
  273. it("should leave fallback pixel unit with root em value", function() {
  274. var options = {
  275. replace: false
  276. };
  277. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  278. var expected = ".rule { font-size: 15px; font-size: 0.9375rem }";
  279. expect(processed).toBe(expected);
  280. });
  281. });
  282. describe("mediaQuery", function() {
  283. // Deprecate
  284. it("should replace px in media queries", function() {
  285. var options = {
  286. media_query: true
  287. };
  288. var processed = postcss(pxtorem(options)).process(
  289. "@media (min-width: 500px) { .rule { font-size: 16px } }"
  290. ).css;
  291. var expected = "@media (min-width: 31.25rem) { .rule { font-size: 1rem } }";
  292. expect(processed).toBe(expected);
  293. });
  294. it("should replace px in media queries", function() {
  295. var options = {
  296. mediaQuery: true
  297. };
  298. var processed = postcss(pxtorem(options)).process(
  299. "@media (min-width: 500px) { .rule { font-size: 16px } }"
  300. ).css;
  301. var expected = "@media (min-width: 31.25rem) { .rule { font-size: 1rem } }";
  302. expect(processed).toBe(expected);
  303. });
  304. });
  305. describe("minPixelValue", function() {
  306. it("should not replace values below minPixelValue", function() {
  307. var options = {
  308. propWhiteList: [],
  309. minPixelValue: 2
  310. };
  311. var rules =
  312. ".rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }";
  313. var expected =
  314. ".rule { border: 1px solid #000; font-size: 1rem; margin: 1px 0.625rem; }";
  315. var processed = postcss(pxtorem(options)).process(rules).css;
  316. expect(processed).toBe(expected);
  317. });
  318. });
  319. describe("filter-prop-list", function() {
  320. it('should find "exact" matches from propList', function() {
  321. var propList = [
  322. "font-size",
  323. "margin",
  324. "!padding",
  325. "*border*",
  326. "*",
  327. "*y",
  328. "!*font*"
  329. ];
  330. var expected = "font-size,margin";
  331. expect(filterPropList.exact(propList).join()).toBe(expected);
  332. });
  333. it('should find "contain" matches from propList and reduce to string', function() {
  334. var propList = [
  335. "font-size",
  336. "*margin*",
  337. "!padding",
  338. "*border*",
  339. "*",
  340. "*y",
  341. "!*font*"
  342. ];
  343. var expected = "margin,border";
  344. expect(filterPropList.contain(propList).join()).toBe(expected);
  345. });
  346. it('should find "start" matches from propList and reduce to string', function() {
  347. var propList = [
  348. "font-size",
  349. "*margin*",
  350. "!padding",
  351. "border*",
  352. "*",
  353. "*y",
  354. "!*font*"
  355. ];
  356. var expected = "border";
  357. expect(filterPropList.startWith(propList).join()).toBe(expected);
  358. });
  359. it('should find "end" matches from propList and reduce to string', function() {
  360. var propList = [
  361. "font-size",
  362. "*margin*",
  363. "!padding",
  364. "border*",
  365. "*",
  366. "*y",
  367. "!*font*"
  368. ];
  369. var expected = "y";
  370. expect(filterPropList.endWith(propList).join()).toBe(expected);
  371. });
  372. it('should find "not" matches from propList and reduce to string', function() {
  373. var propList = [
  374. "font-size",
  375. "*margin*",
  376. "!padding",
  377. "border*",
  378. "*",
  379. "*y",
  380. "!*font*"
  381. ];
  382. var expected = "padding";
  383. expect(filterPropList.notExact(propList).join()).toBe(expected);
  384. });
  385. it('should find "not contain" matches from propList and reduce to string', function() {
  386. var propList = [
  387. "font-size",
  388. "*margin*",
  389. "!padding",
  390. "!border*",
  391. "*",
  392. "*y",
  393. "!*font*"
  394. ];
  395. var expected = "font";
  396. expect(filterPropList.notContain(propList).join()).toBe(expected);
  397. });
  398. it('should find "not start" matches from propList and reduce to string', function() {
  399. var propList = [
  400. "font-size",
  401. "*margin*",
  402. "!padding",
  403. "!border*",
  404. "*",
  405. "*y",
  406. "!*font*"
  407. ];
  408. var expected = "border";
  409. expect(filterPropList.notStartWith(propList).join()).toBe(expected);
  410. });
  411. it('should find "not end" matches from propList and reduce to string', function() {
  412. var propList = [
  413. "font-size",
  414. "*margin*",
  415. "!padding",
  416. "!border*",
  417. "*",
  418. "!*y",
  419. "!*font*"
  420. ];
  421. var expected = "y";
  422. expect(filterPropList.notEndWith(propList).join()).toBe(expected);
  423. });
  424. });