NumberFormat.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. describe("errors", () => {
  2. test("structurally invalid tag", () => {
  3. expect(() => {
  4. new Intl.NumberFormat("root");
  5. }).toThrowWithMessage(RangeError, "root is not a structurally valid language tag");
  6. expect(() => {
  7. new Intl.NumberFormat("en-");
  8. }).toThrowWithMessage(RangeError, "en- is not a structurally valid language tag");
  9. expect(() => {
  10. new Intl.NumberFormat("Latn");
  11. }).toThrowWithMessage(RangeError, "Latn is not a structurally valid language tag");
  12. expect(() => {
  13. new Intl.NumberFormat("en-u-aa-U-aa");
  14. }).toThrowWithMessage(RangeError, "en-u-aa-U-aa is not a structurally valid language tag");
  15. });
  16. test("options is an invalid type", () => {
  17. expect(() => {
  18. new Intl.NumberFormat("en", null);
  19. }).toThrowWithMessage(TypeError, "ToObject on null or undefined");
  20. });
  21. test("localeMatcher option is invalid ", () => {
  22. expect(() => {
  23. new Intl.NumberFormat("en", { localeMatcher: "hello!" });
  24. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option localeMatcher");
  25. });
  26. test("numberingSystem option is invalid ", () => {
  27. expect(() => {
  28. new Intl.NumberFormat("en", { numberingSystem: "hello!" });
  29. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option numberingSystem");
  30. });
  31. test("style option is invalid ", () => {
  32. expect(() => {
  33. new Intl.NumberFormat("en", { style: "hello!" });
  34. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option style");
  35. });
  36. test("currency option is undefined when required ", () => {
  37. expect(() => {
  38. new Intl.NumberFormat("en", { style: "currency" });
  39. }).toThrowWithMessage(
  40. TypeError,
  41. "Option currency must be defined when option style is currency"
  42. );
  43. });
  44. test("currency option is invalid ", () => {
  45. expect(() => {
  46. new Intl.NumberFormat("en", { currency: "hello!" });
  47. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option currency");
  48. });
  49. test("currencyDisplay option is invalid ", () => {
  50. expect(() => {
  51. new Intl.NumberFormat("en", { currencyDisplay: "hello!" });
  52. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option currencyDisplay");
  53. });
  54. test("currencySign option is invalid ", () => {
  55. expect(() => {
  56. new Intl.NumberFormat("en", { currencySign: "hello!" });
  57. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option currencySign");
  58. });
  59. test("unit option is undefined when required ", () => {
  60. expect(() => {
  61. new Intl.NumberFormat("en", { style: "unit" });
  62. }).toThrowWithMessage(TypeError, "Option unit must be defined when option style is unit");
  63. });
  64. test("unit option is invalid ", () => {
  65. expect(() => {
  66. new Intl.NumberFormat("en", { unit: "hello!" });
  67. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option unit");
  68. expect(() => {
  69. new Intl.NumberFormat("en", { unit: "acre-bit" });
  70. }).toThrowWithMessage(RangeError, "acre-bit is not a valid value for option unit");
  71. expect(() => {
  72. new Intl.NumberFormat("en", { unit: "acre-per-bit-per-byte" });
  73. }).toThrowWithMessage(
  74. RangeError,
  75. "acre-per-bit-per-byte is not a valid value for option unit"
  76. );
  77. });
  78. test("unitDisplay option is invalid ", () => {
  79. expect(() => {
  80. new Intl.NumberFormat("en", { unitDisplay: "hello!" });
  81. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option unitDisplay");
  82. });
  83. test("notation option is invalid ", () => {
  84. expect(() => {
  85. new Intl.NumberFormat("en", { notation: "hello!" });
  86. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option notation");
  87. });
  88. test("minimumIntegerDigits option is invalid ", () => {
  89. expect(() => {
  90. new Intl.NumberFormat("en", { minimumIntegerDigits: 1n });
  91. }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number");
  92. expect(() => {
  93. new Intl.NumberFormat("en", { minimumIntegerDigits: "hello!" });
  94. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 1 and 21");
  95. expect(() => {
  96. new Intl.NumberFormat("en", { minimumIntegerDigits: 0 });
  97. }).toThrowWithMessage(RangeError, "Value 0 is NaN or is not between 1 and 21");
  98. expect(() => {
  99. new Intl.NumberFormat("en", { minimumIntegerDigits: 22 });
  100. }).toThrowWithMessage(RangeError, "Value 22 is NaN or is not between 1 and 21");
  101. });
  102. test("minimumFractionDigits option is invalid ", () => {
  103. expect(() => {
  104. new Intl.NumberFormat("en", { minimumFractionDigits: 1n });
  105. }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number");
  106. expect(() => {
  107. new Intl.NumberFormat("en", { minimumFractionDigits: "hello!" });
  108. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 0 and 100");
  109. expect(() => {
  110. new Intl.NumberFormat("en", { minimumFractionDigits: -1 });
  111. }).toThrowWithMessage(RangeError, "Value -1 is NaN or is not between 0 and 100");
  112. expect(() => {
  113. new Intl.NumberFormat("en", { minimumFractionDigits: 101 });
  114. }).toThrowWithMessage(RangeError, "Value 101 is NaN or is not between 0 and 100");
  115. });
  116. test("maximumFractionDigits option is invalid ", () => {
  117. expect(() => {
  118. new Intl.NumberFormat("en", { maximumFractionDigits: 1n });
  119. }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number");
  120. expect(() => {
  121. new Intl.NumberFormat("en", { maximumFractionDigits: "hello!" });
  122. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 0 and 100");
  123. expect(() => {
  124. new Intl.NumberFormat("en", { maximumFractionDigits: -1 });
  125. }).toThrowWithMessage(RangeError, "Value -1 is NaN or is not between 0 and 100");
  126. expect(() => {
  127. new Intl.NumberFormat("en", { maximumFractionDigits: 101 });
  128. }).toThrowWithMessage(RangeError, "Value 101 is NaN or is not between 0 and 100");
  129. expect(() => {
  130. new Intl.NumberFormat("en", { minimumFractionDigits: 10, maximumFractionDigits: 5 });
  131. }).toThrowWithMessage(RangeError, "Minimum value 10 is larger than maximum value 5");
  132. });
  133. test("minimumSignificantDigits option is invalid ", () => {
  134. expect(() => {
  135. new Intl.NumberFormat("en", { minimumSignificantDigits: 1n });
  136. }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number");
  137. expect(() => {
  138. new Intl.NumberFormat("en", { minimumSignificantDigits: "hello!" });
  139. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 1 and 21");
  140. expect(() => {
  141. new Intl.NumberFormat("en", { minimumSignificantDigits: 0 });
  142. }).toThrowWithMessage(RangeError, "Value 0 is NaN or is not between 1 and 21");
  143. expect(() => {
  144. new Intl.NumberFormat("en", { minimumSignificantDigits: 22 });
  145. }).toThrowWithMessage(RangeError, "Value 22 is NaN or is not between 1 and 21");
  146. });
  147. test("maximumSignificantDigits option is invalid ", () => {
  148. expect(() => {
  149. new Intl.NumberFormat("en", { maximumSignificantDigits: 1n });
  150. }).toThrowWithMessage(TypeError, "Cannot convert BigInt to number");
  151. expect(() => {
  152. new Intl.NumberFormat("en", { maximumSignificantDigits: "hello!" });
  153. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 1 and 21");
  154. expect(() => {
  155. new Intl.NumberFormat("en", { maximumSignificantDigits: 0 });
  156. }).toThrowWithMessage(RangeError, "Value 0 is NaN or is not between 1 and 21");
  157. expect(() => {
  158. new Intl.NumberFormat("en", { maximumSignificantDigits: 22 });
  159. }).toThrowWithMessage(RangeError, "Value 22 is NaN or is not between 1 and 21");
  160. });
  161. test("compactDisplay option is invalid ", () => {
  162. expect(() => {
  163. new Intl.NumberFormat("en", { compactDisplay: "hello!" });
  164. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option compactDisplay");
  165. });
  166. test("signDisplay option is invalid ", () => {
  167. expect(() => {
  168. new Intl.NumberFormat("en", { signDisplay: "hello!" });
  169. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option signDisplay");
  170. });
  171. test("useGrouping option is invalid", () => {
  172. expect(() => {
  173. new Intl.NumberFormat("en", { useGrouping: "hello!" });
  174. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option useGrouping");
  175. });
  176. test("roundingPriority option is invalid", () => {
  177. expect(() => {
  178. new Intl.NumberFormat("en", { roundingPriority: "hello!" });
  179. }).toThrowWithMessage(
  180. RangeError,
  181. "hello! is not a valid value for option roundingPriority"
  182. );
  183. });
  184. test("roundingMode option is invalid", () => {
  185. expect(() => {
  186. new Intl.NumberFormat("en", { roundingMode: "hello!" });
  187. }).toThrowWithMessage(RangeError, "hello! is not a valid value for option roundingMode");
  188. });
  189. test("roundingIncrement option is invalid", () => {
  190. expect(() => {
  191. new Intl.NumberFormat("en", { roundingIncrement: "hello!" });
  192. }).toThrowWithMessage(RangeError, "Value NaN is NaN or is not between 1 and 5000");
  193. expect(() => {
  194. new Intl.NumberFormat("en", { roundingIncrement: 0 });
  195. }).toThrowWithMessage(RangeError, "Value 0 is NaN or is not between 1 and 5000");
  196. expect(() => {
  197. new Intl.NumberFormat("en", { roundingIncrement: 5001 });
  198. }).toThrowWithMessage(RangeError, "Value 5001 is NaN or is not between 1 and 5000");
  199. expect(() => {
  200. new Intl.NumberFormat("en", { roundingIncrement: 3 });
  201. }).toThrowWithMessage(RangeError, "3 is not a valid rounding increment");
  202. expect(() => {
  203. new Intl.NumberFormat("en", { roundingIncrement: 5, minimumSignificantDigits: 1 });
  204. }).toThrowWithMessage(
  205. TypeError,
  206. "5 is not a valid rounding increment for rounding type significantDigits"
  207. );
  208. expect(() => {
  209. new Intl.NumberFormat("en", {
  210. roundingIncrement: 5,
  211. minimumFractionDigits: 2,
  212. maximumFractionDigits: 3,
  213. });
  214. }).toThrowWithMessage(
  215. RangeError,
  216. "5 is not a valid rounding increment for inequal min/max fraction digits"
  217. );
  218. });
  219. test("trailingZeroDisplay option is invalid", () => {
  220. expect(() => {
  221. new Intl.NumberFormat("en", { trailingZeroDisplay: "hello!" });
  222. }).toThrowWithMessage(
  223. RangeError,
  224. "hello! is not a valid value for option trailingZeroDisplay"
  225. );
  226. });
  227. });
  228. describe("normal behavior", () => {
  229. test("length is 0", () => {
  230. expect(Intl.NumberFormat).toHaveLength(0);
  231. });
  232. test("all valid localeMatcher options", () => {
  233. ["lookup", "best fit"].forEach(localeMatcher => {
  234. expect(() => {
  235. new Intl.NumberFormat("en", { localeMatcher: localeMatcher });
  236. }).not.toThrow();
  237. });
  238. });
  239. test("valid numberingSystem options", () => {
  240. ["latn", "arab", "abc-def-ghi"].forEach(numberingSystem => {
  241. expect(() => {
  242. new Intl.NumberFormat("en", { numberingSystem: numberingSystem });
  243. }).not.toThrow();
  244. });
  245. });
  246. test("all valid style options", () => {
  247. ["decimal", "percent"].forEach(style => {
  248. expect(() => {
  249. new Intl.NumberFormat("en", { style: style });
  250. }).not.toThrow();
  251. });
  252. expect(() => {
  253. new Intl.NumberFormat("en", { style: "currency", currency: "USD" });
  254. }).not.toThrow();
  255. expect(() => {
  256. new Intl.NumberFormat("en", { style: "unit", unit: "degree" });
  257. }).not.toThrow();
  258. });
  259. test("valid currency options", () => {
  260. ["USD", "EUR", "XAG"].forEach(currency => {
  261. expect(() => {
  262. new Intl.NumberFormat("en", { currency: currency });
  263. }).not.toThrow();
  264. });
  265. });
  266. test("all valid currencyDisplay options", () => {
  267. ["code", "symbol", "narrowSymbol", "name"].forEach(currencyDisplay => {
  268. expect(() => {
  269. new Intl.NumberFormat("en", { currencyDisplay: currencyDisplay });
  270. }).not.toThrow();
  271. });
  272. });
  273. test("all valid currencySign options", () => {
  274. ["standard", "accounting"].forEach(currencySign => {
  275. expect(() => {
  276. new Intl.NumberFormat("en", { currencySign: currencySign });
  277. }).not.toThrow();
  278. });
  279. });
  280. test("valid unit options", () => {
  281. ["acre", "acre-per-bit"].forEach(unit => {
  282. expect(() => {
  283. new Intl.NumberFormat("en", { unit: unit });
  284. }).not.toThrow();
  285. });
  286. });
  287. test("all valid unitDisplay options", () => {
  288. ["short", "narrow", "long"].forEach(unitDisplay => {
  289. expect(() => {
  290. new Intl.NumberFormat("en", { unitDisplay: unitDisplay });
  291. }).not.toThrow();
  292. });
  293. });
  294. test("all valid notation options", () => {
  295. ["standard", "scientific", "engineering", "compact"].forEach(notation => {
  296. expect(() => {
  297. new Intl.NumberFormat("en", { notation: notation });
  298. }).not.toThrow();
  299. });
  300. });
  301. test("all valid minimumIntegerDigits options", () => {
  302. for (let i = 1; i <= 21; ++i) {
  303. expect(() => {
  304. new Intl.NumberFormat("en", { minimumIntegerDigits: i });
  305. }).not.toThrow();
  306. }
  307. });
  308. test("all valid minimumFractionDigits options", () => {
  309. for (let i = 0; i <= 100; ++i) {
  310. expect(() => {
  311. new Intl.NumberFormat("en", { minimumFractionDigits: i });
  312. }).not.toThrow();
  313. }
  314. });
  315. test("all valid maximumFractionDigits options", () => {
  316. for (let i = 0; i <= 100; ++i) {
  317. expect(() => {
  318. new Intl.NumberFormat("en", { maximumFractionDigits: i });
  319. }).not.toThrow();
  320. }
  321. });
  322. test("all valid minimumSignificantDigits options", () => {
  323. for (let i = 1; i <= 21; ++i) {
  324. expect(() => {
  325. new Intl.NumberFormat("en", { minimumSignificantDigits: i });
  326. }).not.toThrow();
  327. }
  328. });
  329. test("all valid maximumSignificantDigits options", () => {
  330. for (let i = 1; i <= 21; ++i) {
  331. expect(() => {
  332. new Intl.NumberFormat("en", { maximumSignificantDigits: i });
  333. }).not.toThrow();
  334. }
  335. });
  336. test("all valid compactDisplay options", () => {
  337. ["short", "long"].forEach(compactDisplay => {
  338. expect(() => {
  339. new Intl.NumberFormat("en", { compactDisplay: compactDisplay });
  340. }).not.toThrow();
  341. });
  342. });
  343. test("all valid signDisplay options", () => {
  344. ["auto", "never", "always", "exceptZero", "negative"].forEach(signDisplay => {
  345. expect(() => {
  346. new Intl.NumberFormat("en", { signDisplay: signDisplay });
  347. }).not.toThrow();
  348. });
  349. });
  350. test("valid useGrouping options", () => {
  351. ["min2", "auto", "always", false, true, "false", "true", ""].forEach(useGrouping => {
  352. expect(() => {
  353. new Intl.NumberFormat("en", { useGrouping: useGrouping });
  354. }).not.toThrow();
  355. });
  356. });
  357. test("all valid roundingPriority options", () => {
  358. ["auto", "morePrecision", "lessPrecision"].forEach(roundingPriority => {
  359. expect(() => {
  360. new Intl.NumberFormat("en", { roundingPriority: roundingPriority });
  361. }).not.toThrow();
  362. });
  363. });
  364. test("all valid roundingMode options", () => {
  365. [
  366. "ceil",
  367. "floor",
  368. "expand",
  369. "trunc",
  370. "halfCeil",
  371. "halfFloor",
  372. "halfExpand",
  373. "halfTrunc",
  374. "halfEven",
  375. ].forEach(roundingMode => {
  376. expect(() => {
  377. new Intl.NumberFormat("en", { roundingMode: roundingMode });
  378. }).not.toThrow();
  379. });
  380. });
  381. test("all valid roundingIncrement options", () => {
  382. [1, 2, 5, 10, 20, 25, 50, 100, 200, 250, 500, 1000, 2000, 2500, 5000].forEach(
  383. roundingIncrement => {
  384. expect(() => {
  385. new Intl.NumberFormat("en", { roundingIncrement: roundingIncrement });
  386. }).not.toThrow();
  387. }
  388. );
  389. });
  390. test("all valid trailingZeroDisplay options", () => {
  391. ["auto", "stripIfInteger"].forEach(trailingZeroDisplay => {
  392. expect(() => {
  393. new Intl.NumberFormat("en", { trailingZeroDisplay: trailingZeroDisplay });
  394. }).not.toThrow();
  395. });
  396. });
  397. });