Commit 61e9fcf3 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '300689-use-mock-apollo-to-test-commit-section-mutation' into 'master'

Use mock apollo to test commit section mutation

See merge request gitlab-org/gitlab!75267
parents 41fc3257 3621d16d
...@@ -87,7 +87,7 @@ export default { ...@@ -87,7 +87,7 @@ export default {
try { try {
const { const {
data: { data: {
commitCreate: { errors }, commitCreate: { errors, commitPipelinePath: pipelineEtag },
}, },
} = await this.$apollo.mutate({ } = await this.$apollo.mutate({
mutation: commitCIFile, mutation: commitCIFile,
...@@ -101,14 +101,12 @@ export default { ...@@ -101,14 +101,12 @@ export default {
content: this.ciFileContent, content: this.ciFileContent,
lastCommitId: this.commitSha, lastCommitId: this.commitSha,
}, },
update(_, { data }) {
const pipelineEtag = data?.commitCreate?.commit?.commitPipelinePath;
if (pipelineEtag) {
this.$apollo.mutate({ mutation: updatePipelineEtag, variables: pipelineEtag });
}
},
}); });
if (pipelineEtag) {
this.updatePipelineEtag(pipelineEtag);
}
if (errors?.length) { if (errors?.length) {
this.$emit('showError', { type: COMMIT_FAILURE, reasons: errors }); this.$emit('showError', { type: COMMIT_FAILURE, reasons: errors });
} else if (openMergeRequest) { } else if (openMergeRequest) {
...@@ -139,6 +137,9 @@ export default { ...@@ -139,6 +137,9 @@ export default {
variables: { lastCommitBranch }, variables: { lastCommitBranch },
}); });
}, },
updatePipelineEtag(pipelineEtag) {
this.$apollo.mutate({ mutation: updatePipelineEtag, variables: { pipelineEtag } });
},
}, },
}; };
</script> </script>
......
...@@ -19,7 +19,9 @@ mutation commitCIFile( ...@@ -19,7 +19,9 @@ mutation commitCIFile(
] ]
} }
) { ) {
__typename
commit { commit {
__typename
sha sha
} }
commitPipelinePath commitPipelinePath
......
import { nextTick } from 'vue';
import { GlFormInput, GlFormTextarea } from '@gitlab/ui'; import { GlFormInput, GlFormTextarea } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
...@@ -32,7 +33,6 @@ describe('Pipeline Editor | Commit Form', () => { ...@@ -32,7 +33,6 @@ describe('Pipeline Editor | Commit Form', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
describe('when the form is displayed', () => { describe('when the form is displayed', () => {
...@@ -121,7 +121,7 @@ describe('Pipeline Editor | Commit Form', () => { ...@@ -121,7 +121,7 @@ describe('Pipeline Editor | Commit Form', () => {
beforeEach(async () => { beforeEach(async () => {
createComponent(); createComponent();
wrapper.setProps({ scrollToCommitForm: true }); wrapper.setProps({ scrollToCommitForm: true });
await wrapper.vm.$nextTick(); await nextTick();
}); });
it('scrolls into view', () => { it('scrolls into view', () => {
......
import VueApollo from 'vue-apollo';
import { GlFormTextarea, GlFormInput, GlLoadingIcon } from '@gitlab/ui'; import { GlFormTextarea, GlFormInput, GlLoadingIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { createLocalVue, mount } from '@vue/test-utils';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { objectToQuery, redirectTo } from '~/lib/utils/url_utility'; import { objectToQuery, redirectTo } from '~/lib/utils/url_utility';
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
...@@ -10,18 +12,22 @@ import { ...@@ -10,18 +12,22 @@ import {
COMMIT_SUCCESS, COMMIT_SUCCESS,
} from '~/pipeline_editor/constants'; } from '~/pipeline_editor/constants';
import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql'; import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql';
import updatePipelineEtag from '~/pipeline_editor/graphql/mutations/update_pipeline_etag.mutation.graphql';
import { import {
mockCiConfigPath, mockCiConfigPath,
mockCiYml, mockCiYml,
mockCommitCreateResponse,
mockCommitCreateResponseNewEtag,
mockCommitSha, mockCommitSha,
mockCommitNextSha,
mockCommitMessage, mockCommitMessage,
mockDefaultBranch, mockDefaultBranch,
mockProjectFullPath, mockProjectFullPath,
mockNewMergeRequestPath, mockNewMergeRequestPath,
} from '../../mock_data'; } from '../../mock_data';
const localVue = createLocalVue();
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(), redirectTo: jest.fn(),
refreshCurrentPage: jest.fn(), refreshCurrentPage: jest.fn(),
...@@ -47,7 +53,8 @@ const mockProvide = { ...@@ -47,7 +53,8 @@ const mockProvide = {
describe('Pipeline Editor | Commit section', () => { describe('Pipeline Editor | Commit section', () => {
let wrapper; let wrapper;
let mockMutate; let mockApollo;
const mockMutateCommitData = jest.fn();
const defaultProps = { const defaultProps = {
ciFileContent: mockCiYml, ciFileContent: mockCiYml,
...@@ -55,18 +62,7 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -55,18 +62,7 @@ describe('Pipeline Editor | Commit section', () => {
isNewCiConfigFile: false, isNewCiConfigFile: false,
}; };
const createComponent = ({ props = {}, options = {}, provide = {} } = {}) => { const createComponent = ({ apolloConfig = {}, props = {}, options = {}, provide = {} } = {}) => {
mockMutate = jest.fn().mockResolvedValue({
data: {
commitCreate: {
errors: [],
commit: {
sha: mockCommitNextSha,
},
},
},
});
wrapper = mount(CommitSection, { wrapper = mount(CommitSection, {
propsData: { ...defaultProps, ...props }, propsData: { ...defaultProps, ...props },
provide: { ...mockProvide, ...provide }, provide: { ...mockProvide, ...provide },
...@@ -75,16 +71,25 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -75,16 +71,25 @@ describe('Pipeline Editor | Commit section', () => {
currentBranch: mockDefaultBranch, currentBranch: mockDefaultBranch,
}; };
}, },
mocks: {
$apollo: {
mutate: mockMutate,
},
},
attachTo: document.body, attachTo: document.body,
...apolloConfig,
...options, ...options,
}); });
}; };
const createComponentWithApollo = (options) => {
const handlers = [[commitCreate, mockMutateCommitData]];
localVue.use(VueApollo);
mockApollo = createMockApollo(handlers);
const apolloConfig = {
localVue,
apolloProvider: mockApollo,
};
createComponent({ ...options, apolloConfig });
};
const findCommitForm = () => wrapper.findComponent(CommitForm); const findCommitForm = () => wrapper.findComponent(CommitForm);
const findCommitBtnLoadingIcon = () => const findCommitBtnLoadingIcon = () =>
wrapper.find('[type="submit"]').findComponent(GlLoadingIcon); wrapper.find('[type="submit"]').findComponent(GlLoadingIcon);
...@@ -104,66 +109,53 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -104,66 +109,53 @@ describe('Pipeline Editor | Commit section', () => {
}; };
afterEach(() => { afterEach(() => {
mockMutate.mockReset();
wrapper.destroy(); wrapper.destroy();
}); });
describe('when the user commits a new file', () => { describe('when the user commits a new file', () => {
beforeEach(async () => { beforeEach(async () => {
createComponent({ props: { isNewCiConfigFile: true } }); mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
createComponentWithApollo({ props: { isNewCiConfigFile: true } });
await submitCommit(); await submitCommit();
}); });
it('calls the mutation with the CREATE action', () => { it('calls the mutation with the CREATE action', () => {
// the extra calls are for updating client queries (currentBranch and lastCommitBranch) expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
expect(mockMutate).toHaveBeenCalledTimes(3); expect(mockMutateCommitData).toHaveBeenCalledWith({
expect(mockMutate).toHaveBeenCalledWith({ ...mockVariables,
mutation: commitCreate, action: COMMIT_ACTION_CREATE,
update: expect.any(Function), branch: mockDefaultBranch,
variables: {
...mockVariables,
action: COMMIT_ACTION_CREATE,
branch: mockDefaultBranch,
},
}); });
}); });
}); });
describe('when the user commits an update to an existing file', () => { describe('when the user commits an update to an existing file', () => {
beforeEach(async () => { beforeEach(async () => {
createComponent(); createComponentWithApollo();
await submitCommit(); await submitCommit();
}); });
it('calls the mutation with the UPDATE action', () => { it('calls the mutation with the UPDATE action', () => {
expect(mockMutate).toHaveBeenCalledTimes(3); expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
expect(mockMutate).toHaveBeenCalledWith({ expect(mockMutateCommitData).toHaveBeenCalledWith({
mutation: commitCreate, ...mockVariables,
update: expect.any(Function), action: COMMIT_ACTION_UPDATE,
variables: { branch: mockDefaultBranch,
...mockVariables,
action: COMMIT_ACTION_UPDATE,
branch: mockDefaultBranch,
},
}); });
}); });
}); });
describe('when the user commits changes to the current branch', () => { describe('when the user commits changes to the current branch', () => {
beforeEach(async () => { beforeEach(async () => {
createComponent(); createComponentWithApollo();
await submitCommit(); await submitCommit();
}); });
it('calls the mutation with the current branch', () => { it('calls the mutation with the current branch', () => {
expect(mockMutate).toHaveBeenCalledTimes(3); expect(mockMutateCommitData).toHaveBeenCalledTimes(1);
expect(mockMutate).toHaveBeenCalledWith({ expect(mockMutateCommitData).toHaveBeenCalledWith({
mutation: commitCreate, ...mockVariables,
update: expect.any(Function), branch: mockDefaultBranch,
variables: {
...mockVariables,
branch: mockDefaultBranch,
},
}); });
}); });
...@@ -183,14 +175,10 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -183,14 +175,10 @@ describe('Pipeline Editor | Commit section', () => {
it('a second commit submits the latest sha, keeping the form updated', async () => { it('a second commit submits the latest sha, keeping the form updated', async () => {
await submitCommit(); await submitCommit();
expect(mockMutate).toHaveBeenCalledTimes(6); expect(mockMutateCommitData).toHaveBeenCalledTimes(2);
expect(mockMutate).toHaveBeenCalledWith({ expect(mockMutateCommitData).toHaveBeenCalledWith({
mutation: commitCreate, ...mockVariables,
update: expect.any(Function), branch: mockDefaultBranch,
variables: {
...mockVariables,
branch: mockDefaultBranch,
},
}); });
}); });
}); });
...@@ -199,20 +187,16 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -199,20 +187,16 @@ describe('Pipeline Editor | Commit section', () => {
const newBranch = 'new-branch'; const newBranch = 'new-branch';
beforeEach(async () => { beforeEach(async () => {
createComponent(); createComponentWithApollo();
await submitCommit({ await submitCommit({
branch: newBranch, branch: newBranch,
}); });
}); });
it('calls the mutation with the new branch', () => { it('calls the mutation with the new branch', () => {
expect(mockMutate).toHaveBeenCalledWith({ expect(mockMutateCommitData).toHaveBeenCalledWith({
mutation: commitCreate, ...mockVariables,
update: expect.any(Function), branch: newBranch,
variables: {
...mockVariables,
branch: newBranch,
},
}); });
}); });
...@@ -225,7 +209,7 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -225,7 +209,7 @@ describe('Pipeline Editor | Commit section', () => {
const newBranch = 'new-branch'; const newBranch = 'new-branch';
beforeEach(async () => { beforeEach(async () => {
createComponent(); createComponentWithApollo();
await submitCommit({ await submitCommit({
branch: newBranch, branch: newBranch,
openMergeRequest: true, openMergeRequest: true,
...@@ -244,11 +228,11 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -244,11 +228,11 @@ describe('Pipeline Editor | Commit section', () => {
describe('when the commit is ocurring', () => { describe('when the commit is ocurring', () => {
beforeEach(() => { beforeEach(() => {
createComponent(); createComponentWithApollo();
}); });
it('shows a saving state', async () => { it('shows a saving state', async () => {
mockMutate.mockImplementationOnce(() => { mockMutateCommitData.mockImplementationOnce(() => {
expect(findCommitBtnLoadingIcon().exists()).toBe(true); expect(findCommitBtnLoadingIcon().exists()).toBe(true);
return Promise.resolve(); return Promise.resolve();
}); });
...@@ -261,6 +245,26 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -261,6 +245,26 @@ describe('Pipeline Editor | Commit section', () => {
}); });
}); });
describe('when the commit returns a different etag path', () => {
beforeEach(async () => {
createComponentWithApollo();
jest.spyOn(wrapper.vm.$apollo, 'mutate');
mockMutateCommitData.mockResolvedValue(mockCommitCreateResponseNewEtag);
await submitCommit();
});
it('calls the client mutation to update the etag', () => {
// 1:Commit submission, 2:etag update, 3:currentBranch update, 4:lastCommit update
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(4);
expect(wrapper.vm.$apollo.mutate).toHaveBeenNthCalledWith(2, {
mutation: updatePipelineEtag,
variables: {
pipelineEtag: mockCommitCreateResponseNewEtag.data.commitCreate.commitPipelinePath,
},
});
});
});
it('sets listeners on commit form', () => { it('sets listeners on commit form', () => {
const handler = jest.fn(); const handler = jest.fn();
createComponent({ options: { listeners: { event: handler } } }); createComponent({ options: { listeners: { event: handler } } });
......
...@@ -453,3 +453,31 @@ export const mockErrors = [ ...@@ -453,3 +453,31 @@ export const mockErrors = [
export const mockWarnings = [ export const mockWarnings = [
'"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"', '"jobs:multi_project_job may allow multiple pipelines to run for a single action due to `rules:when` clause with no `workflow:rules` - read more: https://docs.gitlab.com/ee/ci/troubleshooting.html#pipeline-warnings"',
]; ];
export const mockCommitCreateResponse = {
data: {
commitCreate: {
__typename: 'CommitCreatePayload',
errors: [],
commit: {
__typename: 'Commit',
sha: mockCommitNextSha,
},
commitPipelinePath: '',
},
},
};
export const mockCommitCreateResponseNewEtag = {
data: {
commitCreate: {
__typename: 'CommitCreatePayload',
errors: [],
commit: {
__typename: 'Commit',
sha: mockCommitNextSha,
},
commitPipelinePath: '/api/graphql:pipelines/sha/550ceace1acd373c84d02bd539cb9d4614f786db',
},
},
};
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