Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 

1390 řádky
38 KiB

  1. /* eslint-env mocha */
  2. import expect from "expect"
  3. import { Map, fromJS, OrderedMap } from "immutable"
  4. import {
  5. mapToList,
  6. parseSearch,
  7. serializeSearch,
  8. validatePattern,
  9. validateMinLength,
  10. validateMaxLength,
  11. validateDateTime,
  12. validateGuid,
  13. validateNumber,
  14. validateInteger,
  15. validateParam,
  16. validateFile,
  17. validateMaximum,
  18. validateMinimum,
  19. fromJSOrdered,
  20. getAcceptControllingResponse,
  21. createDeepLinkPath,
  22. escapeDeepLinkPath,
  23. getExtensions,
  24. getCommonExtensions,
  25. sanitizeUrl,
  26. extractFileNameFromContentDispositionHeader,
  27. deeplyStripKey,
  28. getSampleSchema,
  29. paramToIdentifier,
  30. paramToValue,
  31. } from "core/utils"
  32. import win from "core/window"
  33. describe("utils", function() {
  34. describe("mapToList", function(){
  35. it("should convert a map to a list, setting `key`", function(){
  36. // With
  37. const aMap = fromJS({
  38. a: {
  39. one: 1,
  40. },
  41. b: {
  42. two: 2,
  43. }
  44. })
  45. // When
  46. const aList = mapToList(aMap, "someKey")
  47. // Then
  48. expect(aList.toJS()).toEqual([
  49. { someKey: "a", one: 1 },
  50. { someKey: "b", two: 2 },
  51. ])
  52. })
  53. it("should flatten an arbitrarily deep map", function(){
  54. // With
  55. const aMap = fromJS({
  56. a: {
  57. one: {
  58. alpha: true
  59. }
  60. },
  61. b: {
  62. two: {
  63. bravo: true
  64. },
  65. three: {
  66. charlie: true
  67. }
  68. }
  69. })
  70. // When
  71. const aList = mapToList(aMap, ["levelA", "levelB"])
  72. // Then
  73. expect(aList.toJS()).toEqual([
  74. { levelA: "a", levelB: "one", alpha: true },
  75. { levelA: "b", levelB: "two", bravo: true },
  76. { levelA: "b", levelB: "three", charlie: true },
  77. ])
  78. })
  79. it("should handle an empty map", function(){
  80. // With
  81. const aMap = fromJS({})
  82. // When
  83. const aList = mapToList(aMap, ["levelA", "levelB"])
  84. // Then
  85. expect(aList.toJS()).toEqual([])
  86. })
  87. })
  88. describe("extractFileNameFromContentDispositionHeader", function(){
  89. it("should extract quoted filename", function(){
  90. let cdHeader = "attachment; filename=\"file name.jpg\""
  91. let expectedResult = "file name.jpg"
  92. expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
  93. })
  94. it("should extract filename", function(){
  95. let cdHeader = "attachment; filename=filename.jpg"
  96. let expectedResult = "filename.jpg"
  97. expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
  98. })
  99. it("should extract quoted filename in utf-8", function(){
  100. let cdHeader = "attachment; filename*=UTF-8''\"%D1%84%D0%B0%D0%B9%D0%BB.txt\""
  101. let expectedResult = "файл.txt"
  102. expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
  103. })
  104. it("should extract filename in utf-8", function(){
  105. let cdHeader = "attachment; filename*=utf-8'ru'%D1%84%D0%B0%D0%B9%D0%BB.txt"
  106. let expectedResult = "файл.txt"
  107. expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
  108. })
  109. it("should not extract filename and return null", function(){
  110. let cdHeader = "attachment; no file name provided"
  111. let expectedResult = null
  112. expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
  113. })
  114. })
  115. describe("validateMaximum", function() {
  116. let errorMessage = "Value must be less than Maximum"
  117. it("doesn't return for valid input", function() {
  118. expect(validateMaximum(9, 10)).toBeFalsy()
  119. expect(validateMaximum(19, 20)).toBeFalsy()
  120. })
  121. it("returns a message for invalid input", function() {
  122. expect(validateMaximum(1, 0)).toEqual(errorMessage)
  123. expect(validateMaximum(10, 9)).toEqual(errorMessage)
  124. expect(validateMaximum(20, 19)).toEqual(errorMessage)
  125. })
  126. })
  127. describe("validateMinimum", function() {
  128. let errorMessage = "Value must be greater than Minimum"
  129. it("doesn't return for valid input", function() {
  130. expect(validateMinimum(2, 1)).toBeFalsy()
  131. expect(validateMinimum(20, 10)).toBeFalsy()
  132. })
  133. it("returns a message for invalid input", function() {
  134. expect(validateMinimum(-1, 0)).toEqual(errorMessage)
  135. expect(validateMinimum(1, 2)).toEqual(errorMessage)
  136. expect(validateMinimum(10, 20)).toEqual(errorMessage)
  137. })
  138. })
  139. describe("validateNumber", function() {
  140. let errorMessage = "Value must be a number"
  141. it("doesn't return for whole numbers", function() {
  142. expect(validateNumber(0)).toBeFalsy()
  143. expect(validateNumber(1)).toBeFalsy()
  144. expect(validateNumber(20)).toBeFalsy()
  145. expect(validateNumber(5000000)).toBeFalsy()
  146. expect(validateNumber("1")).toBeFalsy()
  147. expect(validateNumber("2")).toBeFalsy()
  148. expect(validateNumber(-1)).toBeFalsy()
  149. expect(validateNumber(-20)).toBeFalsy()
  150. expect(validateNumber(-5000000)).toBeFalsy()
  151. })
  152. it("doesn't return for negative numbers", function() {
  153. expect(validateNumber(-1)).toBeFalsy()
  154. expect(validateNumber(-20)).toBeFalsy()
  155. expect(validateNumber(-5000000)).toBeFalsy()
  156. })
  157. it("doesn't return for decimal numbers", function() {
  158. expect(validateNumber(1.1)).toBeFalsy()
  159. expect(validateNumber(2.5)).toBeFalsy()
  160. expect(validateNumber(-30.99)).toBeFalsy()
  161. })
  162. it("returns a message for strings", function() {
  163. expect(validateNumber("")).toEqual(errorMessage)
  164. expect(validateNumber(" ")).toEqual(errorMessage)
  165. expect(validateNumber("test")).toEqual(errorMessage)
  166. })
  167. it("returns a message for invalid input", function() {
  168. expect(validateNumber(undefined)).toEqual(errorMessage)
  169. expect(validateNumber(null)).toEqual(errorMessage)
  170. expect(validateNumber({})).toEqual(errorMessage)
  171. expect(validateNumber([])).toEqual(errorMessage)
  172. expect(validateNumber(true)).toEqual(errorMessage)
  173. expect(validateNumber(false)).toEqual(errorMessage)
  174. })
  175. })
  176. describe("validateInteger", function() {
  177. let errorMessage = "Value must be an integer"
  178. it("doesn't return for positive integers", function() {
  179. expect(validateInteger(0)).toBeFalsy()
  180. expect(validateInteger(1)).toBeFalsy()
  181. expect(validateInteger(20)).toBeFalsy()
  182. expect(validateInteger(5000000)).toBeFalsy()
  183. expect(validateInteger("1")).toBeFalsy()
  184. expect(validateInteger("2")).toBeFalsy()
  185. expect(validateInteger(-1)).toBeFalsy()
  186. expect(validateInteger(-20)).toBeFalsy()
  187. expect(validateInteger(-5000000)).toBeFalsy()
  188. })
  189. it("doesn't return for negative integers", function() {
  190. expect(validateInteger(-1)).toBeFalsy()
  191. expect(validateInteger(-20)).toBeFalsy()
  192. expect(validateInteger(-5000000)).toBeFalsy()
  193. })
  194. it("returns a message for decimal values", function() {
  195. expect(validateInteger(1.1)).toEqual(errorMessage)
  196. expect(validateInteger(2.5)).toEqual(errorMessage)
  197. expect(validateInteger(-30.99)).toEqual(errorMessage)
  198. })
  199. it("returns a message for strings", function() {
  200. expect(validateInteger("")).toEqual(errorMessage)
  201. expect(validateInteger(" ")).toEqual(errorMessage)
  202. expect(validateInteger("test")).toEqual(errorMessage)
  203. })
  204. it("returns a message for invalid input", function() {
  205. expect(validateInteger(undefined)).toEqual(errorMessage)
  206. expect(validateInteger(null)).toEqual(errorMessage)
  207. expect(validateInteger({})).toEqual(errorMessage)
  208. expect(validateInteger([])).toEqual(errorMessage)
  209. expect(validateInteger(true)).toEqual(errorMessage)
  210. expect(validateInteger(false)).toEqual(errorMessage)
  211. })
  212. })
  213. describe("validateFile", function() {
  214. let errorMessage = "Value must be a file"
  215. it("validates against objects which are instances of 'File'", function() {
  216. let fileObj = new win.File([], "Test File")
  217. expect(validateFile(fileObj)).toBeFalsy()
  218. expect(validateFile(null)).toBeFalsy()
  219. expect(validateFile(undefined)).toBeFalsy()
  220. expect(validateFile(1)).toEqual(errorMessage)
  221. expect(validateFile("string")).toEqual(errorMessage)
  222. })
  223. })
  224. describe("validateDateTime", function() {
  225. let errorMessage = "Value must be a DateTime"
  226. it("doesn't return for valid dates", function() {
  227. expect(validateDateTime("Mon, 25 Dec 1995 13:30:00 +0430")).toBeFalsy()
  228. })
  229. it("returns a message for invalid input'", function() {
  230. expect(validateDateTime(null)).toEqual(errorMessage)
  231. expect(validateDateTime("string")).toEqual(errorMessage)
  232. })
  233. })
  234. describe("validateGuid", function() {
  235. let errorMessage = "Value must be a Guid"
  236. it("doesn't return for valid guid", function() {
  237. expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
  238. expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
  239. expect(validateGuid("8CE4811E-CEC5-4A29-891A-15D1917153C1")).toBeFalsy()
  240. expect(validateGuid("6ffefd8e-a018-e811-bbf9-60f67727d806")).toBeFalsy()
  241. expect(validateGuid("6FFEFD8E-A018-E811-BBF9-60F67727D806")).toBeFalsy()
  242. expect(validateGuid("00000000-0000-0000-0000-000000000000")).toBeFalsy()
  243. })
  244. it("returns a message for invalid input'", function() {
  245. expect(validateGuid(1)).toEqual(errorMessage)
  246. expect(validateGuid("string")).toEqual(errorMessage)
  247. })
  248. })
  249. describe("validateMaxLength", function() {
  250. let errorMessage = "Value must be less than MaxLength"
  251. it("doesn't return for valid guid", function() {
  252. expect(validateMaxLength("a", 1)).toBeFalsy()
  253. expect(validateMaxLength("abc", 5)).toBeFalsy()
  254. })
  255. it("returns a message for invalid input'", function() {
  256. expect(validateMaxLength("abc", 0)).toEqual(errorMessage)
  257. expect(validateMaxLength("abc", 1)).toEqual(errorMessage)
  258. expect(validateMaxLength("abc", 2)).toEqual(errorMessage)
  259. })
  260. })
  261. describe("validateMinLength", function() {
  262. let errorMessage = "Value must be greater than MinLength"
  263. it("doesn't return for valid guid", function() {
  264. expect(validateMinLength("a", 1)).toBeFalsy()
  265. expect(validateMinLength("abc", 2)).toBeFalsy()
  266. })
  267. it("returns a message for invalid input'", function() {
  268. expect(validateMinLength("abc", 5)).toEqual(errorMessage)
  269. expect(validateMinLength("abc", 8)).toEqual(errorMessage)
  270. })
  271. })
  272. describe("validatePattern", function() {
  273. let rxPattern = "^(red|blue)"
  274. let errorMessage = "Value must follow pattern " + rxPattern
  275. it("doesn't return for a match", function() {
  276. expect(validatePattern("red", rxPattern)).toBeFalsy()
  277. expect(validatePattern("blue", rxPattern)).toBeFalsy()
  278. })
  279. it("returns a message for invalid pattern", function() {
  280. expect(validatePattern("pink", rxPattern)).toEqual(errorMessage)
  281. expect(validatePattern("123", rxPattern)).toEqual(errorMessage)
  282. })
  283. it("fails gracefully when an invalid regex value is passed", function() {
  284. expect(() => validatePattern("aValue", "---")).toNotThrow()
  285. expect(() => validatePattern("aValue", 1234)).toNotThrow()
  286. expect(() => validatePattern("aValue", null)).toNotThrow()
  287. expect(() => validatePattern("aValue", [])).toNotThrow()
  288. })
  289. })
  290. describe("validateParam", function() {
  291. let param = null
  292. let value = null
  293. let result = null
  294. const assertValidateParam = (param, value, expectedError) => {
  295. // Swagger 2.0 version
  296. result = validateParam( fromJS(param), fromJS(value))
  297. expect( result ).toEqual( expectedError )
  298. // OAS3 version, using `schema` sub-object
  299. let oas3Param = {
  300. required: param.required,
  301. schema: {
  302. ...param,
  303. required: undefined
  304. }
  305. }
  306. result = validateParam( fromJS(oas3Param), fromJS(value), {
  307. isOAS3: true
  308. })
  309. expect( result ).toEqual( expectedError )
  310. }
  311. const assertValidateOas3Param = (param, value, expectedError) => {
  312. // for cases where you _only_ want to try OAS3
  313. result = validateParam(fromJS(param), value, {
  314. isOAS3: true
  315. })
  316. expect( result ).toEqual( expectedError )
  317. }
  318. it("should check the isOAS3 flag when validating parameters", function() {
  319. // This should "skip" validation because there is no `schema` property
  320. // and we are telling `validateParam` this is an OAS3 spec
  321. param = fromJS({
  322. required: true
  323. })
  324. value = ""
  325. result = validateParam( param, value, {
  326. isOAS3: true
  327. } )
  328. expect( result ).toEqual( [] )
  329. })
  330. it("validates required OAS3 objects", function() {
  331. // valid object
  332. param = {
  333. required: true,
  334. schema: {
  335. type: "object"
  336. }
  337. }
  338. value = {
  339. abc: 123
  340. }
  341. assertValidateOas3Param(param, value, [])
  342. // valid object-as-string
  343. param = {
  344. required: true,
  345. schema: {
  346. type: "object"
  347. }
  348. }
  349. value = JSON.stringify({
  350. abc: 123
  351. })
  352. assertValidateOas3Param(param, value, [])
  353. // invalid object-as-string
  354. param = {
  355. required: true,
  356. schema: {
  357. type: "object"
  358. }
  359. }
  360. value = "{{}"
  361. assertValidateOas3Param(param, value, ["Parameter string value must be valid JSON"])
  362. // missing when required
  363. param = {
  364. required: true,
  365. schema: {
  366. type: "object"
  367. },
  368. }
  369. value = undefined
  370. assertValidateOas3Param(param, value, ["Required field is not provided"])
  371. })
  372. it("validates optional OAS3 objects", function() {
  373. // valid object
  374. param = {
  375. schema: {
  376. type: "object"
  377. }
  378. }
  379. value = {
  380. abc: 123
  381. }
  382. assertValidateOas3Param(param, value, [])
  383. // valid object-as-string
  384. param = {
  385. schema: {
  386. type: "object"
  387. }
  388. }
  389. value = JSON.stringify({
  390. abc: 123
  391. })
  392. assertValidateOas3Param(param, value, [])
  393. // invalid object-as-string
  394. param = {
  395. schema: {
  396. type: "object"
  397. }
  398. }
  399. value = "{{}"
  400. assertValidateOas3Param(param, value, ["Parameter string value must be valid JSON"])
  401. // missing when not required
  402. param = {
  403. schema: {
  404. type: "object"
  405. },
  406. }
  407. value = undefined
  408. assertValidateOas3Param(param, value, [])
  409. })
  410. it("validates required strings", function() {
  411. // invalid string
  412. param = {
  413. required: true,
  414. type: "string"
  415. }
  416. value = ""
  417. assertValidateParam(param, value, ["Required field is not provided"])
  418. // valid string
  419. param = {
  420. required: true,
  421. type: "string"
  422. }
  423. value = "test string"
  424. assertValidateParam(param, value, [])
  425. // valid string with min and max length
  426. param = {
  427. required: true,
  428. type: "string",
  429. maxLength: 50,
  430. minLength: 1
  431. }
  432. value = "test string"
  433. assertValidateParam(param, value, [])
  434. })
  435. it("validates required strings with min and max length", function() {
  436. // invalid string with max length
  437. param = {
  438. required: true,
  439. type: "string",
  440. maxLength: 5
  441. }
  442. value = "test string"
  443. assertValidateParam(param, value, ["Value must be less than MaxLength"])
  444. // invalid string with max length 0
  445. param = {
  446. required: true,
  447. type: "string",
  448. maxLength: 0
  449. }
  450. value = "test string"
  451. assertValidateParam(param, value, ["Value must be less than MaxLength"])
  452. // invalid string with min length
  453. param = {
  454. required: true,
  455. type: "string",
  456. minLength: 50
  457. }
  458. value = "test string"
  459. assertValidateParam(param, value, ["Value must be greater than MinLength"])
  460. })
  461. it("validates optional strings", function() {
  462. // valid (empty) string
  463. param = {
  464. required: false,
  465. type: "string"
  466. }
  467. value = ""
  468. assertValidateParam(param, value, [])
  469. // valid string
  470. param = {
  471. required: false,
  472. type: "string"
  473. }
  474. value = "test"
  475. assertValidateParam(param, value, [])
  476. })
  477. it("validates required files", function() {
  478. // invalid file
  479. param = {
  480. required: true,
  481. type: "file"
  482. }
  483. value = undefined
  484. assertValidateParam(param, value, ["Required field is not provided"])
  485. // valid file
  486. param = {
  487. required: true,
  488. type: "file"
  489. }
  490. value = new win.File()
  491. assertValidateParam(param, value, [])
  492. })
  493. it("validates optional files", function() {
  494. // invalid file
  495. param = {
  496. required: false,
  497. type: "file"
  498. }
  499. value = "not a file"
  500. assertValidateParam(param, value, ["Value must be a file"])
  501. // valid (empty) file
  502. param = {
  503. required: false,
  504. type: "file"
  505. }
  506. value = undefined
  507. assertValidateParam(param, value, [])
  508. // valid file
  509. param = {
  510. required: false,
  511. type: "file"
  512. }
  513. value = new win.File()
  514. assertValidateParam(param, value, [])
  515. })
  516. it("validates required arrays", function() {
  517. // invalid (empty) array
  518. param = {
  519. required: true,
  520. type: "array"
  521. }
  522. value = []
  523. assertValidateParam(param, value, ["Required field is not provided"])
  524. // invalid (not an array)
  525. param = {
  526. required: true,
  527. type: "array"
  528. }
  529. value = undefined
  530. assertValidateParam(param, value, ["Required field is not provided"])
  531. // invalid array, items do not match correct type
  532. param = {
  533. required: true,
  534. type: "array",
  535. items: {
  536. type: "string"
  537. }
  538. }
  539. value = [1]
  540. assertValidateParam(param, value, [{index: 0, error: "Value must be a string"}])
  541. // valid array, with no 'type' for items
  542. param = {
  543. required: true,
  544. type: "array"
  545. }
  546. value = [1]
  547. assertValidateParam(param, value, [])
  548. // valid array, items match type
  549. param = {
  550. required: true,
  551. type: "array",
  552. items: {
  553. type: "string"
  554. }
  555. }
  556. value = ["1"]
  557. assertValidateParam(param, value, [])
  558. })
  559. it("validates optional arrays", function() {
  560. // valid, empty array
  561. param = {
  562. required: false,
  563. type: "array"
  564. }
  565. value = []
  566. assertValidateParam(param, value, [])
  567. // invalid, items do not match correct type
  568. param = {
  569. required: false,
  570. type: "array",
  571. items: {
  572. type: "number"
  573. }
  574. }
  575. value = ["number"]
  576. assertValidateParam(param, value, [{index: 0, error: "Value must be a number"}])
  577. // valid
  578. param = {
  579. required: false,
  580. type: "array",
  581. items: {
  582. type: "string"
  583. }
  584. }
  585. value = ["test"]
  586. assertValidateParam(param, value, [])
  587. })
  588. it("validates required booleans", function() {
  589. // invalid boolean value
  590. param = {
  591. required: true,
  592. type: "boolean"
  593. }
  594. value = undefined
  595. assertValidateParam(param, value, ["Required field is not provided"])
  596. // invalid boolean value (not a boolean)
  597. param = {
  598. required: true,
  599. type: "boolean"
  600. }
  601. value = "test string"
  602. assertValidateParam(param, value, ["Value must be a boolean"])
  603. // valid boolean value
  604. param = {
  605. required: true,
  606. type: "boolean"
  607. }
  608. value = "true"
  609. assertValidateParam(param, value, [])
  610. // valid boolean value
  611. param = {
  612. required: true,
  613. type: "boolean"
  614. }
  615. value = false
  616. assertValidateParam(param, value, [])
  617. })
  618. it("validates optional booleans", function() {
  619. // valid (empty) boolean value
  620. param = {
  621. required: false,
  622. type: "boolean"
  623. }
  624. value = undefined
  625. assertValidateParam(param, value, [])
  626. // invalid boolean value (not a boolean)
  627. param = {
  628. required: false,
  629. type: "boolean"
  630. }
  631. value = "test string"
  632. assertValidateParam(param, value, ["Value must be a boolean"])
  633. // valid boolean value
  634. param = {
  635. required: false,
  636. type: "boolean"
  637. }
  638. value = "true"
  639. assertValidateParam(param, value, [])
  640. // valid boolean value
  641. param = {
  642. required: false,
  643. type: "boolean"
  644. }
  645. value = false
  646. assertValidateParam(param, value, [])
  647. })
  648. it("validates required numbers", function() {
  649. // invalid number, string instead of a number
  650. param = {
  651. required: true,
  652. type: "number"
  653. }
  654. value = "test"
  655. assertValidateParam(param, value, ["Value must be a number"])
  656. // invalid number, undefined value
  657. param = {
  658. required: true,
  659. type: "number"
  660. }
  661. value = undefined
  662. assertValidateParam(param, value, ["Required field is not provided"])
  663. // valid number with min and max
  664. param = {
  665. required: true,
  666. type: "number",
  667. minimum: 5,
  668. maximum: 99
  669. }
  670. value = 10
  671. assertValidateParam(param, value, [])
  672. // valid negative number with min and max
  673. param = {
  674. required: true,
  675. type: "number",
  676. minimum: -50,
  677. maximum: -5
  678. }
  679. value = -10
  680. assertValidateParam(param, value, [])
  681. // invalid number with maximum:0
  682. param = {
  683. required: true,
  684. type: "number",
  685. maximum: 0
  686. }
  687. value = 1
  688. assertValidateParam(param, value, ["Value must be less than Maximum"])
  689. // invalid number with minimum:0
  690. param = {
  691. required: true,
  692. type: "number",
  693. minimum: 0
  694. }
  695. value = -10
  696. assertValidateParam(param, value, ["Value must be greater than Minimum"])
  697. })
  698. it("validates optional numbers", function() {
  699. // invalid number, string instead of a number
  700. param = {
  701. required: false,
  702. type: "number"
  703. }
  704. value = "test"
  705. assertValidateParam(param, value, ["Value must be a number"])
  706. // valid (empty) number
  707. param = {
  708. required: false,
  709. type: "number"
  710. }
  711. value = undefined
  712. assertValidateParam(param, value, [])
  713. // valid number
  714. param = {
  715. required: false,
  716. type: "number"
  717. }
  718. value = 10
  719. assertValidateParam(param, value, [])
  720. })
  721. it("validates required integers", function() {
  722. // invalid integer, string instead of an integer
  723. param = {
  724. required: true,
  725. type: "integer"
  726. }
  727. value = "test"
  728. assertValidateParam(param, value, ["Value must be an integer"])
  729. // invalid integer, undefined value
  730. param = {
  731. required: true,
  732. type: "integer"
  733. }
  734. value = undefined
  735. assertValidateParam(param, value, ["Required field is not provided"])
  736. // valid integer, but 0 is falsy in JS
  737. param = {
  738. required: true,
  739. type: "integer"
  740. }
  741. value = 0
  742. assertValidateParam(param, value, [])
  743. // valid integer
  744. param = {
  745. required: true,
  746. type: "integer"
  747. }
  748. value = 10
  749. assertValidateParam(param, value, [])
  750. })
  751. it("validates optional integers", function() {
  752. // invalid integer, string instead of an integer
  753. param = {
  754. required: false,
  755. type: "integer"
  756. }
  757. value = "test"
  758. assertValidateParam(param, value, ["Value must be an integer"])
  759. // valid (empty) integer
  760. param = {
  761. required: false,
  762. type: "integer"
  763. }
  764. value = undefined
  765. assertValidateParam(param, value, [])
  766. // integers
  767. param = {
  768. required: false,
  769. type: "integer"
  770. }
  771. value = 10
  772. assertValidateParam(param, value, [])
  773. })
  774. })
  775. describe("fromJSOrdered", () => {
  776. it("should create an OrderedMap from an object", () => {
  777. const param = {
  778. value: "test"
  779. }
  780. const result = fromJSOrdered(param).toJS()
  781. expect( result ).toEqual( { value: "test" } )
  782. })
  783. it("should not use an object's length property for Map size", () => {
  784. const param = {
  785. length: 5
  786. }
  787. const result = fromJSOrdered(param).toJS()
  788. expect( result ).toEqual( { length: 5 } )
  789. })
  790. it("should create an OrderedMap from an array", () => {
  791. const param = [1, 1, 2, 3, 5, 8]
  792. const result = fromJSOrdered(param).toJS()
  793. expect( result ).toEqual( [1, 1, 2, 3, 5, 8] )
  794. })
  795. })
  796. describe("getAcceptControllingResponse", () => {
  797. it("should return the first 2xx response with a media type", () => {
  798. const responses = fromJSOrdered({
  799. "200": {
  800. content: {
  801. "application/json": {
  802. schema: {
  803. type: "object"
  804. }
  805. }
  806. }
  807. },
  808. "201": {
  809. content: {
  810. "application/json": {
  811. schema: {
  812. type: "object"
  813. }
  814. }
  815. }
  816. }
  817. })
  818. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("200"))
  819. })
  820. it("should skip 2xx responses without defined media types", () => {
  821. const responses = fromJSOrdered({
  822. "200": {
  823. content: {
  824. "application/json": {
  825. schema: {
  826. type: "object"
  827. }
  828. }
  829. }
  830. },
  831. "201": {
  832. content: {
  833. "application/json": {
  834. schema: {
  835. type: "object"
  836. }
  837. }
  838. }
  839. }
  840. })
  841. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("201"))
  842. })
  843. it("should default to the `default` response if it has defined media types", () => {
  844. const responses = fromJSOrdered({
  845. "200": {
  846. description: "quite empty"
  847. },
  848. "201": {
  849. description: "quite empty"
  850. },
  851. default: {
  852. content: {
  853. "application/json": {
  854. schema: {
  855. type: "object"
  856. }
  857. }
  858. }
  859. }
  860. })
  861. expect(getAcceptControllingResponse(responses)).toEqual(responses.get("default"))
  862. })
  863. it("should return null if there are no suitable controlling responses", () => {
  864. const responses = fromJSOrdered({
  865. "200": {
  866. description: "quite empty"
  867. },
  868. "201": {
  869. description: "quite empty"
  870. },
  871. "default": {
  872. description: "also empty.."
  873. }
  874. })
  875. expect(getAcceptControllingResponse(responses)).toBe(null)
  876. })
  877. it("should return null if an empty OrderedMap is passed", () => {
  878. const responses = fromJSOrdered()
  879. expect(getAcceptControllingResponse(responses)).toBe(null)
  880. })
  881. it("should return null if anything except an OrderedMap is passed", () => {
  882. const responses = {}
  883. expect(getAcceptControllingResponse(responses)).toBe(null)
  884. })
  885. })
  886. describe("createDeepLinkPath", function() {
  887. it("creates a deep link path replacing spaces with underscores", function() {
  888. const result = createDeepLinkPath("tag id with spaces")
  889. expect(result).toEqual("tag%20id%20with%20spaces")
  890. })
  891. it("trims input when creating a deep link path", function() {
  892. let result = createDeepLinkPath(" spaces before and after ")
  893. expect(result).toEqual("spaces%20before%20and%20after")
  894. result = createDeepLinkPath(" ")
  895. expect(result).toEqual("")
  896. })
  897. it("creates a deep link path with special characters", function() {
  898. const result = createDeepLinkPath("!@#$%^&*(){}[]")
  899. expect(result).toEqual("!@#$%^&*(){}[]")
  900. })
  901. it("returns an empty string for invalid input", function() {
  902. expect( createDeepLinkPath(null) ).toEqual("")
  903. expect( createDeepLinkPath(undefined) ).toEqual("")
  904. expect( createDeepLinkPath(1) ).toEqual("")
  905. expect( createDeepLinkPath([]) ).toEqual("")
  906. expect( createDeepLinkPath({}) ).toEqual("")
  907. })
  908. })
  909. describe("escapeDeepLinkPath", function() {
  910. it("creates and escapes a deep link path", function() {
  911. const result = escapeDeepLinkPath("tag id with spaces?")
  912. expect(result).toEqual("tag_id_with_spaces\\?")
  913. })
  914. it("escapes a deep link path that starts with a number", function() {
  915. const result = escapeDeepLinkPath("123")
  916. expect(result).toEqual("\\31 23")
  917. })
  918. it("escapes a deep link path with a class selector", function() {
  919. const result = escapeDeepLinkPath("hello.world")
  920. expect(result).toEqual("hello\\.world")
  921. })
  922. it("escapes a deep link path with an id selector", function() {
  923. const result = escapeDeepLinkPath("hello#world")
  924. expect(result).toEqual("hello\\#world")
  925. })
  926. it("escapes a deep link path with a space", function() {
  927. const result = escapeDeepLinkPath("hello world")
  928. expect(result).toEqual("hello_world")
  929. })
  930. it("escapes a deep link path with a percent-encoded space", function() {
  931. const result = escapeDeepLinkPath("hello%20world")
  932. expect(result).toEqual("hello_world")
  933. })
  934. })
  935. describe("getExtensions", function() {
  936. const objTest = Map([[ "x-test", "a"], ["minimum", "b"]])
  937. it("does not error on empty array", function() {
  938. const result1 = getExtensions([])
  939. expect(result1).toEqual([])
  940. const result2 = getCommonExtensions([])
  941. expect(result2).toEqual([])
  942. })
  943. it("gets only the x- keys", function() {
  944. const result = getExtensions(objTest)
  945. expect(result).toEqual(Map([[ "x-test", "a"]]))
  946. })
  947. it("gets the common keys", function() {
  948. const result = getCommonExtensions(objTest, true)
  949. expect(result).toEqual(Map([[ "minimum", "b"]]))
  950. })
  951. })
  952. describe("deeplyStripKey", function() {
  953. it("should filter out a specified key", function() {
  954. const input = {
  955. $$ref: "#/this/is/my/ref",
  956. a: {
  957. $$ref: "#/this/is/my/other/ref",
  958. value: 12345
  959. }
  960. }
  961. const result = deeplyStripKey(input, "$$ref")
  962. expect(result).toEqual({
  963. a: {
  964. value: 12345
  965. }
  966. })
  967. })
  968. it("should filter out a specified key by predicate", function() {
  969. const input = {
  970. $$ref: "#/this/is/my/ref",
  971. a: {
  972. $$ref: "#/keep/this/one",
  973. value: 12345
  974. }
  975. }
  976. const result = deeplyStripKey(input, "$$ref", (v) => v !== "#/keep/this/one")
  977. expect(result).toEqual({
  978. a: {
  979. value: 12345,
  980. $$ref: "#/keep/this/one"
  981. }
  982. })
  983. })
  984. it("should only call the predicate when the key matches", function() {
  985. const input = {
  986. $$ref: "#/this/is/my/ref",
  987. a: {
  988. $$ref: "#/this/is/my/other/ref",
  989. value: 12345
  990. }
  991. }
  992. let count = 0
  993. const result = deeplyStripKey(input, "$$ref", () => {
  994. count++
  995. return true
  996. })
  997. expect(count).toEqual(2)
  998. })
  999. })
  1000. describe("parse and serialize search", function() {
  1001. afterEach(function() {
  1002. win.location.search = ""
  1003. })
  1004. describe("parsing", function() {
  1005. it("works with empty search", function() {
  1006. win.location.search = ""
  1007. expect(parseSearch()).toEqual({})
  1008. })
  1009. it("works with only one key", function() {
  1010. win.location.search = "?foo"
  1011. expect(parseSearch()).toEqual({foo: ""})
  1012. })
  1013. it("works with keys and values", function() {
  1014. win.location.search = "?foo=fooval&bar&baz=bazval"
  1015. expect(parseSearch()).toEqual({foo: "fooval", bar: "", baz: "bazval"})
  1016. })
  1017. it("decode url encoded components", function() {
  1018. win.location.search = "?foo=foo%20bar"
  1019. expect(parseSearch()).toEqual({foo: "foo bar"})
  1020. })
  1021. })
  1022. describe("serializing", function() {
  1023. it("works with empty map", function() {
  1024. expect(serializeSearch({})).toEqual("")
  1025. })
  1026. it("works with multiple keys with and without values", function() {
  1027. expect(serializeSearch({foo: "", bar: "barval"})).toEqual("foo=&bar=barval")
  1028. })
  1029. it("encode url components", function() {
  1030. expect(serializeSearch({foo: "foo bar"})).toEqual("foo=foo%20bar")
  1031. })
  1032. })
  1033. })
  1034. describe("sanitizeUrl", function() {
  1035. it("should sanitize a `javascript:` url", function() {
  1036. const res = sanitizeUrl("javascript:alert('bam!')")
  1037. expect(res).toEqual("about:blank")
  1038. })
  1039. it("should sanitize a `data:` url", function() {
  1040. const res = sanitizeUrl(`data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=`)
  1041. expect(res).toEqual("about:blank")
  1042. })
  1043. it("should not modify a `http:` url", function() {
  1044. const res = sanitizeUrl(`http://swagger.io/`)
  1045. expect(res).toEqual("http://swagger.io/")
  1046. })
  1047. it("should not modify a `https:` url", function() {
  1048. const res = sanitizeUrl(`https://swagger.io/`)
  1049. expect(res).toEqual("https://swagger.io/")
  1050. })
  1051. it("should gracefully handle empty strings", function() {
  1052. expect(sanitizeUrl("")).toEqual("")
  1053. })
  1054. it("should gracefully handle non-string values", function() {
  1055. expect(sanitizeUrl(123)).toEqual("")
  1056. expect(sanitizeUrl(null)).toEqual("")
  1057. expect(sanitizeUrl(undefined)).toEqual("")
  1058. expect(sanitizeUrl([])).toEqual("")
  1059. expect(sanitizeUrl({})).toEqual("")
  1060. })
  1061. })
  1062. describe("getSampleSchema", function() {
  1063. const oriDate = Date
  1064. before(function() {
  1065. Date = function () {
  1066. this.toISOString = function () {
  1067. return "2018-07-07T07:07:05.189Z"
  1068. }
  1069. }
  1070. })
  1071. after(function() {
  1072. Date = oriDate
  1073. })
  1074. it("should not unnecessarily stringify non-object values", function() {
  1075. // Given
  1076. const res = getSampleSchema({
  1077. type: "string",
  1078. format: "date-time"
  1079. })
  1080. // Then
  1081. expect(res).toEqual(new Date().toISOString())
  1082. })
  1083. })
  1084. describe("paramToIdentifier", function() {
  1085. it("should convert an Immutable parameter map to an identifier", () => {
  1086. const param = fromJS({
  1087. name: "id",
  1088. in: "query"
  1089. })
  1090. const res = paramToIdentifier(param)
  1091. expect(res).toEqual("query.id.hash-606199662")
  1092. })
  1093. it("should convert an Immutable parameter map to a set of identifiers", () => {
  1094. const param = fromJS({
  1095. name: "id",
  1096. in: "query"
  1097. })
  1098. const res = paramToIdentifier(param, { returnAll: true })
  1099. expect(res).toEqual([
  1100. "query.id.hash-606199662",
  1101. "query.id",
  1102. "id"
  1103. ])
  1104. })
  1105. it("should convert an unhashable Immutable parameter map to an identifier", () => {
  1106. const param = fromJS({
  1107. name: "id",
  1108. in: "query"
  1109. })
  1110. param.hashCode = null
  1111. const res = paramToIdentifier(param)
  1112. expect(res).toEqual("query.id")
  1113. })
  1114. it("should convert an unhashable Immutable parameter map to a set of identifiers", () => {
  1115. const param = fromJS({
  1116. name: "id",
  1117. in: "query"
  1118. })
  1119. param.hashCode = null
  1120. const res = paramToIdentifier(param, { returnAll: true })
  1121. expect(res).toEqual([
  1122. "query.id",
  1123. "id"
  1124. ])
  1125. })
  1126. it("should convert an Immutable parameter map lacking an `in` value to an identifier", () => {
  1127. const param = fromJS({
  1128. name: "id"
  1129. })
  1130. const res = paramToIdentifier(param)
  1131. expect(res).toEqual("id")
  1132. })
  1133. it("should convert an Immutable parameter map lacking an `in` value to an identifier", () => {
  1134. const param = fromJS({
  1135. name: "id"
  1136. })
  1137. const res = paramToIdentifier(param, { returnAll: true })
  1138. expect(res).toEqual(["id"])
  1139. })
  1140. it("should throw gracefully when given a non-Immutable parameter input", () => {
  1141. const param = {
  1142. name: "id"
  1143. }
  1144. let error = null
  1145. let res = null
  1146. try {
  1147. const res = paramToIdentifier(param)
  1148. } catch(e) {
  1149. error = e
  1150. }
  1151. expect(error).toBeA(Error)
  1152. expect(error.message).toInclude("received a non-Im.Map parameter as input")
  1153. expect(res).toEqual(null)
  1154. })
  1155. })
  1156. describe("paramToValue", function() {
  1157. it("should identify a hash-keyed value", () => {
  1158. const param = fromJS({
  1159. name: "id",
  1160. in: "query"
  1161. })
  1162. const paramValues = {
  1163. "query.id.hash-606199662": "asdf"
  1164. }
  1165. const res = paramToValue(param, paramValues)
  1166. expect(res).toEqual("asdf")
  1167. })
  1168. it("should identify a in+name value", () => {
  1169. const param = fromJS({
  1170. name: "id",
  1171. in: "query"
  1172. })
  1173. const paramValues = {
  1174. "query.id": "asdf"
  1175. }
  1176. const res = paramToValue(param, paramValues)
  1177. expect(res).toEqual("asdf")
  1178. })
  1179. it("should identify a name value", () => {
  1180. const param = fromJS({
  1181. name: "id",
  1182. in: "query"
  1183. })
  1184. const paramValues = {
  1185. "id": "asdf"
  1186. }
  1187. const res = paramToValue(param, paramValues)
  1188. expect(res).toEqual("asdf")
  1189. })
  1190. })
  1191. })