diff --git a/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_form.vue b/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_form.vue
index 665606c3d5de5bb0d7efb16d5b1c323d2266255e..4c71f3d5753ab2722ba29c2d48c72c6fb531dba3 100644
--- a/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_form.vue
+++ b/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_form.vue
@@ -1,9 +1,9 @@
 <script>
 import { GlLink, GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui';
-import { cloneDeep } from 'lodash';
+import { cloneDeep, uniqueId } from 'lodash';
 import createFlash from '~/flash';
 import { s__, __ } from '~/locale';
-import { DEFAULT_ESCALATION_RULE } from '../constants';
+import { DEFAULT_ACTION, DEFAULT_ESCALATION_RULE } from '../constants';
 import getOncallSchedulesQuery from '../graphql/queries/get_oncall_schedules.query.graphql';
 import EscalationRule from './escalation_rule.vue';
 
@@ -48,7 +48,6 @@ export default {
     return {
       schedules: [],
       rules: [],
-      uid: 0,
     };
   },
   apollo: {
@@ -74,11 +73,29 @@ export default {
     },
   },
   mounted() {
-    this.addRule();
+    this.rules = this.form.rules.map((rule) => {
+      const {
+        status,
+        elapsedTimeSeconds,
+        oncallSchedule: { iid: oncallScheduleIid },
+      } = rule;
+
+      return {
+        status,
+        elapsedTimeSeconds,
+        action: DEFAULT_ACTION,
+        oncallScheduleIid,
+        key: uniqueId(),
+      };
+    });
+
+    if (!this.rules.length) {
+      this.addRule();
+    }
   },
   methods: {
     addRule() {
-      this.rules.push({ ...cloneDeep(DEFAULT_ESCALATION_RULE), key: this.getUid() });
+      this.rules.push({ ...cloneDeep(DEFAULT_ESCALATION_RULE), key: uniqueId() });
     },
     updateEscalationRules(index, rule) {
       this.rules[index] = { ...this.rules[index], ...rule };
@@ -91,10 +108,6 @@ export default {
     emitRulesUpdate() {
       this.$emit('update-escalation-policy-form', { field: 'rules', value: this.rules });
     },
-    getUid() {
-      this.uid += 1;
-      return this.uid;
-    },
   },
 };
 </script>
diff --git a/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_modal.vue b/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_modal.vue
index 485405250badd33c8ac32a10e4531234c73ab675..729e849cc3c8bf90c32c8c7a7cea0cd7390bb328 100644
--- a/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_modal.vue
+++ b/ee/app/assets/javascripts/escalation_policies/components/add_edit_escalation_policy_modal.vue
@@ -1,10 +1,13 @@
 <script>
 import { GlModal, GlAlert } from '@gitlab/ui';
-import { set } from 'lodash';
+import { set, isEqual } from 'lodash';
 import { s__, __ } from '~/locale';
-import { addEscalationPolicyModalId } from '../constants';
-import { updateStoreOnEscalationPolicyCreate } from '../graphql/cache_updates';
+import {
+  updateStoreOnEscalationPolicyCreate,
+  updateStoreOnEscalationPolicyUpdate,
+} from '../graphql/cache_updates';
 import createEscalationPolicyMutation from '../graphql/mutations/create_escalation_policy.mutation.graphql';
+import updateEscalationPolicyMutation from '../graphql/mutations/update_escalation_policy.mutation.graphql';
 import getEscalationPoliciesQuery from '../graphql/queries/get_escalation_policies.query.graphql';
 import { isNameFieldValid, getRulesValidationState } from '../utils';
 import AddEditEscalationPolicyForm from './add_edit_escalation_policy_form.vue';
@@ -17,7 +20,6 @@ export const i18n = {
 
 export default {
   i18n,
-  addEscalationPolicyModalId,
   components: {
     GlModal,
     GlAlert,
@@ -30,15 +32,21 @@ export default {
       required: false,
       default: () => ({}),
     },
+    isEditMode: {
+      type: Boolean,
+      required: false,
+      default: false,
+    },
+    modalId: {
+      type: String,
+      required: true,
+    },
   },
   data() {
     return {
       loading: false,
-      form: {
-        name: this.escalationPolicy.name,
-        description: this.escalationPolicy.description,
-        rules: [],
-      },
+      form: this.getInitialState(),
+      initialState: this.getInitialState(),
       validationState: {
         name: null,
         rules: [],
@@ -47,14 +55,17 @@ export default {
     };
   },
   computed: {
+    title() {
+      return this.isEditMode ? i18n.editEscalationPolicy : i18n.addEscalationPolicy;
+    },
     actionsProps() {
       return {
         primary: {
-          text: i18n.addEscalationPolicy,
+          text: this.title,
           attributes: [
             { variant: 'info' },
             { loading: this.loading },
-            { disabled: !this.isFormValid },
+            { disabled: !this.isFormValid || !this.isFormDirty },
           ],
         },
         cancel: {
@@ -65,13 +76,32 @@ export default {
     isFormValid() {
       return (
         this.validationState.name &&
+        (this.isEditMode ? true : this.validationState.rules.length) &&
         this.validationState.rules.every(
           ({ isTimeValid, isScheduleValid }) => isTimeValid && isScheduleValid,
         )
       );
     },
+    isFormDirty() {
+      return (
+        this.form.name !== this.initialState.name ||
+        this.form.description !== this.initialState.description ||
+        !isEqual(this.getRules(this.form.rules), this.getRules(this.initialState.rules))
+      );
+    },
+    requestParams() {
+      const id = this.isEditMode ? { id: this.escalationPolicy.id } : {};
+      return { ...this.form, ...id, rules: this.getRules(this.form.rules) };
+    },
   },
   methods: {
+    getInitialState() {
+      return {
+        name: this.escalationPolicy.name ?? '',
+        description: this.escalationPolicy.description ?? '',
+        rules: this.escalationPolicy.rules ?? [],
+      };
+    },
     updateForm({ field, value }) {
       set(this.form, field, value);
       this.validateForm(field);
@@ -85,7 +115,7 @@ export default {
           variables: {
             input: {
               projectPath,
-              ...this.getRequestParams(),
+              ...this.requestParams,
             },
           },
           update(store, { data }) {
@@ -117,14 +147,51 @@ export default {
           this.loading = false;
         });
     },
-    getRequestParams() {
-      const rules = this.form.rules.map(({ status, elapsedTimeSeconds, oncallScheduleIid }) => ({
-        status,
-        elapsedTimeSeconds,
-        oncallScheduleIid,
-      }));
-
-      return { ...this.form, rules };
+    updateEscalationPolicy() {
+      this.loading = true;
+      const { projectPath } = this;
+      this.$apollo
+        .mutate({
+          mutation: updateEscalationPolicyMutation,
+          variables: {
+            input: this.requestParams,
+          },
+          update(store, { data }) {
+            updateStoreOnEscalationPolicyUpdate(store, getEscalationPoliciesQuery, data, {
+              projectPath,
+            });
+          },
+        })
+        .then(
+          ({
+            data: {
+              escalationPolicyUpdate: {
+                errors: [error],
+              },
+            },
+          }) => {
+            if (error) {
+              throw error;
+            }
+            this.$refs.addUpdateEscalationPolicyModal.hide();
+            this.resetForm();
+          },
+        )
+        .catch((error) => {
+          this.error = error;
+        })
+        .finally(() => {
+          this.loading = false;
+        });
+    },
+    getRules(rules) {
+      return rules.map(
+        ({ status, elapsedTimeSeconds, oncallScheduleIid, oncallSchedule: { iid } = {} }) => ({
+          status,
+          elapsedTimeSeconds,
+          oncallScheduleIid: oncallScheduleIid || iid,
+        }),
+      );
     },
     validateForm(field) {
       if (field === 'name') {
@@ -138,11 +205,21 @@ export default {
       this.error = null;
     },
     resetForm() {
-      this.form = {
-        name: '',
-        description: '',
-        rules: [],
-      };
+      if (this.isEditMode) {
+        const { name, description, rules } = this.escalationPolicy;
+        this.form = {
+          name,
+          description,
+          rules,
+        };
+      } else {
+        this.form = {
+          name: '',
+          description: '',
+          rules: [],
+        };
+      }
+
       this.validationState = {
         name: null,
         rules: [],
@@ -157,11 +234,11 @@ export default {
   <gl-modal
     ref="addUpdateEscalationPolicyModal"
     class="escalation-policy-modal"
-    :modal-id="$options.addEscalationPolicyModalId"
-    :title="$options.i18n.addEscalationPolicy"
+    :modal-id="modalId"
+    :title="title"
     :action-primary="actionsProps.primary"
     :action-cancel="actionsProps.cancel"
-    @primary.prevent="createEscalationPolicy"
+    @primary.prevent="isEditMode ? updateEscalationPolicy() : createEscalationPolicy()"
     @canceled="resetForm"
     @close="resetForm"
   >
diff --git a/ee/app/assets/javascripts/escalation_policies/components/escalation_policies_wrapper.vue b/ee/app/assets/javascripts/escalation_policies/components/escalation_policies_wrapper.vue
index e04e096b1d4e0ef5e8d607bc4890b7d2fc6c5976..ac39b636f01820d6d4505511182396b4f34f6579 100644
--- a/ee/app/assets/javascripts/escalation_policies/components/escalation_policies_wrapper.vue
+++ b/ee/app/assets/javascripts/escalation_policies/components/escalation_policies_wrapper.vue
@@ -72,15 +72,6 @@ export default {
     <template v-else-if="hasPolicies">
       <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
         <h2>{{ $options.i18n.title }}</h2>
-        <gl-button
-          v-gl-modal="$options.addEscalationPolicyModalId"
-          :title="$options.i18n.addPolicy"
-          category="secondary"
-          variant="confirm"
-          class="gl-mt-5"
-        >
-          {{ $options.i18n.addPolicy }}
-        </gl-button>
       </div>
       <escalation-policy
         v-for="(policy, index) in escalationPolicies"
diff --git a/ee/app/assets/javascripts/escalation_policies/components/escalation_policy.vue b/ee/app/assets/javascripts/escalation_policies/components/escalation_policy.vue
index 3d291382e77e8f68302df448c354bf0b483a36fe..7422d9c6fa666ad41aa9939a329e9be865e83e0e 100644
--- a/ee/app/assets/javascripts/escalation_policies/components/escalation_policy.vue
+++ b/ee/app/assets/javascripts/escalation_policies/components/escalation_policy.vue
@@ -15,7 +15,9 @@ import {
   ALERT_STATUSES,
   DEFAULT_ACTION,
   deleteEscalationPolicyModalId,
+  editEscalationPolicyModalId,
 } from '../constants';
+import EditEscalationPolicyModal from './add_edit_escalation_policy_modal.vue';
 import DeleteEscalationPolicyModal from './delete_escalation_policy_modal.vue';
 
 export const i18n = {
@@ -45,6 +47,7 @@ export default {
     GlIcon,
     GlCollapse,
     DeleteEscalationPolicyModal,
+    EditEscalationPolicyModal,
   },
   directives: {
     GlModal: GlModalDirective,
@@ -75,6 +78,9 @@ export default {
     policyVisibleAngleIconLabel() {
       return this.isPolicyVisible ? __('Collapse') : __('Expand');
     },
+    editPolicyModalId() {
+      return `${editEscalationPolicyModalId}-${this.policy.id}`;
+    },
     deletePolicyModalId() {
       return `${deleteEscalationPolicyModalId}-${this.policy.id}`;
     },
@@ -106,11 +112,11 @@ export default {
           <h3 class="gl-font-weight-bold gl-font-lg gl-m-0">{{ policy.name }}</h3>
           <gl-button-group class="gl-ml-auto">
             <gl-button
+              v-gl-modal="editPolicyModalId"
               v-gl-tooltip
               :title="$options.i18n.editPolicy"
               icon="pencil"
               :aria-label="$options.i18n.editPolicy"
-              disabled
             />
             <gl-button
               v-gl-modal="deletePolicyModalId"
@@ -163,5 +169,10 @@ export default {
     </gl-card>
 
     <delete-escalation-policy-modal :escalation-policy="policy" :modal-id="deletePolicyModalId" />
+    <edit-escalation-policy-modal
+      :escalation-policy="policy"
+      :modal-id="editPolicyModalId"
+      is-edit-mode
+    />
   </div>
 </template>
diff --git a/ee/app/assets/javascripts/escalation_policies/graphql/cache_updates.js b/ee/app/assets/javascripts/escalation_policies/graphql/cache_updates.js
index 0007146d58e0c16e61ccbf6f2fea226eb852f6b2..ff47ab3d08cc745180c64603b549b0fa205a9773 100644
--- a/ee/app/assets/javascripts/escalation_policies/graphql/cache_updates.js
+++ b/ee/app/assets/javascripts/escalation_policies/graphql/cache_updates.js
@@ -3,10 +3,13 @@ import createFlash from '~/flash';
 
 import { s__ } from '~/locale';
 
-export const DELETE_ESCALATION_POLICY_ERROR = s__(
+const DELETE_ESCALATION_POLICY_ERROR = s__(
   'EscalationPolicies|The escalation policy could not be deleted. Please try again.',
 );
 
+const UPDATE_ESCALATION_POLICY_ERROR = s__(
+  'EscalationPolicies|The escalation policy could not be updated. Please try again',
+);
 const addEscalationPolicyToStore = (store, query, { escalationPolicyCreate }, variables) => {
   const policy = escalationPolicyCreate?.escalationPolicy;
   if (!policy) {
@@ -29,6 +32,32 @@ const addEscalationPolicyToStore = (store, query, { escalationPolicyCreate }, va
   });
 };
 
+const updateEscalationPolicyInStore = (store, query, { escalationPolicyUpdate }, variables) => {
+  const policy = escalationPolicyUpdate?.escalationPolicy;
+  if (!policy) {
+    return;
+  }
+
+  const sourceData = store.readQuery({
+    query,
+    variables,
+  });
+
+  const data = produce(sourceData, (draftData) => {
+    draftData.project.incidentManagementEscalationPolicies.nodes = draftData.project.incidentManagementEscalationPolicies.nodes.map(
+      (policyToUpdate) => {
+        return policyToUpdate.id === policy.id ? policy : policyToUpdate;
+      },
+    );
+  });
+
+  store.writeQuery({
+    query,
+    variables,
+    data,
+  });
+};
+
 const deleteEscalationPolicFromStore = (store, query, { escalationPolicyDestroy }, variables) => {
   const escalationPolicy = escalationPolicyDestroy?.escalationPolicy;
 
@@ -66,6 +95,15 @@ export const updateStoreOnEscalationPolicyCreate = (store, query, data, variable
     addEscalationPolicyToStore(store, query, data, variables);
   }
 };
+
+export const updateStoreOnEscalationPolicyUpdate = (store, query, data, variables) => {
+  if (hasErrors(data)) {
+    onError(data, UPDATE_ESCALATION_POLICY_ERROR);
+  } else {
+    updateEscalationPolicyInStore(store, query, data, variables);
+  }
+};
+
 export const updateStoreAfterEscalationPolicyDelete = (store, query, data, variables) => {
   if (hasErrors(data)) {
     onError(data, DELETE_ESCALATION_POLICY_ERROR);
diff --git a/ee/app/assets/javascripts/escalation_policies/graphql/mutations/update_escalation_policy.mutation.graphql b/ee/app/assets/javascripts/escalation_policies/graphql/mutations/update_escalation_policy.mutation.graphql
new file mode 100644
index 0000000000000000000000000000000000000000..8b1acf21a7d648d598146a47ebf1f60588a81ffb
--- /dev/null
+++ b/ee/app/assets/javascripts/escalation_policies/graphql/mutations/update_escalation_policy.mutation.graphql
@@ -0,0 +1,10 @@
+#import "../fragments/escalation_policy.fragment.graphql"
+
+mutation escalationPolicyUpdate($input: EscalationPolicyUpdateInput!) {
+  escalationPolicyUpdate(input: $input) {
+    escalationPolicy {
+      ...EscalationPolicy
+    }
+    errors
+  }
+}
diff --git a/ee/spec/frontend/escalation_policies/__snapshots__/escalation_policy_spec.js.snap b/ee/spec/frontend/escalation_policies/__snapshots__/escalation_policy_spec.js.snap
index 63e39e6bff5a5a4ea558ff4306599f0ecad8a956..29436559e3a940828316ea5fa4035d6719aa020d 100644
--- a/ee/spec/frontend/escalation_policies/__snapshots__/escalation_policy_spec.js.snap
+++ b/ee/spec/frontend/escalation_policies/__snapshots__/escalation_policy_spec.js.snap
@@ -117,5 +117,11 @@ exports[`EscalationPolicy renders policy with rules 1`] = `
     escalationpolicy="[object Object]"
     modalid="deleteEscalationPolicyModal-37"
   />
+   
+  <edit-escalation-policy-modal-stub
+    escalationpolicy="[object Object]"
+    iseditmode="true"
+    modalid="editEscalationPolicyModal-37"
+  />
 </div>
 `;
diff --git a/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_form_spec.js b/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_form_spec.js
index f114c1945564f76e61f92fb9014db6441ea7d6d6..22439e7ea157bff98aea1107ef57c9ce3742097a 100644
--- a/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_form_spec.js
+++ b/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_form_spec.js
@@ -18,6 +18,7 @@ describe('AddEscalationPolicyForm', () => {
         form: {
           name: mockPolicies[1].name,
           description: mockPolicies[1].description,
+          rules: [],
         },
         validationState: {
           name: true,
@@ -48,8 +49,14 @@ describe('AddEscalationPolicyForm', () => {
   const findAddRuleLink = () => wrapper.findComponent(GlLink);
 
   describe('Escalation rules', () => {
-    it('should render one default rule', () => {
-      expect(findRules().length).toBe(1);
+    it('should render one default rule when rules were not provided', () => {
+      expect(findRules()).toHaveLength(1);
+    });
+
+    it('should render all the rules if they were provided', async () => {
+      createComponent({ props: { form: { rules: mockPolicies[1].rules } } });
+      await wrapper.vm.$nextTick();
+      expect(findRules()).toHaveLength(mockPolicies[1].rules.length);
     });
 
     it('should contain a link to add escalation rules', () => {
diff --git a/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_modal_spec.js b/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_modal_spec.js
index ef40686ae55b560e2eab6343d4c99ba7072e09b4..f196809be3ffbb12987d77b85f17ea2d56687d02 100644
--- a/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_modal_spec.js
+++ b/ee/spec/frontend/escalation_policies/add_edit_escalation_policy_modal_spec.js
@@ -5,26 +5,37 @@ import AddEscalationPolicyForm from 'ee/escalation_policies/components/add_edit_
 import AddEscalationPolicyModal, {
   i18n,
 } from 'ee/escalation_policies/components/add_edit_escalation_policy_modal.vue';
+
+import {
+  addEscalationPolicyModalId,
+  editEscalationPolicyModalId,
+} from 'ee/escalation_policies/constants';
+import createEscalationPolicyMutation from 'ee/escalation_policies/graphql/mutations/create_escalation_policy.mutation.graphql';
+import updateEscalationPolicyMutation from 'ee/escalation_policies/graphql/mutations/update_escalation_policy.mutation.graphql';
 import waitForPromises from 'helpers/wait_for_promises';
 import mockPolicies from './mocks/mockPolicies.json';
 
-describe('AddEscalationPolicyModal', () => {
+describe('AddEditsEscalationPolicyModal', () => {
   let wrapper;
   const projectPath = 'group/project';
   const mockHideModal = jest.fn();
   const mutate = jest.fn();
-  const mockPolicy = cloneDeep(mockPolicies[0]);
+  const mockEscalationPolicy = cloneDeep(mockPolicies[0]);
+  const updatedName = 'Policy name';
+  const updatedDescription = 'Policy description';
+  const updatedRules = [{ status: 'RESOLVED', elapsedTimeSeconds: 10, oncallScheduleIid: 1 }];
 
-  const createComponent = ({ escalationPolicy, data } = {}) => {
+  const createComponent = ({ escalationPolicy, isEditMode = false, modalId, data } = {}) => {
     wrapper = shallowMount(AddEscalationPolicyModal, {
       data() {
         return {
-          form: mockPolicy,
           ...data,
         };
       },
       propsData: {
         escalationPolicy,
+        isEditMode,
+        modalId,
       },
       provide: {
         projectPath,
@@ -38,9 +49,6 @@ describe('AddEscalationPolicyModal', () => {
 
     wrapper.vm.$refs.addUpdateEscalationPolicyModal.hide = mockHideModal;
   };
-  beforeEach(() => {
-    createComponent();
-  });
 
   afterEach(() => {
     wrapper.destroy();
@@ -50,32 +58,118 @@ describe('AddEscalationPolicyModal', () => {
   const findEscalationPolicyForm = () => wrapper.findComponent(AddEscalationPolicyForm);
   const findAlert = () => wrapper.findComponent(GlAlert);
 
-  describe('renders create modal with the correct information', () => {
-    it('renders modal title', () => {
-      expect(findModal().attributes('title')).toBe(i18n.addEscalationPolicy);
+  const updateForm = () => {
+    const emitUpdate = (args) =>
+      findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', args);
+
+    emitUpdate({
+      field: 'name',
+      value: updatedName,
+    });
+    emitUpdate({
+      field: 'description',
+      value: updatedDescription,
+    });
+    emitUpdate({
+      field: 'rules',
+      value: updatedRules,
+    });
+  };
+
+  describe('Create escalation policy', () => {
+    beforeEach(() => {
+      createComponent({ modalId: addEscalationPolicyModalId });
     });
 
-    it('renders the form inside the modal', () => {
-      expect(findEscalationPolicyForm().exists()).toBe(true);
+    it('renders create modal with correct information', () => {
+      const modal = findModal();
+      expect(modal.props('title')).toBe(i18n.addEscalationPolicy);
+      expect(modal.props('modalId')).toBe(addEscalationPolicyModalId);
     });
 
     it('makes a request with form data to create an escalation policy', () => {
       mutate.mockResolvedValueOnce({});
+      updateForm();
       findModal().vm.$emit('primary', { preventDefault: jest.fn() });
-      const rules = mockPolicy.rules.map(
-        ({ status, elapsedTimeSeconds, oncallSchedule: { id } }) => ({
-          status,
-          elapsedTimeSeconds,
-          oncallScheduleIid: id,
+      expect(mutate).toHaveBeenCalledWith(
+        expect.objectContaining({
+          mutation: createEscalationPolicyMutation,
+          variables: {
+            input: {
+              projectPath,
+              name: updatedName,
+              description: updatedDescription,
+              rules: updatedRules,
+            },
+          },
+          update: expect.any(Function),
         }),
       );
+    });
+
+    it('clears the form on modal cancel', async () => {
+      updateForm();
+      expect(findEscalationPolicyForm().props('form')).toMatchObject({
+        name: updatedName,
+        description: updatedDescription,
+        rules: updatedRules,
+      });
+
+      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
+      await wrapper.vm.$nextTick();
+      expect(findEscalationPolicyForm().props('form')).toMatchObject({
+        name: '',
+        description: '',
+        rules: [],
+      });
+    });
+
+    it('clears the validation state on modal cancel', async () => {
+      const form = findEscalationPolicyForm();
+      const getNameValidationState = () => form.props('validationState').name;
+      expect(getNameValidationState()).toBe(null);
+
+      form.vm.$emit('update-escalation-policy-form', {
+        field: 'name',
+        value: '',
+      });
+      await wrapper.vm.$nextTick();
+      expect(getNameValidationState()).toBe(false);
+
+      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
+      await wrapper.vm.$nextTick();
+      expect(getNameValidationState()).toBe(null);
+    });
+  });
+
+  describe('Update escalation policy', () => {
+    beforeEach(() => {
+      createComponent({
+        modalId: editEscalationPolicyModalId,
+        escalationPolicy: mockEscalationPolicy,
+        isEditMode: true,
+      });
+    });
+
+    it('renders update modal with correct information', () => {
+      const modal = findModal();
+      expect(modal.props('title')).toBe(i18n.editEscalationPolicy);
+      expect(modal.props('modalId')).toBe(editEscalationPolicyModalId);
+    });
+
+    it('makes a request with form data to update an escalation policy', () => {
+      mutate.mockResolvedValueOnce({});
+      updateForm();
+      findModal().vm.$emit('primary', { preventDefault: jest.fn() });
       expect(mutate).toHaveBeenCalledWith(
         expect.objectContaining({
+          mutation: updateEscalationPolicyMutation,
           variables: {
             input: {
-              projectPath,
-              ...mockPolicy,
-              rules,
+              name: updatedName,
+              description: updatedDescription,
+              rules: updatedRules,
+              id: mockEscalationPolicy.id,
             },
           },
           update: expect.any(Function),
@@ -83,6 +177,52 @@ describe('AddEscalationPolicyModal', () => {
       );
     });
 
+    it('clears the form on modal cancel', async () => {
+      updateForm();
+      const getForm = () => findEscalationPolicyForm().props('form');
+      expect(getForm()).toMatchObject({
+        name: updatedName,
+        description: updatedDescription,
+        rules: updatedRules,
+      });
+
+      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
+      const { name, description, rules } = mockEscalationPolicy;
+
+      await wrapper.vm.$nextTick();
+
+      expect(getForm()).toMatchObject({
+        name,
+        description,
+        rules,
+      });
+    });
+
+    it('clears the validation state on modal cancel', async () => {
+      const form = findEscalationPolicyForm();
+      const getNameValidationState = () => form.props('validationState').name;
+      expect(getNameValidationState()).toBe(null);
+
+      expect(wrapper.vm.validationState.name).toBe(null);
+
+      form.vm.$emit('update-escalation-policy-form', {
+        field: 'name',
+        value: '',
+      });
+      await wrapper.vm.$nextTick();
+      expect(getNameValidationState()).toBe(false);
+
+      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
+      await wrapper.vm.$nextTick();
+      expect(getNameValidationState()).toBe(null);
+    });
+  });
+
+  describe('Create/update success/failure', () => {
+    beforeEach(() => {
+      createComponent({ modalId: addEscalationPolicyModalId });
+    });
+
     it('hides the modal on successful policy creation', async () => {
       mutate.mockResolvedValueOnce({ data: { escalationPolicyCreate: { errors: [] } } });
       findModal().vm.$emit('primary', { preventDefault: jest.fn() });
@@ -100,35 +240,13 @@ describe('AddEscalationPolicyModal', () => {
       expect(alert.exists()).toBe(true);
       expect(alert.text()).toContain(error);
     });
+  });
 
-    it('clears the form on modal cancel', () => {
-      expect(wrapper.vm.form).toEqual(mockPolicy);
-      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
-      expect(wrapper.vm.form).toEqual({
-        name: '',
-        description: '',
-        rules: [],
-      });
-
-      expect(wrapper.vm.validationState).toEqual({
-        name: null,
-        rules: [],
-      });
-    });
-
-    it('clears the validation state on modal cancel', () => {
-      expect(wrapper.vm.validationState.name).toBe(null);
-      findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', {
-        field: 'name',
-        value: '',
-      });
-      expect(wrapper.vm.validationState.name).toBe(false);
-      findModal().vm.$emit('canceled', { preventDefault: jest.fn() });
-      expect(wrapper.vm.validationState.name).toBe(null);
+  describe('Modal buttons', () => {
+    beforeEach(() => {
+      createComponent({ modalId: addEscalationPolicyModalId });
     });
-  });
 
-  describe('modal buttons', () => {
     it('should disable primary button when form is invalid', async () => {
       findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', {
         field: 'name',
@@ -139,10 +257,15 @@ describe('AddEscalationPolicyModal', () => {
     });
 
     it('should enable primary button when form is valid', async () => {
-      findEscalationPolicyForm().vm.$emit('update-escalation-policy-form', {
+      const form = findEscalationPolicyForm();
+      form.vm.$emit('update-escalation-policy-form', {
         field: 'name',
         value: 'Some policy name',
       });
+      form.vm.$emit('update-escalation-policy-form', {
+        field: 'rules',
+        value: [{ status: 'RESOLVED', elapsedTimeSeconds: 10, oncallScheduleIid: 1 }],
+      });
       await wrapper.vm.$nextTick();
       expect(findModal().props('actionPrimary').attributes).toContainEqual({ disabled: false });
     });
diff --git a/ee/spec/frontend/escalation_policies/escalation_policy_spec.js b/ee/spec/frontend/escalation_policies/escalation_policy_spec.js
index 2b91e4efecb1147b5975f89baf94fa94ab6ff697..8fcf159e20983b191091d3ea158340a916dc207f 100644
--- a/ee/spec/frontend/escalation_policies/escalation_policy_spec.js
+++ b/ee/spec/frontend/escalation_policies/escalation_policy_spec.js
@@ -1,16 +1,24 @@
 import { GlSprintf } from '@gitlab/ui';
 import { shallowMount } from '@vue/test-utils';
 import { cloneDeep } from 'lodash';
+import EditEscalationPolicyModal from 'ee/escalation_policies/components/add_edit_escalation_policy_modal.vue';
+import DeleteEscalationPolicyModal from 'ee/escalation_policies/components/delete_escalation_policy_modal.vue';
 import EscalationPolicy from 'ee/escalation_policies/components/escalation_policy.vue';
 
+import {
+  deleteEscalationPolicyModalId,
+  editEscalationPolicyModalId,
+} from 'ee/escalation_policies/constants';
 import mockPolicies from './mocks/mockPolicies.json';
 
 describe('EscalationPolicy', () => {
   let wrapper;
+  const escalationPolicy = cloneDeep(mockPolicies[0]);
+
   const createComponent = () => {
     wrapper = shallowMount(EscalationPolicy, {
       propsData: {
-        policy: cloneDeep(mockPolicies[0]),
+        policy: escalationPolicy,
         index: 0,
       },
       stubs: {
@@ -27,7 +35,33 @@ describe('EscalationPolicy', () => {
     wrapper.destroy();
   });
 
+  const findDeleteModal = () => wrapper.findComponent(DeleteEscalationPolicyModal);
+  const findEditModal = () => wrapper.findComponent(EditEscalationPolicyModal);
+
   it('renders policy with rules', () => {
     expect(wrapper.element).toMatchSnapshot();
   });
+
+  describe('Modals', () => {
+    describe('delete policy modal', () => {
+      it('should render a modal and provide it with correct id', () => {
+        const modal = findDeleteModal();
+        expect(modal.exists()).toBe(true);
+        expect(modal.props('modalId')).toBe(
+          `${deleteEscalationPolicyModalId}-${escalationPolicy.id}`,
+        );
+      });
+    });
+
+    describe('edit policy modal', () => {
+      it('should render a modal and provide it with correct id and isEditMode props', () => {
+        const modal = findEditModal();
+        expect(modal.exists()).toBe(true);
+        expect(modal.props('modalId')).toBe(
+          `${editEscalationPolicyModalId}-${escalationPolicy.id}`,
+        );
+        expect(modal.props('isEditMode')).toBe(true);
+      });
+    });
+  });
 });
diff --git a/ee/spec/frontend/escalation_policies/escalation_policy_wrapper_spec.js b/ee/spec/frontend/escalation_policies/escalation_policy_wrapper_spec.js
index c1c8ac12f89c4b73f8f39ac2b0e73b32b5bc3a48..9cdbb9063ad50b40ec47b62f1dc536d7cfc1c2f0 100644
--- a/ee/spec/frontend/escalation_policies/escalation_policy_wrapper_spec.js
+++ b/ee/spec/frontend/escalation_policies/escalation_policy_wrapper_spec.js
@@ -44,8 +44,6 @@ describe('Escalation Policies Wrapper', () => {
   const findLoader = () => wrapper.findComponent(GlLoadingIcon);
   const findEmptyState = () => wrapper.findComponent(GlEmptyState);
   const findEscalationPolicies = () => wrapper.findAllComponents(EscalationPolicy);
-  const findAddPolicyBtn = () =>
-    wrapper.findByRole('button', { name: EscalationPoliciesWrapper.i18n.addPolicy });
 
   describe.each`
     state             | loading  | escalationPolicies        | showsEmptyState | showsLoader
@@ -72,10 +70,6 @@ describe('Escalation Policies Wrapper', () => {
       it(`does ${escalationPolicies.length ? 'show' : 'not show'} escalation policies`, () => {
         expect(findEscalationPolicies()).toHaveLength(escalationPolicies.length);
       });
-
-      it(`does ${escalationPolicies.length ? 'show' : 'not show'} "Add policy" button`, () => {
-        expect(findAddPolicyBtn().exists()).toBe(Boolean(escalationPolicies.length));
-      });
     });
   });
 });
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 88c337eaa57596f64f55b8058f656f288c67ed15..e735fa871046ab8574edc51aa13dd9749c3ab109 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -13120,6 +13120,9 @@ msgstr ""
 msgid "EscalationPolicies|The escalation policy could not be deleted. Please try again."
 msgstr ""
 
+msgid "EscalationPolicies|The escalation policy could not be updated. Please try again"
+msgstr ""
+
 msgid "EscalationPolicies|mins"
 msgstr ""