Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/sessions/new')
-rw-r--r--spec/frontend/sessions/new/components/email_verification_spec.js251
-rw-r--r--spec/frontend/sessions/new/components/update_email_spec.js180
2 files changed, 431 insertions, 0 deletions
diff --git a/spec/frontend/sessions/new/components/email_verification_spec.js b/spec/frontend/sessions/new/components/email_verification_spec.js
new file mode 100644
index 00000000000..30ba2782f2f
--- /dev/null
+++ b/spec/frontend/sessions/new/components/email_verification_spec.js
@@ -0,0 +1,251 @@
+import { GlForm, GlFormInput } from '@gitlab/ui';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { s__ } from '~/locale';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import EmailVerification from '~/sessions/new/components/email_verification.vue';
+import UpdateEmail from '~/sessions/new/components/update_email.vue';
+import { visitUrl } from '~/lib/utils/url_utility';
+import {
+ I18N_EMAIL_EMPTY_CODE,
+ I18N_EMAIL_INVALID_CODE,
+ I18N_GENERIC_ERROR,
+ I18N_UPDATE_EMAIL,
+ I18N_RESEND_LINK,
+ I18N_EMAIL_RESEND_SUCCESS,
+} from '~/sessions/new/constants';
+
+jest.mock('~/alert');
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ visitUrl: jest.fn(),
+}));
+
+describe('EmailVerification', () => {
+ let wrapper;
+ let axiosMock;
+
+ const defaultPropsData = {
+ obfuscatedEmail: 'al**@g*****.com',
+ verifyPath: '/users/sign_in',
+ resendPath: '/users/resend_verification_code',
+ isOfferEmailReset: true,
+ updateEmailPath: '/users/update_email',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = mountExtended(EmailVerification, {
+ propsData: { ...defaultPropsData, ...props },
+ });
+ };
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findCodeInput = () => wrapper.findComponent(GlFormInput);
+ const findUpdateEmail = () => wrapper.findComponent(UpdateEmail);
+ const findSubmitButton = () => wrapper.find('[type="submit"]');
+ const findResendLink = () => wrapper.findByText(I18N_RESEND_LINK);
+ const findUpdateEmailLink = () => wrapper.findByText(I18N_UPDATE_EMAIL);
+ const enterCode = (code) => findCodeInput().setValue(code);
+ const submitForm = () => findForm().trigger('submit');
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ createComponent();
+ });
+
+ afterEach(() => {
+ createAlert.mockClear();
+ axiosMock.restore();
+ });
+
+ describe('rendering the form', () => {
+ it('contains the obfuscated email address', () => {
+ expect(wrapper.text()).toContain(defaultPropsData.obfuscatedEmail);
+ });
+ });
+
+ describe('verifying the code', () => {
+ describe('when successfully verifying the code', () => {
+ const redirectPath = 'root';
+
+ beforeEach(async () => {
+ enterCode('123456');
+
+ axiosMock
+ .onPost(defaultPropsData.verifyPath)
+ .reply(HTTP_STATUS_OK, { status: 'success', redirect_path: redirectPath });
+
+ await submitForm();
+ await axios.waitForAll();
+ });
+
+ it('redirects to the returned redirect path', () => {
+ expect(visitUrl).toHaveBeenCalledWith(redirectPath);
+ });
+ });
+
+ describe('error messages', () => {
+ it.each`
+ scenario | code | submit | codeValid | errorShown | message
+ ${'shows no error messages before submitting the form'} | ${''} | ${false} | ${false} | ${false} | ${null}
+ ${'shows no error messages before submitting the form'} | ${'xxx'} | ${false} | ${false} | ${false} | ${null}
+ ${'shows no error messages before submitting the form'} | ${'123456'} | ${false} | ${true} | ${false} | ${null}
+ ${'shows empty code error message when submitting the form'} | ${''} | ${true} | ${false} | ${true} | ${I18N_EMAIL_EMPTY_CODE}
+ ${'shows invalid error message when submitting the form'} | ${'xxx'} | ${true} | ${false} | ${true} | ${I18N_EMAIL_INVALID_CODE}
+ ${'shows incorrect code error message returned from the server'} | ${'123456'} | ${true} | ${true} | ${true} | ${s__('IdentityVerification|The code is incorrect. Enter it again, or send a new code.')}
+ `(`$scenario with code $code`, async ({ code, submit, codeValid, errorShown, message }) => {
+ enterCode(code);
+
+ if (submit && codeValid) {
+ axiosMock
+ .onPost(defaultPropsData.verifyPath)
+ .replyOnce(HTTP_STATUS_OK, { status: 'failure', message });
+ }
+
+ if (submit) {
+ await submitForm();
+ await axios.waitForAll();
+ }
+
+ expect(findCodeInput().classes('is-invalid')).toBe(errorShown);
+ expect(findSubmitButton().props('disabled')).toBe(errorShown);
+ if (message) expect(wrapper.text()).toContain(message);
+ });
+
+ it('keeps showing error messages for invalid codes after submitting the form', async () => {
+ const serverErrorMessage = 'error message';
+
+ enterCode('123456');
+
+ axiosMock
+ .onPost(defaultPropsData.verifyPath)
+ .replyOnce(HTTP_STATUS_OK, { status: 'failure', message: serverErrorMessage });
+
+ await submitForm();
+ await axios.waitForAll();
+
+ expect(wrapper.text()).toContain(serverErrorMessage);
+
+ await enterCode('');
+ expect(wrapper.text()).toContain(I18N_EMAIL_EMPTY_CODE);
+
+ await enterCode('xxx');
+ expect(wrapper.text()).toContain(I18N_EMAIL_INVALID_CODE);
+ });
+
+ it('captures the error and shows an alert message when the request failed', async () => {
+ enterCode('123456');
+
+ axiosMock.onPost(defaultPropsData.verifyPath).replyOnce(HTTP_STATUS_OK, null);
+
+ await submitForm();
+ await axios.waitForAll();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: I18N_GENERIC_ERROR,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+
+ it('captures the error and shows an alert message when the request undefined', async () => {
+ enterCode('123456');
+
+ axiosMock.onPost(defaultPropsData.verifyPath).reply(HTTP_STATUS_OK, { status: undefined });
+
+ await submitForm();
+ await axios.waitForAll();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: I18N_GENERIC_ERROR,
+ captureError: true,
+ error: undefined,
+ });
+ });
+ });
+ });
+
+ describe('resending the code', () => {
+ const failedMessage = 'Failure sending the code';
+ const successAlertObject = {
+ message: I18N_EMAIL_RESEND_SUCCESS,
+ variant: VARIANT_SUCCESS,
+ };
+ const failedAlertObject = {
+ message: failedMessage,
+ };
+ const undefinedAlertObject = {
+ captureError: true,
+ error: undefined,
+ message: I18N_GENERIC_ERROR,
+ };
+ const genericAlertObject = {
+ message: I18N_GENERIC_ERROR,
+ captureError: true,
+ error: expect.any(Error),
+ };
+
+ it.each`
+ scenario | statusCode | response | alertObject
+ ${'the code was successfully resend'} | ${HTTP_STATUS_OK} | ${{ status: 'success' }} | ${successAlertObject}
+ ${'there was a problem resending the code'} | ${HTTP_STATUS_OK} | ${{ status: 'failure', message: failedMessage }} | ${failedAlertObject}
+ ${'when the request is undefined'} | ${HTTP_STATUS_OK} | ${{ status: undefined }} | ${undefinedAlertObject}
+ ${'when the request failed'} | ${HTTP_STATUS_NOT_FOUND} | ${null} | ${genericAlertObject}
+ `(`shows an alert message when $scenario`, async ({ statusCode, response, alertObject }) => {
+ enterCode('xxx');
+
+ await submitForm();
+
+ axiosMock.onPost(defaultPropsData.resendPath).replyOnce(statusCode, response);
+
+ findResendLink().trigger('click');
+
+ await axios.waitForAll();
+
+ expect(createAlert).toHaveBeenCalledWith(alertObject);
+ expect(findCodeInput().element.value).toBe('');
+ });
+ });
+
+ describe('updating the email', () => {
+ it('contains the link to show the update email form', () => {
+ expect(findUpdateEmailLink().exists()).toBe(true);
+ });
+
+ describe('when the isOfferEmailReset property is set to false', () => {
+ beforeEach(() => {
+ createComponent({ isOfferEmailReset: false });
+ });
+
+ it('does not contain the link to show the update email form', () => {
+ expect(findUpdateEmailLink().exists()).toBe(false);
+ });
+ });
+
+ it('shows the UpdateEmail component when clicking the link', async () => {
+ expect(findUpdateEmail().exists()).toBe(false);
+
+ await findUpdateEmailLink().trigger('click');
+
+ expect(findUpdateEmail().exists()).toBe(true);
+ });
+
+ describe('when the UpdateEmail component triggers verifyToken', () => {
+ const newEmail = 'new@ema.il';
+
+ beforeEach(async () => {
+ enterCode('123');
+ await findUpdateEmailLink().trigger('click');
+ findUpdateEmail().vm.$emit('verifyToken', newEmail);
+ });
+
+ it('hides the UpdateEmail component, shows the updated email address and resets the form', () => {
+ expect(findUpdateEmail().exists()).toBe(false);
+ expect(wrapper.text()).toContain(newEmail);
+ expect(findCodeInput().element.value).toBe('');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sessions/new/components/update_email_spec.js b/spec/frontend/sessions/new/components/update_email_spec.js
new file mode 100644
index 00000000000..822720da898
--- /dev/null
+++ b/spec/frontend/sessions/new/components/update_email_spec.js
@@ -0,0 +1,180 @@
+import { GlForm, GlFormInput } from '@gitlab/ui';
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { HTTP_STATUS_NOT_FOUND, HTTP_STATUS_OK } from '~/lib/utils/http_status';
+import UpdateEmail from '~/sessions/new/components/update_email.vue';
+import {
+ I18N_CANCEL,
+ I18N_EMAIL_INVALID,
+ I18N_UPDATE_EMAIL_SUCCESS,
+ I18N_GENERIC_ERROR,
+ SUCCESS_RESPONSE,
+ FAILURE_RESPONSE,
+} from '~/sessions/new/constants';
+
+const validEmailAddress = 'foo+bar@ema.il';
+const invalidEmailAddress = 'invalid@ema@il';
+
+jest.mock('~/alert');
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ visitUrl: jest.fn(),
+}));
+
+describe('EmailVerification', () => {
+ let wrapper;
+ let axiosMock;
+
+ const defaultPropsData = {
+ updateEmailPath: '/users/update_email',
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = mountExtended(UpdateEmail, {
+ propsData: { ...defaultPropsData, ...props },
+ });
+ };
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findEmailInput = () => wrapper.findComponent(GlFormInput);
+ const findSubmitButton = () => wrapper.find('[type="submit"]');
+ const findCancelLink = () => wrapper.findByText(I18N_CANCEL);
+ const enterEmail = (email) => findEmailInput().setValue(email);
+ const submitForm = () => findForm().trigger('submit');
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ createComponent();
+ });
+
+ afterEach(() => {
+ createAlert.mockClear();
+ axiosMock.restore();
+ });
+
+ describe('when successfully verifying the email address', () => {
+ beforeEach(async () => {
+ enterEmail(validEmailAddress);
+
+ axiosMock
+ .onPatch(defaultPropsData.updateEmailPath)
+ .reply(HTTP_STATUS_OK, { status: SUCCESS_RESPONSE });
+
+ submitForm();
+ await axios.waitForAll();
+ });
+
+ it('shows a successfully updated alert', () => {
+ expect(createAlert).toHaveBeenCalledWith({
+ message: I18N_UPDATE_EMAIL_SUCCESS,
+ variant: VARIANT_SUCCESS,
+ });
+ });
+
+ it('emits a verifyToken event with the updated email address', () => {
+ expect(wrapper.emitted('verifyToken')[0]).toEqual([validEmailAddress]);
+ });
+ });
+
+ describe('error messages', () => {
+ beforeEach(() => {
+ enterEmail(invalidEmailAddress);
+ });
+
+ describe('when trying to submit an invalid email address', () => {
+ it('shows no error message before submitting the form', () => {
+ expect(wrapper.text()).not.toContain(I18N_EMAIL_INVALID);
+ expect(findSubmitButton().props('disabled')).toBe(false);
+ });
+
+ describe('when submitting the form', () => {
+ beforeEach(async () => {
+ submitForm();
+ await axios.waitForAll();
+ });
+
+ it('shows an error message and disables the submit button', () => {
+ expect(wrapper.text()).toContain(I18N_EMAIL_INVALID);
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ });
+
+ describe('when entering a valid email address', () => {
+ beforeEach(() => {
+ enterEmail(validEmailAddress);
+ });
+
+ it('hides the error message and enables the submit button again', () => {
+ expect(wrapper.text()).not.toContain(I18N_EMAIL_INVALID);
+ expect(findSubmitButton().props('disabled')).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('when the server responds with an error message', () => {
+ const serverErrorMessage = 'server error message';
+
+ beforeEach(async () => {
+ enterEmail(validEmailAddress);
+
+ axiosMock
+ .onPatch(defaultPropsData.updateEmailPath)
+ .replyOnce(HTTP_STATUS_OK, { status: FAILURE_RESPONSE, message: serverErrorMessage });
+
+ submitForm();
+ await axios.waitForAll();
+ });
+
+ it('shows the error message and disables the submit button', () => {
+ expect(wrapper.text()).toContain(serverErrorMessage);
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ });
+
+ describe('when entering a valid email address', () => {
+ beforeEach(async () => {
+ await enterEmail('');
+ enterEmail(validEmailAddress);
+ });
+
+ it('hides the error message and enables the submit button again', () => {
+ expect(wrapper.text()).not.toContain(serverErrorMessage);
+ expect(findSubmitButton().props('disabled')).toBe(false);
+ });
+ });
+ });
+
+ describe('when the server responds unexpectedly', () => {
+ it.each`
+ scenario | statusCode
+ ${'the response is undefined'} | ${HTTP_STATUS_OK}
+ ${'the request failed'} | ${HTTP_STATUS_NOT_FOUND}
+ `(`shows an alert when $scenario`, async ({ statusCode }) => {
+ enterEmail(validEmailAddress);
+
+ axiosMock.onPatch(defaultPropsData.updateEmailPath).replyOnce(statusCode);
+
+ submitForm();
+
+ await axios.waitForAll();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: I18N_GENERIC_ERROR,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+ });
+ });
+
+ describe('when clicking the cancel link', () => {
+ beforeEach(() => {
+ findCancelLink().trigger('click');
+ });
+
+ it('emits a verifyToken event without an email address', () => {
+ expect(wrapper.emitted('verifyToken')[0]).toEqual([]);
+ });
+ });
+});