diff options
Diffstat (limited to 'spec/frontend/repository')
3 files changed, 178 insertions, 288 deletions
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js index 59db537282b..d40e97bf5a3 100644 --- a/spec/frontend/repository/components/blob_content_viewer_spec.js +++ b/spec/frontend/repository/components/blob_content_viewer_spec.js @@ -1,5 +1,5 @@ import { GlLoadingIcon } from '@gitlab/ui'; -import { shallowMount, mount, createLocalVue } from '@vue/test-utils'; +import { mount, shallowMount, createLocalVue } from '@vue/test-utils'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { nextTick } from 'vue'; @@ -19,6 +19,15 @@ import TextViewer from '~/repository/components/blob_viewers/text_viewer.vue'; import blobInfoQuery from '~/repository/queries/blob_info.query.graphql'; import { redirectTo } from '~/lib/utils/url_utility'; import { isLoggedIn } from '~/lib/utils/common_utils'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import { + simpleViewerMock, + richViewerMock, + projectMock, + userPermissionsMock, + propsMock, + refMock, +} from '../mock_data'; jest.mock('~/repository/components/blob_viewers'); jest.mock('~/lib/utils/url_utility'); @@ -27,151 +36,63 @@ jest.mock('~/lib/utils/common_utils'); let wrapper; let mockResolver; -const simpleMockData = { - name: 'some_file.js', - size: 123, - rawSize: 123, - rawTextBlob: 'raw content', - type: 'text', - fileType: 'text', - tooLarge: false, - path: 'some_file.js', - webPath: 'some_file.js', - editBlobPath: 'some_file.js/edit', - ideEditPath: 'some_file.js/ide/edit', - forkAndEditPath: 'some_file.js/fork/edit', - ideForkAndEditPath: 'some_file.js/fork/ide', - canModifyBlob: true, - storedExternally: false, - rawPath: 'some_file.js', - externalStorageUrl: 'some_file.js', - replacePath: 'some_file.js/replace', - deletePath: 'some_file.js/delete', - simpleViewer: { - fileType: 'text', - tooLarge: false, - type: 'simple', - renderError: null, - }, - richViewer: null, -}; -const richMockData = { - ...simpleMockData, - richViewer: { - fileType: 'markup', - tooLarge: false, - type: 'rich', - renderError: null, - }, -}; - -const projectMockData = { - userPermissions: { - pushCode: true, - downloadCode: true, - createMergeRequestIn: true, - forkProject: true, - }, - repository: { - empty: false, - }, -}; - const localVue = createLocalVue(); const mockAxios = new MockAdapter(axios); -const createComponentWithApollo = (mockData = {}, inject = {}) => { +const createComponent = async (mockData = {}, mountFn = shallowMount) => { localVue.use(VueApollo); - const defaultPushCode = projectMockData.userPermissions.pushCode; - const defaultDownloadCode = projectMockData.userPermissions.downloadCode; - const defaultEmptyRepo = projectMockData.repository.empty; const { - blobs, - emptyRepo = defaultEmptyRepo, - canPushCode = defaultPushCode, - canDownloadCode = defaultDownloadCode, - createMergeRequestIn = projectMockData.userPermissions.createMergeRequestIn, - forkProject = projectMockData.userPermissions.forkProject, - pathLocks = [], + blob = simpleViewerMock, + empty = projectMock.repository.empty, + pushCode = userPermissionsMock.pushCode, + forkProject = userPermissionsMock.forkProject, + downloadCode = userPermissionsMock.downloadCode, + createMergeRequestIn = userPermissionsMock.createMergeRequestIn, + isBinary, + inject = {}, } = mockData; - mockResolver = jest.fn().mockResolvedValue({ - data: { - project: { - id: '1234', - userPermissions: { - pushCode: canPushCode, - downloadCode: canDownloadCode, - createMergeRequestIn, - forkProject, - }, - pathLocks: { - nodes: pathLocks, - }, - repository: { - empty: emptyRepo, - blobs: { - nodes: [blobs], - }, - }, - }, + const project = { + ...projectMock, + userPermissions: { + pushCode, + forkProject, + downloadCode, + createMergeRequestIn, + }, + repository: { + empty, + blobs: { nodes: [blob] }, }, + }; + + mockResolver = jest.fn().mockResolvedValue({ + data: { isBinary, project }, }); const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]); - wrapper = shallowMount(BlobContentViewer, { - localVue, - apolloProvider: fakeApollo, - propsData: { - path: 'some_file.js', - projectPath: 'some/path', - }, - mixins: [ - { - data: () => ({ ref: 'default-ref' }), - }, - ], - provide: { - ...inject, - }, - }); -}; + wrapper = extendedWrapper( + mountFn(BlobContentViewer, { + localVue, + apolloProvider: fakeApollo, + propsData: propsMock, + mixins: [{ data: () => ({ ref: refMock }) }], + provide: { ...inject }, + }), + ); -const createFactory = (mountFn) => ( - { props = {}, mockData = {}, stubs = {} } = {}, - loading = false, -) => { - wrapper = mountFn(BlobContentViewer, { - propsData: { - path: 'some_file.js', - projectPath: 'some/path', - ...props, - }, - mocks: { - $apollo: { - queries: { - project: { - loading, - refetch: jest.fn(), - }, - }, - }, - }, - stubs, - }); + wrapper.setData({ project, isBinary }); - wrapper.setData(mockData); + await waitForPromises(); }; -const factory = createFactory(shallowMount); -const fullFactory = createFactory(mount); - describe('Blob content viewer component', () => { const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findBlobHeader = () => wrapper.findComponent(BlobHeader); const findBlobEdit = () => wrapper.findComponent(BlobEdit); + const findPipelineEditor = () => wrapper.findByTestId('pipeline-editor'); const findBlobContent = () => wrapper.findComponent(BlobContent); const findBlobButtonGroup = () => wrapper.findComponent(BlobButtonGroup); const findForkSuggestion = () => wrapper.findComponent(ForkSuggestion); @@ -187,25 +108,24 @@ describe('Blob content viewer component', () => { }); it('renders a GlLoadingIcon component', () => { - factory({ mockData: { blobInfo: simpleMockData } }, true); + createComponent(); expect(findLoadingIcon().exists()).toBe(true); }); describe('simple viewer', () => { - beforeEach(() => { - factory({ mockData: { blobInfo: simpleMockData } }); - }); + it('renders a BlobHeader component', async () => { + await createComponent(); - it('renders a BlobHeader component', () => { expect(findBlobHeader().props('activeViewerType')).toEqual('simple'); expect(findBlobHeader().props('hasRenderError')).toEqual(false); expect(findBlobHeader().props('hideViewerSwitcher')).toEqual(true); - expect(findBlobHeader().props('blob')).toEqual(simpleMockData); + expect(findBlobHeader().props('blob')).toEqual(simpleViewerMock); }); - it('renders a BlobContent component', () => { - expect(findBlobContent().props('loading')).toEqual(false); + it('renders a BlobContent component', async () => { + await createComponent(); + expect(findBlobContent().props('isRawContent')).toBe(true); expect(findBlobContent().props('activeViewer')).toEqual({ fileType: 'text', @@ -217,8 +137,7 @@ describe('Blob content viewer component', () => { describe('legacy viewers', () => { it('loads a legacy viewer when a viewer component is not available', async () => { - createComponentWithApollo({ blobs: { ...simpleMockData, fileType: 'unknown' } }); - await waitForPromises(); + await createComponent({ blob: { ...simpleViewerMock, fileType: 'unknown' } }); expect(mockAxios.history.get).toHaveLength(1); expect(mockAxios.history.get[0].url).toEqual('some_file.js?format=json&viewer=simple'); @@ -227,21 +146,18 @@ describe('Blob content viewer component', () => { }); describe('rich viewer', () => { - beforeEach(() => { - factory({ - mockData: { blobInfo: richMockData, activeViewerType: 'rich' }, - }); - }); + it('renders a BlobHeader component', async () => { + await createComponent({ blob: richViewerMock }); - it('renders a BlobHeader component', () => { expect(findBlobHeader().props('activeViewerType')).toEqual('rich'); expect(findBlobHeader().props('hasRenderError')).toEqual(false); expect(findBlobHeader().props('hideViewerSwitcher')).toEqual(false); - expect(findBlobHeader().props('blob')).toEqual(richMockData); + expect(findBlobHeader().props('blob')).toEqual(richViewerMock); }); - it('renders a BlobContent component', () => { - expect(findBlobContent().props('loading')).toEqual(false); + it('renders a BlobContent component', async () => { + await createComponent({ blob: richViewerMock }); + expect(findBlobContent().props('isRawContent')).toBe(true); expect(findBlobContent().props('activeViewer')).toEqual({ fileType: 'markup', @@ -252,6 +168,8 @@ describe('Blob content viewer component', () => { }); it('updates viewer type when viewer changed is clicked', async () => { + await createComponent({ blob: richViewerMock }); + expect(findBlobContent().props('activeViewer')).toEqual( expect.objectContaining({ type: 'rich', @@ -273,8 +191,7 @@ describe('Blob content viewer component', () => { describe('legacy viewers', () => { it('loads a legacy viewer when a viewer component is not available', async () => { - createComponentWithApollo({ blobs: { ...richMockData, fileType: 'unknown' } }); - await waitForPromises(); + await createComponent({ blob: { ...richViewerMock, fileType: 'unknown' } }); expect(mockAxios.history.get).toHaveLength(1); expect(mockAxios.history.get[0].url).toEqual('some_file.js?format=json&viewer=rich'); @@ -287,9 +204,9 @@ describe('Blob content viewer component', () => { viewerProps.mockRestore(); }); - it('does not render a BlobContent component if a Blob viewer is available', () => { - loadViewer.mockReturnValueOnce(() => true); - factory({ mockData: { blobInfo: richMockData } }); + it('does not render a BlobContent component if a Blob viewer is available', async () => { + loadViewer.mockReturnValue(() => true); + await createComponent({ blob: richViewerMock }); expect(findBlobContent().exists()).toBe(false); }); @@ -305,15 +222,13 @@ describe('Blob content viewer component', () => { loadViewer.mockReturnValue(loadViewerReturnValue); viewerProps.mockReturnValue(viewerPropsReturnValue); - factory({ - mockData: { - blobInfo: { - ...simpleMockData, - fileType: null, - simpleViewer: { - ...simpleMockData.simpleViewer, - fileType: viewer, - }, + createComponent({ + blob: { + ...simpleViewerMock, + fileType: 'null', + simpleViewer: { + ...simpleViewerMock.simpleViewer, + fileType: viewer, }, }, }); @@ -327,18 +242,10 @@ describe('Blob content viewer component', () => { }); describe('BlobHeader action slot', () => { - const { ideEditPath, editBlobPath } = simpleMockData; + const { ideEditPath, editBlobPath } = simpleViewerMock; it('renders BlobHeaderEdit buttons in simple viewer', async () => { - fullFactory({ - mockData: { blobInfo: simpleMockData }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - - await nextTick(); + await createComponent({ inject: { BlobContent: true, BlobReplace: true } }, mount); expect(findBlobEdit().props()).toMatchObject({ editPath: editBlobPath, @@ -348,15 +255,7 @@ describe('Blob content viewer component', () => { }); it('renders BlobHeaderEdit button in rich viewer', async () => { - fullFactory({ - mockData: { blobInfo: richMockData }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - - await nextTick(); + await createComponent({ blob: richViewerMock }, mount); expect(findBlobEdit().props()).toMatchObject({ editPath: editBlobPath, @@ -366,15 +265,7 @@ describe('Blob content viewer component', () => { }); it('renders BlobHeaderEdit button for binary files', async () => { - fullFactory({ - mockData: { blobInfo: richMockData, isBinary: true }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - - await nextTick(); + await createComponent({ blob: richViewerMock, isBinary: true }, mount); expect(findBlobEdit().props()).toMatchObject({ editPath: editBlobPath, @@ -383,42 +274,36 @@ describe('Blob content viewer component', () => { }); }); - describe('blob header binary file', () => { - it.each([richMockData, { simpleViewer: { fileType: 'download' } }])( - 'passes the correct isBinary value when viewing a binary file', - async (blobInfo) => { - fullFactory({ - mockData: { - blobInfo, - isBinary: true, - }, - stubs: { BlobContent: true, BlobReplace: true }, - }); + it('renders Pipeline Editor button for .gitlab-ci files', async () => { + const pipelineEditorPath = 'some/path/.gitlab-ce'; + const blob = { ...simpleViewerMock, pipelineEditorPath }; + await createComponent({ blob, inject: { BlobContent: true, BlobReplace: true } }, mount); - await nextTick(); + expect(findPipelineEditor().exists()).toBe(true); + expect(findPipelineEditor().attributes('href')).toBe(pipelineEditorPath); + }); - expect(findBlobHeader().props('isBinary')).toBe(true); - }, - ); + describe('blob header binary file', () => { + it('passes the correct isBinary value when viewing a binary file', async () => { + await createComponent({ blob: richViewerMock, isBinary: true }); + + expect(findBlobHeader().props('isBinary')).toBe(true); + }); it('passes the correct header props when viewing a non-text file', async () => { - fullFactory({ - mockData: { - blobInfo: { - ...simpleMockData, + await createComponent( + { + blob: { + ...simpleViewerMock, simpleViewer: { - ...simpleMockData.simpleViewer, + ...simpleViewerMock.simpleViewer, fileType: 'image', }, }, + isBinary: true, }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - - await nextTick(); + mount, + ); expect(findBlobHeader().props('hideViewerSwitcher')).toBe(true); expect(findBlobHeader().props('isBinary')).toBe(true); @@ -427,27 +312,16 @@ describe('Blob content viewer component', () => { }); describe('BlobButtonGroup', () => { - const { name, path, replacePath, webPath } = simpleMockData; + const { name, path, replacePath, webPath } = simpleViewerMock; const { userPermissions: { pushCode, downloadCode }, repository: { empty }, - } = projectMockData; + } = projectMock; it('renders component', async () => { window.gon.current_user_id = 1; - fullFactory({ - mockData: { - blobInfo: simpleMockData, - project: { userPermissions: { pushCode, downloadCode }, repository: { empty } }, - }, - stubs: { - BlobContent: true, - BlobButtonGroup: true, - }, - }); - - await nextTick(); + await createComponent({ pushCode, downloadCode, empty }, mount); expect(findBlobButtonGroup().props()).toMatchObject({ name, @@ -467,21 +341,14 @@ describe('Blob content viewer component', () => { ${false} | ${true} | ${false} ${true} | ${false} | ${false} `('passes the correct lock states', async ({ canPushCode, canDownloadCode, canLock }) => { - fullFactory({ - mockData: { - blobInfo: simpleMockData, - project: { - userPermissions: { pushCode: canPushCode, downloadCode: canDownloadCode }, - repository: { empty }, - }, + await createComponent( + { + pushCode: canPushCode, + downloadCode: canDownloadCode, + empty, }, - stubs: { - BlobContent: true, - BlobButtonGroup: true, - }, - }); - - await nextTick(); + mount, + ); expect(findBlobButtonGroup().props('canLock')).toBe(canLock); }); @@ -489,15 +356,7 @@ describe('Blob content viewer component', () => { it('does not render if not logged in', async () => { isLoggedIn.mockReturnValueOnce(false); - fullFactory({ - mockData: { blobInfo: simpleMockData }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - - await nextTick(); + await createComponent(); expect(findBlobButtonGroup().exists()).toBe(false); }); @@ -506,10 +365,7 @@ describe('Blob content viewer component', () => { describe('blob info query', () => { it('is called with originalBranch value if the prop has a value', async () => { - const inject = { originalBranch: 'some-branch' }; - createComponentWithApollo({ blobs: simpleMockData }, inject); - - await waitForPromises(); + await createComponent({ inject: { originalBranch: 'some-branch' } }); expect(mockResolver).toHaveBeenCalledWith( expect.objectContaining({ @@ -519,10 +375,7 @@ describe('Blob content viewer component', () => { }); it('is called with ref value if the originalBranch prop has no value', async () => { - const inject = { originalBranch: null }; - createComponentWithApollo({ blobs: simpleMockData }, inject); - - await waitForPromises(); + await createComponent(); expect(mockResolver).toHaveBeenCalledWith( expect.objectContaining({ @@ -533,24 +386,16 @@ describe('Blob content viewer component', () => { }); describe('edit blob', () => { - beforeEach(() => { - fullFactory({ - mockData: { blobInfo: simpleMockData }, - stubs: { - BlobContent: true, - BlobReplace: true, - }, - }); - }); + beforeEach(() => createComponent({}, mount)); it('simple edit redirects to the simple editor', () => { findBlobEdit().vm.$emit('edit', 'simple'); - expect(redirectTo).toHaveBeenCalledWith(simpleMockData.editBlobPath); + expect(redirectTo).toHaveBeenCalledWith(simpleViewerMock.editBlobPath); }); it('IDE edit redirects to the IDE editor', () => { findBlobEdit().vm.$emit('edit', 'ide'); - expect(redirectTo).toHaveBeenCalledWith(simpleMockData.ideEditPath); + expect(redirectTo).toHaveBeenCalledWith(simpleViewerMock.ideEditPath); }); it.each` @@ -569,16 +414,14 @@ describe('Blob content viewer component', () => { showForkSuggestion, }) => { isLoggedIn.mockReturnValueOnce(loggedIn); - fullFactory({ - mockData: { - blobInfo: { ...simpleMockData, canModifyBlob }, - project: { userPermissions: { createMergeRequestIn, forkProject } }, + await createComponent( + { + blob: { ...simpleViewerMock, canModifyBlob }, + createMergeRequestIn, + forkProject, }, - stubs: { - BlobContent: true, - BlobButtonGroup: true, - }, - }); + mount, + ); findBlobEdit().vm.$emit('edit', 'simple'); await nextTick(); diff --git a/spec/frontend/repository/components/upload_blob_modal_spec.js b/spec/frontend/repository/components/upload_blob_modal_spec.js index 08a6583b60c..36847107558 100644 --- a/spec/frontend/repository/components/upload_blob_modal_spec.js +++ b/spec/frontend/repository/components/upload_blob_modal_spec.js @@ -6,11 +6,9 @@ import waitForPromises from 'helpers/wait_for_promises'; import createFlash from '~/flash'; import httpStatusCodes from '~/lib/utils/http_status'; import { visitUrl } from '~/lib/utils/url_utility'; -import { trackFileUploadEvent } from '~/projects/upload_file_experiment_tracking'; import UploadBlobModal from '~/repository/components/upload_blob_modal.vue'; import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue'; -jest.mock('~/projects/upload_file_experiment_tracking'); jest.mock('~/flash'); jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn(), @@ -162,10 +160,6 @@ describe('UploadBlobModal', () => { await waitForPromises(); }); - it('tracks the click_upload_modal_trigger event when opening the modal', () => { - expect(trackFileUploadEvent).toHaveBeenCalledWith('click_upload_modal_form_submit'); - }); - it('redirects to the uploaded file', () => { expect(visitUrl).toHaveBeenCalled(); }); @@ -185,10 +179,6 @@ describe('UploadBlobModal', () => { await waitForPromises(); }); - it('does not track an event', () => { - expect(trackFileUploadEvent).not.toHaveBeenCalled(); - }); - it('creates a flash error', () => { expect(createFlash).toHaveBeenCalledWith({ message: 'Error uploading file. Please try again.', diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js new file mode 100644 index 00000000000..adf5991ac3c --- /dev/null +++ b/spec/frontend/repository/mock_data.js @@ -0,0 +1,57 @@ +export const simpleViewerMock = { + name: 'some_file.js', + size: 123, + rawSize: 123, + rawTextBlob: 'raw content', + fileType: 'text', + path: 'some_file.js', + webPath: 'some_file.js', + editBlobPath: 'some_file.js/edit', + ideEditPath: 'some_file.js/ide/edit', + forkAndEditPath: 'some_file.js/fork/edit', + ideForkAndEditPath: 'some_file.js/fork/ide', + canModifyBlob: true, + storedExternally: false, + rawPath: 'some_file.js', + replacePath: 'some_file.js/replace', + pipelineEditorPath: '', + simpleViewer: { + fileType: 'text', + tooLarge: false, + type: 'simple', + renderError: null, + }, + richViewer: null, +}; + +export const richViewerMock = { + ...simpleViewerMock, + richViewer: { + fileType: 'markup', + tooLarge: false, + type: 'rich', + renderError: null, + }, +}; + +export const userPermissionsMock = { + pushCode: true, + forkProject: true, + downloadCode: true, + createMergeRequestIn: true, +}; + +export const projectMock = { + id: '1234', + userPermissions: userPermissionsMock, + pathLocks: { + nodes: [], + }, + repository: { + empty: false, + }, +}; + +export const propsMock = { path: 'some_file.js', projectPath: 'some/path' }; + +export const refMock = 'default-ref'; |