pxtorem-spec.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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 ignore px in custom property names", function() {
  40. var rules =
  41. ":root { --rem-14px: 14px; } .rule { font-size: var(--rem-14px); }";
  42. var expected =
  43. ":root { --rem-14px: 0.875rem; } .rule { font-size: var(--rem-14px); }";
  44. var options = {
  45. propList: ["--*", "font-size"]
  46. };
  47. var processed = postcss(pxtorem(options)).process(rules).css;
  48. expect(processed).toBe(expected);
  49. });
  50. it("should handle < 1 values and values without a leading 0", function() {
  51. var rules = ".rule { margin: 0.5rem .5px -0.2px -.2em }";
  52. var expected = ".rule { margin: 0.5rem 0.03125rem -0.0125rem -.2em }";
  53. var options = {
  54. propList: ["margin"]
  55. };
  56. var processed = postcss(pxtorem(options)).process(rules).css;
  57. expect(processed).toBe(expected);
  58. });
  59. it("should not add properties that already exist", function() {
  60. var expected = ".rule { font-size: 16px; font-size: 1rem; }";
  61. var processed = postcss(pxtorem()).process(expected).css;
  62. expect(processed).toBe(expected);
  63. });
  64. it("should remain unitless if 0", function() {
  65. var expected = ".rule { font-size: 0px; font-size: 0; }";
  66. var processed = postcss(pxtorem()).process(expected).css;
  67. expect(processed).toBe(expected);
  68. });
  69. });
  70. describe("value parsing", function() {
  71. it("should not replace values in double quotes or single quotes - legacy", function() {
  72. var options = {
  73. propWhiteList: []
  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 double quotes or single quotes", function() {
  83. var options = {
  84. propList: ["*"]
  85. };
  86. var rules =
  87. ".rule { content: '16px'; font-family: \"16px\"; font-size: 16px; }";
  88. var expected =
  89. ".rule { content: '16px'; font-family: \"16px\"; font-size: 1rem; }";
  90. var processed = postcss(pxtorem(options)).process(rules).css;
  91. expect(processed).toBe(expected);
  92. });
  93. it("should not replace values in `url()` - legacy", function() {
  94. var options = {
  95. propWhiteList: []
  96. };
  97. var rules = ".rule { background: url(16px.jpg); font-size: 16px; }";
  98. var expected = ".rule { background: url(16px.jpg); font-size: 1rem; }";
  99. var processed = postcss(pxtorem(options)).process(rules).css;
  100. expect(processed).toBe(expected);
  101. });
  102. it("should not replace values in `url()`", function() {
  103. var options = {
  104. propList: ["*"]
  105. };
  106. var rules = ".rule { background: url(16px.jpg); font-size: 16px; }";
  107. var expected = ".rule { background: url(16px.jpg); font-size: 1rem; }";
  108. var processed = postcss(pxtorem(options)).process(rules).css;
  109. expect(processed).toBe(expected);
  110. });
  111. it("should not replace values with an uppercase P or X", function() {
  112. var options = {
  113. propList: ["*"]
  114. };
  115. var rules =
  116. ".rule { margin: 12px calc(100% - 14PX); height: calc(100% - 20px); font-size: 12Px; line-height: 16px; }";
  117. var expected =
  118. ".rule { margin: 0.75rem calc(100% - 14PX); height: calc(100% - 1.25rem); font-size: 12Px; line-height: 1rem; }";
  119. var processed = postcss(pxtorem(options)).process(rules).css;
  120. expect(processed).toBe(expected);
  121. });
  122. });
  123. describe("rootValue", function() {
  124. // Deprecate
  125. it("should replace using a root value of 10 - legacy", function() {
  126. var expected = ".rule { font-size: 1.5rem }";
  127. var options = {
  128. root_value: 10
  129. };
  130. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  131. expect(processed).toBe(expected);
  132. });
  133. it("should replace using a root value of 10", function() {
  134. var expected = ".rule { font-size: 1.5rem }";
  135. var options = {
  136. rootValue: 10
  137. };
  138. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  139. expect(processed).toBe(expected);
  140. });
  141. it("should replace using different root values with different files", function() {
  142. var css2 = ".rule { font-size: 20px }";
  143. var expected = ".rule { font-size: 1rem }";
  144. var options = {
  145. rootValue: function(input) {
  146. if (input.from.indexOf("basic.css") !== -1) {
  147. return 15;
  148. }
  149. return 20;
  150. }
  151. };
  152. var processed1 = postcss(pxtorem(options)).process(basicCSS, {
  153. from: "/tmp/basic.css"
  154. }).css;
  155. var processed2 = postcss(pxtorem(options)).process(css2, {
  156. from: "/tmp/whatever.css"
  157. }).css;
  158. expect(processed1).toBe(expected);
  159. expect(processed2).toBe(expected);
  160. });
  161. });
  162. describe("unitPrecision", function() {
  163. // Deprecate
  164. it("should replace using a decimal of 2 places - legacy", function() {
  165. var expected = ".rule { font-size: 0.94rem }";
  166. var options = {
  167. unit_precision: 2
  168. };
  169. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  170. expect(processed).toBe(expected);
  171. });
  172. it("should replace using a decimal of 2 places", function() {
  173. var expected = ".rule { font-size: 0.94rem }";
  174. var options = {
  175. unitPrecision: 2
  176. };
  177. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  178. expect(processed).toBe(expected);
  179. });
  180. });
  181. describe("propWhiteList", function() {
  182. // Deprecate
  183. it("should only replace properties in the white list - legacy", function() {
  184. var expected = ".rule { font-size: 15px }";
  185. var options = {
  186. prop_white_list: ["font"]
  187. };
  188. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  189. expect(processed).toBe(expected);
  190. });
  191. it("should only replace properties in the white list - legacy", function() {
  192. var expected = ".rule { font-size: 15px }";
  193. var options = {
  194. propWhiteList: ["font"]
  195. };
  196. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  197. expect(processed).toBe(expected);
  198. });
  199. it("should only replace properties in the white list - legacy", function() {
  200. var css = ".rule { margin: 16px; margin-left: 10px }";
  201. var expected = ".rule { margin: 1rem; margin-left: 10px }";
  202. var options = {
  203. propWhiteList: ["margin"]
  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", 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: 1rem; margin: 1rem; margin-left: 5px; padding: 5px; padding-right: 1rem }";
  213. var options = {
  214. propWhiteList: ["*font*", "margin*", "!margin-left", "*-right", "pad"]
  215. };
  216. var processed = postcss(pxtorem(options)).process(css).css;
  217. expect(processed).toBe(expected);
  218. });
  219. it("should only replace properties in the prop list with wildcard", function() {
  220. var css =
  221. ".rule { font-size: 16px; margin: 16px; margin-left: 5px; padding: 5px; padding-right: 16px }";
  222. var expected =
  223. ".rule { font-size: 16px; margin: 1rem; margin-left: 5px; padding: 5px; padding-right: 16px }";
  224. var options = {
  225. propWhiteList: ["*", "!margin-left", "!*padding*", "!font*"]
  226. };
  227. var processed = postcss(pxtorem(options)).process(css).css;
  228. expect(processed).toBe(expected);
  229. });
  230. it("should replace all properties when white list is empty", function() {
  231. var rules = ".rule { margin: 16px; font-size: 15px }";
  232. var expected = ".rule { margin: 1rem; font-size: 0.9375rem }";
  233. var options = {
  234. propWhiteList: []
  235. };
  236. var processed = postcss(pxtorem(options)).process(rules).css;
  237. expect(processed).toBe(expected);
  238. });
  239. });
  240. describe("selectorBlackList", function() {
  241. // Deprecate
  242. it("should ignore selectors in the selector black list - legacy", function() {
  243. var rules = ".rule { font-size: 15px } .rule2 { font-size: 15px }";
  244. var expected = ".rule { font-size: 0.9375rem } .rule2 { font-size: 15px }";
  245. var options = {
  246. selector_black_list: [".rule2"]
  247. };
  248. var processed = postcss(pxtorem(options)).process(rules).css;
  249. expect(processed).toBe(expected);
  250. });
  251. it("should ignore selectors in the selector black list", function() {
  252. var rules = ".rule { font-size: 15px } .rule2 { font-size: 15px }";
  253. var expected = ".rule { font-size: 0.9375rem } .rule2 { font-size: 15px }";
  254. var options = {
  255. selectorBlackList: [".rule2"]
  256. };
  257. var processed = postcss(pxtorem(options)).process(rules).css;
  258. expect(processed).toBe(expected);
  259. });
  260. it("should ignore every selector with `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: 1rem; } .class-body$ { font-size: 16px; } .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. it("should only ignore exactly `body`", function() {
  272. var rules =
  273. "body { font-size: 16px; } .class-body { font-size: 16px; } .simple-class { font-size: 16px; }";
  274. var expected =
  275. "body { font-size: 16px; } .class-body { font-size: 1rem; } .simple-class { font-size: 1rem; }";
  276. var options = {
  277. selectorBlackList: [/^body$/]
  278. };
  279. var processed = postcss(pxtorem(options)).process(rules).css;
  280. expect(processed).toBe(expected);
  281. });
  282. });
  283. describe("replace", function() {
  284. it("should leave fallback pixel unit with root em value", function() {
  285. var options = {
  286. replace: false
  287. };
  288. var processed = postcss(pxtorem(options)).process(basicCSS).css;
  289. var expected = ".rule { font-size: 15px; font-size: 0.9375rem }";
  290. expect(processed).toBe(expected);
  291. });
  292. });
  293. describe("mediaQuery", function() {
  294. // Deprecate
  295. it("should replace px in media queries", function() {
  296. var options = {
  297. media_query: true
  298. };
  299. var processed = postcss(pxtorem(options)).process(
  300. "@media (min-width: 500px) { .rule { font-size: 16px } }"
  301. ).css;
  302. var expected = "@media (min-width: 31.25rem) { .rule { font-size: 1rem } }";
  303. expect(processed).toBe(expected);
  304. });
  305. it("should replace px in media queries", function() {
  306. var options = {
  307. mediaQuery: true
  308. };
  309. var processed = postcss(pxtorem(options)).process(
  310. "@media (min-width: 500px) { .rule { font-size: 16px } }"
  311. ).css;
  312. var expected = "@media (min-width: 31.25rem) { .rule { font-size: 1rem } }";
  313. expect(processed).toBe(expected);
  314. });
  315. });
  316. describe("minPixelValue", function() {
  317. it("should not replace values below minPixelValue", function() {
  318. var options = {
  319. propWhiteList: [],
  320. minPixelValue: 2
  321. };
  322. var rules =
  323. ".rule { border: 1px solid #000; font-size: 16px; margin: 1px 10px; }";
  324. var expected =
  325. ".rule { border: 1px solid #000; font-size: 1rem; margin: 1px 0.625rem; }";
  326. var processed = postcss(pxtorem(options)).process(rules).css;
  327. expect(processed).toBe(expected);
  328. });
  329. });
  330. describe("filter-prop-list", function() {
  331. it('should find "exact" matches from propList', function() {
  332. var propList = [
  333. "font-size",
  334. "margin",
  335. "!padding",
  336. "*border*",
  337. "*",
  338. "*y",
  339. "!*font*"
  340. ];
  341. var expected = "font-size,margin";
  342. expect(filterPropList.exact(propList).join()).toBe(expected);
  343. });
  344. it('should find "contain" matches from propList and reduce to string', function() {
  345. var propList = [
  346. "font-size",
  347. "*margin*",
  348. "!padding",
  349. "*border*",
  350. "*",
  351. "*y",
  352. "!*font*"
  353. ];
  354. var expected = "margin,border";
  355. expect(filterPropList.contain(propList).join()).toBe(expected);
  356. });
  357. it('should find "start" matches from propList and reduce to string', function() {
  358. var propList = [
  359. "font-size",
  360. "*margin*",
  361. "!padding",
  362. "border*",
  363. "*",
  364. "*y",
  365. "!*font*"
  366. ];
  367. var expected = "border";
  368. expect(filterPropList.startWith(propList).join()).toBe(expected);
  369. });
  370. it('should find "end" matches from propList and reduce to string', function() {
  371. var propList = [
  372. "font-size",
  373. "*margin*",
  374. "!padding",
  375. "border*",
  376. "*",
  377. "*y",
  378. "!*font*"
  379. ];
  380. var expected = "y";
  381. expect(filterPropList.endWith(propList).join()).toBe(expected);
  382. });
  383. it('should find "not" matches from propList and reduce to string', function() {
  384. var propList = [
  385. "font-size",
  386. "*margin*",
  387. "!padding",
  388. "border*",
  389. "*",
  390. "*y",
  391. "!*font*"
  392. ];
  393. var expected = "padding";
  394. expect(filterPropList.notExact(propList).join()).toBe(expected);
  395. });
  396. it('should find "not contain" matches from propList and reduce to string', function() {
  397. var propList = [
  398. "font-size",
  399. "*margin*",
  400. "!padding",
  401. "!border*",
  402. "*",
  403. "*y",
  404. "!*font*"
  405. ];
  406. var expected = "font";
  407. expect(filterPropList.notContain(propList).join()).toBe(expected);
  408. });
  409. it('should find "not start" matches from propList and reduce to string', function() {
  410. var propList = [
  411. "font-size",
  412. "*margin*",
  413. "!padding",
  414. "!border*",
  415. "*",
  416. "*y",
  417. "!*font*"
  418. ];
  419. var expected = "border";
  420. expect(filterPropList.notStartWith(propList).join()).toBe(expected);
  421. });
  422. it('should find "not end" matches from propList and reduce to string', function() {
  423. var propList = [
  424. "font-size",
  425. "*margin*",
  426. "!padding",
  427. "!border*",
  428. "*",
  429. "!*y",
  430. "!*font*"
  431. ];
  432. var expected = "y";
  433. expect(filterPropList.notEndWith(propList).join()).toBe(expected);
  434. });
  435. });
  436. describe("exclude", function() {
  437. it("should ignore file path with exclude RegEx", function() {
  438. var options = {
  439. exclude: /exclude/i
  440. };
  441. var processed = postcss(pxtorem(options)).process(basicCSS, {
  442. from: "exclude/path"
  443. }).css;
  444. expect(processed).toBe(basicCSS);
  445. });
  446. it("should not ignore file path with exclude String", function() {
  447. var options = {
  448. exclude: "exclude"
  449. };
  450. var processed = postcss(pxtorem(options)).process(basicCSS, {
  451. from: "exclude/path"
  452. }).css;
  453. expect(processed).toBe(basicCSS);
  454. });
  455. it("should not ignore file path with exclude function", function() {
  456. var options = {
  457. exclude: function(file) {
  458. return file.indexOf("exclude") !== -1;
  459. }
  460. };
  461. var processed = postcss(pxtorem(options)).process(basicCSS, {
  462. from: "exclude/path"
  463. }).css;
  464. expect(processed).toBe(basicCSS);
  465. });
  466. it("should only replace properties in the prop list with wildcard", function() {
  467. var input =
  468. "h1 { margin: 0 0 20rpx; font-size: 32rpx; line-height: 1.2; letter-spacing: 1rpx; width: 30px;}";
  469. var output =
  470. "h1 { margin: 0 0 1.25rem; font-size: 2rem; line-height: 1.2; letter-spacing: 0.0625rem; width: 30px;}";
  471. var options = {
  472. unit: "rpx",
  473. propList: ["*"]
  474. };
  475. var processed = postcss(pxtorem(options)).process(input).css;
  476. expect(processed).toBe(output);
  477. });
  478. });