diff --git a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/app.vue b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/app.vue index 62cd5c7e256b5086a75b962ca0bd2623c6f90f8f..6b2a56bfe958c96123efb53765ab2539f0af8770 100644 --- a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/app.vue +++ b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/app.vue @@ -125,13 +125,14 @@ export default { <gl-alert v-if="alertMessage" class="checkout-alert" variant="danger" :dismissible="false"> {{ alertMessage }} </gl-alert> - <checkout :plan="plan"> + <checkout :plan="plan" @alertError="alertError"> <template #purchase-details> <addon-purchase-details :product-label="plan.label" :quantity="quantity" :show-alert="true" :alert-text="i18n.alertText" + @alertError="alertError" > <template #formula> {{ formulaText }} diff --git a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue index 8d5b49e383ab1f22771b41fef1741a0dc83ebde9..06e36166e998374e6b1f26f3283a3fbbfdc1d893 100644 --- a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue +++ b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout.vue @@ -1,10 +1,10 @@ <script> +import { logError } from '~/lib/logger'; import updateState from 'ee/subscriptions/graphql/mutations/update_state.mutation.graphql'; import BillingAddress from 'jh_else_ee/vue_shared/purchase_flow/components/checkout/billing_address.vue'; import ConfirmOrder from 'ee/vue_shared/purchase_flow/components/checkout/confirm_order.vue'; import PaymentMethod from 'ee/vue_shared/purchase_flow/components/checkout/payment_method.vue'; import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants'; -import createFlash from '~/flash'; import { s__ } from '~/locale'; export default { @@ -32,9 +32,13 @@ export default { }, }) .catch((error) => { - createFlash({ message: GENERAL_ERROR_MESSAGE, error, captureError: true }); + this.emitError(error); }); }, + emitError(error) { + this.$emit('alertError', GENERAL_ERROR_MESSAGE); + logError(error); + }, }, i18n: { checkout: s__('Checkout|Checkout'), @@ -43,7 +47,6 @@ export default { </script> <template> <div class="checkout gl-display-flex gl-flex-direction-column gl-align-items-center"> - <div class="flash-container"></div> <h2 class="gl-align-self-start gl-mt-6 gl-mb-7 gl-mb-lg-5">{{ $options.i18n.checkout }}</h2> <slot name="purchase-details"></slot> <billing-address /> diff --git a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue index 7894db582bcb55b30742d78ed47e7943fd725fcd..7397fe804571a92909038fbf36d86682972928f4 100644 --- a/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue +++ b/ee/app/assets/javascripts/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue @@ -1,10 +1,10 @@ <script> import { GlAlert, GlFormInput } from '@gitlab/ui'; +import { logError } from '~/lib/logger'; import { STEPS } from 'ee/subscriptions/constants'; import updateState from 'ee/subscriptions/graphql/mutations/update_state.mutation.graphql'; import Step from 'ee/vue_shared/purchase_flow/components/step.vue'; import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants'; -import createFlash from '~/flash'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; import { I18N_DETAILS_STEP_TITLE, @@ -64,9 +64,13 @@ export default { }, }) .catch((error) => { - createFlash({ message: GENERAL_ERROR_MESSAGE, error, captureError: true }); + this.emitError(error); }); }, + emitError(error) { + this.$emit('alertError', GENERAL_ERROR_MESSAGE); + logError(error); + }, }, i18n: { stepTitle: I18N_DETAILS_STEP_TITLE, diff --git a/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details_spec.js b/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details_spec.js index 8a4f75bda01496f7ae3850681a9ee035de2f6188..4735c1c5fbed29f5d64d78082cf45d01f28c2b44 100644 --- a/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details_spec.js +++ b/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details_spec.js @@ -1,23 +1,24 @@ -import { GlAlert } from '@gitlab/ui'; +import { GlAlert, GlFormInput } from '@gitlab/ui'; import Vue from 'vue'; import { merge } from 'lodash'; import VueApollo from 'vue-apollo'; import { stateData as initialStateData } from 'ee_jest/subscriptions/mock_data'; import AddonPurchaseDetails from 'ee/subscriptions/buy_addons_shared/components/checkout/addon_purchase_details.vue'; -import subscriptionsResolvers from 'ee/subscriptions/buy_addons_shared/graphql/resolvers'; import stateQuery from 'ee/subscriptions/graphql/queries/state.query.graphql'; import Step from 'ee/vue_shared/purchase_flow/components/step.vue'; -import purchaseFlowResolvers from 'ee/vue_shared/purchase_flow/graphql/resolvers'; import createMockApollo from 'helpers/mock_apollo_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper'; +import waitForPromises from 'helpers/wait_for_promises'; +import { GENERAL_ERROR_MESSAGE } from 'ee/vue_shared/purchase_flow/constants'; Vue.use(VueApollo); describe('AddonPurchaseDetails', () => { - const resolvers = { ...purchaseFlowResolvers, ...subscriptionsResolvers }; let wrapper; + let updateState = jest.fn(); const createMockApolloProvider = (stateData = {}) => { + const resolvers = { Mutation: { updateState } }; const mockApollo = createMockApollo([], resolvers); const data = merge({}, initialStateData, stateData); mockApollo.clients.defaultClient.cache.writeQuery({ @@ -47,6 +48,7 @@ describe('AddonPurchaseDetails', () => { const findQuantity = () => wrapper.findComponent({ ref: 'quantity' }); const findGlAlert = () => wrapper.findComponent(GlAlert); + const findGlFormInput = () => wrapper.findComponent(GlFormInput); const findProductLabel = () => wrapper.findByTestId('product-label'); const isStepValid = () => wrapper.findComponent(Step).props('isValid'); @@ -102,4 +104,21 @@ describe('AddonPurchaseDetails', () => { expect(findGlAlert().text()).toMatchInterpolatedText('Alert text about your purchase'); }); }); + + describe('when the mutation fails', () => { + beforeEach(() => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + updateState = jest.fn().mockRejectedValue(new Error('Error om input change')); + createComponent(); + }); + + it('should emit `alertError` event', async () => { + findGlFormInput().element.value = 2; + findGlFormInput().trigger('input'); + + await waitForPromises(); + + expect(wrapper.emitted('alertError')).toEqual([[GENERAL_ERROR_MESSAGE]]); + }); + }); }); diff --git a/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout_spec.js b/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout_spec.js index cc93ee59d813a4115ab1b2641566d98bd3386876..c4f8c2ca473561f6a6dadbbacb5fbe878837d43f 100644 --- a/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout_spec.js +++ b/ee/spec/frontend/subscriptions/buy_addons_shared/components/checkout_spec.js @@ -14,10 +14,7 @@ import { stateData as mockStateData, } from 'ee_jest/subscriptions/mock_data'; import createMockApollo from 'helpers/mock_apollo_helper'; -import createFlash from '~/flash'; -import flushPromises from 'helpers/flush_promises'; - -jest.mock('~/flash'); +import waitForPromises from 'helpers/wait_for_promises'; Vue.use(VueApollo); @@ -93,18 +90,16 @@ describe('Checkout', () => { }); describe('when the mutation fails', () => { - beforeEach(() => { + beforeEach(async () => { + jest.spyOn(console, 'error').mockImplementation(() => {}); updateState = jest.fn().mockRejectedValue(new Error('Yikes!')); createComponent(); - return flushPromises(); + + await waitForPromises(); }); - it('displays a flash message', () => { - expect(createFlash).toHaveBeenCalledWith({ - message: GENERAL_ERROR_MESSAGE, - error: new Error('Yikes!'), - captureError: true, - }); + it('should emit `alertError` event', () => { + expect(wrapper.emitted('alertError')).toEqual([[GENERAL_ERROR_MESSAGE]]); }); }); });