diff options
Diffstat (limited to 'spec/frontend/pipeline_editor/pipeline_editor_app_spec.js')
-rw-r--r-- | spec/frontend/pipeline_editor/pipeline_editor_app_spec.js | 118 |
1 files changed, 89 insertions, 29 deletions
diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js index 46d0452f437..887d296222f 100644 --- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js +++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js @@ -7,6 +7,8 @@ import httpStatusCodes from '~/lib/utils/http_status'; import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import TextEditor from '~/pipeline_editor/components/editor/text_editor.vue'; +import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue'; +import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue'; import { COMMIT_SUCCESS, COMMIT_FAILURE, LOAD_FAILURE_UNKNOWN } from '~/pipeline_editor/constants'; import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.graphql'; import PipelineEditorApp from '~/pipeline_editor/pipeline_editor_app.vue'; @@ -29,6 +31,9 @@ const MockEditorLite = { const mockProvide = { ciConfigPath: mockCiConfigPath, defaultBranch: mockDefaultBranch, + glFeatures: { + pipelineEditorEmptyStateAction: false, + }, projectFullPath: mockProjectFullPath, }; @@ -39,14 +44,17 @@ describe('Pipeline editor app component', () => { let mockBlobContentData; let mockCiConfigData; - const createComponent = ({ blobLoading = false, options = {} } = {}) => { + const createComponent = ({ blobLoading = false, options = {}, provide = {} } = {}) => { wrapper = shallowMount(PipelineEditorApp, { - provide: mockProvide, + provide: { ...mockProvide, ...provide }, stubs: { GlTabs, GlButton, CommitForm, + PipelineEditorHome, + PipelineEditorTabs, EditorLite: MockEditorLite, + PipelineEditorEmptyState, }, mocks: { $apollo: { @@ -64,7 +72,7 @@ describe('Pipeline editor app component', () => { }); }; - const createComponentWithApollo = ({ props = {} } = {}) => { + const createComponentWithApollo = ({ props = {}, provide = {} } = {}) => { const handlers = [[getCiConfigData, mockCiConfigData]]; const resolvers = { Query: { @@ -85,13 +93,16 @@ describe('Pipeline editor app component', () => { apolloProvider: mockApollo, }; - createComponent({ props, options }); + createComponent({ props, provide, options }); }; const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); const findAlert = () => wrapper.findComponent(GlAlert); const findEditorHome = () => wrapper.findComponent(PipelineEditorHome); const findTextEditor = () => wrapper.findComponent(TextEditor); + const findEmptyState = () => wrapper.findComponent(PipelineEditorEmptyState); + const findEmptyStateButton = () => + wrapper.findComponent(PipelineEditorEmptyState).findComponent(GlButton); beforeEach(() => { mockBlobContentData = jest.fn(); @@ -103,7 +114,6 @@ describe('Pipeline editor app component', () => { mockCiConfigData.mockReset(); wrapper.destroy(); - wrapper = null; }); it('displays a loading icon if the blob query is loading', () => { @@ -146,45 +156,79 @@ describe('Pipeline editor app component', () => { }); }); - describe('when no file exists', () => { - const noFileAlertMsg = - 'There is no .gitlab-ci.yml file in this repository, please add one and visit the Pipeline Editor again.'; + describe('when no CI config file exists', () => { + describe('in a project without a repository', () => { + it('shows an empty state and does not show editor home component', async () => { + mockBlobContentData.mockRejectedValueOnce({ + response: { + status: httpStatusCodes.BAD_REQUEST, + }, + }); + createComponentWithApollo(); - it('shows a 404 error message and does not show editor home component', async () => { - mockBlobContentData.mockRejectedValueOnce({ - response: { - status: httpStatusCodes.NOT_FOUND, - }, + await waitForPromises(); + + expect(findEmptyState().exists()).toBe(true); + expect(findAlert().exists()).toBe(false); + expect(findEditorHome().exists()).toBe(false); }); - createComponentWithApollo(); + }); - await waitForPromises(); + describe('in a project with a repository', () => { + it('shows an empty state and does not show editor home component', async () => { + mockBlobContentData.mockRejectedValueOnce({ + response: { + status: httpStatusCodes.NOT_FOUND, + }, + }); + createComponentWithApollo(); - expect(findAlert().text()).toBe(noFileAlertMsg); - expect(findEditorHome().exists()).toBe(false); + await waitForPromises(); + + expect(findEmptyState().exists()).toBe(true); + expect(findAlert().exists()).toBe(false); + expect(findEditorHome().exists()).toBe(false); + }); + }); + + describe('because of a fetching error', () => { + it('shows a unkown error message', async () => { + mockBlobContentData.mockRejectedValueOnce(new Error('My error!')); + createComponentWithApollo(); + await waitForPromises(); + + expect(findEmptyState().exists()).toBe(false); + expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[LOAD_FAILURE_UNKNOWN]); + expect(findEditorHome().exists()).toBe(true); + }); }); + }); - it('shows a 400 error message and does not show editor home component', async () => { + describe('when landing on the empty state with feature flag on', () => { + it('user can click on CTA button and see an empty editor', async () => { mockBlobContentData.mockRejectedValueOnce({ response: { - status: httpStatusCodes.BAD_REQUEST, + status: httpStatusCodes.NOT_FOUND, + }, + }); + + createComponentWithApollo({ + provide: { + glFeatures: { + pipelineEditorEmptyStateAction: true, + }, }, }); - createComponentWithApollo(); await waitForPromises(); - expect(findAlert().text()).toBe(noFileAlertMsg); - expect(findEditorHome().exists()).toBe(false); - }); + expect(findEmptyState().exists()).toBe(true); + expect(findTextEditor().exists()).toBe(false); - it('shows a unkown error message', async () => { - mockBlobContentData.mockRejectedValueOnce(new Error('My error!')); - createComponentWithApollo(); - await waitForPromises(); + await findEmptyStateButton().vm.$emit('click'); - expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[LOAD_FAILURE_UNKNOWN]); - expect(findEditorHome().exists()).toBe(true); + expect(findEmptyState().exists()).toBe(false); + expect(findTextEditor().exists()).toBe(true); }); }); @@ -193,6 +237,7 @@ describe('Pipeline editor app component', () => { describe('and the commit mutation succeeds', () => { beforeEach(() => { + window.scrollTo = jest.fn(); createComponent(); findEditorHome().vm.$emit('commit', { type: COMMIT_SUCCESS }); @@ -201,11 +246,16 @@ describe('Pipeline editor app component', () => { it('shows a confirmation message', () => { expect(findAlert().text()).toBe(wrapper.vm.$options.successTexts[COMMIT_SUCCESS]); }); + + it('scrolls to the top of the page to bring attention to the confirmation message', () => { + expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' }); + }); }); describe('and the commit mutation fails', () => { const commitFailedReasons = ['Commit failed']; beforeEach(() => { + window.scrollTo = jest.fn(); createComponent(); findEditorHome().vm.$emit('showError', { @@ -219,11 +269,17 @@ describe('Pipeline editor app component', () => { `${updateFailureMessage} ${commitFailedReasons[0]}`, ); }); + + it('scrolls to the top of the page to bring attention to the error message', () => { + expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' }); + }); }); + describe('when an unknown error occurs', () => { const unknownReasons = ['Commit failed']; beforeEach(() => { + window.scrollTo = jest.fn(); createComponent(); findEditorHome().vm.$emit('showError', { @@ -237,6 +293,10 @@ describe('Pipeline editor app component', () => { `${updateFailureMessage} ${unknownReasons[0]}`, ); }); + + it('scrolls to the top of the page to bring attention to the error message', () => { + expect(window.scrollTo).toHaveBeenCalledWith({ top: 0, behavior: 'smooth' }); + }); }); }); }); |