diff options
Diffstat (limited to 'spec/frontend/snippets/components/edit_spec.js')
-rw-r--r-- | spec/frontend/snippets/components/edit_spec.js | 136 |
1 files changed, 132 insertions, 4 deletions
diff --git a/spec/frontend/snippets/components/edit_spec.js b/spec/frontend/snippets/components/edit_spec.js index ba62a0a92ca..83f46dd347f 100644 --- a/spec/frontend/snippets/components/edit_spec.js +++ b/spec/frontend/snippets/components/edit_spec.js @@ -1,5 +1,6 @@ import { shallowMount } from '@vue/test-utils'; import axios from '~/lib/utils/axios_utils'; +import Flash from '~/flash'; import { GlLoadingIcon } from '@gitlab/ui'; import { joinPaths, redirectTo } from '~/lib/utils/url_utility'; @@ -10,6 +11,7 @@ import SnippetVisibilityEdit from '~/snippets/components/snippet_visibility_edit import SnippetBlobEdit from '~/snippets/components/snippet_blob_edit.vue'; import TitleField from '~/vue_shared/components/form/title.vue'; import FormFooterActions from '~/vue_shared/components/form/form_footer_actions.vue'; +import { SNIPPET_CREATE_MUTATION_ERROR, SNIPPET_UPDATE_MUTATION_ERROR } from '~/snippets/constants'; import UpdateSnippetMutation from '~/snippets/mutations/updateSnippet.mutation.graphql'; import CreateSnippetMutation from '~/snippets/mutations/createSnippet.mutation.graphql'; @@ -27,6 +29,8 @@ jest.mock('~/lib/utils/url_utility', () => ({ .mockReturnValue('contentApiURL'), })); +jest.mock('~/flash'); + let flashSpy; const contentMock = 'Foo Bar'; @@ -34,6 +38,10 @@ const rawPathMock = '/foo/bar'; const rawProjectPathMock = '/project/path'; const newlyEditedSnippetUrl = 'http://foo.bar'; const apiError = { message: 'Ufff' }; +const mutationError = 'Bummer'; + +const attachedFilePath1 = 'foo/bar'; +const attachedFilePath2 = 'alpha/beta'; const defaultProps = { snippetGid: 'gid://gitlab/PersonalSnippet/42', @@ -56,10 +64,26 @@ describe('Snippet Edit app', () => { }, }); + const resolveMutateWithErrors = jest.fn().mockResolvedValue({ + data: { + updateSnippet: { + errors: [mutationError], + snippet: { + webUrl: newlyEditedSnippetUrl, + }, + }, + createSnippet: { + errors: [mutationError], + snippet: null, + }, + }, + }); + const rejectMutation = jest.fn().mockRejectedValue(apiError); const mutationTypes = { RESOLVE: resolveMutate, + RESOLVE_WITH_ERRORS: resolveMutateWithErrors, REJECT: rejectMutation, }; @@ -99,8 +123,9 @@ describe('Snippet Edit app', () => { wrapper.destroy(); }); - const findSubmitButton = () => wrapper.find('[type=submit]'); + const findSubmitButton = () => wrapper.find('[data-testid="snippet-submit-btn"]'); const findCancellButton = () => wrapper.find('[data-testid="snippet-cancel-btn"]'); + const clickSubmitBtn = () => wrapper.find('[data-testid="snippet-edit-form"]').trigger('submit'); describe('rendering', () => { it('renders loader while the query is in flight', () => { @@ -268,28 +293,131 @@ describe('Snippet Edit app', () => { }, }; - wrapper.vm.handleFormSubmit(); + clickSubmitBtn(); + expect(resolveMutate).toHaveBeenCalledWith(mutationPayload); }); it('redirects to snippet view on successful mutation', () => { createComponent(); - wrapper.vm.handleFormSubmit(); + clickSubmitBtn(); + return waitForPromises().then(() => { expect(redirectTo).toHaveBeenCalledWith(newlyEditedSnippetUrl); }); }); + it.each` + newSnippet | projectPath | mutationName + ${true} | ${rawProjectPathMock} | ${'CreateSnippetMutation with projectPath'} + ${true} | ${''} | ${'CreateSnippetMutation without projectPath'} + ${false} | ${rawProjectPathMock} | ${'UpdateSnippetMutation with projectPath'} + ${false} | ${''} | ${'UpdateSnippetMutation without projectPath'} + `( + 'does not redirect to snippet view if the seemingly successful' + + ' $mutationName response contains errors', + ({ newSnippet, projectPath }) => { + createComponent({ + data: { + newSnippet, + }, + props: { + ...defaultProps, + projectPath, + }, + mutationRes: mutationTypes.RESOLVE_WITH_ERRORS, + }); + + clickSubmitBtn(); + + return waitForPromises().then(() => { + expect(redirectTo).not.toHaveBeenCalled(); + expect(flashSpy).toHaveBeenCalledWith(mutationError); + }); + }, + ); + it('flashes an error if mutation failed', () => { createComponent({ mutationRes: mutationTypes.REJECT, }); - wrapper.vm.handleFormSubmit(); + + clickSubmitBtn(); + return waitForPromises().then(() => { expect(redirectTo).not.toHaveBeenCalled(); expect(flashSpy).toHaveBeenCalledWith(apiError); }); }); + + it.each` + isNew | status | expectation + ${true} | ${`new`} | ${SNIPPET_CREATE_MUTATION_ERROR.replace('%{err}', '')} + ${false} | ${`existing`} | ${SNIPPET_UPDATE_MUTATION_ERROR.replace('%{err}', '')} + `( + `renders the correct error message if mutation fails for $status snippet`, + ({ isNew, expectation }) => { + createComponent({ + data: { + newSnippet: isNew, + }, + mutationRes: mutationTypes.REJECT, + }); + + clickSubmitBtn(); + + return waitForPromises().then(() => { + expect(Flash).toHaveBeenCalledWith(expect.stringContaining(expectation)); + }); + }, + ); + }); + + describe('correctly includes attached files into the mutation', () => { + const createMutationPayload = expectation => { + return expect.objectContaining({ + variables: { + input: expect.objectContaining({ uploadedFiles: expectation }), + }, + }); + }; + + const updateMutationPayload = () => { + return expect.objectContaining({ + variables: { + input: expect.not.objectContaining({ uploadedFiles: expect.anything() }), + }, + }); + }; + + it.each` + paths | expectation + ${[attachedFilePath1]} | ${[attachedFilePath1]} + ${[attachedFilePath1, attachedFilePath2]} | ${[attachedFilePath1, attachedFilePath2]} + ${[]} | ${[]} + `(`correctly sends paths for $paths.length files`, ({ paths, expectation }) => { + createComponent({ + data: { + newSnippet: true, + }, + }); + + const fixtures = paths.map(path => { + return path ? `<input name="files[]" value="${path}">` : undefined; + }); + wrapper.vm.$el.innerHTML += fixtures.join(''); + + clickSubmitBtn(); + + expect(resolveMutate).toHaveBeenCalledWith(createMutationPayload(expectation)); + }); + + it(`neither fails nor sends 'uploadedFiles' to update mutation`, () => { + createComponent(); + + clickSubmitBtn(); + expect(resolveMutate).toHaveBeenCalledWith(updateMutationPayload()); + }); }); }); }); |