Commit 17249ad9 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '118841_05-node-form-api' into 'master'

Geo Node Form in Vue - API/Validations

Closes #118841

See merge request gitlab-org/gitlab!25851
parents 3a166309 c8488d67
...@@ -263,4 +263,14 @@ export default { ...@@ -263,4 +263,14 @@ export default {
return axios.post(url); return axios.post(url);
}, },
createGeoNode(node) {
const url = Api.buildUrl(this.geoNodesPath);
return axios.post(url, node);
},
updateGeoNode(node) {
const url = Api.buildUrl(this.geoNodesPath);
return axios.put(`${url}/${node.id}`, node);
},
}; };
<script> <script>
import { __ } from '~/locale';
import GeoNodeForm from './geo_node_form.vue'; import GeoNodeForm from './geo_node_form.vue';
export default { export default {
...@@ -21,12 +22,17 @@ export default { ...@@ -21,12 +22,17 @@ export default {
default: null, default: null,
}, },
}, },
computed: {
pageTitle() {
return this.node ? __('Edit Geo Node') : __('New Geo Node');
},
},
}; };
</script> </script>
<template> <template>
<article class="geo-node-form-container"> <article class="geo-node-form-container">
<h3 class="page-title">{{ node ? __('Edit Geo Node') : __('New Geo Node') }}</h3> <h3 class="page-title">{{ pageTitle }}</h3>
<geo-node-form v-bind="$props" /> <geo-node-form v-bind="$props" />
</article> </article>
</template> </template>
<script> <script>
import { mapActions } from 'vuex';
import { GlFormGroup, GlFormInput, GlFormCheckbox, GlButton } from '@gitlab/ui'; import { GlFormGroup, GlFormInput, GlFormCheckbox, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import { visitUrl } from '~/lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import GeoNodeFormCore from './geo_node_form_core.vue'; import GeoNodeFormCore from './geo_node_form_core.vue';
import GeoNodeFormSelectiveSync from './geo_node_form_selective_sync.vue'; import GeoNodeFormSelectiveSync from './geo_node_form_selective_sync.vue';
...@@ -50,12 +52,18 @@ export default { ...@@ -50,12 +52,18 @@ export default {
}, },
}; };
}, },
computed: {
saveButtonTitle() {
return this.node ? __('Update') : __('Save');
},
},
created() { created() {
if (this.node) { if (this.node) {
this.nodeData = { ...this.node }; this.nodeData = { ...this.node };
} }
}, },
methods: { methods: {
...mapActions(['saveGeoNode']),
redirect() { redirect() {
visitUrl('/admin/geo/nodes'); visitUrl('/admin/geo/nodes');
}, },
...@@ -115,7 +123,9 @@ export default { ...@@ -115,7 +123,9 @@ export default {
</gl-form-group> </gl-form-group>
</section> </section>
<section class="d-flex align-items-center mt-4"> <section class="d-flex align-items-center mt-4">
<gl-button id="node-save-button" variant="success">{{ __('Save') }}</gl-button> <gl-button id="node-save-button" variant="success" @click="saveGeoNode(nodeData)">{{
saveButtonTitle
}}</gl-button>
<gl-button id="node-cancel-button" class="ml-auto" @click="redirect">{{ <gl-button id="node-cancel-button" class="ml-auto" @click="redirect">{{
__('Cancel') __('Cancel')
}}</gl-button> }}</gl-button>
......
<script> <script>
import { GlFormGroup, GlFormInput, GlSprintf } from '@gitlab/ui'; import { GlFormGroup, GlFormInput, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import { isSafeURL } from '~/lib/utils/url_utility';
export default { export default {
name: 'GeoNodeFormCore', name: 'GeoNodeFormCore',
...@@ -14,12 +16,43 @@ export default { ...@@ -14,12 +16,43 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
fieldBlurs: {
name: false,
url: false,
},
errors: {
name: __('Name must be between 1 and 255 characters'),
url: __('URL must be a valid url (ex: https://gitlab.com)'),
},
};
},
computed: {
validName() {
return !(this.fieldBlurs.name && (!this.nodeData.name || this.nodeData.name.length > 255));
},
validUrl() {
return !(this.fieldBlurs.url && !isSafeURL(this.nodeData.url));
},
},
methods: {
blur(field) {
this.fieldBlurs[field] = true;
},
},
}; };
</script> </script>
<template> <template>
<section class="form-row"> <section class="form-row">
<gl-form-group class="col-sm-6" :label="__('Name')" label-for="node-name-field"> <gl-form-group
class="col-sm-6"
:label="__('Name')"
label-for="node-name-field"
:state="validName"
:invalid-feedback="errors.name"
>
<template #description> <template #description>
<gl-sprintf <gl-sprintf
:message=" :message="
...@@ -36,15 +69,22 @@ export default { ...@@ -36,15 +69,22 @@ export default {
</template> </template>
</gl-sprintf> </gl-sprintf>
</template> </template>
<gl-form-input id="node-name-field" v-model="nodeData.name" type="text" /> <gl-form-input
id="node-name-field"
v-model="nodeData.name"
type="text"
@blur="blur('name')"
/>
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
class="col-sm-6" class="col-sm-6"
:label="__('URL')" :label="__('URL')"
label-for="node-url-field" label-for="node-url-field"
:description="__('The user-facing URL of the Geo node')" :description="__('The user-facing URL of the Geo node')"
:state="validUrl"
:invalid-feedback="errors.url"
> >
<gl-form-input id="node-url-field" v-model="nodeData.url" type="text" /> <gl-form-input id="node-url-field" v-model="nodeData.url" type="text" @blur="blur('url')" />
</gl-form-group> </gl-form-group>
</section> </section>
</template> </template>
import Api from '~/api'; import Api from '~/api';
import ApiEE from 'ee/api';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { visitUrl } from '~/lib/utils/url_utility';
import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -22,3 +25,25 @@ export const fetchSyncNamespaces = ({ dispatch }, search) => { ...@@ -22,3 +25,25 @@ export const fetchSyncNamespaces = ({ dispatch }, search) => {
dispatch('receiveSyncNamespacesError'); dispatch('receiveSyncNamespacesError');
}); });
}; };
export const requestSaveGeoNode = ({ commit }) => commit(types.REQUEST_SAVE_GEO_NODE);
export const receiveSaveGeoNodeSuccess = ({ commit }) => {
commit(types.RECEIVE_SAVE_GEO_NODE_COMPLETE);
visitUrl('/admin/geo/nodes');
};
export const receiveSaveGeoNodeError = ({ commit }) => {
createFlash(__(`There was an error saving this Geo Node`));
commit(types.RECEIVE_SAVE_GEO_NODE_COMPLETE);
};
export const saveGeoNode = ({ dispatch }, node) => {
dispatch('requestSaveGeoNode');
const sanitizedNode = convertObjectPropsToSnakeCase(node);
const saveFunc = node.id ? 'updateGeoNode' : 'createGeoNode';
ApiEE[saveFunc](sanitizedNode)
.then(() => dispatch('receiveSaveGeoNodeSuccess'))
.catch(() => {
dispatch('receiveSaveGeoNodeError');
});
};
export const REQUEST_SYNC_NAMESPACES = 'REQUEST_SYNC_NAMESPACES'; export const REQUEST_SYNC_NAMESPACES = 'REQUEST_SYNC_NAMESPACES';
export const RECEIVE_SYNC_NAMESPACES_SUCCESS = 'RECEIVE_SYNC_NAMESPACES_SUCCESS'; export const RECEIVE_SYNC_NAMESPACES_SUCCESS = 'RECEIVE_SYNC_NAMESPACES_SUCCESS';
export const RECEIVE_SYNC_NAMESPACES_ERROR = 'RECEIVE_SYNC_NAMESPACES_ERROR'; export const RECEIVE_SYNC_NAMESPACES_ERROR = 'RECEIVE_SYNC_NAMESPACES_ERROR';
export const REQUEST_SAVE_GEO_NODE = 'REQUEST_SAVE_GEO_NODE';
export const RECEIVE_SAVE_GEO_NODE_COMPLETE = 'RECEIVE_SAVE_GEO_NODE_COMPLETE';
...@@ -12,4 +12,10 @@ export default { ...@@ -12,4 +12,10 @@ export default {
state.isLoading = false; state.isLoading = false;
state.synchronizationNamespaces = []; state.synchronizationNamespaces = [];
}, },
[types.REQUEST_SAVE_GEO_NODE](state) {
state.isLoading = true;
},
[types.RECEIVE_SAVE_GEO_NODE_COMPLETE](state) {
state.isLoading = false;
},
}; };
...@@ -641,4 +641,52 @@ describe('Api', () => { ...@@ -641,4 +641,52 @@ describe('Api', () => {
}); });
}); });
}); });
describe('GeoNode', () => {
let expectedUrl;
let mockNode;
beforeEach(() => {
expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/geo_nodes`;
});
describe('createGeoNode', () => {
it('POSTs with correct action', () => {
mockNode = {
name: 'Mock Node',
url: 'https://mock_node.gitlab.com',
primary: false,
};
jest.spyOn(Api, 'buildUrl').mockReturnValue(expectedUrl);
jest.spyOn(axios, 'post');
mock.onPost(expectedUrl).replyOnce(201, mockNode);
return Api.createGeoNode(mockNode).then(({ data }) => {
expect(data).toEqual(mockNode);
expect(axios.post).toHaveBeenCalledWith(expectedUrl, mockNode);
});
});
});
describe('updateGeoNode', () => {
it('PUTs with correct action', () => {
mockNode = {
id: 1,
name: 'Mock Node',
url: 'https://mock_node.gitlab.com',
primary: false,
};
jest.spyOn(Api, 'buildUrl').mockReturnValue(expectedUrl);
jest.spyOn(axios, 'put');
mock.onPut(`${expectedUrl}/${mockNode.id}`).replyOnce(201, mockNode);
return Api.updateGeoNode(mockNode).then(({ data }) => {
expect(data).toEqual(mockNode);
expect(axios.put).toHaveBeenCalledWith(`${expectedUrl}/${mockNode.id}`, mockNode);
});
});
});
});
}); });
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import GeoNodeFormCore from 'ee/geo_node_form/components/geo_node_form_core.vue'; import GeoNodeFormCore from 'ee/geo_node_form/components/geo_node_form_core.vue';
import { MOCK_NODE } from '../mock_data'; import { MOCK_NODE, STRING_OVER_255 } from '../mock_data';
describe('GeoNodeFormCore', () => { describe('GeoNodeFormCore', () => {
let wrapper; let wrapper;
const propsData = { const defaultProps = {
nodeData: MOCK_NODE, nodeData: MOCK_NODE,
}; };
const createComponent = () => { const createComponent = (props = {}) => {
wrapper = shallowMount(GeoNodeFormCore, { wrapper = shallowMount(GeoNodeFormCore, {
propsData, propsData: {
...defaultProps,
...props,
},
}); });
}; };
...@@ -35,4 +38,68 @@ describe('GeoNodeFormCore', () => { ...@@ -35,4 +38,68 @@ describe('GeoNodeFormCore', () => {
expect(findGeoNodeFormUrlField().exists()).toBe(true); expect(findGeoNodeFormUrlField().exists()).toBe(true);
}); });
}); });
describe('computed', () => {
describe.each`
data | dataDesc | blur | value
${''} | ${'empty'} | ${false} | ${true}
${''} | ${'empty'} | ${true} | ${false}
${STRING_OVER_255} | ${'over 255 chars'} | ${false} | ${true}
${STRING_OVER_255} | ${'over 255 chars'} | ${true} | ${false}
${'Test'} | ${'valid'} | ${false} | ${true}
${'Test'} | ${'valid'} | ${true} | ${true}
`(`validName`, ({ data, dataDesc, blur, value }) => {
beforeEach(() => {
createComponent({
nodeData: { ...defaultProps.nodeData, name: data },
});
});
describe(`when data is: ${dataDesc}`, () => {
it(`returns ${value} when blur is ${blur}`, () => {
wrapper.vm.fieldBlurs.name = blur;
expect(wrapper.vm.validName).toBe(value);
});
});
});
describe.each`
data | dataDesc | blur | value
${''} | ${'empty'} | ${false} | ${true}
${''} | ${'empty'} | ${true} | ${false}
${'abcd'} | ${'invalid url'} | ${false} | ${true}
${'abcd'} | ${'invalid url'} | ${true} | ${false}
${'https://gitlab.com'} | ${'valid url'} | ${false} | ${true}
${'https://gitlab.com'} | ${'valid url'} | ${true} | ${true}
`(`validUrl`, ({ data, dataDesc, blur, value }) => {
beforeEach(() => {
createComponent({
nodeData: { ...defaultProps.nodeData, url: data },
});
});
describe(`when data is: ${dataDesc}`, () => {
it(`returns ${value} when blur is ${blur}`, () => {
wrapper.vm.fieldBlurs.url = blur;
expect(wrapper.vm.validUrl).toBe(value);
});
});
});
});
describe('methods', () => {
describe('blur', () => {
beforeEach(() => {
createComponent();
});
it('sets fieldBlur[field] to true', () => {
expect(wrapper.vm.fieldBlurs.name).toBeFalsy();
wrapper.vm.blur('name');
expect(wrapper.vm.fieldBlurs.name).toBeTruthy();
});
});
});
}); });
...@@ -33,6 +33,7 @@ describe('GeoNodeForm', () => { ...@@ -33,6 +33,7 @@ describe('GeoNodeForm', () => {
const findGeoNodeInternalUrlField = () => wrapper.find('#node-internal-url-field'); const findGeoNodeInternalUrlField = () => wrapper.find('#node-internal-url-field');
const findGeoNodeFormCapacitiesField = () => wrapper.find(GeoNodeFormCapacities); const findGeoNodeFormCapacitiesField = () => wrapper.find(GeoNodeFormCapacities);
const findGeoNodeObjectStorageField = () => wrapper.find('#node-object-storage-field'); const findGeoNodeObjectStorageField = () => wrapper.find('#node-object-storage-field');
const findGeoNodeSaveButton = () => wrapper.find('#node-save-button');
const findGeoNodeCancelButton = () => wrapper.find('#node-cancel-button'); const findGeoNodeCancelButton = () => wrapper.find('#node-cancel-button');
describe('template', () => { describe('template', () => {
...@@ -84,6 +85,18 @@ describe('GeoNodeForm', () => { ...@@ -84,6 +85,18 @@ describe('GeoNodeForm', () => {
}); });
describe('methods', () => { describe('methods', () => {
describe('saveGeoNode', () => {
beforeEach(() => {
createComponent();
wrapper.vm.saveGeoNode = jest.fn();
});
it('calls saveGeoNode when save is clicked', () => {
findGeoNodeSaveButton().vm.$emit('click');
expect(wrapper.vm.saveGeoNode).toHaveBeenCalledWith(MOCK_NODE);
});
});
describe('redirect', () => { describe('redirect', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponent();
...@@ -91,7 +104,7 @@ describe('GeoNodeForm', () => { ...@@ -91,7 +104,7 @@ describe('GeoNodeForm', () => {
it('calls visitUrl when cancel is clicked', () => { it('calls visitUrl when cancel is clicked', () => {
findGeoNodeCancelButton().vm.$emit('click'); findGeoNodeCancelButton().vm.$emit('click');
expect(visitUrl).toHaveBeenCalled(); expect(visitUrl).toHaveBeenCalledWith('/admin/geo/nodes');
}); });
}); });
......
...@@ -43,6 +43,9 @@ export const MOCK_SYNC_NAMESPACES = [ ...@@ -43,6 +43,9 @@ export const MOCK_SYNC_NAMESPACES = [
}, },
]; ];
export const STRING_OVER_255 =
'ynzF7m5XjQQAlHfzPpDLhiaFZH84Zds47cHLWpRqRGTKjmXCe4frDWjIrjzfchpoOOX2jmK4wLRbyw9oTuzFmMPZhTK14mVoZTfaLXOBeH9F0S1XT3v7kszTC4cMLJvNsto7iSQ2PGxTGpZXFSQTL2UuMTTQ5GiARLVLS7CEEW75orbJh5kbKM6CRXpu4EliGRKKSwHMtXQ2ZDi01yvWOXc7ymNHeEooT4aDC7xq7g1uslbq1aVEWylVixSDARob';
export const MOCK_NODE = { export const MOCK_NODE = {
id: 1, id: 1,
name: 'Mock Node', name: 'Mock Node',
......
...@@ -2,17 +2,31 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -2,17 +2,31 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import flash from '~/flash'; import flash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import * as actions from 'ee/geo_node_form/store/actions'; import * as actions from 'ee/geo_node_form/store/actions';
import * as types from 'ee/geo_node_form/store/mutation_types'; import * as types from 'ee/geo_node_form/store/mutation_types';
import createState from 'ee/geo_node_form/store/state'; import createState from 'ee/geo_node_form/store/state';
import { MOCK_SYNC_NAMESPACES } from '../mock_data'; import { MOCK_SYNC_NAMESPACES, MOCK_NODE } from '../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrlMock'),
joinPaths: jest.fn(),
}));
describe('GeoNodeForm Store Actions', () => { describe('GeoNodeForm Store Actions', () => {
let state; let state;
let mock; let mock;
const noCallback = () => {};
const flashCallback = () => {
expect(flash).toHaveBeenCalledTimes(1);
flash.mockClear();
};
const visitUrlCallback = () => {
expect(visitUrl).toHaveBeenCalledWith('/admin/geo/nodes');
};
beforeEach(() => { beforeEach(() => {
state = createState(); state = createState();
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
...@@ -22,83 +36,39 @@ describe('GeoNodeForm Store Actions', () => { ...@@ -22,83 +36,39 @@ describe('GeoNodeForm Store Actions', () => {
mock.restore(); mock.restore();
}); });
describe('requestSyncNamespaces', () => { describe.each`
it('should commit mutation REQUEST_SYNC_NAMESPACES', done => { action | data | mutationName | mutationCall | callback
testAction( ${actions.requestSyncNamespaces} | ${null} | ${types.REQUEST_SYNC_NAMESPACES} | ${{ type: types.REQUEST_SYNC_NAMESPACES }} | ${noCallback}
actions.requestSyncNamespaces, ${actions.receiveSyncNamespacesSuccess} | ${MOCK_SYNC_NAMESPACES} | ${types.RECEIVE_SYNC_NAMESPACES_SUCCESS} | ${{ type: types.RECEIVE_SYNC_NAMESPACES_SUCCESS, payload: MOCK_SYNC_NAMESPACES }} | ${noCallback}
null, ${actions.receiveSyncNamespacesError} | ${null} | ${types.RECEIVE_SYNC_NAMESPACES_ERROR} | ${{ type: types.RECEIVE_SYNC_NAMESPACES_ERROR }} | ${flashCallback}
state, ${actions.requestSaveGeoNode} | ${null} | ${types.REQUEST_SAVE_GEO_NODE} | ${{ type: types.REQUEST_SAVE_GEO_NODE }} | ${noCallback}
[{ type: types.REQUEST_SYNC_NAMESPACES }], ${actions.receiveSaveGeoNodeSuccess} | ${null} | ${types.RECEIVE_SAVE_GEO_NODE_COMPLETE} | ${{ type: types.RECEIVE_SAVE_GEO_NODE_COMPLETE }} | ${visitUrlCallback}
[], ${actions.receiveSaveGeoNodeError} | ${null} | ${types.RECEIVE_SAVE_GEO_NODE_COMPLETE} | ${{ type: types.RECEIVE_SAVE_GEO_NODE_COMPLETE }} | ${flashCallback}
done, `(`non-axios calls`, ({ action, data, mutationName, mutationCall, callback }) => {
); describe(action.name, () => {
}); it(`should commit mutation ${mutationName}`, () => {
}); testAction(action, data, state, [mutationCall], [], callback);
describe('receiveSyncNamespacesSuccess', () => {
it('should commit mutation RECEIVE_SYNC_NAMESPACES_SUCCESS', done => {
testAction(
actions.receiveSyncNamespacesSuccess,
MOCK_SYNC_NAMESPACES,
state,
[{ type: types.RECEIVE_SYNC_NAMESPACES_SUCCESS, payload: MOCK_SYNC_NAMESPACES }],
[],
done,
);
});
});
describe('receiveSyncNamespacesError', () => {
it('should commit mutation RECEIVE_SYNC_NAMESPACES_ERROR', () => {
testAction(
actions.receiveSyncNamespacesError,
null,
state,
[{ type: types.RECEIVE_SYNC_NAMESPACES_ERROR }],
[],
() => {
expect(flash).toHaveBeenCalledTimes(1);
flash.mockClear();
},
);
});
});
describe('fetchSyncNamespaces', () => {
describe('on success', () => {
beforeEach(() => {
mock.onGet().replyOnce(200, MOCK_SYNC_NAMESPACES);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchSyncNamespaces,
{},
state,
[],
[
{ type: 'requestSyncNamespaces' },
{ type: 'receiveSyncNamespacesSuccess', payload: MOCK_SYNC_NAMESPACES },
],
done,
);
}); });
}); });
});
describe('on error', () => { describe.each`
beforeEach(() => { action | axiosMock | data | type | actionCalls
mock.onGet().replyOnce(500, {}); ${actions.fetchSyncNamespaces} | ${{ method: 'onGet', code: 200, res: MOCK_SYNC_NAMESPACES }} | ${null} | ${'success'} | ${[{ type: 'requestSyncNamespaces' }, { type: 'receiveSyncNamespacesSuccess', payload: MOCK_SYNC_NAMESPACES }]}
}); ${actions.fetchSyncNamespaces} | ${{ method: 'onGet', code: 500, res: null }} | ${null} | ${'error'} | ${[{ type: 'requestSyncNamespaces' }, { type: 'receiveSyncNamespacesError' }]}
${actions.saveGeoNode} | ${{ method: 'onPost', code: 200, res: { ...MOCK_NODE, id: null } }} | ${{ ...MOCK_NODE, id: null }} | ${'success'} | ${[{ type: 'requestSaveGeoNode' }, { type: 'receiveSaveGeoNodeSuccess' }]}
it('should dispatch the request and error actions', done => { ${actions.saveGeoNode} | ${{ method: 'onPost', code: 500, res: null }} | ${{ ...MOCK_NODE, id: null }} | ${'error'} | ${[{ type: 'requestSaveGeoNode' }, { type: 'receiveSaveGeoNodeError' }]}
testAction( ${actions.saveGeoNode} | ${{ method: 'onPut', code: 200, res: MOCK_NODE }} | ${MOCK_NODE} | ${'success'} | ${[{ type: 'requestSaveGeoNode' }, { type: 'receiveSaveGeoNodeSuccess' }]}
actions.fetchSyncNamespaces, ${actions.saveGeoNode} | ${{ method: 'onPut', code: 500, res: null }} | ${MOCK_NODE} | ${'error'} | ${[{ type: 'requestSaveGeoNode' }, { type: 'receiveSaveGeoNodeError' }]}
{}, `(`axios calls`, ({ action, axiosMock, data, type, actionCalls }) => {
state, describe(action.name, () => {
[], describe(`on ${type}`, () => {
[{ type: 'requestSyncNamespaces' }, { type: 'receiveSyncNamespacesError' }], beforeEach(() => {
done, mock[axiosMock.method]().replyOnce(axiosMock.code, axiosMock.res);
); });
it(`should dispatch the correct request and actions`, done => {
testAction(action, data, state, [], actionCalls, done);
});
}); });
}); });
}); });
......
...@@ -9,21 +9,26 @@ describe('GeoNodeForm Store Mutations', () => { ...@@ -9,21 +9,26 @@ describe('GeoNodeForm Store Mutations', () => {
state = createState(); state = createState();
}); });
describe('REQUEST_SYNC_NAMESPACES', () => { describe.each`
it('sets isLoading to true', () => { mutation | loadingBefore | loadingAfter
mutations[types.REQUEST_SYNC_NAMESPACES](state); ${types.REQUEST_SYNC_NAMESPACES} | ${false} | ${true}
expect(state.isLoading).toEqual(true); ${types.RECEIVE_SYNC_NAMESPACES_SUCCESS} | ${true} | ${false}
${types.RECEIVE_SYNC_NAMESPACES_ERROR} | ${true} | ${false}
${types.REQUEST_SAVE_GEO_NODE} | ${false} | ${true}
${types.RECEIVE_SAVE_GEO_NODE_COMPLETE} | ${true} | ${false}
${types.RECEIVE_SAVE_GEO_NODE_COMPLETE} | ${true} | ${false}
`(`Loading Mutations: `, ({ mutation, loadingBefore, loadingAfter }) => {
describe(`${mutation}`, () => {
it(`sets isLoading to ${loadingAfter}`, () => {
state.isLoading = loadingBefore;
mutations[mutation](state);
expect(state.isLoading).toEqual(loadingAfter);
});
}); });
}); });
describe('RECEIVE_SYNC_NAMESPACES_SUCCESS', () => { describe('RECEIVE_SYNC_NAMESPACES_SUCCESS', () => {
it('sets isLoading to false', () => {
state.isLoading = true;
mutations[types.RECEIVE_SYNC_NAMESPACES_SUCCESS](state, MOCK_SYNC_NAMESPACES);
expect(state.isLoading).toEqual(false);
});
it('sets synchronizationNamespaces array with namespace data', () => { it('sets synchronizationNamespaces array with namespace data', () => {
mutations[types.RECEIVE_SYNC_NAMESPACES_SUCCESS](state, MOCK_SYNC_NAMESPACES); mutations[types.RECEIVE_SYNC_NAMESPACES_SUCCESS](state, MOCK_SYNC_NAMESPACES);
expect(state.synchronizationNamespaces).toBe(MOCK_SYNC_NAMESPACES); expect(state.synchronizationNamespaces).toBe(MOCK_SYNC_NAMESPACES);
...@@ -31,13 +36,6 @@ describe('GeoNodeForm Store Mutations', () => { ...@@ -31,13 +36,6 @@ describe('GeoNodeForm Store Mutations', () => {
}); });
describe('RECEIVE_SYNC_NAMESPACES_ERROR', () => { describe('RECEIVE_SYNC_NAMESPACES_ERROR', () => {
it('sets isLoading to false', () => {
state.isLoading = true;
mutations[types.RECEIVE_SYNC_NAMESPACES_ERROR](state);
expect(state.isLoading).toEqual(false);
});
it('resets synchronizationNamespaces array', () => { it('resets synchronizationNamespaces array', () => {
state.synchronizationNamespaces = MOCK_SYNC_NAMESPACES; state.synchronizationNamespaces = MOCK_SYNC_NAMESPACES;
......
...@@ -12960,6 +12960,9 @@ msgstr "" ...@@ -12960,6 +12960,9 @@ msgstr ""
msgid "Name has already been taken" msgid "Name has already been taken"
msgstr "" msgstr ""
msgid "Name must be between 1 and 255 characters"
msgstr ""
msgid "Name new label" msgid "Name new label"
msgstr "" msgstr ""
...@@ -20099,6 +20102,9 @@ msgstr "" ...@@ -20099,6 +20102,9 @@ msgstr ""
msgid "There was an error resetting user pipeline minutes." msgid "There was an error resetting user pipeline minutes."
msgstr "" msgstr ""
msgid "There was an error saving this Geo Node"
msgstr ""
msgid "There was an error saving your changes." msgid "There was an error saving your changes."
msgstr "" msgstr ""
...@@ -21264,6 +21270,9 @@ msgstr "" ...@@ -21264,6 +21270,9 @@ msgstr ""
msgid "URL" msgid "URL"
msgstr "" msgstr ""
msgid "URL must be a valid url (ex: https://gitlab.com)"
msgstr ""
msgid "URL of the external storage that will serve the repository static objects (e.g. archives, blobs, ...)." msgid "URL of the external storage that will serve the repository static objects (e.g. archives, blobs, ...)."
msgstr "" msgstr ""
......
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