No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

802 líneas
22 KiB

  1. /* eslint-env mocha */
  2. import expect from "expect"
  3. import { fromJS, OrderedMap } from "immutable"
  4. import { mapToList, validateDateTime, validateGuid, validateNumber, validateInteger, validateParam, validateFile, fromJSOrdered, getAcceptControllingResponse, createDeepLinkPath, escapeDeepLinkPath } from "core/utils"
  5. import { validateMaximum, validateMinimum } from "core/utils"
  6. import win from "core/window"
  7. describe("utils", function() {
  8. describe("mapToList", function(){
  9. it("should convert a map to a list, setting `key`", function(){
  10. // With
  11. const aMap = fromJS({
  12. a: {
  13. one: 1,
  14. },
  15. b: {
  16. two: 2,
  17. }
  18. })
  19. // When
  20. const aList = mapToList(aMap, "someKey")
  21. // Then
  22. expect(aList.toJS()).toEqual([
  23. { someKey: "a", one: 1 },
  24. { someKey: "b", two: 2 },
  25. ])
  26. })
  27. it("should flatten an arbitrarily deep map", function(){
  28. // With
  29. const aMap = fromJS({
  30. a: {
  31. one: {
  32. alpha: true
  33. }
  34. },
  35. b: {
  36. two: {
  37. bravo: true
  38. },
  39. three: {
  40. charlie: true
  41. }
  42. }
  43. })
  44. // When
  45. const aList = mapToList(aMap, ["levelA", "levelB"])
  46. // Then
  47. expect(aList.toJS()).toEqual([
  48. { levelA: "a", levelB: "one", alpha: true },
  49. { levelA: "b", levelB: "two", bravo: true },
  50. { levelA: "b", levelB: "three", charlie: true },
  51. ])
  52. })
  53. it("should handle an empty map", function(){
  54. // With
  55. const aMap = fromJS({})
  56. // When
  57. const aList = mapToList(aMap, ["levelA", "levelB"])
  58. // Then
  59. expect(aList.toJS()).toEqual([])
  60. })
  61. })
  62. describe("validateMaximum", function() {
  63. let errorMessage = "Value must be less than Maximum"
  64. it("doesn't return for valid input", function() {
  65. expect(validateMaximum(9, 10)).toBeFalsy()
  66. expect(validateMaximum(19, 20)).toBeFalsy()
  67. })
  68. it("returns a message for invalid input", function() {
  69. expect(validateMaximum(10, 9)).toEqual(errorMessage)
  70. expect(validateMaximum(20, 19)).toEqual(errorMessage)
  71. })
  72. })
  73. describe("validateMinimum", function() {
  74. let errorMessage = "Value must be greater than Minimum"
  75. it("doesn't return for valid input", function() {
  76. expect(validateMinimum(2, 1)).toBeFalsy()
  77. expect(validateMinimum(20, 10)).toBeFalsy()
  78. })
  79. it("returns a message for invalid input", function() {
  80. expect(validateMinimum(1, 2)).toEqual(errorMessage)
  81. expect(validateMinimum(10, 20)).toEqual(errorMessage)
  82. })
  83. })
  84. describe("validateNumber", function() {
  85. let errorMessage = "Value must be a number"
  86. it("doesn't return for whole numbers", function() {
  87. expect(validateNumber(0)).toBeFalsy()
  88. expect(validateNumber(1)).toBeFalsy()
  89. expect(validateNumber(20)).toBeFalsy()
  90. expect(validateNumber(5000000)).toBeFalsy()
  91. expect(validateNumber("1")).toBeFalsy()
  92. expect(validateNumber("2")).toBeFalsy()
  93. expect(validateNumber(-1)).toBeFalsy()
  94. expect(validateNumber(-20)).toBeFalsy()
  95. expect(validateNumber(-5000000)).toBeFalsy()
  96. })
  97. it("doesn't return for negative numbers", function() {
  98. expect(validateNumber(-1)).toBeFalsy()
  99. expect(validateNumber(-20)).toBeFalsy()
  100. expect(validateNumber(-5000000)).toBeFalsy()
  101. })
  102. it("doesn't return for decimal numbers", function() {
  103. expect(validateNumber(1.1)).toBeFalsy()
  104. expect(validateNumber(2.5)).toBeFalsy()
  105. expect(validateNumber(-30.99)).toBeFalsy()
  106. })
  107. it("returns a message for strings", function() {
  108. expect(validateNumber("")).toEqual(errorMessage)
  109. expect(validateNumber(" ")).toEqual(errorMessage)
  110. expect(validateNumber("test")).toEqual(errorMessage)
  111. })
  112. it("returns a message for invalid input", function() {
  113. expect(validateNumber(undefined)).toEqual(errorMessage)
  114. expect(validateNumber(null)).toEqual(errorMessage)
  115. expect(validateNumber({})).toEqual(errorMessage)
  116. expect(validateNumber([])).toEqual(errorMessage)
  117. expect(validateNumber(true)).toEqual(errorMessage)
  118. expect(validateNumber(false)).toEqual(errorMessage)
  119. })
  120. })
  121. describe("validateInteger", function() {
  122. let errorMessage = "Value must be an integer"
  123. it("doesn't return for positive integers", function() {
  124. expect(validateInteger(0)).toBeFalsy()
  125. expect(validateInteger(1)).toBeFalsy()
  126. expect(validateInteger(20)).toBeFalsy()
  127. expect(validateInteger(5000000)).toBeFalsy()
  128. expect(validateInteger("1")).toBeFalsy()
  129. expect(validateInteger("2")).toBeFalsy()
  130. expect(validateInteger(-1)).toBeFalsy()
  131. expect(validateInteger(-20)).toBeFalsy()
  132. expect(validateInteger(-5000000)).toBeFalsy()
  133. })
  134. it("doesn't return for negative integers", function() {
  135. expect(validateInteger(-1)).toBeFalsy()
  136. expect(validateInteger(-20)).toBeFalsy()
  137. expect(validateInteger(-5000000)).toBeFalsy()
  138. })
  139. it("returns a message for decimal values", function() {
  140. expect(validateInteger(1.1)).toEqual(errorMessage)
  141. expect(validateInteger(2.5)).toEqual(errorMessage)
  142. expect(validateInteger(-30.99)).toEqual(errorMessage)
  143. })
  144. it("returns a message for strings", function() {
  145. expect(validateInteger("")).toEqual(errorMessage)
  146. expect(validateInteger(" ")).toEqual(errorMessage)
  147. expect(validateInteger("test")).toEqual(errorMessage)
  148. })
  149. it("returns a message for invalid input", function() {
  150. expect(validateInteger(undefined)).toEqual(errorMessage)
  151. expect(validateInteger(null)).toEqual(errorMessage)
  152. expect(validateInteger({})).toEqual(errorMessage)
  153. expect(validateInteger([])).toEqual(errorMessage)
  154. expect(validateInteger(true)).toEqual(errorMessage)
  155. expect(validateInteger(false)).toEqual(errorMessage)
  156. })
  157. })
  158. describe("validateFile", function() {
  159. let errorMessage = "Value must be a file"
  160. it("validates against objects which are instances of 'File'", function() {
  161. let fileObj = new win.File([], "Test File")
  162. expect(validateFile(fileObj)).toBeFalsy()
  163. expect(validateFile(null)).toBeFalsy()
  164. expect(validateFile(undefined)).toBeFalsy()
  165. expect(validateFile(1)).toEqual(errorMessage)
  166. expect(validateFile("string")).toEqual(errorMessage)
  167. })
  168. })
  169. describe("validateDateTime", function() {
  170. let errorMessage = "Value must be a DateTime"
  171. it("doesn't return for valid dates", function() {
  172. expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy()
  173. })
  174. it("returns a message for invalid input'", function() {
  175. expect(validateDateTime(null)).toEqual(errorMessage)
  176. expect(validateDateTime("string")).toEqual(errorMessage)
  177. })
  178. })
  179. describe("validateGuid", function() {
  180. let errorMessage = "Value must be a Guid"
  181. it("doesn't return for valid guid", function() {
  182. expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
  183. expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
  184. })
  185. it("returns a message for invalid input'", function() {
  186. expect(validateGuid(1)).toEqual(errorMessage)
  187. expect(validateGuid("string")).toEqual(errorMessage)
  188. })
  189. })
  190. describe("validateParam", function() {
  191. let param = null
  192. let result = null
  193. it("skips validation when `type` is not specified", function() {
  194. // invalid type
  195. param = fromJS({
  196. required: false,
  197. type: undefined,
  198. value: ""
  199. })
  200. result = validateParam( param, false )
  201. expect( result ).toEqual( [] )
  202. })
  203. it("validates required strings", function() {
  204. // invalid string
  205. param = fromJS({
  206. required: true,
  207. type: "string",
  208. value: ""
  209. })
  210. result = validateParam( param, false )
  211. expect( result ).toEqual( ["Required field is not provided"] )
  212. // valid string
  213. param = fromJS({
  214. required: true,
  215. type: "string",
  216. value: "test string"
  217. })
  218. result = validateParam( param, false )
  219. expect( result ).toEqual( [] )
  220. })
  221. it("validates optional strings", function() {
  222. // valid (empty) string
  223. param = fromJS({
  224. required: false,
  225. type: "string",
  226. value: ""
  227. })
  228. result = validateParam( param, false )
  229. expect( result ).toEqual( [] )
  230. // valid string
  231. param = fromJS({
  232. required: false,
  233. type: "string",
  234. value: "test"
  235. })
  236. result = validateParam( param, false )
  237. expect( result ).toEqual( [] )
  238. })
  239. it("validates required files", function() {
  240. // invalid file
  241. param = fromJS({
  242. required: true,
  243. type: "file",
  244. value: undefined
  245. })
  246. result = validateParam( param, false )
  247. expect( result ).toEqual( ["Required field is not provided"] )
  248. // valid file
  249. param = fromJS({
  250. required: true,
  251. type: "file",
  252. value: new win.File()
  253. })
  254. result = validateParam( param, false )
  255. expect( result ).toEqual( [] )
  256. })
  257. it("validates optional files", function() {
  258. // invalid file
  259. param = fromJS({
  260. required: false,
  261. type: "file",
  262. value: "not a file"
  263. })
  264. result = validateParam( param, false )
  265. expect( result ).toEqual( ["Value must be a file"] )
  266. // valid (empty) file
  267. param = fromJS({
  268. required: false,
  269. type: "file",
  270. value: undefined
  271. })
  272. result = validateParam( param, false )
  273. expect( result ).toEqual( [] )
  274. // valid file
  275. param = fromJS({
  276. required: false,
  277. type: "file",
  278. value: new win.File()
  279. })
  280. result = validateParam( param, false )
  281. expect( result ).toEqual( [] )
  282. })
  283. it("validates required arrays", function() {
  284. // invalid (empty) array
  285. param = fromJS({
  286. required: true,
  287. type: "array",
  288. value: []
  289. })
  290. result = validateParam( param, false )
  291. expect( result ).toEqual( ["Required field is not provided"] )
  292. // invalid (not an array)
  293. param = fromJS({
  294. required: true,
  295. type: "array",
  296. value: undefined
  297. })
  298. result = validateParam( param, false )
  299. expect( result ).toEqual( ["Required field is not provided"] )
  300. // invalid array, items do not match correct type
  301. param = fromJS({
  302. required: true,
  303. type: "array",
  304. value: [1],
  305. items: {
  306. type: "string"
  307. }
  308. })
  309. result = validateParam( param, false )
  310. expect( result ).toEqual( [{index: 0, error: "Value must be a string"}] )
  311. // valid array, with no 'type' for items
  312. param = fromJS({
  313. required: true,
  314. type: "array",
  315. value: ["1"]
  316. })
  317. result = validateParam( param, false )
  318. expect( result ).toEqual( [] )
  319. // valid array, items match type
  320. param = fromJS({
  321. required: true,
  322. type: "array",
  323. value: ["1"],
  324. items: {
  325. type: "string"
  326. }
  327. })
  328. result = validateParam( param, false )
  329. expect( result ).toEqual( [] )
  330. })
  331. it("validates optional arrays", function() {
  332. // valid, empty array
  333. param = fromJS({
  334. required: false,
  335. type: "array",
  336. value: []
  337. })
  338. result = validateParam( param, false )
  339. expect( result ).toEqual( [] )
  340. // invalid, items do not match correct type
  341. param = fromJS({
  342. required: false,
  343. type: "array",
  344. value: ["number"],
  345. items: {
  346. type: "number"
  347. }
  348. })
  349. result = validateParam( param, false )
  350. expect( result ).toEqual( [{index: 0, error: "Value must be a number"}] )
  351. // valid
  352. param = fromJS({
  353. required: false,
  354. type: "array",
  355. value: ["test"],
  356. items: {
  357. type: "string"
  358. }
  359. })
  360. result = validateParam( param, false )
  361. expect( result ).toEqual( [] )
  362. })
  363. it("validates required booleans", function() {
  364. // invalid boolean value
  365. param = fromJS({
  366. required: true,
  367. type: "boolean",
  368. value: undefined
  369. })
  370. result = validateParam( param, false )
  371. expect( result ).toEqual( ["Required field is not provided"] )
  372. // invalid boolean value (not a boolean)
  373. param = fromJS({
  374. required: true,
  375. type: "boolean",
  376. value: "test string"
  377. })
  378. result = validateParam( param, false )
  379. expect( result ).toEqual( ["Required field is not provided"] )
  380. // valid boolean value
  381. param = fromJS({
  382. required: true,
  383. type: "boolean",
  384. value: "true"
  385. })
  386. result = validateParam( param, false )
  387. expect( result ).toEqual( [] )
  388. // valid boolean value
  389. param = fromJS({
  390. required: true,
  391. type: "boolean",
  392. value: false
  393. })
  394. result = validateParam( param, false )
  395. expect( result ).toEqual( [] )
  396. })
  397. it("validates optional booleans", function() {
  398. // valid (empty) boolean value
  399. param = fromJS({
  400. required: false,
  401. type: "boolean",
  402. value: undefined
  403. })
  404. result = validateParam( param, false )
  405. expect( result ).toEqual( [] )
  406. // invalid boolean value (not a boolean)
  407. param = fromJS({
  408. required: false,
  409. type: "boolean",
  410. value: "test string"
  411. })
  412. result = validateParam( param, false )
  413. expect( result ).toEqual( ["Value must be a boolean"] )
  414. // valid boolean value
  415. param = fromJS({
  416. required: false,
  417. type: "boolean",
  418. value: "true"
  419. })
  420. result = validateParam( param, false )
  421. expect( result ).toEqual( [] )
  422. // valid boolean value
  423. param = fromJS({
  424. required: false,
  425. type: "boolean",
  426. value: false
  427. })
  428. result = validateParam( param, false )
  429. expect( result ).toEqual( [] )
  430. })
  431. it("validates required numbers", function() {
  432. // invalid number, string instead of a number
  433. param = fromJS({
  434. required: true,
  435. type: "number",
  436. value: "test"
  437. })
  438. result = validateParam( param, false )
  439. expect( result ).toEqual( ["Required field is not provided"] )
  440. // invalid number, undefined value
  441. param = fromJS({
  442. required: true,
  443. type: "number",
  444. value: undefined
  445. })
  446. result = validateParam( param, false )
  447. expect( result ).toEqual( ["Required field is not provided"] )
  448. // valid number with min and max
  449. param = fromJS({
  450. required: true,
  451. type: "number",
  452. value: 10,
  453. minimum: 5,
  454. maximum: 99
  455. })
  456. result = validateParam( param, false )
  457. expect( result ).toEqual( [] )
  458. // valid negative number with min and max
  459. param = fromJS({
  460. required: true,
  461. type: "number",
  462. value: -10,
  463. minimum: -50,
  464. maximum: -5
  465. })
  466. result = validateParam( param, false )
  467. expect( result ).toEqual( [] )
  468. })
  469. it("validates optional numbers", function() {
  470. // invalid number, string instead of a number
  471. param = fromJS({
  472. required: false,
  473. type: "number",
  474. value: "test"
  475. })
  476. result = validateParam( param, false )
  477. expect( result ).toEqual( ["Value must be a number"] )
  478. // valid (empty) number
  479. param = fromJS({
  480. required: false,
  481. type: "number",
  482. value: undefined
  483. })
  484. result = validateParam( param, false )
  485. expect( result ).toEqual( [] )
  486. // valid number
  487. param = fromJS({
  488. required: false,
  489. type: "number",
  490. value: 10
  491. })
  492. result = validateParam( param, false )
  493. expect( result ).toEqual( [] )
  494. })
  495. it("validates required integers", function() {
  496. // invalid integer, string instead of an integer
  497. param = fromJS({
  498. required: true,
  499. type: "integer",
  500. value: "test"
  501. })
  502. result = validateParam( param, false )
  503. expect( result ).toEqual( ["Required field is not provided"] )
  504. // invalid integer, undefined value
  505. param = fromJS({
  506. required: true,
  507. type: "integer",
  508. value: undefined
  509. })
  510. result = validateParam( param, false )
  511. expect( result ).toEqual( ["Required field is not provided"] )
  512. // valid integer
  513. param = fromJS({
  514. required: true,
  515. type: "integer",
  516. value: 10
  517. })
  518. result = validateParam( param, false )
  519. expect( result ).toEqual( [] )
  520. })
  521. it("validates optional integers", function() {
  522. // invalid integer, string instead of an integer
  523. param = fromJS({
  524. required: false,
  525. type: "integer",
  526. value: "test"
  527. })
  528. result = validateParam( param, false )
  529. expect( result ).toEqual( ["Value must be an integer"] )
  530. // valid (empty) integer
  531. param = fromJS({
  532. required: false,
  533. type: "integer",
  534. value: undefined
  535. })
  536. result = validateParam( param, false )
  537. expect( result ).toEqual( [] )
  538. // integers
  539. param = fromJS({
  540. required: false,
  541. type: "integer",
  542. value: 10
  543. })
  544. result = validateParam( param, false )
  545. expect( result ).toEqual( [] )
  546. })
  547. })
  548. describe("fromJSOrdered", () => {
  549. it("should create an OrderedMap from an object", () => {
  550. const param = {
  551. value: "test"
  552. }
  553. const result = fromJSOrdered(param).toJS()
  554. expect( result ).toEqual( { value: "test" } )
  555. })
  556. it("should not use an object's length property for Map size", () => {
  557. const param = {
  558. length: 5
  559. }
  560. const result = fromJSOrdered(param).toJS()
  561. expect( result ).toEqual( { length: 5 } )
  562. })
  563. it("should create an OrderedMap from an array", () => {
  564. const param = [1, 1, 2, 3, 5, 8]
  565. const result = fromJSOrdered(param).toJS()
  566. expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
  567. })
  568. })
  569. describe("getAcceptControllingResponse", () => {
  570. it("should return the first 2xx response with a media type", () => {
  571. const responses = fromJSOrdered({
  572. "200": {
  573. content: {
  574. "application/json": {
  575. schema: {
  576. type: "object"
  577. }
  578. }
  579. }
  580. },
  581. "201": {
  582. content: {
  583. "application/json": {
  584. schema: {
  585. type: "object"
  586. }
  587. }
  588. }
  589. }
  590. })
  591. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("200"))
  592. })
  593. it("should skip 2xx responses without defined media types", () => {
  594. const responses = fromJSOrdered({
  595. "200": {
  596. content: {
  597. "application/json": {
  598. schema: {
  599. type: "object"
  600. }
  601. }
  602. }
  603. },
  604. "201": {
  605. content: {
  606. "application/json": {
  607. schema: {
  608. type: "object"
  609. }
  610. }
  611. }
  612. }
  613. })
  614. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("201"))
  615. })
  616. it("should default to the `default` response if it has defined media types", () => {
  617. const responses = fromJSOrdered({
  618. "200": {
  619. description: "quite empty"
  620. },
  621. "201": {
  622. description: "quite empty"
  623. },
  624. default: {
  625. content: {
  626. "application/json": {
  627. schema: {
  628. type: "object"
  629. }
  630. }
  631. }
  632. }
  633. })
  634. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("default"))
  635. })
  636. it("should return null if there are no suitable controlling responses", () => {
  637. const responses = fromJSOrdered({
  638. "200": {
  639. description: "quite empty"
  640. },
  641. "201": {
  642. description: "quite empty"
  643. },
  644. "default": {
  645. description: "also empty.."
  646. }
  647. })
  648. expect(getAcceptControllingResponse(responses)).toBe(null)
  649. })
  650. it("should return null if an empty OrderedMap is passed", () => {
  651. const responses = fromJSOrdered()
  652. expect(getAcceptControllingResponse(responses)).toBe(null)
  653. })
  654. it("should return null if anything except an OrderedMap is passed", () => {
  655. const responses = {}
  656. expect(getAcceptControllingResponse(responses)).toBe(null)
  657. })
  658. })
  659. describe("createDeepLinkPath", function() {
  660. it("creates a deep link path replacing spaces with underscores", function() {
  661. const result = createDeepLinkPath("tag id with spaces")
  662. expect(result).toEqual("tag_id_with_spaces")
  663. })
  664. it("trims input when creating a deep link path", function() {
  665. let result = createDeepLinkPath(" spaces before and after ")
  666. expect(result).toEqual("spaces_before_and_after")
  667. result = createDeepLinkPath(" ")
  668. expect(result).toEqual("")
  669. })
  670. it("creates a deep link path with special characters", function() {
  671. const result = createDeepLinkPath("!@#$%^&*(){}[]")
  672. expect(result).toEqual("!@#$%^&*(){}[]")
  673. })
  674. it("returns an empty string for invalid input", function() {
  675. expect( createDeepLinkPath(null) ).toEqual("")
  676. expect( createDeepLinkPath(undefined) ).toEqual("")
  677. expect( createDeepLinkPath(1) ).toEqual("")
  678. expect( createDeepLinkPath([]) ).toEqual("")
  679. expect( createDeepLinkPath({}) ).toEqual("")
  680. })
  681. })
  682. describe("escapeDeepLinkPath", function() {
  683. it("creates and escapes a deep link path", function() {
  684. const result = escapeDeepLinkPath("tag id with spaces?")
  685. expect(result).toEqual("tag_id_with_spaces\\?")
  686. })
  687. it("escapes a deep link path that starts with a number", function() {
  688. const result = escapeDeepLinkPath("123")
  689. expect(result).toEqual("\\31 23")
  690. })
  691. it("escapes a deep link path with a class selector", function() {
  692. const result = escapeDeepLinkPath("hello.world")
  693. expect(result).toEqual("hello\\.world")
  694. })
  695. it("escapes a deep link path with an id selector", function() {
  696. const result = escapeDeepLinkPath("hello#world")
  697. expect(result).toEqual("hello\\#world")
  698. })
  699. })
  700. })