diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-06-18 11:18:50 +0000 |
commit | 8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781 (patch) | |
tree | a77e7fe7a93de11213032ed4ab1f33a3db51b738 /spec/frontend/snippets/components | |
parent | 00b35af3db1abfe813a778f643dad221aad51fca (diff) | |
download | gitlab-ce-8c7f4e9d5f36cff46365a7f8c4b9c21578c1e781.tar.gz |
Add latest changes from gitlab-org/gitlab@13-1-stable-ee
Diffstat (limited to 'spec/frontend/snippets/components')
6 files changed, 219 insertions, 27 deletions
diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap index 301ec5652a9..959bc24eef6 100644 --- a/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap +++ b/spec/frontend/snippets/components/__snapshots__/snippet_blob_edit_spec.js.snap @@ -12,7 +12,7 @@ exports[`Snippet Blob Edit component rendering matches the snapshot 1`] = ` class="file-holder snippet" > <blob-header-edit-stub - data-qa-selector="snippet_file_name" + data-qa-selector="file_name_field" value="lorem.txt" /> diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap index 9fd4cba5b87..297ad16b681 100644 --- a/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap +++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_edit_spec.js.snap @@ -4,7 +4,9 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] = <div class="form-group js-description-input" > - <label> + <label + for="snippet-description" + > Description (optional) </label> @@ -21,27 +23,67 @@ exports[`Snippet Description Edit component rendering matches the snapshot 1`] = /> </div> - <markdown-field-stub - addspacingclasses="true" - canattachfile="true" - class="js-expanded" - enableautocomplete="true" - helppagepath="" - markdowndocspath="help/" - markdownpreviewpath="foo/" - note="[object Object]" - quickactionsdocspath="" - textareavalue="" + <div + class="js-vue-markdown-field md-area position-relative js-expanded gfm-form" > - <textarea - aria-label="Description" - class="note-textarea js-gfm-input js-autosize markdown-area" - data-qa-selector="snippet_description_field" - data-supports-quick-actions="false" - dir="auto" - placeholder="Write a comment or drag your files here…" + <markdown-header-stub + linecontent="" /> - </markdown-field-stub> + + <div + class="md-write-holder" + > + <div + class="zen-backdrop div-dropzone-wrapper" + > + <div + class="div-dropzone js-invalid-dropzone" + > + <textarea + aria-label="Description" + class="note-textarea js-gfm-input js-autosize markdown-area" + data-qa-selector="snippet_description_field" + data-supports-quick-actions="false" + dir="auto" + id="snippet-description" + placeholder="Write a comment or drag your files here…" + style="overflow-x: hidden; word-wrap: break-word; overflow-y: hidden;" + /> + <div + class="div-dropzone-hover" + > + <i + class="fa fa-paperclip div-dropzone-icon" + /> + </div> + </div> + + <a + aria-label="Leave zen mode" + class="zen-control zen-control-leave js-zen-leave gl-text-gray-700" + href="#" + > + <icon-stub + name="screen-normal" + size="16" + /> + </a> + + <markdown-toolbar-stub + canattachfile="true" + markdowndocspath="help/" + quickactionsdocspath="" + /> + </div> + </div> + + <div + class="js-vue-md-preview md md-preview-holder" + style="display: none;" + /> + + <!----> + </div> </div> </div> `; diff --git a/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap b/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap index 9ebc4e81baf..9fb43815cbc 100644 --- a/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap +++ b/spec/frontend/snippets/components/__snapshots__/snippet_description_view_spec.js.snap @@ -3,7 +3,7 @@ exports[`Snippet Description component matches the snapshot 1`] = ` <markdown-field-view-stub class="snippet-description" - data-qa-selector="snippet_description_field" + data-qa-selector="snippet_description_content" > <div class="md js-snippet-description" 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()); + }); }); }); }); diff --git a/spec/frontend/snippets/components/snippet_blob_view_spec.js b/spec/frontend/snippets/components/snippet_blob_view_spec.js index d06489cffa9..e4d8ee9b7df 100644 --- a/spec/frontend/snippets/components/snippet_blob_view_spec.js +++ b/spec/frontend/snippets/components/snippet_blob_view_spec.js @@ -3,7 +3,11 @@ import SnippetBlobView from '~/snippets/components/snippet_blob_view.vue'; import BlobHeader from '~/blob/components/blob_header.vue'; import BlobEmbeddable from '~/blob/components/blob_embeddable.vue'; import BlobContent from '~/blob/components/blob_content.vue'; -import { BLOB_RENDER_EVENT_LOAD, BLOB_RENDER_EVENT_SHOW_SOURCE } from '~/blob/components/constants'; +import { + BLOB_RENDER_EVENT_LOAD, + BLOB_RENDER_EVENT_SHOW_SOURCE, + BLOB_RENDER_ERRORS, +} from '~/blob/components/constants'; import { RichViewer, SimpleViewer } from '~/vue_shared/components/blob_viewers'; import { SNIPPET_VISIBILITY_PRIVATE, @@ -109,6 +113,20 @@ describe('Blob Embeddable', () => { }); }); + it('passes information about render error down to blob header', () => { + createComponent({ + blob: { + ...BlobMock, + simpleViewer: { + ...SimpleViewerMock, + renderError: BLOB_RENDER_ERRORS.REASONS.COLLAPSED.id, + }, + }, + }); + + expect(wrapper.find(BlobHeader).props('hasRenderError')).toBe(true); + }); + describe('URLS with hash', () => { beforeEach(() => { window.location.hash = '#LC2'; diff --git a/spec/frontend/snippets/components/snippet_description_edit_spec.js b/spec/frontend/snippets/components/snippet_description_edit_spec.js index c5e667747c6..816ab4e48de 100644 --- a/spec/frontend/snippets/components/snippet_description_edit_spec.js +++ b/spec/frontend/snippets/components/snippet_description_edit_spec.js @@ -1,4 +1,5 @@ import SnippetDescriptionEdit from '~/snippets/components/snippet_description_edit.vue'; +import MarkdownField from '~/vue_shared/components/markdown/field.vue'; import { shallowMount } from '@vue/test-utils'; describe('Snippet Description Edit component', () => { @@ -15,6 +16,9 @@ describe('Snippet Description Edit component', () => { markdownPreviewPath, markdownDocsPath, }, + stubs: { + MarkdownField, + }, }); } |