diff options
Diffstat (limited to 'spec')
7 files changed, 236 insertions, 37 deletions
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js index fdefa16ac19..f34c2fb69eb 100644 --- a/spec/frontend/api_spec.js +++ b/spec/frontend/api_spec.js @@ -651,7 +651,7 @@ describe('Api', () => { describe('when an error occurs while getting a raw file', () => { it('rejects the Promise', () => { - mock.onDelete(expectedUrl).replyOnce(500); + mock.onPost(expectedUrl).replyOnce(500); return Api.getRawFile(dummyProjectPath, dummyFilePath).catch(() => { expect(mock.history.get).toHaveLength(1); @@ -659,4 +659,36 @@ describe('Api', () => { }); }); }); + + describe('createProjectMergeRequest', () => { + const dummyProjectPath = 'gitlab-org/gitlab'; + const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${encodeURIComponent( + dummyProjectPath, + )}/merge_requests`; + const options = { + source_branch: 'feature', + target_branch: 'master', + title: 'Add feature', + }; + + describe('when the merge request is successfully created', () => { + it('resolves the Promise', () => { + mock.onPost(expectedUrl, options).replyOnce(201); + + return Api.createProjectMergeRequest(dummyProjectPath, options).then(() => { + expect(mock.history.post).toHaveLength(1); + }); + }); + }); + + describe('when an error occurs while getting a raw file', () => { + it('rejects the Promise', () => { + mock.onPost(expectedUrl).replyOnce(500); + + return Api.createProjectMergeRequest(dummyProjectPath).catch(() => { + expect(mock.history.post).toHaveLength(1); + }); + }); + }); + }); }); diff --git a/spec/frontend/snippets/components/snippet_blob_view_spec.js b/spec/frontend/snippets/components/snippet_blob_view_spec.js index c4f1dd0ca35..1f6038bc7f0 100644 --- a/spec/frontend/snippets/components/snippet_blob_view_spec.js +++ b/spec/frontend/snippets/components/snippet_blob_view_spec.js @@ -1,5 +1,4 @@ import { mount } from '@vue/test-utils'; -import { GlLoadingIcon } from '@gitlab/ui'; 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'; @@ -19,23 +18,15 @@ describe('Blob Embeddable', () => { id: 'gid://foo.bar/snippet', webUrl: 'https://foo.bar', visibilityLevel: SNIPPET_VISIBILITY_PUBLIC, + blob: BlobMock, }; const dataMock = { - blob: BlobMock, activeViewerType: SimpleViewerMock.type, }; - function createComponent( - props = {}, - data = dataMock, - blobLoading = false, - contentLoading = false, - ) { + function createComponent(props = {}, data = dataMock, contentLoading = false) { const $apollo = { queries: { - blob: { - loading: blobLoading, - }, blobContent: { loading: contentLoading, }, @@ -87,12 +78,6 @@ describe('Blob Embeddable', () => { expect(wrapper.find(BlobEmbeddable).exists()).toBe(true); }); - it('shows loading icon while blob data is in flight', () => { - createComponent({}, dataMock, true); - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); - expect(wrapper.find('.snippet-file-content').exists()).toBe(false); - }); - it('sets simple viewer correctly', () => { createComponent(); expect(wrapper.find(SimpleViewer).exists()).toBe(true); @@ -133,14 +118,14 @@ describe('Blob Embeddable', () => { }); it('renders simple viewer by default if URL contains hash', () => { - createComponent(); + createComponent({}, {}); expect(wrapper.vm.activeViewerType).toBe(SimpleViewerMock.type); expect(wrapper.find(SimpleViewer).exists()).toBe(true); }); describe('switchViewer()', () => { - it('by default switches to the passed viewer', () => { + it('switches to the passed viewer', () => { createComponent(); wrapper.vm.switchViewer(RichViewerMock.type); @@ -157,22 +142,6 @@ describe('Blob Embeddable', () => { expect(wrapper.find(SimpleViewer).exists()).toBe(true); }); }); - - it('respects hash over richViewer in the blob when corresponding parameter is passed', () => { - createComponent( - {}, - { - blob: BlobMock, - }, - ); - expect(wrapper.vm.blob.richViewer).toEqual(expect.any(Object)); - - wrapper.vm.switchViewer(RichViewerMock.type, true); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.vm.activeViewerType).toBe(SimpleViewerMock.type); - expect(wrapper.find(SimpleViewer).exists()).toBe(true); - }); - }); }); }); }); diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 9e1c14515e6..1993636ab12 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -34,3 +34,11 @@ export const savedContentMeta = { }; export const submitChangesError = 'Could not save changes'; +export const commitMultipleResponse = { + short_id: 'ed899a2f4b5', + web_url: '/commit/ed899a2f4b5', +}; +export const createMergeRequestResponse = { + iid: '123', + web_url: '/merge_requests/123', +}; diff --git a/spec/frontend/static_site_editor/services/generate_branch_name_spec.js b/spec/frontend/static_site_editor/services/generate_branch_name_spec.js new file mode 100644 index 00000000000..0624fc3b7b4 --- /dev/null +++ b/spec/frontend/static_site_editor/services/generate_branch_name_spec.js @@ -0,0 +1,22 @@ +import { DEFAULT_TARGET_BRANCH, BRANCH_SUFFIX_COUNT } from '~/static_site_editor/constants'; +import generateBranchName from '~/static_site_editor/services/generate_branch_name'; + +import { username } from '../mock_data'; + +describe('generateBranchName', () => { + const timestamp = 12345678901234; + + beforeEach(() => { + jest.spyOn(Date, 'now').mockReturnValueOnce(timestamp); + }); + + it('generates a name that includes the username and target branch', () => { + expect(generateBranchName(username)).toMatch(`${username}-${DEFAULT_TARGET_BRANCH}`); + }); + + it(`adds the first ${BRANCH_SUFFIX_COUNT} numbers of the current timestamp`, () => { + expect(generateBranchName(username)).toMatch( + timestamp.toString().substring(BRANCH_SUFFIX_COUNT), + ); + }); +}); diff --git a/spec/frontend/static_site_editor/services/submit_content_changes_spec.js b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js new file mode 100644 index 00000000000..9a0bd88b57d --- /dev/null +++ b/spec/frontend/static_site_editor/services/submit_content_changes_spec.js @@ -0,0 +1,131 @@ +import Api from '~/api'; +import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils'; + +import { + DEFAULT_TARGET_BRANCH, + SUBMIT_CHANGES_BRANCH_ERROR, + SUBMIT_CHANGES_COMMIT_ERROR, + SUBMIT_CHANGES_MERGE_REQUEST_ERROR, +} from '~/static_site_editor/constants'; +import generateBranchName from '~/static_site_editor/services/generate_branch_name'; +import submitContentChanges from '~/static_site_editor/services/submit_content_changes'; + +import { + username, + projectId, + commitMultipleResponse, + createMergeRequestResponse, + sourcePath, + sourceContent as content, +} from '../mock_data'; + +jest.mock('~/static_site_editor/services/generate_branch_name'); + +describe('submitContentChanges', () => { + const mergeRequestTitle = `Update ${sourcePath} file`; + const branch = 'branch-name'; + + beforeEach(() => { + jest.spyOn(Api, 'createBranch').mockResolvedValue(); + jest.spyOn(Api, 'commitMultiple').mockResolvedValue({ data: commitMultipleResponse }); + jest + .spyOn(Api, 'createProjectMergeRequest') + .mockResolvedValue({ data: createMergeRequestResponse }); + + generateBranchName.mockReturnValue(branch); + }); + + it('creates a branch named after the username and target branch', () => { + return submitContentChanges({ username, projectId }).then(() => { + expect(Api.createBranch).toHaveBeenCalledWith(projectId, { + ref: DEFAULT_TARGET_BRANCH, + branch, + }); + }); + }); + + it('notifies error when branch could not be created', () => { + Api.createBranch.mockRejectedValueOnce(); + + expect(submitContentChanges({ username, projectId })).rejects.toThrow( + SUBMIT_CHANGES_BRANCH_ERROR, + ); + }); + + it('commits the content changes to the branch when creating branch succeeds', () => { + return submitContentChanges({ username, projectId, sourcePath, content }).then(() => { + expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, { + branch, + commit_message: mergeRequestTitle, + actions: [ + { + action: 'update', + file_path: sourcePath, + content, + }, + ], + }); + }); + }); + + it('notifies error when content could not be committed', () => { + Api.commitMultiple.mockRejectedValueOnce(); + + expect(submitContentChanges({ username, projectId })).rejects.toThrow( + SUBMIT_CHANGES_COMMIT_ERROR, + ); + }); + + it('creates a merge request when commiting changes succeeds', () => { + return submitContentChanges({ username, projectId, sourcePath, content }).then(() => { + expect(Api.createProjectMergeRequest).toHaveBeenCalledWith( + projectId, + convertObjectPropsToSnakeCase({ + title: mergeRequestTitle, + targetBranch: DEFAULT_TARGET_BRANCH, + sourceBranch: branch, + }), + ); + }); + }); + + it('notifies error when merge request could not be created', () => { + Api.createProjectMergeRequest.mockRejectedValueOnce(); + + expect(submitContentChanges({ username, projectId })).rejects.toThrow( + SUBMIT_CHANGES_MERGE_REQUEST_ERROR, + ); + }); + + describe('when changes are submitted successfully', () => { + let result; + + beforeEach(() => { + return submitContentChanges({ username, projectId, sourcePath, content }).then(_result => { + result = _result; + }); + }); + + it('returns the branch name', () => { + expect(result).toMatchObject({ branch: { label: branch } }); + }); + + it('returns commit short id and web url', () => { + expect(result).toMatchObject({ + commit: { + label: commitMultipleResponse.short_id, + url: commitMultipleResponse.web_url, + }, + }); + }); + + it('returns merge request iid and web url', () => { + expect(result).toMatchObject({ + mergeRequest: { + label: createMergeRequestResponse.iid, + url: createMergeRequestResponse.web_url, + }, + }); + }); + }); +}); diff --git a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb index e260e4463f4..c616310a72c 100644 --- a/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb +++ b/spec/requests/api/graphql/project/merge_request/diff_notes_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' describe 'getting notes for a merge request' do include GraphqlHelpers - let(:noteable) { create(:merge_request) } + let_it_be(:noteable) { create(:merge_request) } def noteable_query(noteable_fields) <<~QRY diff --git a/spec/requests/api/graphql/project/merge_request_spec.rb b/spec/requests/api/graphql/project/merge_request_spec.rb index e1fe6470881..a1b3111ff71 100644 --- a/spec/requests/api/graphql/project/merge_request_spec.rb +++ b/spec/requests/api/graphql/project/merge_request_spec.rb @@ -93,4 +93,41 @@ describe 'getting merge request information nested in a project' do expect(merge_request_graphql_data['pipelines']['edges'].size).to eq(1) end end + + context 'when limiting the number of results' do + let(:merge_requests_graphql_data) { graphql_data['project']['mergeRequests']['edges'] } + + let!(:merge_requests) do + [ + create(:merge_request, source_project: project, source_branch: 'branch-1'), + create(:merge_request, source_project: project, source_branch: 'branch-2'), + create(:merge_request, source_project: project, source_branch: 'branch-3') + ] + end + + let(:fields) do + <<~QUERY + edges { + node { + iid, + title + } + } + QUERY + end + + let(:query) do + graphql_query_for( + 'project', + { 'fullPath' => project.full_path }, + "mergeRequests(first: 2) { #{fields} }" + ) + end + + it 'returns the correct number of results' do + post_graphql(query, current_user: current_user) + + expect(merge_requests_graphql_data.size).to eq 2 + end + end end |