Commit 8edbea2f authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch...

Merge branch '331130-follow-up-unify-status-checks-and-approval-rules-branch-selector-component' into 'master'

Unify status checks and approval rules protected branch selector component

See merge request gitlab-org/gitlab!62446
parents 8d4dcf93 2f5a98ff
<script>
import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { debounce } from 'lodash';
import Api from 'ee/api';
import { __ } from '~/locale';
import { BRANCH_FETCH_DELAY, ANY_BRANCH } from '../constants';
export default {
components: {
GlDropdown,
GlDropdownItem,
GlSearchBoxByType,
},
props: {
projectId: {
type: String,
required: true,
},
initRule: {
type: Object,
required: false,
default: null,
},
isInvalid: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
branches: [],
initialLoading: false,
searching: false,
searchTerm: '',
selected: this.initRule?.protectedBranches[0] || ANY_BRANCH,
};
},
computed: {
dropdownClass() {
return {
'gl-w-full': true,
'gl-dropdown-menu-full-width': true,
'is-invalid': this.isInvalid,
};
},
dropdownText() {
return this.selected.name;
},
},
mounted() {
this.initialLoading = true;
this.fetchBranches()
.then(() => {
this.initialLoading = false;
})
.catch(() => {});
},
methods: {
async fetchBranches(term) {
this.searching = true;
const excludeAnyBranch = term && !term.toLowerCase().includes('any');
const branches = await Api.projectProtectedBranches(this.projectId, term);
this.branches = excludeAnyBranch ? branches : [ANY_BRANCH, ...branches];
this.searching = false;
},
search: debounce(function debouncedSearch() {
this.fetchBranches(this.searchTerm);
}, BRANCH_FETCH_DELAY),
isSelectedBranch(id) {
return this.selected.id === id;
},
onSelect(branch) {
this.selected = branch;
this.$emit('input', branch.id);
},
branchNameClass(id) {
return {
monospace: id !== null,
};
},
},
i18n: {
header: __('Select branch'),
},
};
</script>
<template>
<gl-dropdown
:class="dropdownClass"
:text="dropdownText"
:loading="initialLoading"
:header-text="$options.i18n.header"
>
<template #header>
<gl-search-box-by-type v-model="searchTerm" :is-loading="searching" @input="search" />
</template>
<gl-dropdown-item
v-for="branch in branches"
:key="branch.id"
:is-check-item="true"
:is-checked="isSelectedBranch(branch.id)"
@click="onSelect(branch)"
>
<span :class="branchNameClass(branch.id)">{{ branch.name }}</span>
</gl-dropdown-item>
</gl-dropdown>
</template>
<script> <script>
import { GlFormGroup, GlFormInput } from '@gitlab/ui'; import { GlFormGroup, GlFormInput } from '@gitlab/ui';
import { groupBy, isNumber } from 'lodash'; import { groupBy, isEqual, isNumber } from 'lodash';
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selector/protected_branches_selector.vue';
import { isSafeURL } from '~/lib/utils/url_utility'; import { isSafeURL } from '~/lib/utils/url_utility';
import { sprintf, __, s__ } from '~/locale'; import { sprintf, __, s__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { import {
ANY_BRANCH,
TYPE_USER, TYPE_USER,
TYPE_GROUP, TYPE_GROUP,
TYPE_HIDDEN_GROUPS, TYPE_HIDDEN_GROUPS,
...@@ -15,7 +17,6 @@ import { ...@@ -15,7 +17,6 @@ import {
import ApproverTypeSelect from './approver_type_select.vue'; import ApproverTypeSelect from './approver_type_select.vue';
import ApproversList from './approvers_list.vue'; import ApproversList from './approvers_list.vue';
import ApproversSelect from './approvers_select.vue'; import ApproversSelect from './approvers_select.vue';
import BranchesSelect from './branches_select.vue';
const DEFAULT_NAME = 'Default'; const DEFAULT_NAME = 'Default';
const DEFAULT_NAME_FOR_LICENSE_REPORT = 'License-Check'; const DEFAULT_NAME_FOR_LICENSE_REPORT = 'License-Check';
...@@ -31,9 +32,9 @@ export default { ...@@ -31,9 +32,9 @@ export default {
ApproverTypeSelect, ApproverTypeSelect,
ApproversList, ApproversList,
ApproversSelect, ApproversSelect,
BranchesSelect,
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
ProtectedBranchesSelector,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
props: { props: {
...@@ -144,7 +145,10 @@ export default { ...@@ -144,7 +145,10 @@ export default {
return ''; return '';
}, },
invalidBranches() { invalidBranches() {
if (!this.isMrEdit && this.branches.some((id) => typeof id !== 'number')) { if (
!this.isMrEdit &&
!this.branches.every((branch) => isEqual(branch, ANY_BRANCH) || isNumber(branch?.id))
) {
return this.$options.i18n.validations.branchesRequired; return this.$options.i18n.validations.branchesRequired;
} }
...@@ -219,7 +223,7 @@ export default { ...@@ -219,7 +223,7 @@ export default {
userRecords: this.users, userRecords: this.users,
groupRecords: this.groups, groupRecords: this.groups,
removeHiddenGroups: this.removeHiddenGroups, removeHiddenGroups: this.removeHiddenGroups,
protectedBranchIds: this.branches, protectedBranchIds: this.branches.map((x) => x.id),
}; };
}, },
isEditing() { isEditing() {
...@@ -355,7 +359,7 @@ export default { ...@@ -355,7 +359,7 @@ export default {
return { return {
name: this.initRule.name || '', name: this.initRule.name || '',
externalUrl: this.initRule.externalUrl, externalUrl: this.initRule.externalUrl,
branches: this.initRule.protectedBranches?.map((x) => x.id) || [], branches: this.initRule.protectedBranches || [],
ruleType: this.initRule.ruleType, ruleType: this.initRule.ruleType,
approvers: [], approvers: [],
}; };
...@@ -365,7 +369,7 @@ export default { ...@@ -365,7 +369,7 @@ export default {
const users = this.initRule.users.map((x) => ({ ...x, type: TYPE_USER })); const users = this.initRule.users.map((x) => ({ ...x, type: TYPE_USER }));
const groups = this.initRule.groups.map((x) => ({ ...x, type: TYPE_GROUP })); const groups = this.initRule.groups.map((x) => ({ ...x, type: TYPE_GROUP }));
const branches = this.initRule.protectedBranches?.map((x) => x.id) || []; const branches = this.initRule.protectedBranches || [];
return { return {
name: this.initRule.name || '', name: this.initRule.name || '',
...@@ -444,11 +448,11 @@ export default { ...@@ -444,11 +448,11 @@ export default {
:invalid-feedback="invalidBranches" :invalid-feedback="invalidBranches"
data-testid="branches-group" data-testid="branches-group"
> >
<branches-select <protected-branches-selector
v-model="branchesToAdd" v-model="branchesToAdd"
:project-id="settings.projectId" :project-id="settings.projectId"
:is-invalid="!isValidBranches" :is-invalid="!isValidBranches"
:init-rule="rule" :selected-branches="branches"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group v-if="showApproverTypeSelect" :label="$options.i18n.form.approvalTypeLabel"> <gl-form-group v-if="showApproverTypeSelect" :label="$options.i18n.form.approvalTypeLabel">
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlAlert, GlFormGroup, GlFormInput } from '@gitlab/ui'; import { GlAlert, GlFormGroup, GlFormInput } from '@gitlab/ui';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { isEqual, isNumber } from 'lodash'; import { isEqual, isNumber } from 'lodash';
import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selector/protected_branches_selector.vue';
import { isSafeURL } from '~/lib/utils/url_utility'; import { isSafeURL } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import { import {
...@@ -10,11 +11,10 @@ import { ...@@ -10,11 +11,10 @@ import {
NAME_TAKEN_SERVER_ERROR, NAME_TAKEN_SERVER_ERROR,
URL_TAKEN_SERVER_ERROR, URL_TAKEN_SERVER_ERROR,
} from '../constants'; } from '../constants';
import BranchesSelect from './branches_select.vue';
export default { export default {
components: { components: {
BranchesSelect, ProtectedBranchesSelector,
GlAlert, GlAlert,
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
...@@ -184,7 +184,7 @@ export default { ...@@ -184,7 +184,7 @@ export default {
:invalid-feedback="$options.i18n.validations.branchesRequired" :invalid-feedback="$options.i18n.validations.branchesRequired"
data-testid="branches-group" data-testid="branches-group"
> >
<branches-select <protected-branches-selector
v-model="branchesToAdd" v-model="branchesToAdd"
:project-id="projectId" :project-id="projectId"
:is-invalid="!branchesState" :is-invalid="!branchesState"
......
import { __ } from '~/locale';
export const BRANCH_FETCH_DELAY = 250;
export const ANY_BRANCH = {
id: null,
name: __('Any branch'),
};
...@@ -3,7 +3,7 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; ...@@ -3,7 +3,7 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import Api from 'ee/api'; import Api from 'ee/api';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { BRANCH_FETCH_DELAY, ANY_BRANCH } from '../constants'; import { BRANCH_FETCH_DELAY, ANY_BRANCH } from './constants';
export default { export default {
components: { components: {
......
import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import Api from 'ee/api';
import BranchesSelect from 'ee/approvals/components/branches_select.vue';
import waitForPromises from 'helpers/wait_for_promises';
const TEST_DEFAULT_BRANCH = { name: 'Any branch' };
const TEST_PROJECT_ID = '1';
const TEST_PROTECTED_BRANCHES = [
{ id: 1, name: 'main' },
{ id: 2, name: 'development' },
];
const TEST_BRANCHES_SELECTIONS = [TEST_DEFAULT_BRANCH, ...TEST_PROTECTED_BRANCHES];
const branchNames = () => TEST_BRANCHES_SELECTIONS.map((branch) => branch.name);
const protectedBranchNames = () => TEST_PROTECTED_BRANCHES.map((branch) => branch.name);
Vue.use(Vuex);
describe('Branches Select', () => {
let wrapper;
let store;
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findSearch = () => wrapper.findComponent(GlSearchBoxByType);
const createComponent = (props = {}, mountFn = shallowMount) => {
wrapper = mountFn(BranchesSelect, {
propsData: {
projectId: '1',
...props,
},
store: new Vuex.Store(store),
attachTo: document.body,
});
};
beforeEach(() => {
jest
.spyOn(Api, 'projectProtectedBranches')
.mockReturnValue(Promise.resolve(TEST_PROTECTED_BRANCHES));
});
afterEach(() => {
wrapper.destroy();
});
it('renders dropdown', async () => {
createComponent();
await waitForPromises();
expect(findDropdown().exists()).toBe(true);
});
it('sets the initially selected item', async () => {
createComponent(
{
initRule: {
protectedBranches: [
{
id: 1,
name: 'main',
},
],
},
},
mount,
);
await waitForPromises();
expect(findDropdown().props('text')).toBe('main');
expect(
findDropdownItems()
.filter((item) => item.text() === 'main')
.at(0)
.props('isChecked'),
).toBe(true);
});
it('displays all the protected branches and any branch', async () => {
createComponent();
await Vue.nextTick();
expect(findDropdown().props('loading')).toBe(true);
await waitForPromises();
expect(findDropdownItems()).toHaveLength(branchNames().length);
expect(findDropdown().props('loading')).toBe(false);
});
describe('with search term', () => {
beforeEach(() => {
createComponent({}, mount);
return waitForPromises();
});
it('fetches protected branches with search term', async () => {
const term = 'lorem';
findSearch().vm.$emit('input', term);
await Vue.nextTick();
expect(findSearch().props('isLoading')).toBe(true);
await waitForPromises();
expect(Api.projectProtectedBranches).toHaveBeenCalledWith(TEST_PROJECT_ID, term);
expect(findSearch().props('isLoading')).toBe(false);
});
it('fetches protected branches with no any branch if there is a search', async () => {
findSearch().vm.$emit('input', 'main');
await waitForPromises();
expect(findDropdownItems()).toHaveLength(protectedBranchNames().length);
});
it('fetches protected branches with any branch if search contains term "any"', async () => {
findSearch().vm.$emit('input', 'any');
await waitForPromises();
expect(findDropdownItems()).toHaveLength(branchNames().length);
});
});
it('when the branch is changed it sets the isChecked property and emits the input event', async () => {
createComponent({}, mount);
await waitForPromises();
await findDropdownItems().at(1).vm.$emit('click');
expect(findDropdownItems().at(1).props('isChecked')).toBe(true);
expect(wrapper.emitted().input).toStrictEqual([[1]]);
});
});
...@@ -5,7 +5,6 @@ import Vuex from 'vuex'; ...@@ -5,7 +5,6 @@ import Vuex from 'vuex';
import ApproverTypeSelect from 'ee/approvals/components/approver_type_select.vue'; import ApproverTypeSelect from 'ee/approvals/components/approver_type_select.vue';
import ApproversList from 'ee/approvals/components/approvers_list.vue'; import ApproversList from 'ee/approvals/components/approvers_list.vue';
import ApproversSelect from 'ee/approvals/components/approvers_select.vue'; import ApproversSelect from 'ee/approvals/components/approvers_select.vue';
import BranchesSelect from 'ee/approvals/components/branches_select.vue';
import RuleForm from 'ee/approvals/components/rule_form.vue'; import RuleForm from 'ee/approvals/components/rule_form.vue';
import { import {
TYPE_USER, TYPE_USER,
...@@ -15,6 +14,7 @@ import { ...@@ -15,6 +14,7 @@ import {
} from 'ee/approvals/constants'; } from 'ee/approvals/constants';
import { createStoreOptions } from 'ee/approvals/stores'; import { createStoreOptions } from 'ee/approvals/stores';
import projectSettingsModule from 'ee/approvals/stores/modules/project_settings'; import projectSettingsModule from 'ee/approvals/stores/modules/project_settings';
import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selector/protected_branches_selector.vue';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
...@@ -91,6 +91,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -91,6 +91,7 @@ describe('EE Approvals RuleForm', () => {
props: ['state', 'disabled', 'value'], props: ['state', 'disabled', 'value'],
template: `<input />`, template: `<input />`,
}), }),
BranchesSelect: stubComponent(ProtectedBranchesSelector),
}, },
}), }),
); );
...@@ -104,7 +105,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -104,7 +105,7 @@ describe('EE Approvals RuleForm', () => {
const findApproversSelect = () => wrapper.findComponent(ApproversSelect); const findApproversSelect = () => wrapper.findComponent(ApproversSelect);
const findApproversValidation = () => wrapper.findByTestId('approvers-group'); const findApproversValidation = () => wrapper.findByTestId('approvers-group');
const findApproversList = () => wrapper.findComponent(ApproversList); const findApproversList = () => wrapper.findComponent(ApproversList);
const findBranchesSelect = () => wrapper.findComponent(BranchesSelect); const findProtectedBranchesSelector = () => wrapper.findComponent(ProtectedBranchesSelector);
const findApproverTypeSelect = () => wrapper.findComponent(ApproverTypeSelect); const findApproverTypeSelect = () => wrapper.findComponent(ApproverTypeSelect);
const findExternalUrlInput = () => wrapper.findByTestId('status-checks-url'); const findExternalUrlInput = () => wrapper.findByTestId('status-checks-url');
const findExternalUrlValidation = () => wrapper.findByTestId('status-checks-url-group'); const findExternalUrlValidation = () => wrapper.findByTestId('status-checks-url-group');
...@@ -162,7 +163,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -162,7 +163,7 @@ describe('EE Approvals RuleForm', () => {
}); });
it('on load, it populates initial protected branch ids', () => { it('on load, it populates initial protected branch ids', () => {
expect(findBranchesSelect().props('initRule').protectedBranches).toEqual( expect(findProtectedBranchesSelector().props('selectedBranches')).toEqual(
TEST_PROTECTED_BRANCHES, TEST_PROTECTED_BRANCHES,
); );
}); });
...@@ -186,7 +187,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -186,7 +187,7 @@ describe('EE Approvals RuleForm', () => {
isMrEdit: false, isMrEdit: false,
}); });
await findBranchesSelect().vm.$emit('input', '3'); await findProtectedBranchesSelector().vm.$emit('input', '3');
await findForm().trigger('submit'); await findForm().trigger('submit');
await nextTick(); await nextTick();
...@@ -206,7 +207,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -206,7 +207,7 @@ describe('EE Approvals RuleForm', () => {
const groups = [2, 3]; const groups = [2, 3];
const userRecords = users.map((id) => ({ id, type: TYPE_USER })); const userRecords = users.map((id) => ({ id, type: TYPE_USER }));
const groupRecords = groups.map((id) => ({ id, type: TYPE_GROUP })); const groupRecords = groups.map((id) => ({ id, type: TYPE_GROUP }));
const branches = [TEST_PROTECTED_BRANCHES[0].id]; const branches = [TEST_PROTECTED_BRANCHES[0]];
const expected = { const expected = {
id: null, id: null,
name: 'Lorem', name: 'Lorem',
...@@ -216,13 +217,13 @@ describe('EE Approvals RuleForm', () => { ...@@ -216,13 +217,13 @@ describe('EE Approvals RuleForm', () => {
userRecords, userRecords,
groupRecords, groupRecords,
removeHiddenGroups: false, removeHiddenGroups: false,
protectedBranchIds: branches, protectedBranchIds: branches.map((x) => x.id),
}; };
await findNameInput().vm.$emit('input', expected.name); await findNameInput().vm.$emit('input', expected.name);
await findApprovalsRequiredInput().vm.$emit('input', expected.approvalsRequired); await findApprovalsRequiredInput().vm.$emit('input', expected.approvalsRequired);
await findApproversList().vm.$emit('input', [...groupRecords, ...userRecords]); await findApproversList().vm.$emit('input', [...groupRecords, ...userRecords]);
await findBranchesSelect().vm.$emit('input', branches[0]); await findProtectedBranchesSelector().vm.$emit('input', branches[0]);
await findForm().trigger('submit'); await findForm().trigger('submit');
expect(actions.postRule).toHaveBeenCalledWith(expect.anything(), expected); expect(actions.postRule).toHaveBeenCalledWith(expect.anything(), expected);
...@@ -265,7 +266,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -265,7 +266,7 @@ describe('EE Approvals RuleForm', () => {
it('renders the inputs for external rules', () => { it('renders the inputs for external rules', () => {
expect(findNameInput().exists()).toBe(true); expect(findNameInput().exists()).toBe(true);
expect(findExternalUrlInput().exists()).toBe(true); expect(findExternalUrlInput().exists()).toBe(true);
expect(findBranchesSelect().exists()).toBe(true); expect(findProtectedBranchesSelector().exists()).toBe(true);
}); });
it('does not render the user and group input fields', () => { it('does not render the user and group input fields', () => {
...@@ -296,18 +297,18 @@ describe('EE Approvals RuleForm', () => { ...@@ -296,18 +297,18 @@ describe('EE Approvals RuleForm', () => {
}); });
describe('with valid data', () => { describe('with valid data', () => {
const branches = [TEST_PROTECTED_BRANCHES[0].id]; const branches = [TEST_PROTECTED_BRANCHES[0]];
const expected = { const expected = {
id: null, id: null,
name: 'Lorem', name: 'Lorem',
externalUrl: 'https://gitlab.com/', externalUrl: 'https://gitlab.com/',
protectedBranchIds: branches, protectedBranchIds: branches.map((x) => x.id),
}; };
beforeEach(async () => { beforeEach(async () => {
await findNameInput().vm.$emit('input', expected.name); await findNameInput().vm.$emit('input', expected.name);
await findExternalUrlInput().vm.$emit('input', expected.externalUrl); await findExternalUrlInput().vm.$emit('input', expected.externalUrl);
await findBranchesSelect().vm.$emit('input', branches[0]); await findProtectedBranchesSelector().vm.$emit('input', branches[0]);
}); });
it('on submit, posts external approval rule', async () => { it('on submit, posts external approval rule', async () => {
...@@ -389,7 +390,7 @@ describe('EE Approvals RuleForm', () => { ...@@ -389,7 +390,7 @@ describe('EE Approvals RuleForm', () => {
const groups = [2, 3]; const groups = [2, 3];
const userRecords = users.map((id) => ({ id, type: TYPE_USER })); const userRecords = users.map((id) => ({ id, type: TYPE_USER }));
const groupRecords = groups.map((id) => ({ id, type: TYPE_GROUP })); const groupRecords = groups.map((id) => ({ id, type: TYPE_GROUP }));
const branches = [TEST_PROTECTED_BRANCHES[0].id]; const branches = [TEST_PROTECTED_BRANCHES[0]];
const expected = { const expected = {
id: null, id: null,
name: 'Lorem', name: 'Lorem',
...@@ -399,14 +400,14 @@ describe('EE Approvals RuleForm', () => { ...@@ -399,14 +400,14 @@ describe('EE Approvals RuleForm', () => {
userRecords, userRecords,
groupRecords, groupRecords,
removeHiddenGroups: false, removeHiddenGroups: false,
protectedBranchIds: branches, protectedBranchIds: branches.map((x) => x.id),
}; };
beforeEach(async () => { beforeEach(async () => {
await findNameInput().vm.$emit('input', expected.name); await findNameInput().vm.$emit('input', expected.name);
await findApprovalsRequiredInput().vm.$emit('input', expected.approvalsRequired); await findApprovalsRequiredInput().vm.$emit('input', expected.approvalsRequired);
await findApproversList().vm.$emit('input', [...groupRecords, ...userRecords]); await findApproversList().vm.$emit('input', [...groupRecords, ...userRecords]);
await findBranchesSelect().vm.$emit('input', branches[0]); await findProtectedBranchesSelector().vm.$emit('input', branches[0]);
}); });
it('on submit, posts rule', async () => { it('on submit, posts rule', async () => {
......
import { GlAlert, GlFormGroup, GlFormInput } from '@gitlab/ui'; import { GlAlert, GlFormGroup, GlFormInput } from '@gitlab/ui';
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import BranchesSelect from 'ee/status_checks/components/branches_select.vue';
import Form from 'ee/status_checks/components/form.vue'; import Form from 'ee/status_checks/components/form.vue';
import { NAME_TAKEN_SERVER_ERROR, URL_TAKEN_SERVER_ERROR } from 'ee/status_checks/constants'; import { NAME_TAKEN_SERVER_ERROR, URL_TAKEN_SERVER_ERROR } from 'ee/status_checks/constants';
import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selector/protected_branches_selector.vue';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { TEST_PROTECTED_BRANCHES } from '../mock_data'; import { TEST_PROTECTED_BRANCHES } from '../../vue_shared/components/branches_selector/mock_data';
const projectId = '1'; const projectId = '1';
const statusCheck = { const statusCheck = {
...@@ -17,13 +17,11 @@ const sentryError = new Error('Network error'); ...@@ -17,13 +17,11 @@ const sentryError = new Error('Network error');
describe('Status checks form', () => { describe('Status checks form', () => {
let wrapper; let wrapper;
const submitHandler = jest.fn();
const createWrapper = (props = {}) => { const createWrapper = (props = {}) => {
wrapper = shallowMountExtended(Form, { wrapper = shallowMountExtended(Form, {
propsData: { propsData: {
projectId, projectId,
submitHandler,
...props, ...props,
}, },
stubs: { stubs: {
...@@ -34,7 +32,7 @@ describe('Status checks form', () => { ...@@ -34,7 +32,7 @@ describe('Status checks form', () => {
props: ['state', 'disabled', 'value'], props: ['state', 'disabled', 'value'],
template: `<input />`, template: `<input />`,
}), }),
BranchesSelect: stubComponent(BranchesSelect), BranchesSelect: stubComponent(ProtectedBranchesSelector),
}, },
}); });
}; };
...@@ -42,7 +40,7 @@ describe('Status checks form', () => { ...@@ -42,7 +40,7 @@ describe('Status checks form', () => {
const findForm = () => wrapper.find('form'); const findForm = () => wrapper.find('form');
const findNameInput = () => wrapper.findByTestId('name'); const findNameInput = () => wrapper.findByTestId('name');
const findNameValidation = () => wrapper.findByTestId('name-group'); const findNameValidation = () => wrapper.findByTestId('name-group');
const findBranchesSelect = () => wrapper.findComponent(BranchesSelect); const findProtectedBranchesSelector = () => wrapper.findComponent(ProtectedBranchesSelector);
const findUrlInput = () => wrapper.findByTestId('url'); const findUrlInput = () => wrapper.findByTestId('url');
const findUrlValidation = () => wrapper.findByTestId('url-group'); const findUrlValidation = () => wrapper.findByTestId('url-group');
const findBranchesValidation = () => wrapper.findByTestId('branches-group'); const findBranchesValidation = () => wrapper.findByTestId('branches-group');
...@@ -65,7 +63,7 @@ describe('Status checks form', () => { ...@@ -65,7 +63,7 @@ describe('Status checks form', () => {
expect(inputsAreValid()).toBe(true); expect(inputsAreValid()).toBe(true);
expect(findNameInput().props('value')).toBe(''); expect(findNameInput().props('value')).toBe('');
expect(findBranchesSelect().props('selectedBranches')).toStrictEqual([]); expect(findProtectedBranchesSelector().props('selectedBranches')).toStrictEqual([]);
expect(findUrlInput().props('value')).toBe(''); expect(findUrlInput().props('value')).toBe('');
}); });
...@@ -74,7 +72,7 @@ describe('Status checks form', () => { ...@@ -74,7 +72,7 @@ describe('Status checks form', () => {
expect(inputsAreValid()).toBe(true); expect(inputsAreValid()).toBe(true);
expect(findNameInput().props('value')).toBe(statusCheck.name); expect(findNameInput().props('value')).toBe(statusCheck.name);
expect(findBranchesSelect().props('selectedBranches')).toStrictEqual( expect(findProtectedBranchesSelector().props('selectedBranches')).toStrictEqual(
statusCheck.protectedBranches, statusCheck.protectedBranches,
); );
expect(findUrlInput().props('value')).toBe(statusCheck.externalUrl); expect(findUrlInput().props('value')).toBe(statusCheck.externalUrl);
...@@ -146,7 +144,7 @@ describe('Status checks form', () => { ...@@ -146,7 +144,7 @@ describe('Status checks form', () => {
}); });
it('sends the error to sentry', () => { it('sends the error to sentry', () => {
findBranchesSelect().vm.$emit('apiError', true, sentryError); findProtectedBranchesSelector().vm.$emit('apiError', true, sentryError);
expect(Sentry.captureException.mock.calls[0][0]).toStrictEqual(sentryError); expect(Sentry.captureException.mock.calls[0][0]).toStrictEqual(sentryError);
}); });
...@@ -154,22 +152,22 @@ describe('Status checks form', () => { ...@@ -154,22 +152,22 @@ describe('Status checks form', () => {
it('shows the alert', async () => { it('shows the alert', async () => {
expect(findBranchesErrorAlert().exists()).toBe(false); expect(findBranchesErrorAlert().exists()).toBe(false);
await findBranchesSelect().vm.$emit('apiError', true, sentryError); await findProtectedBranchesSelector().vm.$emit('apiError', true, sentryError);
expect(findBranchesErrorAlert().exists()).toBe(true); expect(findBranchesErrorAlert().exists()).toBe(true);
}); });
it('hides the alert if the apiError is reset', async () => { it('hides the alert if the apiError is reset', async () => {
await findBranchesSelect().vm.$emit('apiError', true, sentryError); await findProtectedBranchesSelector().vm.$emit('apiError', true, sentryError);
expect(findBranchesErrorAlert().exists()).toBe(true); expect(findBranchesErrorAlert().exists()).toBe(true);
await findBranchesSelect().vm.$emit('apiError', false); await findProtectedBranchesSelector().vm.$emit('apiError', false);
expect(findBranchesErrorAlert().exists()).toBe(false); expect(findBranchesErrorAlert().exists()).toBe(false);
}); });
it('only calls sentry once while the branches api is failing', () => { it('only calls sentry once while the branches api is failing', () => {
findBranchesSelect().vm.$emit('apiError', true, sentryError); findProtectedBranchesSelector().vm.$emit('apiError', true, sentryError);
findBranchesSelect().vm.$emit('apiError', true, sentryError); findProtectedBranchesSelector().vm.$emit('apiError', true, sentryError);
expect(Sentry.captureException.mock.calls).toEqual([[sentryError]]); expect(Sentry.captureException.mock.calls).toEqual([[sentryError]]);
}); });
......
...@@ -3,7 +3,7 @@ import Vue from 'vue'; ...@@ -3,7 +3,7 @@ import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import ModalUpdate from 'ee/status_checks/components/modal_update.vue'; import ModalUpdate from 'ee/status_checks/components/modal_update.vue';
import SharedModal from 'ee/status_checks/components/shared_modal.vue'; import SharedModal from 'ee/status_checks/components/shared_modal.vue';
import { TEST_PROTECTED_BRANCHES } from '../mock_data'; import { TEST_PROTECTED_BRANCHES } from '../../vue_shared/components/branches_selector/mock_data';
Vue.use(Vuex); Vue.use(Vuex);
......
...@@ -7,7 +7,7 @@ import { EMPTY_STATUS_CHECK } from 'ee/status_checks/constants'; ...@@ -7,7 +7,7 @@ import { EMPTY_STATUS_CHECK } from 'ee/status_checks/constants';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { TEST_PROTECTED_BRANCHES } from '../mock_data'; import { TEST_PROTECTED_BRANCHES } from '../../vue_shared/components/branches_selector/mock_data';
Vue.use(Vuex); Vue.use(Vuex);
......
...@@ -2,20 +2,20 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; ...@@ -2,20 +2,20 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import { nextTick } from 'vue'; import { nextTick } from 'vue';
import Api from 'ee/api'; import Api from 'ee/api';
import BranchesSelect from 'ee/status_checks/components/branches_select.vue'; import ProtectedBranchesSelector from 'ee/vue_shared/components/branches_selector/protected_branches_selector.vue';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { import {
TEST_DEFAULT_BRANCH, TEST_DEFAULT_BRANCH,
TEST_BRANCHES_SELECTIONS, TEST_BRANCHES_SELECTIONS,
TEST_PROJECT_ID, TEST_PROJECT_ID,
TEST_PROTECTED_BRANCHES, TEST_PROTECTED_BRANCHES,
} from '../mock_data'; } from './mock_data';
const branchNames = () => TEST_BRANCHES_SELECTIONS.map((branch) => branch.name); const branchNames = () => TEST_BRANCHES_SELECTIONS.map((branch) => branch.name);
const protectedBranchNames = () => TEST_PROTECTED_BRANCHES.map((branch) => branch.name); const protectedBranchNames = () => TEST_PROTECTED_BRANCHES.map((branch) => branch.name);
const error = new Error('Something went wrong'); const error = new Error('Something went wrong');
describe('Branches Select', () => { describe('Protected Branches Selector', () => {
let wrapper; let wrapper;
const findDropdown = () => wrapper.findComponent(GlDropdown); const findDropdown = () => wrapper.findComponent(GlDropdown);
...@@ -23,7 +23,7 @@ describe('Branches Select', () => { ...@@ -23,7 +23,7 @@ describe('Branches Select', () => {
const findSearch = () => wrapper.findComponent(GlSearchBoxByType); const findSearch = () => wrapper.findComponent(GlSearchBoxByType);
const createComponent = (props = {}, mountFn = shallowMount) => { const createComponent = (props = {}, mountFn = shallowMount) => {
wrapper = mountFn(BranchesSelect, { wrapper = mountFn(ProtectedBranchesSelector, {
propsData: { propsData: {
projectId: '1', projectId: '1',
...props, ...props,
...@@ -82,7 +82,7 @@ describe('Branches Select', () => { ...@@ -82,7 +82,7 @@ describe('Branches Select', () => {
expect(findDropdown().props('loading')).toBe(true); expect(findDropdown().props('loading')).toBe(true);
await waitForPromises(); await waitForPromises();
expect(wrapper.emitted().apiError).toStrictEqual([[false]]); expect(wrapper.emitted('apiError')).toStrictEqual([[false]]);
expect(findDropdownItems()).toHaveLength(branchNames().length); expect(findDropdownItems()).toHaveLength(branchNames().length);
expect(findDropdown().props('loading')).toBe(false); expect(findDropdown().props('loading')).toBe(false);
}); });
...@@ -94,7 +94,7 @@ describe('Branches Select', () => { ...@@ -94,7 +94,7 @@ describe('Branches Select', () => {
}); });
it('emits the `apiError` event', () => { it('emits the `apiError` event', () => {
expect(wrapper.emitted().apiError).toStrictEqual([[true, error]]); expect(wrapper.emitted('apiError')).toStrictEqual([[true, error]]);
}); });
it('returns just the any branch dropdown items', () => { it('returns just the any branch dropdown items', () => {
...@@ -119,7 +119,7 @@ describe('Branches Select', () => { ...@@ -119,7 +119,7 @@ describe('Branches Select', () => {
await waitForPromises(); await waitForPromises();
expect(Api.projectProtectedBranches).toHaveBeenCalledWith(TEST_PROJECT_ID, term); expect(Api.projectProtectedBranches).toHaveBeenCalledWith(TEST_PROJECT_ID, term);
expect(wrapper.emitted().apiError).toStrictEqual([[false], [false]]); expect(wrapper.emitted('apiError')).toStrictEqual([[false], [false]]);
expect(findSearch().props('isLoading')).toBe(false); expect(findSearch().props('isLoading')).toBe(false);
}); });
...@@ -146,7 +146,7 @@ describe('Branches Select', () => { ...@@ -146,7 +146,7 @@ describe('Branches Select', () => {
}); });
it('emits the `apiError` event', () => { it('emits the `apiError` event', () => {
expect(wrapper.emitted().apiError).toStrictEqual([[false], [true, error]]); expect(wrapper.emitted('apiError')).toStrictEqual([[false], [true, error]]);
}); });
it('returns no dropdown items', () => { it('returns no dropdown items', () => {
...@@ -163,7 +163,7 @@ describe('Branches Select', () => { ...@@ -163,7 +163,7 @@ describe('Branches Select', () => {
}); });
it('emits the `apiError` event', () => { it('emits the `apiError` event', () => {
expect(wrapper.emitted().apiError).toStrictEqual([[false], [true, error]]); expect(wrapper.emitted('apiError')).toStrictEqual([[false], [true, error]]);
}); });
it('returns just the any branch dropdown item', () => { it('returns just the any branch dropdown item', () => {
...@@ -179,6 +179,6 @@ describe('Branches Select', () => { ...@@ -179,6 +179,6 @@ describe('Branches Select', () => {
await findDropdownItems().at(1).vm.$emit('click'); await findDropdownItems().at(1).vm.$emit('click');
expect(findDropdownItems().at(1).props('isChecked')).toBe(true); expect(findDropdownItems().at(1).props('isChecked')).toBe(true);
expect(wrapper.emitted().input).toStrictEqual([[TEST_PROTECTED_BRANCHES[0]]]); expect(wrapper.emitted('input')).toStrictEqual([[TEST_PROTECTED_BRANCHES[0]]]);
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment