Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

889 linhas
24 KiB

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