You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

821 rivejä
23 KiB

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