Commit 6b063be7 authored by Illya Klymov's avatar Illya Klymov

Ensure error reported when bulk import target is existing project

When targetting existing project using bulk import feature report
correct error
parent 7222bd20
...@@ -15,7 +15,7 @@ import ImportStatus from '../../components/import_status.vue'; ...@@ -15,7 +15,7 @@ import ImportStatus from '../../components/import_status.vue';
import { STATUSES } from '../../constants'; import { STATUSES } from '../../constants';
import addValidationErrorMutation from '../graphql/mutations/add_validation_error.mutation.graphql'; import addValidationErrorMutation from '../graphql/mutations/add_validation_error.mutation.graphql';
import removeValidationErrorMutation from '../graphql/mutations/remove_validation_error.mutation.graphql'; import removeValidationErrorMutation from '../graphql/mutations/remove_validation_error.mutation.graphql';
import groupQuery from '../graphql/queries/group.query.graphql'; import groupAndProjectQuery from '../graphql/queries/groupAndProject.query.graphql';
const DEBOUNCE_INTERVAL = 300; const DEBOUNCE_INTERVAL = 300;
...@@ -47,21 +47,21 @@ export default { ...@@ -47,21 +47,21 @@ export default {
}, },
apollo: { apollo: {
existingGroup: { existingGroupAndProject: {
query: groupQuery, query: groupAndProjectQuery,
debounce: DEBOUNCE_INTERVAL, debounce: DEBOUNCE_INTERVAL,
variables() { variables() {
return { return {
fullPath: this.fullPath, fullPath: this.fullPath,
}; };
}, },
update({ existingGroup }) { update({ existingGroup, existingProject }) {
const variables = { const variables = {
field: 'new_name', field: 'new_name',
sourceGroupId: this.group.id, sourceGroupId: this.group.id,
}; };
if (!existingGroup) { if (!existingGroup && !existingProject) {
this.$apollo.mutate({ this.$apollo.mutate({
mutation: removeValidationErrorMutation, mutation: removeValidationErrorMutation,
variables, variables,
...@@ -71,7 +71,7 @@ export default { ...@@ -71,7 +71,7 @@ export default {
mutation: addValidationErrorMutation, mutation: addValidationErrorMutation,
variables: { variables: {
...variables, ...variables,
message: s__('BulkImport|Name already exists.'), message: this.$options.i18n.NAME_ALREADY_EXISTS,
}, },
}); });
} }
...@@ -115,6 +115,10 @@ export default { ...@@ -115,6 +115,10 @@ export default {
return joinPaths(gon.relative_url_root || '/', this.fullPath); return joinPaths(gon.relative_url_root || '/', this.fullPath);
}, },
}, },
i18n: {
NAME_ALREADY_EXISTS: s__('BulkImport|Name already exists.'),
},
}; };
</script> </script>
......
query group($fullPath: ID!) { query groupAndProject($fullPath: ID!) {
existingGroup: group(fullPath: $fullPath) { existingGroup: group(fullPath: $fullPath) {
id id
} }
existingProject: project(fullPath: $fullPath) {
id
}
} }
...@@ -5,11 +5,15 @@ import VueApollo from 'vue-apollo'; ...@@ -5,11 +5,15 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import { STATUSES } from '~/import_entities/constants'; import { STATUSES } from '~/import_entities/constants';
import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue'; import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue';
import groupQuery from '~/import_entities/import_groups/graphql/queries/group.query.graphql'; import addValidationErrorMutation from '~/import_entities/import_groups/graphql/mutations/add_validation_error.mutation.graphql';
import removeValidationErrorMutation from '~/import_entities/import_groups/graphql/mutations/remove_validation_error.mutation.graphql';
import groupAndProjectQuery from '~/import_entities/import_groups/graphql/queries/groupAndProject.query.graphql';
import { availableNamespacesFixture } from '../graphql/fixtures'; import { availableNamespacesFixture } from '../graphql/fixtures';
Vue.use(VueApollo); Vue.use(VueApollo);
const { i18n: I18N } = ImportTableRow;
const getFakeGroup = (status) => ({ const getFakeGroup = (status) => ({
web_url: 'https://fake.host/', web_url: 'https://fake.host/',
full_path: 'fake_group_1', full_path: 'fake_group_1',
...@@ -25,6 +29,7 @@ const getFakeGroup = (status) => ({ ...@@ -25,6 +29,7 @@ const getFakeGroup = (status) => ({
const EXISTING_GROUP_TARGET_NAMESPACE = 'existing-group'; const EXISTING_GROUP_TARGET_NAMESPACE = 'existing-group';
const EXISTING_GROUP_PATH = 'existing-path'; const EXISTING_GROUP_PATH = 'existing-path';
const EXISTING_PROJECT_PATH = 'existing-project-path';
describe('import table row', () => { describe('import table row', () => {
let wrapper; let wrapper;
...@@ -41,13 +46,19 @@ describe('import table row', () => { ...@@ -41,13 +46,19 @@ describe('import table row', () => {
const createComponent = (props) => { const createComponent = (props) => {
apolloProvider = createMockApollo([ apolloProvider = createMockApollo([
[ [
groupQuery, groupAndProjectQuery,
({ fullPath }) => { ({ fullPath }) => {
const existingGroup = const existingGroup =
fullPath === `${EXISTING_GROUP_TARGET_NAMESPACE}/${EXISTING_GROUP_PATH}` fullPath === `${EXISTING_GROUP_TARGET_NAMESPACE}/${EXISTING_GROUP_PATH}`
? { id: 1 } ? { id: 1 }
: null; : null;
return Promise.resolve({ data: { existingGroup } });
const existingProject =
fullPath === `${EXISTING_GROUP_TARGET_NAMESPACE}/${EXISTING_PROJECT_PATH}`
? { id: 1 }
: null;
return Promise.resolve({ data: { existingGroup, existingProject } });
}, },
], ],
]); ]);
...@@ -173,7 +184,7 @@ describe('import table row', () => { ...@@ -173,7 +184,7 @@ describe('import table row', () => {
}); });
describe('validations', () => { describe('validations', () => {
it('Reports invalid group name when name is not matching regex', () => { it('reports invalid group name when name is not matching regex', () => {
createComponent({ createComponent({
group: { group: {
...getFakeGroup(STATUSES.NONE), ...getFakeGroup(STATUSES.NONE),
...@@ -188,7 +199,7 @@ describe('import table row', () => { ...@@ -188,7 +199,7 @@ describe('import table row', () => {
expect(wrapper.text()).toContain('Please choose a group URL with no special characters.'); expect(wrapper.text()).toContain('Please choose a group URL with no special characters.');
}); });
it('Reports invalid group name if relevant validation error exists', async () => { it('reports invalid group name if relevant validation error exists', async () => {
const FAKE_ERROR_MESSAGE = 'fake error'; const FAKE_ERROR_MESSAGE = 'fake error';
createComponent({ createComponent({
...@@ -208,5 +219,101 @@ describe('import table row', () => { ...@@ -208,5 +219,101 @@ describe('import table row', () => {
expect(wrapper.text()).toContain(FAKE_ERROR_MESSAGE); expect(wrapper.text()).toContain(FAKE_ERROR_MESSAGE);
}); });
it('sets validation error when targetting existing group', async () => {
const testGroup = getFakeGroup(STATUSES.NONE);
createComponent({
group: {
...testGroup,
import_target: {
target_namespace: EXISTING_GROUP_TARGET_NAMESPACE,
new_name: EXISTING_GROUP_PATH,
},
},
});
jest.spyOn(wrapper.vm.$apollo, 'mutate');
jest.runOnlyPendingTimers();
await nextTick();
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: addValidationErrorMutation,
variables: {
field: 'new_name',
message: I18N.NAME_ALREADY_EXISTS,
sourceGroupId: testGroup.id,
},
});
});
it('sets validation error when targetting existing project', async () => {
const testGroup = getFakeGroup(STATUSES.NONE);
createComponent({
group: {
...testGroup,
import_target: {
target_namespace: EXISTING_GROUP_TARGET_NAMESPACE,
new_name: EXISTING_PROJECT_PATH,
},
},
});
jest.spyOn(wrapper.vm.$apollo, 'mutate');
jest.runOnlyPendingTimers();
await nextTick();
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: addValidationErrorMutation,
variables: {
field: 'new_name',
message: I18N.NAME_ALREADY_EXISTS,
sourceGroupId: testGroup.id,
},
});
});
it('clears validation error when target is updated', async () => {
const testGroup = getFakeGroup(STATUSES.NONE);
createComponent({
group: {
...testGroup,
import_target: {
target_namespace: EXISTING_GROUP_TARGET_NAMESPACE,
new_name: EXISTING_PROJECT_PATH,
},
},
});
jest.runOnlyPendingTimers();
await nextTick();
jest.spyOn(wrapper.vm.$apollo, 'mutate');
await wrapper.setProps({
group: {
...testGroup,
import_target: {
target_namespace: 'valid_namespace',
new_name: 'valid_path',
},
},
});
jest.runOnlyPendingTimers();
await nextTick();
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: removeValidationErrorMutation,
variables: {
field: 'new_name',
sourceGroupId: testGroup.id,
},
});
});
}); });
}); });
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