diff options
Diffstat (limited to 'spec/frontend/pipeline_new/components/pipeline_new_form_spec.js')
-rw-r--r-- | spec/frontend/pipeline_new/components/pipeline_new_form_spec.js | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js b/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js deleted file mode 100644 index 2360dd7d103..00000000000 --- a/spec/frontend/pipeline_new/components/pipeline_new_form_spec.js +++ /dev/null @@ -1,466 +0,0 @@ -import Vue, { nextTick } from 'vue'; -import VueApollo from 'vue-apollo'; -import { GlForm, GlDropdownItem, GlSprintf, GlLoadingIcon } from '@gitlab/ui'; -import MockAdapter from 'axios-mock-adapter'; -import CreditCardValidationRequiredAlert from 'ee_component/billings/components/cc_validation_required_alert.vue'; -import createMockApollo from 'helpers/mock_apollo_helper'; -import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; -import { TEST_HOST } from 'helpers/test_constants'; -import waitForPromises from 'helpers/wait_for_promises'; -import axios from '~/lib/utils/axios_utils'; -import httpStatusCodes from '~/lib/utils/http_status'; -import { redirectTo } from '~/lib/utils/url_utility'; -import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue'; -import ciConfigVariablesQuery from '~/pipeline_new/graphql/queries/ci_config_variables.graphql'; -import { resolvers } from '~/pipeline_new/graphql/resolvers'; -import RefsDropdown from '~/pipeline_new/components/refs_dropdown.vue'; -import { - mockCreditCardValidationRequiredError, - mockCiConfigVariablesResponse, - mockCiConfigVariablesResponseWithoutDesc, - mockEmptyCiConfigVariablesResponse, - mockError, - mockQueryParams, - mockPostParams, - mockProjectId, - mockRefs, - mockYamlVariables, -} from '../mock_data'; - -Vue.use(VueApollo); - -jest.mock('~/lib/utils/url_utility', () => ({ - redirectTo: jest.fn(), -})); - -const projectRefsEndpoint = '/root/project/refs'; -const pipelinesPath = '/root/project/-/pipelines'; -const projectPath = '/root/project/-/pipelines/config_variables'; -const newPipelinePostResponse = { id: 1 }; -const defaultBranch = 'main'; - -describe('Pipeline New Form', () => { - let wrapper; - let mock; - let mockApollo; - let mockCiConfigVariables; - let dummySubmitEvent; - - const findForm = () => wrapper.findComponent(GlForm); - const findRefsDropdown = () => wrapper.findComponent(RefsDropdown); - const findSubmitButton = () => wrapper.findByTestId('run_pipeline_button'); - const findVariableRows = () => wrapper.findAllByTestId('ci-variable-row'); - const findRemoveIcons = () => wrapper.findAllByTestId('remove-ci-variable-row'); - const findVariableTypes = () => wrapper.findAllByTestId('pipeline-form-ci-variable-type'); - const findKeyInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-key'); - const findValueInputs = () => wrapper.findAllByTestId('pipeline-form-ci-variable-value'); - const findValueDropdowns = () => - wrapper.findAllByTestId('pipeline-form-ci-variable-value-dropdown'); - const findValueDropdownItems = (dropdown) => dropdown.findAllComponents(GlDropdownItem); - const findErrorAlert = () => wrapper.findByTestId('run-pipeline-error-alert'); - const findWarningAlert = () => wrapper.findByTestId('run-pipeline-warning-alert'); - const findWarningAlertSummary = () => findWarningAlert().findComponent(GlSprintf); - const findWarnings = () => wrapper.findAllByTestId('run-pipeline-warning'); - const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); - const findCCAlert = () => wrapper.findComponent(CreditCardValidationRequiredAlert); - const getFormPostParams = () => JSON.parse(mock.history.post[0].data); - - const selectBranch = async (branch) => { - // Select a branch in the dropdown - findRefsDropdown().vm.$emit('input', { - shortName: branch, - fullName: `refs/heads/${branch}`, - }); - - await waitForPromises(); - }; - - const changeKeyInputValue = async (keyInputIndex, value) => { - const input = findKeyInputs().at(keyInputIndex); - input.element.value = value; - input.trigger('change'); - - await nextTick(); - }; - - const createComponentWithApollo = ({ method = shallowMountExtended, props = {} } = {}) => { - const handlers = [[ciConfigVariablesQuery, mockCiConfigVariables]]; - mockApollo = createMockApollo(handlers, resolvers); - - wrapper = method(PipelineNewForm, { - apolloProvider: mockApollo, - provide: { - projectRefsEndpoint, - }, - propsData: { - projectId: mockProjectId, - pipelinesPath, - projectPath, - defaultBranch, - refParam: defaultBranch, - settingsLink: '', - maxWarnings: 25, - ...props, - }, - }); - }; - - beforeEach(() => { - mock = new MockAdapter(axios); - mockCiConfigVariables = jest.fn(); - mock.onGet(projectRefsEndpoint).reply(httpStatusCodes.OK, mockRefs); - - dummySubmitEvent = { - preventDefault: jest.fn(), - }; - }); - - afterEach(() => { - mock.restore(); - wrapper.destroy(); - }); - - describe('Form', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockEmptyCiConfigVariablesResponse); - createComponentWithApollo({ props: mockQueryParams, method: mountExtended }); - await waitForPromises(); - }); - - it('displays the correct values for the provided query params', async () => { - expect(findVariableTypes().at(0).props('text')).toBe('Variable'); - expect(findVariableTypes().at(1).props('text')).toBe('File'); - expect(findRefsDropdown().props('value')).toEqual({ shortName: 'tag-1' }); - expect(findVariableRows()).toHaveLength(3); - }); - - it('displays a variable from provided query params', () => { - expect(findKeyInputs().at(0).element.value).toBe('test_var'); - expect(findValueInputs().at(0).element.value).toBe('test_var_val'); - }); - - it('displays an empty variable for the user to fill out', async () => { - expect(findKeyInputs().at(2).element.value).toBe(''); - expect(findValueInputs().at(2).element.value).toBe(''); - expect(findVariableTypes().at(2).props('text')).toBe('Variable'); - }); - - it('does not display remove icon for last row', () => { - expect(findRemoveIcons()).toHaveLength(2); - }); - - it('removes ci variable row on remove icon button click', async () => { - findRemoveIcons().at(1).trigger('click'); - - await nextTick(); - - expect(findVariableRows()).toHaveLength(2); - }); - - it('creates blank variable on input change event', async () => { - const input = findKeyInputs().at(2); - input.element.value = 'test_var_2'; - input.trigger('change'); - - await nextTick(); - - expect(findVariableRows()).toHaveLength(4); - expect(findKeyInputs().at(3).element.value).toBe(''); - expect(findValueInputs().at(3).element.value).toBe(''); - }); - }); - - describe('Pipeline creation', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockEmptyCiConfigVariablesResponse); - mock.onPost(pipelinesPath).reply(httpStatusCodes.OK, newPipelinePostResponse); - }); - - it('does not submit the native HTML form', async () => { - createComponentWithApollo(); - - findForm().vm.$emit('submit', dummySubmitEvent); - - expect(dummySubmitEvent.preventDefault).toHaveBeenCalled(); - }); - - it('disables the submit button immediately after submitting', async () => { - createComponentWithApollo(); - - expect(findSubmitButton().props('disabled')).toBe(false); - - findForm().vm.$emit('submit', dummySubmitEvent); - await waitForPromises(); - - expect(findSubmitButton().props('disabled')).toBe(true); - }); - - it('creates pipeline with full ref and variables', async () => { - createComponentWithApollo(); - - findForm().vm.$emit('submit', dummySubmitEvent); - await waitForPromises(); - - expect(getFormPostParams().ref).toEqual(`refs/heads/${defaultBranch}`); - expect(redirectTo).toHaveBeenCalledWith(`${pipelinesPath}/${newPipelinePostResponse.id}`); - }); - - it('creates a pipeline with short ref and variables from the query params', async () => { - createComponentWithApollo({ props: mockQueryParams }); - - await waitForPromises(); - - findForm().vm.$emit('submit', dummySubmitEvent); - - await waitForPromises(); - - expect(getFormPostParams()).toEqual(mockPostParams); - expect(redirectTo).toHaveBeenCalledWith(`${pipelinesPath}/${newPipelinePostResponse.id}`); - }); - }); - - describe('When the ref has been changed', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockEmptyCiConfigVariablesResponse); - createComponentWithApollo({ method: mountExtended }); - - await waitForPromises(); - }); - - it('variables persist between ref changes', async () => { - await selectBranch('main'); - await changeKeyInputValue(0, 'build_var'); - - await selectBranch('branch-1'); - await changeKeyInputValue(0, 'deploy_var'); - - await selectBranch('main'); - - expect(findKeyInputs().at(0).element.value).toBe('build_var'); - expect(findVariableRows().length).toBe(2); - - await selectBranch('branch-1'); - - expect(findKeyInputs().at(0).element.value).toBe('deploy_var'); - expect(findVariableRows().length).toBe(2); - }); - - it('skips query call when form variables are already cached', async () => { - await selectBranch('main'); - await changeKeyInputValue(0, 'build_var'); - - expect(mockCiConfigVariables).toHaveBeenCalledTimes(1); - - await selectBranch('branch-1'); - - expect(mockCiConfigVariables).toHaveBeenCalledTimes(2); - - // no additional call since `main` form values have been cached - await selectBranch('main'); - - expect(mockCiConfigVariables).toHaveBeenCalledTimes(2); - }); - }); - - describe('when yml defines a variable', () => { - it('loading icon is shown when content is requested and hidden when received', async () => { - mockCiConfigVariables.mockResolvedValue(mockEmptyCiConfigVariablesResponse); - createComponentWithApollo({ props: mockQueryParams, method: mountExtended }); - - expect(findLoadingIcon().exists()).toBe(true); - - await waitForPromises(); - - expect(findLoadingIcon().exists()).toBe(false); - }); - - describe('with different predefined values', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockCiConfigVariablesResponse); - createComponentWithApollo({ method: mountExtended }); - await waitForPromises(); - }); - - it('multi-line strings are added to the value field without removing line breaks', () => { - expect(findValueInputs().at(1).element.value).toBe(mockYamlVariables[1].value); - }); - - it('multiple predefined values are rendered as a dropdown', () => { - const dropdown = findValueDropdowns().at(0); - const dropdownItems = findValueDropdownItems(dropdown); - const { valueOptions } = mockYamlVariables[2]; - - expect(dropdownItems.at(0).text()).toBe(valueOptions[0]); - expect(dropdownItems.at(1).text()).toBe(valueOptions[1]); - expect(dropdownItems.at(2).text()).toBe(valueOptions[2]); - }); - - it('variable with multiple predefined values sets value as the default', () => { - const dropdown = findValueDropdowns().at(0); - const { valueOptions } = mockYamlVariables[2]; - - expect(dropdown.props('text')).toBe(valueOptions[1]); - }); - }); - - describe('with description', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockCiConfigVariablesResponse); - createComponentWithApollo({ props: mockQueryParams, method: mountExtended }); - await waitForPromises(); - }); - - it('displays all the variables', async () => { - expect(findVariableRows()).toHaveLength(6); - }); - - it('displays a variable from yml', () => { - expect(findKeyInputs().at(0).element.value).toBe(mockYamlVariables[0].key); - expect(findValueInputs().at(0).element.value).toBe(mockYamlVariables[0].value); - }); - - it('displays a variable from provided query params', () => { - expect(findKeyInputs().at(3).element.value).toBe( - Object.keys(mockQueryParams.variableParams)[0], - ); - expect(findValueInputs().at(3).element.value).toBe( - Object.values(mockQueryParams.fileParams)[0], - ); - }); - - it('adds a description to the first variable from yml', () => { - expect(findVariableRows().at(0).text()).toContain(mockYamlVariables[0].description); - }); - - it('removes the description when a variable key changes', async () => { - findKeyInputs().at(0).element.value = 'yml_var_modified'; - findKeyInputs().at(0).trigger('change'); - - await nextTick(); - - expect(findVariableRows().at(0).text()).not.toContain(mockYamlVariables[0].description); - }); - }); - - describe('without description', () => { - beforeEach(async () => { - mockCiConfigVariables.mockResolvedValue(mockCiConfigVariablesResponseWithoutDesc); - createComponentWithApollo({ method: mountExtended }); - await waitForPromises(); - }); - - it('displays variables with description only', async () => { - expect(findVariableRows()).toHaveLength(2); // extra empty variable is added at the end - }); - }); - }); - - describe('Form errors and warnings', () => { - beforeEach(() => { - mockCiConfigVariables.mockResolvedValue(mockEmptyCiConfigVariablesResponse); - createComponentWithApollo(); - }); - - describe('when the refs cannot be loaded', () => { - beforeEach(() => { - mock - .onGet(projectRefsEndpoint, { params: { search: '' } }) - .reply(httpStatusCodes.INTERNAL_SERVER_ERROR); - - findRefsDropdown().vm.$emit('loadingError'); - }); - - it('shows both an error alert', () => { - expect(findErrorAlert().exists()).toBe(true); - expect(findWarningAlert().exists()).toBe(false); - }); - }); - - describe('when the error response can be handled', () => { - beforeEach(async () => { - mock.onPost(pipelinesPath).reply(httpStatusCodes.BAD_REQUEST, mockError); - - findForm().vm.$emit('submit', dummySubmitEvent); - - await waitForPromises(); - }); - - it('shows both error and warning', () => { - expect(findErrorAlert().exists()).toBe(true); - expect(findWarningAlert().exists()).toBe(true); - }); - - it('shows the correct error', () => { - expect(findErrorAlert().text()).toBe(mockError.errors[0]); - }); - - it('shows the correct warning title', () => { - const { length } = mockError.warnings; - - expect(findWarningAlertSummary().attributes('message')).toBe(`${length} warnings found:`); - }); - - it('shows the correct amount of warnings', () => { - expect(findWarnings()).toHaveLength(mockError.warnings.length); - }); - - it('re-enables the submit button', () => { - expect(findSubmitButton().props('disabled')).toBe(false); - }); - - it('does not show the credit card validation required alert', () => { - expect(findCCAlert().exists()).toBe(false); - }); - - describe('when the error response is credit card validation required', () => { - beforeEach(async () => { - mock - .onPost(pipelinesPath) - .reply(httpStatusCodes.BAD_REQUEST, mockCreditCardValidationRequiredError); - - window.gon = { - subscriptions_url: TEST_HOST, - payment_form_url: TEST_HOST, - }; - - findForm().vm.$emit('submit', dummySubmitEvent); - - await waitForPromises(); - }); - - it('shows credit card validation required alert', () => { - expect(findErrorAlert().exists()).toBe(false); - expect(findCCAlert().exists()).toBe(true); - }); - - it('clears error and hides the alert on dismiss', async () => { - expect(findCCAlert().exists()).toBe(true); - expect(wrapper.vm.$data.error).toBe(mockCreditCardValidationRequiredError.errors[0]); - - findCCAlert().vm.$emit('dismiss'); - - await nextTick(); - - expect(findCCAlert().exists()).toBe(false); - expect(wrapper.vm.$data.error).toBe(null); - }); - }); - }); - - describe('when the error response cannot be handled', () => { - beforeEach(async () => { - mock - .onPost(pipelinesPath) - .reply(httpStatusCodes.INTERNAL_SERVER_ERROR, 'something went wrong'); - - findForm().vm.$emit('submit', dummySubmitEvent); - - await waitForPromises(); - }); - - it('re-enables the submit button', () => { - expect(findSubmitButton().props('disabled')).toBe(false); - }); - }); - }); -}); |