utils.spec.jsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. import {
  2. deepFreeze,
  3. descopeFeatureName,
  4. escapeDoubleQuotes,
  5. explodeSlug,
  6. extractMultilineFields,
  7. parseRepo,
  8. sortProjects,
  9. valueIsEqual,
  10. } from 'sentry/utils';
  11. describe('utils.valueIsEqual', function () {
  12. it('should return true when objects are deeply equal', function () {
  13. const isEqual = valueIsEqual(
  14. {
  15. username: 'foo',
  16. teams: ['bar', 'baz'],
  17. avatar: {
  18. avatarType: 'gravatar',
  19. avatarUuid: null,
  20. },
  21. },
  22. {
  23. username: 'foo',
  24. teams: ['bar', 'baz'],
  25. avatar: {
  26. avatarType: 'gravatar',
  27. avatarUuid: null,
  28. },
  29. },
  30. true
  31. );
  32. expect(isEqual).toBe(true);
  33. });
  34. it('should return false when objects are not deeply equal', function () {
  35. const isEqual = valueIsEqual(
  36. {
  37. username: 'foo',
  38. teams: ['bar', 'baz'],
  39. avatar: {
  40. avatarType: 'gravatar',
  41. avatarUuid: null,
  42. },
  43. },
  44. {
  45. username: 'foo',
  46. teams: ['bar', 'baz'],
  47. avatar: {
  48. avatarType: 'notGravatar',
  49. avatarUuid: null,
  50. },
  51. },
  52. true
  53. );
  54. expect(isEqual).toBe(false);
  55. });
  56. it('should return true when objects are shallowly equal', function () {
  57. const isEqual = valueIsEqual(
  58. {
  59. username: 'foo',
  60. team: 'bar',
  61. avatar: 'gravatar',
  62. },
  63. {
  64. username: 'foo',
  65. team: 'bar',
  66. avatar: 'gravatar',
  67. },
  68. false
  69. );
  70. expect(isEqual).toBe(true);
  71. });
  72. it('should return false when objects are not shallowly equal', function () {
  73. const isEqual = valueIsEqual(
  74. {
  75. username: 'foo',
  76. team: 'bar',
  77. avatar: 'gravatar',
  78. },
  79. {
  80. username: 'foo',
  81. team: 'bar',
  82. avatar: 'notGravatar',
  83. },
  84. false
  85. );
  86. expect(isEqual).toBe(false);
  87. });
  88. it('should not blow up when comparing null value to an object', function () {
  89. let isEqual = valueIsEqual(null, {username: 'foo'}, true);
  90. expect(isEqual).toBe(false);
  91. isEqual = valueIsEqual(
  92. {
  93. username: 'foo',
  94. teams: ['bar', 'baz'],
  95. avatar: null,
  96. },
  97. {
  98. username: 'foo',
  99. teams: ['bar', 'baz'],
  100. avatar: {
  101. avatarType: 'notGravatar',
  102. avatarUuid: null,
  103. },
  104. },
  105. true
  106. );
  107. expect(isEqual).toBe(false);
  108. });
  109. });
  110. describe('utils.extractMultilineFields', function () {
  111. it('should work for basic, simple values', function () {
  112. expect(extractMultilineFields('one\ntwo\nthree')).toEqual(['one', 'two', 'three']);
  113. });
  114. it('should return an empty array if only whitespace', function () {
  115. expect(extractMultilineFields(' \n \n\n\n \n')).toEqual([]);
  116. });
  117. it('should trim values and ignore empty lines', function () {
  118. expect(
  119. extractMultilineFields(
  120. `one
  121. two
  122. three
  123. four
  124. five`
  125. )
  126. ).toEqual(['one', 'two', 'three', 'four', 'five']);
  127. });
  128. });
  129. describe('utils.parseRepo', function () {
  130. it('should work for simple github url', function () {
  131. expect(parseRepo('github.com/example/example')).toEqual('example/example');
  132. });
  133. it('should work for full github url', function () {
  134. expect(parseRepo('https://github.com/example/example')).toEqual('example/example');
  135. });
  136. it('should work for trailing slash', function () {
  137. expect(parseRepo('https://github.com/example/example/')).toEqual('example/example');
  138. });
  139. it('should work for simple BitBucket url', function () {
  140. expect(parseRepo('bitbucket.org/example/example')).toEqual('example/example');
  141. });
  142. it('should work for full BitBucket url', function () {
  143. expect(parseRepo('https://bitbucket.org/example/example')).toEqual('example/example');
  144. });
  145. it('should work for trailing Bitbucket slash', function () {
  146. expect(parseRepo('https://bitbucket.org/example/example/')).toEqual(
  147. 'example/example'
  148. );
  149. });
  150. it('should work for repo only', function () {
  151. expect(parseRepo('example/example')).toEqual('example/example');
  152. });
  153. it('should parse repo from url with extra info', function () {
  154. expect(parseRepo('github.com/example/example/commits/adsadsa')).toEqual(
  155. 'example/example'
  156. );
  157. });
  158. it('should work for nothing passed', function () {
  159. expect(parseRepo()).toEqual();
  160. });
  161. });
  162. describe('utils.explodeSlug', function () {
  163. it('replaces slug special chars with whitespace', function () {
  164. expect(explodeSlug('test--slug__replace-')).toEqual('test slug replace');
  165. });
  166. });
  167. describe('utils.projectDisplayCompare', function () {
  168. it('sorts by bookmark and project slug', function () {
  169. const projects = [
  170. {
  171. isBookmarked: true,
  172. slug: 'm',
  173. },
  174. {
  175. isBookmarked: false,
  176. slug: 'm',
  177. },
  178. {
  179. isBookmarked: false,
  180. slug: 'a',
  181. },
  182. {
  183. isBookmarked: true,
  184. slug: 'a',
  185. },
  186. {
  187. isBookmarked: true,
  188. slug: 'z',
  189. },
  190. {
  191. isBookmarked: false,
  192. slug: 'z',
  193. },
  194. ];
  195. const sortedProjects = sortProjects(projects);
  196. expect(sortedProjects).toEqual([
  197. {
  198. isBookmarked: true,
  199. slug: 'a',
  200. },
  201. {
  202. isBookmarked: true,
  203. slug: 'm',
  204. },
  205. {
  206. isBookmarked: true,
  207. slug: 'z',
  208. },
  209. {
  210. isBookmarked: false,
  211. slug: 'a',
  212. },
  213. {
  214. isBookmarked: false,
  215. slug: 'm',
  216. },
  217. {
  218. isBookmarked: false,
  219. slug: 'z',
  220. },
  221. ]);
  222. });
  223. });
  224. describe('utils.descopeFeatureName', function () {
  225. it('descopes the feature name', () => {
  226. [
  227. ['organizations:feature', 'feature'],
  228. ['projects:feature', 'feature'],
  229. ['unknown-scope:feature', 'unknown-scope:feature'],
  230. ['', ''],
  231. ].forEach(([input, expected]) => expect(descopeFeatureName(input)).toEqual(expected));
  232. });
  233. });
  234. describe('deepFreeze', function () {
  235. it('throws error on attempt to mutate frozen object', function () {
  236. const testObj = deepFreeze({foo: [1, 2, 3]});
  237. [
  238. () => {
  239. testObj.foo.push(4);
  240. },
  241. () => {
  242. testObj.bar = '';
  243. },
  244. () => {
  245. delete testObj.foo;
  246. },
  247. ].forEach(fn => {
  248. expect(fn).toThrow();
  249. });
  250. });
  251. });
  252. describe('utils.escapeDoubleQuotes', function () {
  253. // test cases from https://gist.github.com/getify/3667624
  254. it('should escape any unescaped double quotes', function () {
  255. const cases = [
  256. ['a"b', 'a\\"b'], //
  257. ['a\\"b', 'a\\"b'], //
  258. ['a\\\\"b', 'a\\\\\\"b'],
  259. ['a"b"c', 'a\\"b\\"c'],
  260. ['a""b', 'a\\"\\"b'],
  261. ['""', '\\"\\"'],
  262. ];
  263. for (const testCase of cases) {
  264. const [input, expected] = testCase;
  265. expect(escapeDoubleQuotes(input)).toBe(expected);
  266. }
  267. // should return the same input as the output
  268. const cases2 = ['ab', 'a\\"b', 'a\\\\\\"b'];
  269. for (const test of cases2) {
  270. expect(escapeDoubleQuotes(test)).toBe(test);
  271. }
  272. // don't unnecessarily escape
  273. const actual = escapeDoubleQuotes(escapeDoubleQuotes(escapeDoubleQuotes('a"b')));
  274. expect(actual).toBe('a\\"b');
  275. });
  276. });