Commit 5970bfc7 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch '334742-validate-timezone-presence' into 'master'

Validate timezone presence on schedule creation form

See merge request gitlab-org/gitlab!66946
parents c3b16b0f ae06e067
...@@ -96,7 +96,16 @@ export default { ...@@ -96,7 +96,16 @@ export default {
}, },
}, },
methods: { methods: {
triggerFormValidation() {
this.validateForm('timezone');
},
createSchedule() { createSchedule() {
this.triggerFormValidation();
if (!this.isFormValid) {
return;
}
this.loading = true; this.loading = true;
const { projectPath } = this; const { projectPath } = this;
...@@ -127,6 +136,7 @@ export default { ...@@ -127,6 +136,7 @@ export default {
if (error) { if (error) {
throw error; throw error;
} }
this.$refs.addUpdateScheduleModal.hide(); this.$refs.addUpdateScheduleModal.hide();
this.$emit('scheduleCreated'); this.$emit('scheduleCreated');
this.clearScheduleForm(); this.clearScheduleForm();
...@@ -140,11 +150,12 @@ export default { ...@@ -140,11 +150,12 @@ export default {
}); });
}, },
editSchedule() { editSchedule() {
this.loading = true;
const { const {
projectPath, projectPath,
form: { timezone }, form: { timezone },
} = this; } = this;
this.loading = true;
this.$apollo this.$apollo
.mutate({ .mutate({
......
import { GlModal, GlAlert } from '@gitlab/ui'; import { GlModal, GlAlert } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import AddEditScheduleForm from 'ee/oncall_schedules/components/add_edit_schedule_form.vue'; import AddEditScheduleForm from 'ee/oncall_schedules/components/add_edit_schedule_form.vue';
import AddEditScheduleModal, { import AddEditScheduleModal, {
...@@ -58,9 +59,9 @@ describe('AddScheduleModal', () => { ...@@ -58,9 +59,9 @@ describe('AddScheduleModal', () => {
}; };
async function awaitApolloDomMock() { async function awaitApolloDomMock() {
await wrapper.vm.$nextTick(); // kick off the DOM update await nextTick(); // kick off the DOM update
await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises) await jest.runOnlyPendingTimers(); // kick off the mocked GQL stuff (promises)
await wrapper.vm.$nextTick(); // kick off the DOM update for flash await nextTick(); // kick off the DOM update for flash
} }
async function updateSchedule(localWrapper) { async function updateSchedule(localWrapper) {
...@@ -119,6 +120,8 @@ describe('AddScheduleModal', () => { ...@@ -119,6 +120,8 @@ describe('AddScheduleModal', () => {
const findAlert = () => wrapper.findComponent(GlAlert); const findAlert = () => wrapper.findComponent(GlAlert);
const findModalForm = () => wrapper.findComponent(AddEditScheduleForm); const findModalForm = () => wrapper.findComponent(AddEditScheduleForm);
const submitForm = () => findModal().vm.$emit('primary', { preventDefault: jest.fn() });
describe('Schedule create', () => { describe('Schedule create', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ modalId: addScheduleModalId }); createComponent({ modalId: addScheduleModalId });
...@@ -134,9 +137,32 @@ describe('AddScheduleModal', () => { ...@@ -134,9 +137,32 @@ describe('AddScheduleModal', () => {
}); });
}); });
it('makes a request with form data to create a schedule', () => { it('prevents form submit if schedule is invalid', () => {
mutate.mockResolvedValueOnce({}); createComponent({
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); modalId: addScheduleModalId,
data: { form: { name: 'schedule', timezone: null } },
});
submitForm();
expect(mutate).not.toHaveBeenCalled();
});
it("doesn't hide a modal and shows error alert on fail", async () => {
const error = 'some error';
mutate.mockImplementation(() => Promise.reject(error));
submitForm();
await waitForPromises();
const alert = findAlert();
expect(mockHideModal).not.toHaveBeenCalled();
expect(alert.exists()).toBe(true);
expect(alert.text()).toContain(error);
});
it('makes a request with form data to create a schedule and hides a modal', async () => {
mutate.mockImplementation(() =>
Promise.resolve({ data: { oncallScheduleCreate: { errors: [] } } }),
);
submitForm();
expect(mutate).toHaveBeenCalledWith({ expect(mutate).toHaveBeenCalledWith({
mutation: expect.any(Object), mutation: expect.any(Object),
update: expect.any(Function), update: expect.any(Function),
...@@ -148,29 +174,15 @@ describe('AddScheduleModal', () => { ...@@ -148,29 +174,15 @@ describe('AddScheduleModal', () => {
}, },
}, },
}); });
});
it('hides the modal on successful schedule creation', async () => {
mutate.mockResolvedValueOnce({ data: { oncallScheduleCreate: { errors: [] } } });
findModal().vm.$emit('primary', { preventDefault: jest.fn() });
await waitForPromises(); await waitForPromises();
expect(mockHideModal).toHaveBeenCalled(); expect(mockHideModal).toHaveBeenCalled();
}); });
it("doesn't hide a modal and shows error alert on fail", async () => {
const error = 'some error';
mutate.mockResolvedValueOnce({ data: { oncallScheduleCreate: { errors: [error] } } });
findModal().vm.$emit('primary', { preventDefault: jest.fn() });
await waitForPromises();
const alert = findAlert();
expect(mockHideModal).not.toHaveBeenCalled();
expect(alert.exists()).toBe(true);
expect(alert.text()).toContain(error);
});
it('should clear the schedule form on a successful creation', () => { it('should clear the schedule form on a successful creation', () => {
mutate.mockResolvedValueOnce({}); mutate.mockImplementation(() =>
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); Promise.resolve({ data: { oncallScheduleCreate: { errors: [] } } }),
);
submitForm();
expect(findModalForm().props('form')).toMatchObject({ expect(findModalForm().props('form')).toMatchObject({
name: '', name: '',
description: '', description: '',
...@@ -194,37 +206,31 @@ describe('AddScheduleModal', () => { ...@@ -194,37 +206,31 @@ describe('AddScheduleModal', () => {
}); });
}); });
describe('Schedule update apollo API call', () => { it("doesn't hide the modal on fail", async () => {
it('makes a request with `oncallScheduleUpdate` to update a schedule', () => { const error = 'some error';
mutate.mockResolvedValueOnce({}); mutate.mockRejectedValueOnce(error);
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); submitForm();
expect(mutate).toHaveBeenCalledWith({ await waitForPromises();
mutation: expect.any(Object), expect(mockHideModal).not.toHaveBeenCalled();
update: expect.anything(), });
variables: {
iid: mockSchedule.iid,
projectPath,
name: mockSchedule.name,
description: mockSchedule.description,
timezone: mockSchedule.timezone.identifier,
},
});
});
it('hides the modal on successful schedule creation', async () => { it('makes a request with `oncallScheduleUpdate` to update a schedule and hides a modal on successful update', async () => {
mutate.mockResolvedValueOnce({ data: { oncallScheduleUpdate: { errors: [] } } }); mutate.mockResolvedValueOnce({ data: { oncallScheduleUpdate: { errors: [] } } });
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); submitForm();
await waitForPromises();
expect(mockHideModal).toHaveBeenCalled();
});
it("doesn't hide the modal on fail", async () => { expect(mutate).toHaveBeenCalledWith({
const error = 'some error'; mutation: expect.any(Object),
mutate.mockResolvedValueOnce({ data: { oncallScheduleUpdate: { errors: [error] } } }); update: expect.anything(),
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); variables: {
await waitForPromises(); iid: mockSchedule.iid,
expect(mockHideModal).not.toHaveBeenCalled(); projectPath,
name: mockSchedule.name,
description: mockSchedule.description,
timezone: mockSchedule.timezone.identifier,
},
}); });
await waitForPromises();
expect(mockHideModal).toHaveBeenCalled();
}); });
describe('with mocked Apollo client', () => { describe('with mocked Apollo client', () => {
...@@ -255,7 +261,7 @@ describe('AddScheduleModal', () => { ...@@ -255,7 +261,7 @@ describe('AddScheduleModal', () => {
it('it should not reload the page if the timezone has not changed', async () => { it('it should not reload the page if the timezone has not changed', async () => {
mutate.mockResolvedValueOnce({}); mutate.mockResolvedValueOnce({});
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); submitForm();
await waitForPromises(); await waitForPromises();
expect(window.location.reload).not.toHaveBeenCalled(); expect(window.location.reload).not.toHaveBeenCalled();
}); });
...@@ -268,7 +274,7 @@ describe('AddScheduleModal', () => { ...@@ -268,7 +274,7 @@ describe('AddScheduleModal', () => {
modalId: editScheduleModalId, modalId: editScheduleModalId,
}); });
mutate.mockResolvedValueOnce({}); mutate.mockResolvedValueOnce({});
findModal().vm.$emit('primary', { preventDefault: jest.fn() }); submitForm();
expect(mutate).toHaveBeenCalledWith({ expect(mutate).toHaveBeenCalledWith({
mutation: updateOncallScheduleMutation, mutation: updateOncallScheduleMutation,
update: expect.anything(), update: expect.anything(),
......
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