PageRenderTime 62ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js

https://gitlab.com/alexkeramidas/gitlab-ce
JavaScript | 448 lines | 366 code | 81 blank | 1 comment | 8 complexity | 4fd998b9213a11f3156483950760fadd MD5 | raw file
  1. import Vue from 'vue';
  2. import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
  3. import eventHub from '~/vue_merge_request_widget/event_hub';
  4. import notify from '~/lib/utils/notify';
  5. import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
  6. import mountComponent from 'spec/helpers/vue_mount_component_helper';
  7. import mockData from './mock_data';
  8. const returnPromise = data => new Promise((resolve) => {
  9. resolve({
  10. data,
  11. });
  12. });
  13. describe('mrWidgetOptions', () => {
  14. let vm;
  15. let MrWidgetOptions;
  16. beforeEach(() => {
  17. // Prevent component mounting
  18. delete mrWidgetOptions.el;
  19. MrWidgetOptions = Vue.extend(mrWidgetOptions);
  20. vm = mountComponent(MrWidgetOptions, {
  21. mrData: { ...mockData },
  22. });
  23. });
  24. describe('data', () => {
  25. it('should instantiate Store and Service', () => {
  26. expect(vm.mr).toBeDefined();
  27. expect(vm.service).toBeDefined();
  28. });
  29. });
  30. describe('computed', () => {
  31. describe('componentName', () => {
  32. it('should return merged component', () => {
  33. expect(vm.componentName).toEqual('mr-widget-merged');
  34. });
  35. it('should return conflicts component', () => {
  36. vm.mr.state = 'conflicts';
  37. expect(vm.componentName).toEqual('mr-widget-conflicts');
  38. });
  39. });
  40. describe('shouldRenderMergeHelp', () => {
  41. it('should return false for the initial merged state', () => {
  42. expect(vm.shouldRenderMergeHelp).toBeFalsy();
  43. });
  44. it('should return true for a state which requires help widget', () => {
  45. vm.mr.state = 'conflicts';
  46. expect(vm.shouldRenderMergeHelp).toBeTruthy();
  47. });
  48. });
  49. describe('shouldRenderPipelines', () => {
  50. it('should return true when hasCI is true', () => {
  51. vm.mr.hasCI = true;
  52. expect(vm.shouldRenderPipelines).toBeTruthy();
  53. });
  54. it('should return false when hasCI is false', () => {
  55. vm.mr.hasCI = false;
  56. expect(vm.shouldRenderPipelines).toBeFalsy();
  57. });
  58. });
  59. describe('shouldRenderRelatedLinks', () => {
  60. it('should return false for the initial data', () => {
  61. expect(vm.shouldRenderRelatedLinks).toBeFalsy();
  62. });
  63. it('should return true if there is relatedLinks in MR', () => {
  64. Vue.set(vm.mr, 'relatedLinks', {});
  65. expect(vm.shouldRenderRelatedLinks).toBeTruthy();
  66. });
  67. });
  68. describe('shouldRenderSourceBranchRemovalStatus', () => {
  69. beforeEach(() => {
  70. vm.mr.state = 'readyToMerge';
  71. });
  72. it('should return true when cannot remove source branch and branch will be removed', () => {
  73. vm.mr.canRemoveSourceBranch = false;
  74. vm.mr.shouldRemoveSourceBranch = true;
  75. expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(true);
  76. });
  77. it('should return false when can remove source branch and branch will be removed', () => {
  78. vm.mr.canRemoveSourceBranch = true;
  79. vm.mr.shouldRemoveSourceBranch = true;
  80. expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
  81. });
  82. it('should return false when cannot remove source branch and branch will not be removed', () => {
  83. vm.mr.canRemoveSourceBranch = false;
  84. vm.mr.shouldRemoveSourceBranch = false;
  85. expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
  86. });
  87. it('should return false when in merged state', () => {
  88. vm.mr.canRemoveSourceBranch = false;
  89. vm.mr.shouldRemoveSourceBranch = true;
  90. vm.mr.state = 'merged';
  91. expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
  92. });
  93. it('should return false when in nothing to merge state', () => {
  94. vm.mr.canRemoveSourceBranch = false;
  95. vm.mr.shouldRemoveSourceBranch = true;
  96. vm.mr.state = 'nothingToMerge';
  97. expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
  98. });
  99. });
  100. });
  101. describe('methods', () => {
  102. describe('checkStatus', () => {
  103. it('should tell service to check status', (done) => {
  104. spyOn(vm.service, 'checkStatus').and.returnValue(returnPromise(mockData));
  105. spyOn(vm.mr, 'setData');
  106. spyOn(vm, 'handleNotification');
  107. let isCbExecuted = false;
  108. const cb = () => {
  109. isCbExecuted = true;
  110. };
  111. vm.checkStatus(cb);
  112. setTimeout(() => {
  113. expect(vm.service.checkStatus).toHaveBeenCalled();
  114. expect(vm.mr.setData).toHaveBeenCalled();
  115. expect(vm.handleNotification).toHaveBeenCalledWith(mockData);
  116. expect(isCbExecuted).toBeTruthy();
  117. done();
  118. }, 333);
  119. });
  120. });
  121. describe('initPolling', () => {
  122. it('should call SmartInterval', () => {
  123. spyOn(vm, 'checkStatus').and.returnValue(Promise.resolve());
  124. jasmine.clock().install();
  125. vm.initPolling();
  126. expect(vm.checkStatus).not.toHaveBeenCalled();
  127. jasmine.clock().tick(10000);
  128. expect(vm.pollingInterval).toBeDefined();
  129. expect(vm.checkStatus).toHaveBeenCalled();
  130. jasmine.clock().uninstall();
  131. });
  132. });
  133. describe('initDeploymentsPolling', () => {
  134. it('should call SmartInterval', () => {
  135. spyOn(vm, 'fetchDeployments').and.returnValue(Promise.resolve());
  136. vm.initDeploymentsPolling();
  137. expect(vm.deploymentsInterval).toBeDefined();
  138. expect(vm.fetchDeployments).toHaveBeenCalled();
  139. });
  140. });
  141. describe('fetchDeployments', () => {
  142. it('should fetch deployments', (done) => {
  143. spyOn(vm.service, 'fetchDeployments').and.returnValue(returnPromise([{ id: 1 }]));
  144. vm.fetchDeployments();
  145. setTimeout(() => {
  146. expect(vm.service.fetchDeployments).toHaveBeenCalled();
  147. expect(vm.mr.deployments.length).toEqual(1);
  148. expect(vm.mr.deployments[0].id).toBe(1);
  149. done();
  150. });
  151. });
  152. });
  153. describe('fetchActionsContent', () => {
  154. it('should fetch content of Cherry Pick and Revert modals', (done) => {
  155. spyOn(vm.service, 'fetchMergeActionsContent').and.returnValue(returnPromise('hello world'));
  156. vm.fetchActionsContent();
  157. setTimeout(() => {
  158. expect(vm.service.fetchMergeActionsContent).toHaveBeenCalled();
  159. expect(document.body.textContent).toContain('hello world');
  160. done();
  161. }, 333);
  162. });
  163. });
  164. describe('bindEventHubListeners', () => {
  165. it('should bind eventHub listeners', () => {
  166. spyOn(vm, 'checkStatus').and.returnValue(() => {});
  167. spyOn(vm.service, 'checkStatus').and.returnValue(returnPromise(mockData));
  168. spyOn(vm, 'fetchActionsContent');
  169. spyOn(vm.mr, 'setData');
  170. spyOn(vm, 'resumePolling');
  171. spyOn(vm, 'stopPolling');
  172. spyOn(eventHub, '$on');
  173. vm.bindEventHubListeners();
  174. eventHub.$emit('SetBranchRemoveFlag', ['flag']);
  175. expect(vm.mr.isRemovingSourceBranch).toEqual('flag');
  176. eventHub.$emit('FailedToMerge');
  177. expect(vm.mr.state).toEqual('failedToMerge');
  178. eventHub.$emit('UpdateWidgetData', mockData);
  179. expect(vm.mr.setData).toHaveBeenCalledWith(mockData);
  180. eventHub.$emit('EnablePolling');
  181. expect(vm.resumePolling).toHaveBeenCalled();
  182. eventHub.$emit('DisablePolling');
  183. expect(vm.stopPolling).toHaveBeenCalled();
  184. const listenersWithServiceRequest = {
  185. MRWidgetUpdateRequested: true,
  186. FetchActionsContent: true,
  187. };
  188. const allArgs = eventHub.$on.calls.allArgs();
  189. allArgs.forEach((params) => {
  190. const eventName = params[0];
  191. const callback = params[1];
  192. if (listenersWithServiceRequest[eventName]) {
  193. listenersWithServiceRequest[eventName] = callback;
  194. }
  195. });
  196. listenersWithServiceRequest.MRWidgetUpdateRequested();
  197. expect(vm.checkStatus).toHaveBeenCalled();
  198. listenersWithServiceRequest.FetchActionsContent();
  199. expect(vm.fetchActionsContent).toHaveBeenCalled();
  200. });
  201. });
  202. describe('handleMounted', () => {
  203. it('should call required methods to do the initial kick-off', () => {
  204. spyOn(vm, 'initDeploymentsPolling');
  205. spyOn(vm, 'setFaviconHelper');
  206. vm.handleMounted();
  207. expect(vm.setFaviconHelper).toHaveBeenCalled();
  208. expect(vm.initDeploymentsPolling).toHaveBeenCalled();
  209. });
  210. });
  211. describe('setFavicon', () => {
  212. let faviconElement;
  213. beforeEach(() => {
  214. const favicon = document.createElement('link');
  215. favicon.setAttribute('id', 'favicon');
  216. document.body.appendChild(favicon);
  217. faviconElement = document.getElementById('favicon');
  218. });
  219. afterEach(() => {
  220. document.body.removeChild(document.getElementById('favicon'));
  221. });
  222. it('should call setFavicon method', () => {
  223. vm.setFaviconHelper();
  224. expect(faviconElement.getAttribute('href')).toEqual(vm.mr.ciStatusFaviconPath);
  225. });
  226. it('should not call setFavicon when there is no ciStatusFaviconPath', () => {
  227. vm.mr.ciStatusFaviconPath = null;
  228. vm.setFaviconHelper();
  229. expect(faviconElement.getAttribute('href')).toEqual(null);
  230. });
  231. });
  232. describe('handleNotification', () => {
  233. const data = {
  234. ci_status: 'running',
  235. title: 'title',
  236. pipeline: { details: { status: { label: 'running-label' } } },
  237. };
  238. beforeEach(() => {
  239. spyOn(notify, 'notifyMe');
  240. vm.mr.ciStatus = 'failed';
  241. vm.mr.gitlabLogo = 'logo.png';
  242. });
  243. it('should call notifyMe', () => {
  244. vm.handleNotification(data);
  245. expect(notify.notifyMe).toHaveBeenCalledWith(
  246. 'Pipeline running-label',
  247. 'Pipeline running-label for "title"',
  248. 'logo.png',
  249. );
  250. });
  251. it('should not call notifyMe if the status has not changed', () => {
  252. vm.mr.ciStatus = data.ci_status;
  253. vm.handleNotification(data);
  254. expect(notify.notifyMe).not.toHaveBeenCalled();
  255. });
  256. it('should not notify if no pipeline provided', () => {
  257. vm.handleNotification({
  258. ...data,
  259. pipeline: undefined,
  260. });
  261. expect(notify.notifyMe).not.toHaveBeenCalled();
  262. });
  263. });
  264. describe('resumePolling', () => {
  265. it('should call stopTimer on pollingInterval', () => {
  266. spyOn(vm.pollingInterval, 'resume');
  267. vm.resumePolling();
  268. expect(vm.pollingInterval.resume).toHaveBeenCalled();
  269. });
  270. });
  271. describe('stopPolling', () => {
  272. it('should call stopTimer on pollingInterval', () => {
  273. spyOn(vm.pollingInterval, 'stopTimer');
  274. vm.stopPolling();
  275. expect(vm.pollingInterval.stopTimer).toHaveBeenCalled();
  276. });
  277. });
  278. });
  279. describe('rendering relatedLinks', () => {
  280. beforeEach((done) => {
  281. vm.mr.relatedLinks = {
  282. assignToMe: null,
  283. closing: `
  284. <a class="close-related-link" href="#'>
  285. Close
  286. </a>
  287. `,
  288. mentioned: '',
  289. };
  290. Vue.nextTick(done);
  291. });
  292. it('renders if there are relatedLinks', () => {
  293. expect(vm.$el.querySelector('.close-related-link')).toBeDefined();
  294. });
  295. it('does not render if state is nothingToMerge', (done) => {
  296. vm.mr.state = stateKey.nothingToMerge;
  297. Vue.nextTick(() => {
  298. expect(vm.$el.querySelector('.close-related-link')).toBeNull();
  299. done();
  300. });
  301. });
  302. });
  303. describe('rendering source branch removal status', () => {
  304. it('renders when user cannot remove branch and branch should be removed', (done) => {
  305. vm.mr.canRemoveSourceBranch = false;
  306. vm.mr.shouldRemoveSourceBranch = true;
  307. vm.mr.state = 'readyToMerge';
  308. vm.$nextTick(() => {
  309. const tooltip = vm.$el.querySelector('.fa-question-circle');
  310. expect(vm.$el.textContent).toContain('Removes source branch');
  311. expect(tooltip.getAttribute('data-original-title')).toBe(
  312. 'A user with write access to the source branch selected this option',
  313. );
  314. done();
  315. });
  316. });
  317. it('does not render in merged state', (done) => {
  318. vm.mr.canRemoveSourceBranch = false;
  319. vm.mr.shouldRemoveSourceBranch = true;
  320. vm.mr.state = 'merged';
  321. vm.$nextTick(() => {
  322. expect(vm.$el.textContent).toContain('The source branch has been removed');
  323. expect(vm.$el.textContent).not.toContain('Removes source branch');
  324. done();
  325. });
  326. });
  327. });
  328. describe('rendering deployments', () => {
  329. const deploymentMockData = {
  330. id: 15,
  331. name: 'review/diplo',
  332. url: '/root/acets-review-apps/environments/15',
  333. stop_url: '/root/acets-review-apps/environments/15/stop',
  334. metrics_url: '/root/acets-review-apps/environments/15/deployments/1/metrics',
  335. metrics_monitoring_url: '/root/acets-review-apps/environments/15/metrics',
  336. external_url: 'http://diplo.',
  337. external_url_formatted: 'diplo.',
  338. deployed_at: '2017-03-22T22:44:42.258Z',
  339. deployed_at_formatted: 'Mar 22, 2017 10:44pm',
  340. };
  341. beforeEach((done) => {
  342. vm.mr.deployments.push({
  343. ...deploymentMockData,
  344. }, {
  345. ...deploymentMockData,
  346. id: deploymentMockData.id + 1,
  347. });
  348. vm.$nextTick(done);
  349. });
  350. it('renders multiple deployments', () => {
  351. expect(vm.$el.querySelectorAll('.deploy-heading').length).toBe(2);
  352. });
  353. });
  354. });