Commit 0546b49b authored by Angelo Gulina's avatar Angelo Gulina Committed by Andrew Fontaine

Update errors for Subscription Activation Alert

parent 11a4bfc7
......@@ -5,8 +5,12 @@ import {
CONNECTIVITY_ERROR,
connectivityErrorAlert,
connectivityIssue,
generalActivationError,
generalActivationErrorMessage,
generalActivationErrorTitle,
howToActivateSubscription,
INVALID_CODE_ERROR,
invalidActivationCode,
supportLink,
} from '../constants';
export const troubleshootingHelpLink = helpPagePath('user/admin_area/license.html', {
......@@ -20,11 +24,14 @@ export default {
connectivityIssueTitle: connectivityIssue,
connectivityIssueSubtitle: connectivityErrorAlert.subtitle,
connectivityIssueHelpText: connectivityErrorAlert.helpText,
generalActivationError,
generalActivationErrorMessage,
generalActivationErrorTitle,
howToActivateSubscription,
invalidActivationCode,
},
links: {
subscriptionActivationHelpLink,
supportLink,
troubleshootingHelpLink,
},
components: {
......@@ -40,20 +47,26 @@ export default {
},
},
computed: {
hasConnectivityIssue() {
hasConnectivityIssueError() {
return this.error === CONNECTIVITY_ERROR;
},
hasError() {
return this.error;
},
hasGeneralError() {
return this.error && !this.hasConnectivityIssue;
return ![CONNECTIVITY_ERROR, INVALID_CODE_ERROR].includes(this.error);
},
hasInvalidCodeError() {
return this.error === INVALID_CODE_ERROR;
},
},
};
</script>
<template>
<div>
<div v-if="hasError" data-testid="root">
<gl-alert
v-if="hasConnectivityIssue"
v-if="hasConnectivityIssueError"
variant="danger"
:title="$options.i18n.connectivityIssueTitle"
:dismissible="false"
......@@ -80,19 +93,37 @@ export default {
</template>
</gl-sprintf>
</gl-alert>
<gl-alert
v-if="hasInvalidCodeError"
variant="danger"
:title="$options.i18n.generalActivationErrorTitle"
:dismissible="false"
data-testid="invalid-activation-error-alert"
>
<gl-sprintf :message="$options.i18n.invalidActivationCode">
<template #link="{ content }">
<gl-link :href="$options.links.subscriptionActivationHelpLink" target="_blank">{{
content
}}</gl-link>
</template>
</gl-sprintf>
</gl-alert>
<gl-alert
v-if="hasGeneralError"
variant="danger"
:title="$options.i18n.generalActivationError"
:title="$options.i18n.generalActivationErrorTitle"
:dismissible="false"
data-testid="general-error-alert"
>
<gl-sprintf :message="$options.i18n.howToActivateSubscription">
<template #link="{ content }">
<gl-sprintf :message="$options.i18n.generalActivationErrorMessage">
<template #activationLink="{ content }">
<gl-link :href="$options.links.subscriptionActivationHelpLink" target="_blank">{{
content
}}</gl-link>
</template>
<template #supportLink="{ content }">
<gl-link :href="$options.links.supportLink" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</gl-alert>
</div>
......
......@@ -12,6 +12,8 @@ import validation from '~/vue_shared/directives/validation';
import {
activateLabel,
fieldRequiredMessage,
INVALID_CODE_ERROR,
INVALID_CODE_ERROR_MESSAGE,
subscriptionActivationForm,
subscriptionQueries,
} from '../constants';
......@@ -103,6 +105,9 @@ export default {
const errors = getErrorsAsData(res);
if (errors.length) {
const [error] = errors;
if (error.includes(INVALID_CODE_ERROR_MESSAGE)) {
throw new Error(INVALID_CODE_ERROR);
}
throw new Error(error);
}
this.$emit(SUBSCRIPTION_ACTIVATION_SUCCESS_EVENT);
......
......@@ -115,10 +115,18 @@ export const buySubscriptionCard = {
buttonLabel: s__('SuperSonics|Buy subscription'),
};
export const INVALID_CODE_ERROR_MESSAGE = 'invalid activation code';
export const CONNECTIVITY_ERROR = 'CONNECTIVITY_ERROR';
export const generalActivationError = s__(
export const INVALID_CODE_ERROR = 'INVALID_CODE_ERROR';
export const generalActivationErrorTitle = s__(
'SuperSonics|An error occurred while activating your subscription.',
);
export const generalActivationErrorMessage = s__(
'SuperSonics|You can learn more about %{activationLinkStart}activating your subscription%{activationLinkEnd}. If you need further assistance, please %{supportLinkStart}contact GitLab Support%{supportLinkEnd}.',
);
export const invalidActivationCode = s__(
'SuperSonics|The activation code is not valid. Please make sure to copy it exactly from the Customers Portal or confirmation email. Learn more about %{linkStart}activating your subscription%{linkEnd}.',
);
export const connectivityErrorAlert = {
subtitle: s__(
'SuperSonics|To activate your subscription, connect to GitLab servers through the %{linkStart}Cloud Licensing%{linkEnd} service, a hassle-free way to manage your subscription.',
......@@ -127,3 +135,4 @@ export const connectivityErrorAlert = {
'SuperSonics|Get help for the most common connectivity issues by %{linkStart}troubleshooting the activation code%{linkEnd}.',
),
};
export const supportLink = 'https://about.gitlab.com/support/#contact-support';
import { GlLink, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import {
import SubscriptionActivationErrors, {
subscriptionActivationHelpLink,
troubleshootingHelpLink,
} from 'ee/pages/admin/cloud_licenses/components/subscription_activation_card.vue';
import SubscriptionActivationErrors from 'ee/pages/admin/cloud_licenses/components/subscription_activation_errors.vue';
} from 'ee/pages/admin/cloud_licenses/components/subscription_activation_errors.vue';
import {
CONNECTIVITY_ERROR,
connectivityIssue,
generalActivationError,
generalActivationErrorMessage,
generalActivationErrorTitle,
invalidActivationCode,
INVALID_CODE_ERROR,
supportLink,
} from 'ee/pages/admin/cloud_licenses/constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
......@@ -17,6 +19,8 @@ describe('SubscriptionActivationErrors', () => {
const findConnectivityErrorAlert = () => wrapper.findByTestId('connectivity-error-alert');
const findGeneralErrorAlert = () => wrapper.findByTestId('general-error-alert');
const findInvalidActivationCode = () => wrapper.findByTestId('invalid-activation-error-alert');
const findRoot = () => wrapper.findByTestId('root');
const createComponent = ({ props = {} } = {}) => {
wrapper = extendedWrapper(
......@@ -33,26 +37,54 @@ describe('SubscriptionActivationErrors', () => {
wrapper.destroy();
});
describe('connectivity error', () => {
describe('with no error', () => {
beforeEach(() => {
createComponent({ props: { error: CONNECTIVITY_ERROR } });
createComponent();
});
it('shows the alert', () => {
expect(findConnectivityErrorAlert().props('title')).toBe(connectivityIssue);
it('should not render the component', () => {
expect(findRoot().exists()).toBe(false);
});
});
describe('connectivity error', () => {
beforeEach(() => {
createComponent({ props: { error: CONNECTIVITY_ERROR } });
});
it('shows some help links', () => {
const alert = findConnectivityErrorAlert();
expect(alert.findAllComponents(GlLink).at(0).props('href')).toBe(
expect(alert.findAllComponents(GlLink).at(0).attributes('href')).toBe(
subscriptionActivationHelpLink,
);
expect(alert.findAllComponents(GlLink).at(1).props('href')).toBe(troubleshootingHelpLink);
expect(alert.findAllComponents(GlLink).at(1).attributes('href')).toBe(
troubleshootingHelpLink,
);
});
it('does not show other alerts', () => {
expect(findGeneralErrorAlert().exists()).toBe(false);
expect(findInvalidActivationCode().exists()).toBe(false);
});
});
describe('invalid activation code error', () => {
beforeEach(() => {
createComponent({ props: { error: INVALID_CODE_ERROR } });
});
it('shows the alert', () => {
expect(findInvalidActivationCode().attributes('title')).toBe(generalActivationErrorTitle);
});
it('shows a text to help the user', () => {
expect(findInvalidActivationCode().text()).toMatchInterpolatedText(invalidActivationCode);
});
it('does not show other alerts', () => {
expect(findConnectivityErrorAlert().exists()).toBe(false);
expect(findGeneralErrorAlert().exists()).toBe(false);
});
});
......@@ -62,21 +94,26 @@ describe('SubscriptionActivationErrors', () => {
});
it('shows a general error alert', () => {
expect(findGeneralErrorAlert().props('title')).toBe(generalActivationError);
expect(findGeneralErrorAlert().props('title')).toBe(generalActivationErrorTitle);
});
it('shows a help link', () => {
expect(findGeneralErrorAlert().findComponent(GlLink).props('href')).toBe(
it('shows some help links', () => {
const alert = findGeneralErrorAlert();
expect(alert.findAllComponents(GlLink).at(0).attributes('href')).toBe(
subscriptionActivationHelpLink,
);
expect(alert.findAllComponents(GlLink).at(1).attributes('href')).toBe(supportLink);
});
it('shows a a text to help the user', () => {
expect(findGeneralErrorAlert().text()).toBe('Learn how to activate your subscription.');
it('shows a text to help the user', () => {
expect(findGeneralErrorAlert().text()).toMatchInterpolatedText(generalActivationErrorMessage);
});
it('does not show the connectivity alert', () => {
expect(findConnectivityErrorAlert().exists()).toBe(false);
expect(findInvalidActivationCode().exists()).toBe(false);
});
});
});
......@@ -8,6 +8,7 @@ import SubscriptionActivationForm, {
import {
CONNECTIVITY_ERROR,
fieldRequiredMessage,
INVALID_CODE_ERROR,
subscriptionQueries,
} from 'ee/pages/admin/cloud_licenses/constants';
import createMockApollo from 'helpers/mock_apollo_helper';
......@@ -179,6 +180,24 @@ describe('CloudLicenseApp', () => {
});
});
describe('when the mutation is not successful with invalid activation code error', () => {
const mutationMock = jest
.fn()
.mockResolvedValue(activateLicenseMutationResponse.INVALID_CODE_ERROR);
beforeEach(async () => {
createComponentWithApollo({ mutationMock });
await findActivationCodeInput().vm.$emit('input', fakeActivationCode);
await findAgreementCheckbox().vm.$emit('input', true);
findActivateSubscriptionForm().vm.$emit('submit', createFakeEvent());
});
it('emits an failure event with a connectivity error payload', () => {
expect(wrapper.emitted(SUBSCRIPTION_ACTIVATION_FAILURE_EVENT)).toEqual([
[INVALID_CODE_ERROR],
]);
});
});
describe('when the mutation request fails', () => {
const mutationMock = jest.fn().mockRejectedValue(activateLicenseMutationResponse.FAILURE);
beforeEach(() => {
......
......@@ -81,6 +81,15 @@ export const activateLicenseMutationResponse = {
},
},
},
INVALID_CODE_ERROR: {
data: {
gitlabSubscriptionActivate: {
license: null,
errors: ['invalid activation code'],
__typename: 'GitlabSubscriptionActivatePayload',
},
},
},
ERRORS_AS_DATA: {
data: {
gitlabSubscriptionActivate: {
......
......@@ -31663,6 +31663,9 @@ msgstr ""
msgid "SuperSonics|Sync subscription details"
msgstr ""
msgid "SuperSonics|The activation code is not valid. Please make sure to copy it exactly from the Customers Portal or confirmation email. Learn more about %{linkStart}activating your subscription%{linkEnd}."
msgstr ""
msgid "SuperSonics|The subscription details synced successfully."
msgstr ""
......@@ -31699,6 +31702,9 @@ msgstr ""
msgid "SuperSonics|Valid From"
msgstr ""
msgid "SuperSonics|You can learn more about %{activationLinkStart}activating your subscription%{activationLinkEnd}. If you need further assistance, please %{supportLinkStart}contact GitLab Support%{supportLinkEnd}."
msgstr ""
msgid "SuperSonics|You can no longer sync your subscription details with GitLab. Get help for the most common connectivity issues by %{connectivityHelpLinkStart}troubleshooting the activation code%{connectivityHelpLinkEnd}."
msgstr ""
......
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