/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_modal_spec.js

https://gitlab.com/michold/git-lab-playground · JavaScript · 285 lines · 252 code · 33 blank · 0 comment · 0 complexity · c180a723c6da2979882f1b6d211ac06c MD5 · raw file

  1. import { GlModal, GlAlert } from '@gitlab/ui';
  2. import { shallowMount } from '@vue/test-utils';
  3. import { cloneDeep } from 'lodash';
  4. import { nextTick } from 'vue';
  5. import AddEscalationPolicyForm from 'ee/escalation_policies/components/add_edit_escalation_policy_form.vue';
  6. import AddEscalationPolicyModal, {
  7. i18n,
  8. } from 'ee/escalation_policies/components/add_edit_escalation_policy_modal.vue';
  9. import {
  10. addEscalationPolicyModalId,
  11. editEscalationPolicyModalId,
  12. EMAIL_ONCALL_SCHEDULE_USER,
  13. } from 'ee/escalation_policies/constants';
  14. import createEscalationPolicyMutation from 'ee/escalation_policies/graphql/mutations/create_escalation_policy.mutation.graphql';
  15. import updateEscalationPolicyMutation from 'ee/escalation_policies/graphql/mutations/update_escalation_policy.mutation.graphql';
  16. import waitForPromises from 'helpers/wait_for_promises';
  17. import mockPolicies from './mocks/mockPolicies.json';
  18. describe('AddEditsEscalationPolicyModal', () => {
  19. let wrapper;
  20. const projectPath = 'group/project';
  21. const mockHideModal = jest.fn();
  22. const mutate = jest.fn();
  23. const mockEscalationPolicy = cloneDeep(mockPolicies[0]);
  24. const updatedName = 'Policy name';
  25. const updatedDescription = 'Policy description';
  26. const updatedRules = [{ status: 'RESOLVED', elapsedTimeMinutes: 1, oncallScheduleIid: 1 }];
  27. const serializedRules = [{ status: 'RESOLVED', elapsedTimeSeconds: 60, oncallScheduleIid: 1 }];
  28. const createComponent = ({ escalationPolicy, isEditMode = false, modalId, data } = {}) => {
  29. wrapper = shallowMount(AddEscalationPolicyModal, {
  30. data() {
  31. return {
  32. ...data,
  33. };
  34. },
  35. propsData: {
  36. escalationPolicy,
  37. isEditMode,
  38. modalId,
  39. },
  40. provide: {
  41. projectPath,
  42. },
  43. mocks: {
  44. $apollo: {
  45. mutate,
  46. },
  47. },
  48. });
  49. wrapper.vm.$refs.addUpdateEscalationPolicyModal.hide = mockHideModal;
  50. };
  51. afterEach(() => {
  52. wrapper.destroy();
  53. });
  54. const findModal = () => wrapper.findComponent(GlModal);
  55. const findEscalationPolicyForm = () => wrapper.findComponent(AddEscalationPolicyForm);
  56. const findAlert = () => wrapper.findComponent(GlAlert);
  57. const updateForm = () => {
  58. const emitUpdate = (args) =>
  59. findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', args);
  60. emitUpdate({
  61. field: 'name',
  62. value: updatedName,
  63. });
  64. emitUpdate({
  65. field: 'description',
  66. value: updatedDescription,
  67. });
  68. emitUpdate({
  69. field: 'rules',
  70. value: updatedRules,
  71. });
  72. };
  73. describe('Create escalation policy', () => {
  74. beforeEach(() => {
  75. createComponent({ modalId: addEscalationPolicyModalId });
  76. });
  77. it('renders create modal with correct information', () => {
  78. const modal = findModal();
  79. expect(modal.props('title')).toBe(i18n.addEscalationPolicy);
  80. expect(modal.props('modalId')).toBe(addEscalationPolicyModalId);
  81. });
  82. it('makes a request with form data to create an escalation policy', () => {
  83. mutate.mockResolvedValueOnce({});
  84. updateForm();
  85. findModal().vm.$emit('primary', { preventDefault: jest.fn() });
  86. expect(mutate).toHaveBeenCalledWith(
  87. expect.objectContaining({
  88. mutation: createEscalationPolicyMutation,
  89. variables: {
  90. input: {
  91. projectPath,
  92. name: updatedName,
  93. description: updatedDescription,
  94. rules: serializedRules,
  95. },
  96. },
  97. update: expect.any(Function),
  98. }),
  99. );
  100. });
  101. it('clears the form on modal cancel', async () => {
  102. updateForm();
  103. await nextTick();
  104. expect(findEscalationPolicyForm().props('form')).toMatchObject({
  105. name: updatedName,
  106. description: updatedDescription,
  107. rules: updatedRules,
  108. });
  109. findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
  110. await nextTick();
  111. expect(findEscalationPolicyForm().props('form')).toMatchObject({
  112. name: '',
  113. description: '',
  114. rules: [],
  115. });
  116. });
  117. it('clears the validation state on modal cancel', async () => {
  118. const form = findEscalationPolicyForm();
  119. const getNameValidationState = () => form.props('validationState').name;
  120. expect(getNameValidationState()).toBe(null);
  121. form.vm.$emit('update-escalation-policy-form', {
  122. field: 'name',
  123. value: '',
  124. });
  125. await nextTick();
  126. expect(getNameValidationState()).toBe(false);
  127. findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
  128. await nextTick();
  129. expect(getNameValidationState()).toBe(null);
  130. });
  131. });
  132. describe('Update escalation policy', () => {
  133. beforeEach(() => {
  134. createComponent({
  135. modalId: editEscalationPolicyModalId,
  136. escalationPolicy: mockEscalationPolicy,
  137. isEditMode: true,
  138. });
  139. });
  140. it('renders update modal with correct information', () => {
  141. const modal = findModal();
  142. expect(modal.props('title')).toBe(i18n.editEscalationPolicy);
  143. expect(modal.props('modalId')).toBe(editEscalationPolicyModalId);
  144. });
  145. it('makes a request with form data to update an escalation policy', () => {
  146. mutate.mockResolvedValueOnce({});
  147. updateForm();
  148. findModal().vm.$emit('primary', { preventDefault: jest.fn() });
  149. expect(mutate).toHaveBeenCalledWith(
  150. expect.objectContaining({
  151. mutation: updateEscalationPolicyMutation,
  152. variables: {
  153. input: {
  154. name: updatedName,
  155. description: updatedDescription,
  156. rules: serializedRules,
  157. id: mockEscalationPolicy.id,
  158. },
  159. },
  160. update: expect.any(Function),
  161. }),
  162. );
  163. });
  164. it('clears the form on modal cancel', async () => {
  165. updateForm();
  166. await nextTick();
  167. const getForm = () => findEscalationPolicyForm().props('form');
  168. expect(getForm()).toMatchObject({
  169. name: updatedName,
  170. description: updatedDescription,
  171. rules: updatedRules,
  172. });
  173. findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
  174. const { name, description, rules } = mockEscalationPolicy;
  175. await nextTick();
  176. expect(getForm()).toMatchObject({
  177. name,
  178. description,
  179. rules,
  180. });
  181. });
  182. it('clears the validation state on modal cancel', async () => {
  183. const form = findEscalationPolicyForm();
  184. const getNameValidationState = () => form.props('validationState').name;
  185. expect(getNameValidationState()).toBe(null);
  186. expect(wrapper.vm.validationState.name).toBe(null);
  187. form.vm.$emit('update-escalation-policy-form', {
  188. field: 'name',
  189. value: '',
  190. });
  191. await nextTick();
  192. expect(getNameValidationState()).toBe(false);
  193. findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
  194. await nextTick();
  195. expect(getNameValidationState()).toBe(null);
  196. });
  197. });
  198. describe('Create/update success/failure', () => {
  199. beforeEach(() => {
  200. createComponent({ modalId: addEscalationPolicyModalId });
  201. });
  202. it('hides the modal on successful policy creation', async () => {
  203. mutate.mockResolvedValueOnce({ data: { escalationPolicyCreate: { errors: [] } } });
  204. findModal().vm.$emit('primary', { preventDefault: jest.fn() });
  205. await waitForPromises();
  206. expect(mockHideModal).toHaveBeenCalled();
  207. });
  208. it("doesn't hide a modal and shows error alert on creation failure", async () => {
  209. const error = 'some error';
  210. mutate.mockResolvedValueOnce({ data: { escalationPolicyCreate: { errors: [error] } } });
  211. findModal().vm.$emit('primary', { preventDefault: jest.fn() });
  212. await waitForPromises();
  213. const alert = findAlert();
  214. expect(mockHideModal).not.toHaveBeenCalled();
  215. expect(alert.exists()).toBe(true);
  216. expect(alert.text()).toContain(error);
  217. });
  218. });
  219. describe('Modal buttons', () => {
  220. beforeEach(() => {
  221. createComponent({ modalId: addEscalationPolicyModalId });
  222. });
  223. it('should disable primary button when form is invalid', async () => {
  224. findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', {
  225. field: 'name',
  226. value: '',
  227. });
  228. await nextTick();
  229. expect(findModal().props('actionPrimary').attributes).toContainEqual({ disabled: true });
  230. });
  231. it('should enable primary button when form is valid', async () => {
  232. const form = findEscalationPolicyForm();
  233. form.vm.$emit('update-escalation-policy-form', {
  234. field: 'name',
  235. value: 'Some policy name',
  236. });
  237. form.vm.$emit('update-escalation-policy-form', {
  238. field: 'rules',
  239. value: [
  240. {
  241. status: 'RESOLVED',
  242. elapsedTimeMinutes: 1,
  243. action: EMAIL_ONCALL_SCHEDULE_USER,
  244. oncallScheduleIid: 1,
  245. },
  246. ],
  247. });
  248. await nextTick();
  249. expect(findModal().props('actionPrimary').attributes).toContainEqual({ disabled: false });
  250. });
  251. });
  252. });