Commit 83b9b5c9 authored by Vitaly Slobodin's avatar Vitaly Slobodin Committed by Nicolò Maria Mezzopera

Add CC validation modal to new pipeline page [RUN ALL RSPEC] [RUN AS-IF-FOSS]

parent ded4a188
...@@ -21,7 +21,12 @@ import { backOff } from '~/lib/utils/common_utils'; ...@@ -21,7 +21,12 @@ import { backOff } from '~/lib/utils/common_utils';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { s__, __, n__ } from '~/locale'; import { s__, __, n__ } from '~/locale';
import { VARIABLE_TYPE, FILE_TYPE, CONFIG_VARIABLES_TIMEOUT } from '../constants'; import {
VARIABLE_TYPE,
FILE_TYPE,
CONFIG_VARIABLES_TIMEOUT,
CC_VALIDATION_REQUIRED_ERROR,
} from '../constants';
import filterVariables from '../utils/filter_variables'; import filterVariables from '../utils/filter_variables';
import RefsDropdown from './refs_dropdown.vue'; import RefsDropdown from './refs_dropdown.vue';
...@@ -60,6 +65,8 @@ export default { ...@@ -60,6 +65,8 @@ export default {
GlSprintf, GlSprintf,
GlLoadingIcon, GlLoadingIcon,
RefsDropdown, RefsDropdown,
CcValidationRequiredAlert: () =>
import('ee_component/billings/components/cc_validation_required_alert.vue'),
}, },
directives: { SafeHtml }, directives: { SafeHtml },
props: { props: {
...@@ -143,6 +150,9 @@ export default { ...@@ -143,6 +150,9 @@ export default {
descriptions() { descriptions() {
return this.form[this.refFullName]?.descriptions ?? {}; return this.form[this.refFullName]?.descriptions ?? {};
}, },
ccRequiredError() {
return this.error === CC_VALIDATION_REQUIRED_ERROR;
},
}, },
watch: { watch: {
refValue() { refValue() {
...@@ -329,8 +339,9 @@ export default { ...@@ -329,8 +339,9 @@ export default {
<template> <template>
<gl-form @submit.prevent="createPipeline"> <gl-form @submit.prevent="createPipeline">
<cc-validation-required-alert v-if="ccRequiredError" class="gl-pb-5" />
<gl-alert <gl-alert
v-if="error" v-else-if="error"
:title="errorTitle" :title="errorTitle"
:dismissible="false" :dismissible="false"
variant="danger" variant="danger"
......
...@@ -4,3 +4,6 @@ export const DEBOUNCE_REFS_SEARCH_MS = 250; ...@@ -4,3 +4,6 @@ export const DEBOUNCE_REFS_SEARCH_MS = 250;
export const CONFIG_VARIABLES_TIMEOUT = 5000; export const CONFIG_VARIABLES_TIMEOUT = 5000;
export const BRANCH_REF_TYPE = 'branch'; export const BRANCH_REF_TYPE = 'branch';
export const TAG_REF_TYPE = 'tag'; export const TAG_REF_TYPE = 'tag';
export const CC_VALIDATION_REQUIRED_ERROR =
'Credit card required to be on file in order to create a pipeline';
<script> <script>
import { GlAlert, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui';
import { objectToQuery } from '~/lib/utils/url_utility';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
const IFRAME_QUERY = 'enable_submit=false&pp=disable'; const IFRAME_QUERY = Object.freeze({
enable_submit: false,
user_id: null,
});
// 450 is the mininum required height to get all iframe inputs visible // 450 is the mininum required height to get all iframe inputs visible
const IFRAME_MINIMUM_HEIGHT = 450; const IFRAME_MINIMUM_HEIGHT = 450;
const i18n = Object.freeze({ const i18n = Object.freeze({
...@@ -44,7 +48,9 @@ export default { ...@@ -44,7 +48,9 @@ export default {
}, },
computed: { computed: {
iframeSrc() { iframeSrc() {
return `${this.iframeUrl}?${IFRAME_QUERY}`; const query = { ...IFRAME_QUERY, user_id: gon.current_user_id };
return `${this.iframeUrl}?${objectToQuery(query)}`;
}, },
iframeHeight() { iframeHeight() {
return IFRAME_MINIMUM_HEIGHT * window.devicePixelRatio; return IFRAME_MINIMUM_HEIGHT * window.devicePixelRatio;
...@@ -75,7 +81,14 @@ export default { ...@@ -75,7 +81,14 @@ export default {
return; return;
} }
this.error = event.data; if (event.data.success) {
this.$emit('success');
} else {
this.error = event.data.msg;
this.$refs.zuora.src = this.iframeSrc;
this.$emit('error', this.error);
}
this.isLoading = false; this.isLoading = false;
}, },
isEventAllowedForOrigin(event) { isEventAllowedForOrigin(event) {
...@@ -108,12 +121,12 @@ export default { ...@@ -108,12 +121,12 @@ export default {
</gl-sprintf> </gl-sprintf>
</p> </p>
<gl-alert v-if="error" variant="danger">{{ error.msg }}</gl-alert> <gl-alert v-if="error" variant="danger">{{ error }}</gl-alert>
<gl-loading-icon v-if="isLoading" size="lg" /> <gl-loading-icon v-if="isLoading" size="lg" />
<!-- eslint-disable @gitlab/vue-require-i18n-strings --> <!-- eslint-disable @gitlab/vue-require-i18n-strings -->
<iframe <iframe
v-show="!isLoading" v-show="!isLoading"
id="zuora" ref="zuora"
:src="iframeSrc" :src="iframeSrc"
style="border: none" style="border: none"
width="100%" width="100%"
......
...@@ -18,14 +18,12 @@ export default { ...@@ -18,14 +18,12 @@ export default {
GlSprintf, GlSprintf,
AccountVerificationModal, AccountVerificationModal,
}, },
props: { computed: {
iframeUrl: { iframeUrl() {
type: String, return gon.payment_form_url;
required: true,
}, },
allowedOrigin: { allowedOrigin() {
type: String, return gon.subscriptions_url;
required: true,
}, },
}, },
methods: { methods: {
...@@ -38,7 +36,7 @@ export default { ...@@ -38,7 +36,7 @@ export default {
</script> </script>
<template> <template>
<div class="gl-pt-5"> <div>
<gl-alert <gl-alert
variant="danger" variant="danger"
:dismissible="false" :dismissible="false"
......
import { GlAlert, GlSprintf } from '@gitlab/ui'; import { GlAlert, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import CreditCardValidationRequiredAlert from 'ee/billings/components/cc_validation_required_alert.vue'; import CreditCardValidationRequiredAlert from 'ee/billings/components/cc_validation_required_alert.vue';
import { TEST_HOST } from 'helpers/test_constants';
describe('CreditCardValidationRequiredAlert', () => { describe('CreditCardValidationRequiredAlert', () => {
let wrapper; let wrapper;
const createComponent = () => { const createComponent = () => {
return shallowMount(CreditCardValidationRequiredAlert, { return shallowMount(CreditCardValidationRequiredAlert, {
propsData: {
iframeUrl: 'about:blank',
allowedOrigin: 'about:blank',
},
stubs: { stubs: {
GlSprintf, GlSprintf,
}, },
...@@ -18,6 +15,11 @@ describe('CreditCardValidationRequiredAlert', () => { ...@@ -18,6 +15,11 @@ describe('CreditCardValidationRequiredAlert', () => {
}; };
beforeEach(() => { beforeEach(() => {
window.gon = {
subscriptions_url: TEST_HOST,
payment_form_url: TEST_HOST,
};
wrapper = createComponent(); wrapper = createComponent();
}); });
......
import { GlForm, GlSprintf, GlLoadingIcon } from '@gitlab/ui'; import { GlForm, GlSprintf, GlLoadingIcon } from '@gitlab/ui';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import CreditCardValidationRequiredAlert from 'ee_component/billings/components/cc_validation_required_alert.vue';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue'; import PipelineNewForm from '~/pipeline_new/components/pipeline_new_form.vue';
import RefsDropdown from '~/pipeline_new/components/refs_dropdown.vue'; import RefsDropdown from '~/pipeline_new/components/refs_dropdown.vue';
import { mockQueryParams, mockPostParams, mockProjectId, mockError, mockRefs } from '../mock_data'; import {
mockQueryParams,
mockPostParams,
mockProjectId,
mockError,
mockRefs,
mockCreditCardValidationRequiredError,
} from '../mock_data';
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(), redirectTo: jest.fn(),
...@@ -376,6 +385,32 @@ describe('Pipeline New Form', () => { ...@@ -376,6 +385,32 @@ describe('Pipeline New Form', () => {
it('re-enables the submit button', () => { it('re-enables the submit button', () => {
expect(findSubmitButton().props('disabled')).toBe(false); expect(findSubmitButton().props('disabled')).toBe(false);
}); });
it('does not show the credit card validation required alert', () => {
expect(wrapper.findComponent(CreditCardValidationRequiredAlert).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(wrapper.findComponent(CreditCardValidationRequiredAlert).exists()).toBe(true);
});
});
}); });
describe('when the error response cannot be handled', () => { describe('when the error response cannot be handled', () => {
......
...@@ -40,6 +40,12 @@ export const mockError = { ...@@ -40,6 +40,12 @@ export const mockError = {
total_warnings: 7, total_warnings: 7,
}; };
export const mockCreditCardValidationRequiredError = {
errors: ['Credit card required to be on file in order to create a pipeline'],
warnings: [],
total_warnings: 0,
};
export const mockBranchRefs = ['main', 'dev', 'release']; export const mockBranchRefs = ['main', 'dev', 'release'];
export const mockTagRefs = ['1.0.0', '1.1.0', '1.2.0']; export const mockTagRefs = ['1.0.0', '1.1.0', '1.2.0'];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment