diff --git a/ee/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js b/ee/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
index 533e0e12b2c4653fa9c04970d15c6c884643306a..d318660cf33f528c077256dcd29d7b32bde81a2a 100644
--- a/ee/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
+++ b/ee/app/assets/javascripts/pages/projects/settings/ci_cd/show/index.js
@@ -1,10 +1,6 @@
 import Vue from 'vue';
-import { initProtectedEnvironmentCreate } from 'ee/protected_environments/protected_environment_create';
-import {
-  initProtectedEnvironmentEditList,
-  initEditMultipleEnvironmentApprovalRules,
-} from 'ee/protected_environments/protected_environment_edit_list';
 import { initGroupProtectedEnvironmentList } from 'ee/protected_environments/group_protected_environment_list';
+import { initProtectedEnvironments } from 'ee/protected_environments/protected_environments';
 import LicenseManagement from 'ee/vue_shared/license_compliance/license_management.vue';
 import createStore from 'ee/vue_shared/license_compliance/store/index';
 import showToast from '~/vue_shared/plugins/global_toast';
@@ -33,7 +29,5 @@ if (el?.dataset?.apiUrl) {
 
 toasts.forEach((toast) => showToast(toast.dataset.message));
 
-initProtectedEnvironmentEditList();
 initGroupProtectedEnvironmentList();
-initProtectedEnvironmentCreate();
-initEditMultipleEnvironmentApprovalRules();
+initProtectedEnvironments();
diff --git a/ee/app/assets/javascripts/protected_environments/add_approvers.vue b/ee/app/assets/javascripts/protected_environments/add_approvers.vue
index 00e7b5f3dc6922a04c366887022ab16e58a72417..9208c2e1ab75359ddb31b0aee1afb0f4e4601aae 100644
--- a/ee/app/assets/javascripts/protected_environments/add_approvers.vue
+++ b/ee/app/assets/javascripts/protected_environments/add_approvers.vue
@@ -68,29 +68,20 @@ export default {
       required: false,
       default: false,
     },
+    approvalRules: {
+      type: Array,
+      required: false,
+      default: () => [],
+    },
   },
   data() {
     return {
       approvers: [],
-      approverInfo: [],
+      approverInfo: this.approvalRules,
       uniqueId: uniqueId('deployment-approvers-'),
     };
   },
   computed: {
-    approvalRules() {
-      return this.approverInfo.map((info) => {
-        switch (info.type) {
-          case 'user':
-            return { user_id: info.id, required_approvals: info.approvals };
-          case 'group':
-            return { group_id: info.id, required_approvals: info.approvals };
-          case 'access':
-            return { access_level: info.accessLevel, required_approvals: info.approvals };
-          default:
-            return {};
-        }
-      });
-    },
     hasSelectedApprovers() {
       return Boolean(this.approvers.length);
     },
@@ -118,6 +109,8 @@ export default {
             });
           }),
         );
+
+        this.emitApprovalRules();
       } catch (e) {
         Sentry.captureException(e);
         this.$emit(
@@ -128,14 +121,21 @@ export default {
         );
       }
     },
-    approvalRules() {
-      this.$emit('change', this.approvalRules);
+    approvalRules(rules, oldRules) {
+      if (!rules.length && oldRules.length) {
+        this.approvers = rules;
+      }
     },
   },
   methods: {
     updateApprovers(permissions) {
       this.approvers = permissions;
     },
+    updateApproverInfo(approver, approvals) {
+      const i = this.approverInfo.indexOf(approver);
+      this.$set(this.approverInfo, i, { ...approver, approvals });
+      this.emitApprovalRules();
+    },
     removeApprover({ type, id }) {
       const key = ID_FOR_TYPE[type];
       const index = this.approvers.findIndex(({ [key]: i }) => id === i);
@@ -148,6 +148,21 @@ export default {
     approvalsId(index) {
       return `${this.uniqueId}-${index}`;
     },
+    emitApprovalRules() {
+      const rules = this.approverInfo.map((info) => {
+        switch (info.type) {
+          case 'user':
+            return { user_id: info.id, required_approvals: info.approvals };
+          case 'group':
+            return { group_id: info.id, required_approvals: info.approvals };
+          case 'access':
+            return { access_level: info.accessLevel, required_approvals: info.approvals };
+          default:
+            return {};
+        }
+      });
+      this.$emit('change', rules);
+    },
   },
   i18n: {
     approverLabel: s__('ProtectedEnvironment|Approvers'),
@@ -213,11 +228,12 @@ export default {
           >
             <gl-form-input
               :id="approvalsId(index)"
-              v-model="approver.approvals"
+              :value="approver.approvals"
               :disabled="approver.inputDisabled"
               :state="isApprovalValid(approver.approvals)"
               :name="`approval-count-${approver.name}`"
               type="number"
+              @input="updateApproverInfo(approver, $event)"
             />
             <template #invalid-feedback>
               {{ $options.i18n.approvalsInvalid }}
diff --git a/ee/app/assets/javascripts/protected_environments/create_protected_environment.vue b/ee/app/assets/javascripts/protected_environments/create_protected_environment.vue
index 1f64abcc41c2b8a266ddb5109f045ab16d6545d0..35b11f3b6206821808c6a864c460c0f231853494 100644
--- a/ee/app/assets/javascripts/protected_environments/create_protected_environment.vue
+++ b/ee/app/assets/javascripts/protected_environments/create_protected_environment.vue
@@ -3,6 +3,7 @@ import {
   GlAlert,
   GlButton,
   GlCard,
+  GlForm,
   GlFormGroup,
   GlCollapse,
   GlCollapsibleListbox,
@@ -25,6 +26,7 @@ export default {
     GlButton,
     GlCard,
     GlCollapse,
+    GlForm,
     GlFormGroup,
     GlCollapsibleListbox,
     GlLink,
@@ -33,16 +35,12 @@ export default {
     AddApprovers,
   },
   mixins: [glFeatureFlagsMixin()],
-  inject: { accessLevelsData: { default: [] }, apiLink: {}, docsLink: {} },
-  props: {
-    searchUnprotectedEnvironmentsUrl: {
-      type: String,
-      required: true,
-    },
-    projectId: {
-      type: String,
-      required: true,
-    },
+  inject: {
+    accessLevelsData: { default: [] },
+    apiLink: {},
+    docsLink: {},
+    projectId: { default: '' },
+    searchUnprotectedEnvironmentsUrl: { default: '' },
   },
   data() {
     return {
@@ -55,6 +53,7 @@ export default {
       environmentsLoading: false,
       errorMessage: '',
       alertDismissed: false,
+      loading: false,
     };
   },
   computed: {
@@ -101,6 +100,7 @@ export default {
     },
     submitForm() {
       this.errorMessage = '';
+      this.loading = true;
 
       const protectedEnvironment = {
         name: this.environment,
@@ -109,11 +109,17 @@ export default {
       };
       Api.createProtectedEnvironment(this.projectId, protectedEnvironment)
         .then(() => {
-          window.location.reload();
+          this.$emit('reload');
+          this.deployers = [];
+          this.approvers = [];
+          this.environment = '';
         })
         .catch((error) => {
           Sentry.captureException(error);
           this.errorMessage = __('Failed to protect the environment');
+        })
+        .finally(() => {
+          this.loading = false;
         });
     },
   },
@@ -134,81 +140,90 @@ export default {
     ),
     buttonText: s__('ProtectedEnvironment|Protect'),
   },
-  APPROVAL_COUNT_OPTIONS: ['0', '1', '2', '3', '4', '5'].map((value) => ({ value, text: value })),
 };
 </script>
 <template>
-  <gl-card data-testid="new-protected-environment">
-    <template #header>
-      {{ $options.i18n.header }}
-    </template>
-    <template #default>
-      <gl-alert v-if="errorMessage" variant="danger" class="gl-mb-5" @dismiss="errorMessage = ''">
-        {{ errorMessage }}
-      </gl-alert>
-      <gl-alert
-        v-if="!alertDismissed"
-        :title="$options.i18n.unifiedRulesAlertHeader"
-        class="gl-mb-5"
-        @dismiss="alertDismissed = false"
-      >
-        <p>
-          <gl-sprintf :message="$options.i18n.unifiedRulesAlertText">
-            <template #apiLink="{ content }">
-              <gl-link :href="apiLink">{{ content }}</gl-link>
-            </template>
-            <template #docsLink="{ content }">
-              <gl-link :href="docsLink">{{ content }}</gl-link>
-            </template>
-          </gl-sprintf>
-        </p>
-      </gl-alert>
-      <gl-form-group
-        label-for="environment"
-        data-testid="create-environment"
-        :label="$options.i18n.environmentLabel"
-      >
-        <gl-collapsible-listbox
-          id="create-environment"
-          v-model="environment"
-          :toggle-text="environmentText"
-          :items="environments"
-          :searching="environmentsLoading"
-          searchable
-          @shown="fetchEnvironments"
-          @search="getProtectedEnvironments"
-        />
-      </gl-form-group>
-
-      <gl-collapse :visible="hasSelectedEnvironment">
+  <gl-form @submit.prevent="submitForm">
+    <gl-card data-testid="new-protected-environment">
+      <template #header>
+        {{ $options.i18n.header }}
+      </template>
+      <template #default>
+        <gl-alert v-if="errorMessage" variant="danger" class="gl-mb-5" @dismiss="errorMessage = ''">
+          {{ errorMessage }}
+        </gl-alert>
+        <gl-alert
+          v-if="!alertDismissed"
+          :title="$options.i18n.unifiedRulesAlertHeader"
+          class="gl-mb-5"
+          @dismiss="alertDismissed = false"
+        >
+          <p>
+            <gl-sprintf :message="$options.i18n.unifiedRulesAlertText">
+              <template #apiLink="{ content }">
+                <gl-link :href="apiLink">{{ content }}</gl-link>
+              </template>
+              <template #docsLink="{ content }">
+                <gl-link :href="docsLink">{{ content }}</gl-link>
+              </template>
+            </gl-sprintf>
+          </p>
+        </gl-alert>
         <gl-form-group
-          data-testid="create-deployer-dropdown"
-          label-for="create-deployer-dropdown"
-          :label="$options.i18n.deployerLabel"
+          label-for="environment"
+          data-testid="create-environment"
+          :label="$options.i18n.environmentLabel"
         >
-          <template #label-description>
-            {{ $options.i18n.deployerHelp }}
-          </template>
-          <access-dropdown
-            id="create-deployer-dropdown"
-            :access-levels-data="accessLevelsData"
-            :access-level="$options.ACCESS_LEVELS.DEPLOY"
-            :disabled="disabled"
-            :preselected-items="deployers"
-            @hidden="updateDeployers"
+          <gl-collapsible-listbox
+            id="create-environment"
+            v-model="environment"
+            :toggle-text="environmentText"
+            :items="environments"
+            :searching="environmentsLoading"
+            searchable
+            @shown="fetchEnvironments"
+            @search="getProtectedEnvironments"
           />
         </gl-form-group>
-        <add-approvers
-          :project-id="projectId"
-          @change="updateApprovers"
-          @error="errorMessage = $event"
-        />
-      </gl-collapse>
-    </template>
-    <template #footer>
-      <gl-button category="primary" variant="confirm" :disabled="isFormInvalid" @click="submitForm">
-        {{ $options.i18n.buttonText }}
-      </gl-button>
-    </template>
-  </gl-card>
+
+        <gl-collapse :visible="hasSelectedEnvironment">
+          <gl-form-group
+            data-testid="create-deployer-dropdown"
+            label-for="create-deployer-dropdown"
+            :label="$options.i18n.deployerLabel"
+          >
+            <template #label-description>
+              {{ $options.i18n.deployerHelp }}
+            </template>
+            <access-dropdown
+              id="create-deployer-dropdown"
+              :access-levels-data="accessLevelsData"
+              :access-level="$options.ACCESS_LEVELS.DEPLOY"
+              :disabled="disabled"
+              :items="deployers"
+              @select="updateDeployers"
+            />
+          </gl-form-group>
+          <add-approvers
+            :project-id="projectId"
+            :approval-rules="approvers"
+            @change="updateApprovers"
+            @error="errorMessage = $event"
+          />
+        </gl-collapse>
+      </template>
+      <template #footer>
+        <gl-button
+          type="submit"
+          category="primary"
+          variant="confirm"
+          :loading="loading"
+          :disabled="isFormInvalid"
+          class="js-no-auto-disable"
+        >
+          {{ $options.i18n.buttonText }}
+        </gl-button>
+      </template>
+    </gl-card>
+  </gl-form>
 </template>
diff --git a/ee/app/assets/javascripts/protected_environments/protected_environment_create.js b/ee/app/assets/javascripts/protected_environments/protected_environment_create.js
deleted file mode 100644
index 8e851804d832d271375de3f1e3bbcb2d50c7ef15..0000000000000000000000000000000000000000
--- a/ee/app/assets/javascripts/protected_environments/protected_environment_create.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import Vue from 'vue';
-import CreateProtectedEnvironment from './create_protected_environment.vue';
-
-export const initProtectedEnvironmentCreate = () => {
-  const el = document.querySelector('.js-protected-environment-create-form');
-  if (!el) {
-    return null;
-  }
-
-  const { projectId, apiLink, docsLink } = el.dataset;
-  return new Vue({
-    el,
-    provide: {
-      accessLevelsData: gon?.deploy_access_levels?.roles ?? [],
-      apiLink,
-      docsLink,
-    },
-    render(h) {
-      return h(CreateProtectedEnvironment, {
-        props: {
-          projectId,
-          searchUnprotectedEnvironmentsUrl: gon.search_unprotected_environments_url,
-        },
-      });
-    },
-  });
-};
diff --git a/ee/app/assets/javascripts/protected_environments/protected_environment_edit_list.js b/ee/app/assets/javascripts/protected_environments/protected_environment_edit_list.js
deleted file mode 100644
index 6c44fa013f10e870432dc0674c63f28cd7bb815e..0000000000000000000000000000000000000000
--- a/ee/app/assets/javascripts/protected_environments/protected_environment_edit_list.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import * as Sentry from '@sentry/browser';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import { GlToast } from '@gitlab/ui';
-import { createStore } from './store/edit';
-import ProtectedEnvironmentEdit from './protected_environment_edit.vue';
-import EditProtectedEnvironmentList from './edit_protected_environments_list.vue';
-
-Vue.use(GlToast);
-
-export const initProtectedEnvironmentEditList = () => {
-  const parentContainer = document.querySelector('.js-protected-environments-list');
-  const envEditFormEls = parentContainer?.querySelectorAll('.js-protected-environment-edit-form');
-
-  if (envEditFormEls?.length) {
-    envEditFormEls.forEach((el) => {
-      const {
-        url,
-        label,
-        disabled,
-        preselectedItems,
-        requiredApprovalCount,
-        environmentName,
-        environmentLink,
-        deleteProtectedEnvironmentLink,
-      } = el.dataset;
-
-      let preselected = [];
-      try {
-        preselected = JSON.parse(preselectedItems);
-      } catch (e) {
-        Sentry.captureException(e);
-      }
-      return new Vue({
-        el,
-        render(createElement) {
-          return createElement(ProtectedEnvironmentEdit, {
-            props: {
-              parentContainer,
-              preselectedItems: preselected,
-              url,
-              label,
-              disabled,
-              requiredApprovalCount: parseInt(requiredApprovalCount, 10),
-              environmentName,
-              environmentLink,
-              deleteProtectedEnvironmentLink,
-            },
-          });
-        },
-      });
-    });
-  }
-};
-
-export const initEditMultipleEnvironmentApprovalRules = () => {
-  Vue.use(Vuex);
-
-  const el = document.getElementById('js-edit-protected-environment-list');
-
-  if (!el) {
-    return null;
-  }
-
-  const { projectId } = el.dataset;
-  return new Vue({
-    el,
-    store: createStore({
-      ...el.dataset,
-    }),
-    provide: {
-      projectId,
-      accessLevelsData: gon?.deploy_access_levels?.roles ?? [],
-    },
-    render(createElement) {
-      return createElement(EditProtectedEnvironmentList);
-    },
-  });
-};
diff --git a/ee/app/assets/javascripts/protected_environments/protected_environments.js b/ee/app/assets/javascripts/protected_environments/protected_environments.js
new file mode 100644
index 0000000000000000000000000000000000000000..73d1d3f3d96974d95ae46adfe25ce1fdd82236cc
--- /dev/null
+++ b/ee/app/assets/javascripts/protected_environments/protected_environments.js
@@ -0,0 +1,32 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { createStore } from './store/edit';
+import ProtectedEnvironmentsApp from './protected_environments_app.vue';
+
+export const initProtectedEnvironments = () => {
+  Vue.use(Vuex);
+
+  const el = document.getElementById('js-protected-environments');
+
+  if (!el) {
+    return null;
+  }
+
+  const { projectId, apiLink, docsLink } = el.dataset;
+  return new Vue({
+    el,
+    store: createStore({
+      ...el.dataset,
+    }),
+    provide: {
+      projectId,
+      accessLevelsData: gon?.deploy_access_levels?.roles ?? [],
+      apiLink,
+      docsLink,
+      searchUnprotectedEnvironmentsUrl: gon.search_unprotected_environments_url,
+    },
+    render(createElement) {
+      return createElement(ProtectedEnvironmentsApp);
+    },
+  });
+};
diff --git a/ee/app/assets/javascripts/protected_environments/protected_environments.vue b/ee/app/assets/javascripts/protected_environments/protected_environments.vue
index 4c820826fa095b5778354abf86442a8794d79581..a6582cb106fc88839e88a881441b8ff2e7c9457f 100644
--- a/ee/app/assets/javascripts/protected_environments/protected_environments.vue
+++ b/ee/app/assets/javascripts/protected_environments/protected_environments.vue
@@ -69,6 +69,8 @@ export default {
     },
     unprotect() {
       this.$emit('unprotect', this.environmentToUnprotect);
+    },
+    clearEnvironment() {
       this.environmentToUnprotect = null;
     },
   },
@@ -91,6 +93,7 @@ export default {
       :visible="isUnprotectModalVisible"
       v-bind="$options.modalOptions"
       @primary="unprotect"
+      @hide="clearEnvironment"
     >
       {{ confirmUnprotectText }}
     </gl-modal>
diff --git a/ee/app/assets/javascripts/protected_environments/protected_environments_app.vue b/ee/app/assets/javascripts/protected_environments/protected_environments_app.vue
new file mode 100644
index 0000000000000000000000000000000000000000..d1722195f8b37ccf3f5a10c9114f373e5f3518bc
--- /dev/null
+++ b/ee/app/assets/javascripts/protected_environments/protected_environments_app.vue
@@ -0,0 +1,21 @@
+<script>
+import { mapActions } from 'vuex';
+import EditProtectedEnvironmentList from './edit_protected_environments_list.vue';
+import CreateProtectedEnvironment from './create_protected_environment.vue';
+
+export default {
+  components: {
+    CreateProtectedEnvironment,
+    EditProtectedEnvironmentList,
+  },
+  methods: {
+    ...mapActions(['fetchProtectedEnvironments']),
+  },
+};
+</script>
+<template>
+  <div>
+    <create-protected-environment @reload="fetchProtectedEnvironments" />
+    <edit-protected-environment-list />
+  </div>
+</template>
diff --git a/ee/app/views/projects/protected_environments/_environments_list.html.haml b/ee/app/views/projects/protected_environments/_environments_list.html.haml
deleted file mode 100644
index ecbd578f17c01422540c258f73cf24ee486471b3..0000000000000000000000000000000000000000
--- a/ee/app/views/projects/protected_environments/_environments_list.html.haml
+++ /dev/null
@@ -1 +0,0 @@
-#js-edit-protected-environment-list{ data: { project_id: @project.id } }
diff --git a/ee/app/views/projects/protected_environments/_form.html.haml b/ee/app/views/projects/protected_environments/_form.html.haml
deleted file mode 100644
index 96cf130467d71c037131e6055ffee9d75f34a2d8..0000000000000000000000000000000000000000
--- a/ee/app/views/projects/protected_environments/_form.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-- add_page_specific_style 'page_bundles/ci_cd_settings'
-
-.js-protected-environment-create-form{ data: { project_id: @project.id,
-                                      api_link: help_page_path('api/protected_environments.md'),
-                                      docs_link: help_page_path('ci/environments/deployment_approvals.md', anchor: 'multiple-approval-rules') } }
diff --git a/ee/app/views/projects/settings/ci_cd/_protected_environments.html.haml b/ee/app/views/projects/settings/ci_cd/_protected_environments.html.haml
index 44e34248a72d94be7af2d84148d03c84cbcf3305..067a4b96629383fa8d6f39139cfce874b8487e9d 100644
--- a/ee/app/views/projects/settings/ci_cd/_protected_environments.html.haml
+++ b/ee/app/views/projects/settings/ci_cd/_protected_environments.html.haml
@@ -1,5 +1,5 @@
 - expanded = expanded_by_default?
-- can_admin_project = can?(current_user, :admin_project, @project)
+- add_page_specific_style 'page_bundles/ci_cd_settings'
 
 - if @project.licensed_feature_available?(:protected_environments)
   %section.protected-environments-settings.settings.no-animate#js-protected-environments-settings{ class: ('expanded' if expanded) }
@@ -17,8 +17,9 @@
           - c.with_body do
             = s_('ProtectedEnvironment|No environments in this project are protected.')
 
-      = render 'projects/protected_environments/form'
+      #js-protected-environments{ data: { project_id: @project.id,
+                                      api_link: help_page_path('api/protected_environments.md'),
+                                      docs_link: help_page_path('ci/environments/deployment_approvals.md', anchor: 'multiple-approval-rules') } }
 
-      = render partial: 'projects/protected_environments/environments_list', locals: { can_admin_project: can_admin_project }
       = render partial: 'projects/protected_environments/group_environments_list'
       = render 'projects/protected_environments/deployment_approval_options', project: @project
diff --git a/ee/spec/frontend/protected_environments/create_protected_environment_spec.js b/ee/spec/frontend/protected_environments/create_protected_environment_spec.js
index 12c347f72d732a22d9df68f59d55e06c65eeb82a..76ec54c53db669d75934ca0e98ab991da89fce87 100644
--- a/ee/spec/frontend/protected_environments/create_protected_environment_spec.js
+++ b/ee/spec/frontend/protected_environments/create_protected_environment_spec.js
@@ -1,6 +1,6 @@
 import MockAdapter from 'axios-mock-adapter';
 import { nextTick } from 'vue';
-import { GlAlert, GlCollapsibleListbox, GlFormInput } from '@gitlab/ui';
+import { GlAlert, GlCollapsibleListbox, GlForm } from '@gitlab/ui';
 import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
 import { mountExtended } from 'helpers/vue_test_utils_helper';
 import waitForPromises from 'helpers/wait_for_promises';
@@ -30,14 +30,8 @@ describe('ee/protected_environments/create_protected_environment.vue', () => {
     wrapper.findByTestId('create-environment').findComponent(GlCollapsibleListbox);
   const findAccessDropdown = () =>
     wrapper.findByTestId('create-deployer-dropdown').findComponent(AccessDropdown);
-  const findRequiredCountForApprover = (name) =>
-    wrapper
-      .findAllComponents(GlFormInput)
-      .wrappers.find((w) => w.attributes('name') === `approval-count-${name}`);
   const findAddApprovers = () => wrapper.findComponent(AddApprovers);
-  const findApproverDropdown = () => findAddApprovers().findComponent(AccessDropdown);
-  const findSubmitButton = () =>
-    wrapper.findByRole('button', { name: s__('ProtectedEnvironment|Protect') });
+  const findForm = () => wrapper.findComponent(GlForm);
 
   beforeEach(() => {
     window.gon = {
@@ -58,13 +52,11 @@ describe('ee/protected_environments/create_protected_environment.vue', () => {
     projectId = PROJECT_ID,
   } = {}) => {
     wrapper = mountExtended(CreateProtectedEnvironment, {
-      propsData: {
-        searchUnprotectedEnvironmentsUrl,
-        projectId,
-      },
       provide: {
         apiLink: API_LINK,
         docsLink: DOCS_LINK,
+        searchUnprotectedEnvironmentsUrl,
+        projectId,
         accessLevelsData: [
           {
             id: 40,
@@ -92,13 +84,13 @@ describe('ee/protected_environments/create_protected_environment.vue', () => {
       avatar_url: '/root.png',
       id: 1,
     });
-    findAccessDropdown().vm.$emit('hidden', deployAccessLevels);
+    findAccessDropdown().vm.$emit('select', deployAccessLevels);
     findEnvironmentsListbox().vm.$emit('select', name);
-    findApproverDropdown().vm.$emit('select', deployAccessLevels);
-    await waitForPromises();
-    findRequiredCountForApprover('root').vm.$emit('input', requiredApprovalCount);
-    await nextTick();
-    await findSubmitButton().vm.$emit('click');
+    findAddApprovers().vm.$emit(
+      'change',
+      deployAccessLevels.map((rule) => ({ ...rule, required_approvals: requiredApprovalCount })),
+    );
+    await findForm().trigger('submit');
   };
 
   describe('alert', () => {
@@ -187,17 +179,6 @@ describe('ee/protected_environments/create_protected_environment.vue', () => {
     });
   });
 
-  describe('on successful protected environment', () => {
-    it('should reload the page', async () => {
-      createComponent();
-      mockAxios.onPost().replyOnce(HTTP_STATUS_OK);
-      await submitForm();
-      await waitForPromises();
-
-      expect(window.location.reload).toHaveBeenCalled();
-    });
-  });
-
   describe('on failed protected environment', () => {
     it('should show an error message', async () => {
       mockAxios.onPost().replyOnce(HTTP_STATUS_BAD_REQUEST, {});
@@ -206,8 +187,6 @@ describe('ee/protected_environments/create_protected_environment.vue', () => {
       await waitForPromises();
 
       expect(findAlert().text()).toBe(__('Failed to protect the environment'));
-
-      expect(window.location.reload).not.toHaveBeenCalled();
     });
   });
 });
diff --git a/ee/spec/frontend/protected_environments/protected_environments_app_spec.js b/ee/spec/frontend/protected_environments/protected_environments_app_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e0f89a986cd3a9d7f1d50bedfb19583b35fe2ea
--- /dev/null
+++ b/ee/spec/frontend/protected_environments/protected_environments_app_spec.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ProtectedEnvironmentsApp from 'ee/protected_environments/protected_environments_app.vue';
+import EditProtectedEnvironmentsList from 'ee/protected_environments/edit_protected_environments_list.vue';
+import CreateProtectedEnvironment from 'ee/protected_environments/create_protected_environment.vue';
+
+Vue.use(Vuex);
+
+describe('ee/protected_environments/protected_environments_app.vue', () => {
+  let fetchProtectedEnvironments;
+  let createApp;
+  let editApp;
+
+  beforeEach(() => {
+    fetchProtectedEnvironments = jest.fn();
+    const store = new Vuex.Store({ actions: { fetchProtectedEnvironments } });
+    const wrapper = shallowMountExtended(ProtectedEnvironmentsApp, {
+      store,
+    });
+
+    createApp = wrapper.findComponent(CreateProtectedEnvironment);
+    editApp = wrapper.findComponent(EditProtectedEnvironmentsList);
+  });
+
+  it('mounts the create app', () => {
+    expect(createApp.exists()).toBe(true);
+  });
+
+  it('re-fetches environments when receiving reload', () => {
+    createApp.vm.$emit('reload');
+    expect(fetchProtectedEnvironments).toHaveBeenCalled();
+  });
+
+  it('mounts the edit app', () => {
+    expect(editApp.exists()).toBe(true);
+  });
+});