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/admin')
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js66
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_form_spec.js331
-rw-r--r--spec/frontend/admin/signup_restrictions/mock_data.js41
-rw-r--r--spec/frontend/admin/signup_restrictions/utils.js19
-rw-r--r--spec/frontend/admin/signup_restrictions/utils_spec.js22
-rw-r--r--spec/frontend/admin/users/components/user_date_spec.js2
-rw-r--r--spec/frontend/admin/users/components/users_table_spec.js2
-rw-r--r--spec/frontend/admin/users/new_spec.js76
8 files changed, 557 insertions, 2 deletions
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
new file mode 100644
index 00000000000..ae9b6f57ee0
--- /dev/null
+++ b/spec/frontend/admin/signup_restrictions/components/signup_checkbox_spec.js
@@ -0,0 +1,66 @@
+import { GlFormCheckbox } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import SignupCheckbox from '~/pages/admin/application_settings/general/components/signup_checkbox.vue';
+
+describe('Signup Form', () => {
+ let wrapper;
+
+ const props = {
+ name: 'name',
+ helpText: 'some help text',
+ label: 'a label',
+ value: true,
+ dataQaSelector: 'qa_selector',
+ };
+
+ const mountComponent = () => {
+ wrapper = shallowMount(SignupCheckbox, {
+ propsData: props,
+ stubs: {
+ GlFormCheckbox,
+ },
+ });
+ };
+
+ const findByTestId = (id) => wrapper.find(`[data-testid="${id}"]`);
+ const findHiddenInput = () => findByTestId('input');
+ const findCheckbox = () => wrapper.find(GlFormCheckbox);
+ const findCheckboxLabel = () => findByTestId('label');
+ const findHelpText = () => findByTestId('helpText');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Signup Checkbox', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ describe('hidden input element', () => {
+ it('gets passed correct values from props', () => {
+ expect(findHiddenInput().attributes('name')).toBe(props.name);
+
+ expect(findHiddenInput().attributes('value')).toBe('1');
+ });
+ });
+
+ describe('checkbox', () => {
+ it('gets passed correct checked value', () => {
+ expect(findCheckbox().attributes('checked')).toBe('true');
+ });
+
+ it('gets passed correct label', () => {
+ expect(findCheckboxLabel().text()).toBe(props.label);
+ });
+
+ it('gets passed correct help text', () => {
+ expect(findHelpText().text()).toBe(props.helpText);
+ });
+
+ it('gets passed data qa selector', () => {
+ expect(findCheckbox().attributes('data-qa-selector')).toBe(props.dataQaSelector);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
new file mode 100644
index 00000000000..18339164d5a
--- /dev/null
+++ b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
@@ -0,0 +1,331 @@
+import { GlButton, GlModal } from '@gitlab/ui';
+import { within, fireEvent } from '@testing-library/dom';
+import { shallowMount, mount } from '@vue/test-utils';
+import { stubComponent } from 'helpers/stub_component';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import SignupForm from '~/pages/admin/application_settings/general/components/signup_form.vue';
+import { mockData } from '../mock_data';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+describe('Signup Form', () => {
+ let wrapper;
+ let formSubmitSpy;
+
+ const mountComponent = ({ injectedProps = {}, mountFn = shallowMount, stubs = {} } = {}) => {
+ wrapper = extendedWrapper(
+ mountFn(SignupForm, {
+ provide: {
+ ...mockData,
+ ...injectedProps,
+ },
+ stubs,
+ }),
+ );
+ };
+
+ const queryByLabelText = (text) => within(wrapper.element).queryByLabelText(text);
+
+ const findForm = () => wrapper.findByTestId('form');
+ const findInputCsrf = () => findForm().find('[name="authenticity_token"]');
+ const findFormSubmitButton = () => findForm().find(GlButton);
+
+ const findDenyListRawRadio = () => queryByLabelText('Enter denylist manually');
+ const findDenyListFileRadio = () => queryByLabelText('Upload denylist file');
+
+ const findDenyListRawInputGroup = () => wrapper.findByTestId('domain-denylist-raw-input-group');
+ const findDenyListFileInputGroup = () => wrapper.findByTestId('domain-denylist-file-input-group');
+
+ const findRequireAdminApprovalCheckbox = () =>
+ wrapper.findByTestId('require-admin-approval-checkbox');
+ const findUserCapInput = () => wrapper.findByTestId('user-cap-input');
+ const findModal = () => wrapper.find(GlModal);
+
+ afterEach(() => {
+ wrapper.destroy();
+
+ formSubmitSpy = null;
+ });
+
+ describe('form data', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it.each`
+ prop | propValue | elementSelector | formElementPassedDataType | formElementKey | expected
+ ${'signupEnabled'} | ${mockData.signupEnabled} | ${'[name="application_setting[signup_enabled]"]'} | ${'prop'} | ${'value'} | ${mockData.signupEnabled}
+ ${'requireAdminApprovalAfterUserSignup'} | ${mockData.requireAdminApprovalAfterUserSignup} | ${'[name="application_setting[require_admin_approval_after_user_signup]"]'} | ${'prop'} | ${'value'} | ${mockData.requireAdminApprovalAfterUserSignup}
+ ${'sendUserConfirmationEmail'} | ${mockData.sendUserConfirmationEmail} | ${'[name="application_setting[send_user_confirmation_email]"]'} | ${'prop'} | ${'value'} | ${mockData.sendUserConfirmationEmail}
+ ${'newUserSignupsCap'} | ${mockData.newUserSignupsCap} | ${'[name="application_setting[new_user_signups_cap]"]'} | ${'attribute'} | ${'value'} | ${mockData.newUserSignupsCap}
+ ${'minimumPasswordLength'} | ${mockData.minimumPasswordLength} | ${'[name="application_setting[minimum_password_length]"]'} | ${'attribute'} | ${'value'} | ${mockData.minimumPasswordLength}
+ ${'minimumPasswordLengthMin'} | ${mockData.minimumPasswordLengthMin} | ${'[name="application_setting[minimum_password_length]"]'} | ${'attribute'} | ${'min'} | ${mockData.minimumPasswordLengthMin}
+ ${'minimumPasswordLengthMax'} | ${mockData.minimumPasswordLengthMax} | ${'[name="application_setting[minimum_password_length]"]'} | ${'attribute'} | ${'max'} | ${mockData.minimumPasswordLengthMax}
+ ${'domainAllowlistRaw'} | ${mockData.domainAllowlistRaw} | ${'[name="application_setting[domain_allowlist_raw]"]'} | ${'value'} | ${'value'} | ${mockData.domainAllowlistRaw}
+ ${'domainDenylistEnabled'} | ${mockData.domainDenylistEnabled} | ${'[name="application_setting[domain_denylist_enabled]"]'} | ${'prop'} | ${'value'} | ${mockData.domainDenylistEnabled}
+ ${'denylistTypeRawSelected'} | ${mockData.denylistTypeRawSelected} | ${'[name="denylist_type"]'} | ${'attribute'} | ${'checked'} | ${'raw'}
+ ${'domainDenylistRaw'} | ${mockData.domainDenylistRaw} | ${'[name="application_setting[domain_denylist_raw]"]'} | ${'value'} | ${'value'} | ${mockData.domainDenylistRaw}
+ ${'emailRestrictionsEnabled'} | ${mockData.emailRestrictionsEnabled} | ${'[name="application_setting[email_restrictions_enabled]"]'} | ${'prop'} | ${'value'} | ${mockData.emailRestrictionsEnabled}
+ ${'emailRestrictions'} | ${mockData.emailRestrictions} | ${'[name="application_setting[email_restrictions]"]'} | ${'value'} | ${'value'} | ${mockData.emailRestrictions}
+ ${'afterSignUpText'} | ${mockData.afterSignUpText} | ${'[name="application_setting[after_sign_up_text]"]'} | ${'value'} | ${'value'} | ${mockData.afterSignUpText}
+ `(
+ 'form element $elementSelector gets $expected value for $formElementKey $formElementPassedDataType when prop $prop is set to $propValue',
+ ({ elementSelector, expected, formElementKey, formElementPassedDataType }) => {
+ const formElement = wrapper.find(elementSelector);
+
+ switch (formElementPassedDataType) {
+ case 'attribute':
+ expect(formElement.attributes(formElementKey)).toBe(expected);
+ break;
+ case 'prop':
+ expect(formElement.props(formElementKey)).toBe(expected);
+ break;
+ case 'value':
+ expect(formElement.element.value).toBe(expected);
+ break;
+ default:
+ expect(formElement.props(formElementKey)).toBe(expected);
+ break;
+ }
+ },
+ );
+ it('gets passed the path for action attribute', () => {
+ expect(findForm().attributes('action')).toBe(mockData.settingsPath);
+ });
+
+ it('gets passed the csrf token as a hidden input value', () => {
+ expect(findInputCsrf().attributes('type')).toBe('hidden');
+
+ expect(findInputCsrf().attributes('value')).toBe('mock-csrf-token');
+ });
+ });
+
+ describe('domain deny list', () => {
+ describe('when it is set to raw from props', () => {
+ beforeEach(() => {
+ mountComponent({ mountFn: mount });
+ });
+
+ it('has raw list selected', () => {
+ expect(findDenyListRawRadio().checked).toBe(true);
+ });
+
+ it('has file not selected', () => {
+ expect(findDenyListFileRadio().checked).toBe(false);
+ });
+
+ it('raw list input is displayed', () => {
+ expect(findDenyListRawInputGroup().exists()).toBe(true);
+ });
+
+ it('file input is not displayed', () => {
+ expect(findDenyListFileInputGroup().exists()).toBe(false);
+ });
+
+ describe('when user clicks on file radio', () => {
+ beforeEach(() => {
+ fireEvent.click(findDenyListFileRadio());
+ });
+
+ it('has raw list not selected', () => {
+ expect(findDenyListRawRadio().checked).toBe(false);
+ });
+
+ it('has file selected', () => {
+ expect(findDenyListFileRadio().checked).toBe(true);
+ });
+
+ it('raw list input is not displayed', () => {
+ expect(findDenyListRawInputGroup().exists()).toBe(false);
+ });
+
+ it('file input is displayed', () => {
+ expect(findDenyListFileInputGroup().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('when it is set to file from injected props', () => {
+ beforeEach(() => {
+ mountComponent({ mountFn: mount, injectedProps: { denylistTypeRawSelected: false } });
+ });
+
+ it('has raw list not selected', () => {
+ expect(findDenyListRawRadio().checked).toBe(false);
+ });
+
+ it('has file selected', () => {
+ expect(findDenyListFileRadio().checked).toBe(true);
+ });
+
+ it('raw list input is not displayed', () => {
+ expect(findDenyListRawInputGroup().exists()).toBe(false);
+ });
+
+ it('file input is displayed', () => {
+ expect(findDenyListFileInputGroup().exists()).toBe(true);
+ });
+
+ describe('when user clicks on raw list radio', () => {
+ beforeEach(() => {
+ fireEvent.click(findDenyListRawRadio());
+ });
+
+ it('has raw list selected', () => {
+ expect(findDenyListRawRadio().checked).toBe(true);
+ });
+
+ it('has file not selected', () => {
+ expect(findDenyListFileRadio().checked).toBe(false);
+ });
+
+ it('raw list input is displayed', () => {
+ expect(findDenyListRawInputGroup().exists()).toBe(true);
+ });
+
+ it('file input is not displayed', () => {
+ expect(findDenyListFileInputGroup().exists()).toBe(false);
+ });
+ });
+ });
+ });
+
+ describe('form submit button confirmation modal for side-effect of adding possibly unwanted new users', () => {
+ it.each`
+ requireAdminApprovalAction | userCapAction | buttonEffect
+ ${'unchanged from true'} | ${'unchanged'} | ${'submits form'}
+ ${'unchanged from false'} | ${'unchanged'} | ${'submits form'}
+ ${'toggled off'} | ${'unchanged'} | ${'shows confirmation modal'}
+ ${'toggled on'} | ${'unchanged'} | ${'submits form'}
+ ${'unchanged from false'} | ${'increased'} | ${'shows confirmation modal'}
+ ${'unchanged from true'} | ${'increased'} | ${'shows confirmation modal'}
+ ${'toggled off'} | ${'increased'} | ${'shows confirmation modal'}
+ ${'toggled on'} | ${'increased'} | ${'shows confirmation modal'}
+ ${'toggled on'} | ${'decreased'} | ${'submits form'}
+ ${'unchanged from false'} | ${'changed from limited to unlimited'} | ${'shows confirmation modal'}
+ ${'unchanged from false'} | ${'changed from unlimited to limited'} | ${'submits form'}
+ ${'unchanged from false'} | ${'unchanged from unlimited'} | ${'submits form'}
+ `(
+ '$buttonEffect if require admin approval for new sign-ups is $requireAdminApprovalAction and the user cap is $userCapAction',
+ async ({ requireAdminApprovalAction, userCapAction, buttonEffect }) => {
+ let isModalDisplayed;
+
+ switch (buttonEffect) {
+ case 'shows confirmation modal':
+ isModalDisplayed = true;
+ break;
+ case 'submits form':
+ isModalDisplayed = false;
+ break;
+ default:
+ isModalDisplayed = false;
+ break;
+ }
+
+ const isFormSubmittedWhenClickingFormSubmitButton = !isModalDisplayed;
+
+ const injectedProps = {};
+
+ const USER_CAP_DEFAULT = 5;
+
+ switch (userCapAction) {
+ case 'changed from unlimited to limited':
+ injectedProps.newUserSignupsCap = '';
+ break;
+ case 'unchanged from unlimited':
+ injectedProps.newUserSignupsCap = '';
+ break;
+ default:
+ injectedProps.newUserSignupsCap = USER_CAP_DEFAULT;
+ break;
+ }
+
+ switch (requireAdminApprovalAction) {
+ case 'unchanged from true':
+ injectedProps.requireAdminApprovalAfterUserSignup = true;
+ break;
+ case 'unchanged from false':
+ injectedProps.requireAdminApprovalAfterUserSignup = false;
+ break;
+ case 'toggled off':
+ injectedProps.requireAdminApprovalAfterUserSignup = true;
+ break;
+ case 'toggled on':
+ injectedProps.requireAdminApprovalAfterUserSignup = false;
+ break;
+ default:
+ injectedProps.requireAdminApprovalAfterUserSignup = false;
+ break;
+ }
+
+ formSubmitSpy = jest.spyOn(HTMLFormElement.prototype, 'submit').mockImplementation();
+
+ await mountComponent({
+ injectedProps,
+ stubs: { GlButton, GlModal: stubComponent(GlModal) },
+ });
+
+ findModal().vm.show = jest.fn();
+
+ if (
+ requireAdminApprovalAction === 'toggled off' ||
+ requireAdminApprovalAction === 'toggled on'
+ ) {
+ await findRequireAdminApprovalCheckbox().vm.$emit('input', false);
+ }
+
+ switch (userCapAction) {
+ case 'increased':
+ await findUserCapInput().vm.$emit('input', USER_CAP_DEFAULT + 1);
+ break;
+ case 'decreased':
+ await findUserCapInput().vm.$emit('input', USER_CAP_DEFAULT - 1);
+ break;
+ case 'changed from limited to unlimited':
+ await findUserCapInput().vm.$emit('input', '');
+ break;
+ case 'changed from unlimited to limited':
+ await findUserCapInput().vm.$emit('input', USER_CAP_DEFAULT);
+ break;
+ default:
+ break;
+ }
+
+ await findFormSubmitButton().trigger('click');
+
+ if (isFormSubmittedWhenClickingFormSubmitButton) {
+ expect(formSubmitSpy).toHaveBeenCalled();
+ expect(findModal().vm.show).not.toHaveBeenCalled();
+ } else {
+ expect(formSubmitSpy).not.toHaveBeenCalled();
+ expect(findModal().vm.show).toHaveBeenCalled();
+ }
+ },
+ );
+
+ describe('modal actions', () => {
+ beforeEach(async () => {
+ const INITIAL_USER_CAP = 5;
+
+ await mountComponent({
+ injectedProps: {
+ newUserSignupsCap: INITIAL_USER_CAP,
+ },
+ stubs: { GlButton, GlModal: stubComponent(GlModal) },
+ });
+
+ await findUserCapInput().vm.$emit('input', INITIAL_USER_CAP + 1);
+
+ await findFormSubmitButton().trigger('click');
+ });
+
+ it('submits the form after clicking approve users button', async () => {
+ formSubmitSpy = jest.spyOn(HTMLFormElement.prototype, 'submit').mockImplementation();
+
+ await findModal().vm.$emit('primary');
+
+ expect(formSubmitSpy).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/signup_restrictions/mock_data.js b/spec/frontend/admin/signup_restrictions/mock_data.js
new file mode 100644
index 00000000000..624a5614c9c
--- /dev/null
+++ b/spec/frontend/admin/signup_restrictions/mock_data.js
@@ -0,0 +1,41 @@
+export const rawMockData = {
+ host: 'path/to/host',
+ settingsPath: 'path/to/settings',
+ signupEnabled: 'true',
+ requireAdminApprovalAfterUserSignup: 'true',
+ sendUserConfirmationEmail: 'true',
+ minimumPasswordLength: '8',
+ minimumPasswordLengthMin: '3',
+ minimumPasswordLengthMax: '10',
+ minimumPasswordLengthHelpLink: 'help/link',
+ domainAllowlistRaw: 'domain1.com, domain2.com',
+ newUserSignupsCap: '8',
+ domainDenylistEnabled: 'true',
+ denylistTypeRawSelected: 'true',
+ domainDenylistRaw: 'domain2.com, domain3.com',
+ emailRestrictionsEnabled: 'true',
+ supportedSyntaxLinkUrl: '/supported/syntax/link',
+ emailRestrictions: 'user1@domain.com, user2@domain.com',
+ afterSignUpText: 'Congratulations on your successful sign-up!',
+};
+
+export const mockData = {
+ host: 'path/to/host',
+ settingsPath: 'path/to/settings',
+ signupEnabled: true,
+ requireAdminApprovalAfterUserSignup: true,
+ sendUserConfirmationEmail: true,
+ minimumPasswordLength: '8',
+ minimumPasswordLengthMin: '3',
+ minimumPasswordLengthMax: '10',
+ minimumPasswordLengthHelpLink: 'help/link',
+ domainAllowlistRaw: 'domain1.com, domain2.com',
+ newUserSignupsCap: '8',
+ domainDenylistEnabled: true,
+ denylistTypeRawSelected: true,
+ domainDenylistRaw: 'domain2.com, domain3.com',
+ emailRestrictionsEnabled: true,
+ supportedSyntaxLinkUrl: '/supported/syntax/link',
+ emailRestrictions: 'user1@domain.com, user2@domain.com',
+ afterSignUpText: 'Congratulations on your successful sign-up!',
+};
diff --git a/spec/frontend/admin/signup_restrictions/utils.js b/spec/frontend/admin/signup_restrictions/utils.js
new file mode 100644
index 00000000000..30a95467e09
--- /dev/null
+++ b/spec/frontend/admin/signup_restrictions/utils.js
@@ -0,0 +1,19 @@
+export const setDataAttributes = (data, element) => {
+ Object.keys(data).forEach((key) => {
+ const value = data[key];
+
+ // attribute should be:
+ // - valueless if value is 'true'
+ // - absent if value is 'false'
+ switch (value) {
+ case false:
+ break;
+ case true:
+ element.dataset[`${key}`] = '';
+ break;
+ default:
+ element.dataset[`${key}`] = value;
+ break;
+ }
+ });
+};
diff --git a/spec/frontend/admin/signup_restrictions/utils_spec.js b/spec/frontend/admin/signup_restrictions/utils_spec.js
new file mode 100644
index 00000000000..fd5c4c3317b
--- /dev/null
+++ b/spec/frontend/admin/signup_restrictions/utils_spec.js
@@ -0,0 +1,22 @@
+import { getParsedDataset } from '~/pages/admin/application_settings/utils';
+import { rawMockData, mockData } from './mock_data';
+
+describe('utils', () => {
+ describe('getParsedDataset', () => {
+ it('returns correct results', () => {
+ expect(
+ getParsedDataset({
+ dataset: rawMockData,
+ booleanAttributes: [
+ 'signupEnabled',
+ 'requireAdminApprovalAfterUserSignup',
+ 'sendUserConfirmationEmail',
+ 'domainDenylistEnabled',
+ 'denylistTypeRawSelected',
+ 'emailRestrictionsEnabled',
+ ],
+ }),
+ ).toEqual(mockData);
+ });
+ });
+});
diff --git a/spec/frontend/admin/users/components/user_date_spec.js b/spec/frontend/admin/users/components/user_date_spec.js
index 6428b10059b..1a2f2938db5 100644
--- a/spec/frontend/admin/users/components/user_date_spec.js
+++ b/spec/frontend/admin/users/components/user_date_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import UserDate from '~/admin/users/components/user_date.vue';
+import UserDate from '~/vue_shared/components/user_date.vue';
import { users } from '../mock_data';
const mockDate = users[0].createdAt;
diff --git a/spec/frontend/admin/users/components/users_table_spec.js b/spec/frontend/admin/users/components/users_table_spec.js
index f1fcc20fb65..424b0deebd3 100644
--- a/spec/frontend/admin/users/components/users_table_spec.js
+++ b/spec/frontend/admin/users/components/users_table_spec.js
@@ -3,8 +3,8 @@ import { mount } from '@vue/test-utils';
import AdminUserActions from '~/admin/users/components/user_actions.vue';
import AdminUserAvatar from '~/admin/users/components/user_avatar.vue';
-import AdminUserDate from '~/admin/users/components/user_date.vue';
import AdminUsersTable from '~/admin/users/components/users_table.vue';
+import AdminUserDate from '~/vue_shared/components/user_date.vue';
import { users, paths } from '../mock_data';
diff --git a/spec/frontend/admin/users/new_spec.js b/spec/frontend/admin/users/new_spec.js
new file mode 100644
index 00000000000..692c583dca8
--- /dev/null
+++ b/spec/frontend/admin/users/new_spec.js
@@ -0,0 +1,76 @@
+import {
+ setupInternalUserRegexHandler,
+ ID_USER_EMAIL,
+ ID_USER_EXTERNAL,
+ ID_WARNING,
+} from '~/admin/users/new';
+
+describe('admin/users/new', () => {
+ const FIXTURE = 'admin/users/new_with_internal_user_regex.html';
+
+ let elExternal;
+ let elUserEmail;
+ let elWarningMessage;
+
+ beforeEach(() => {
+ loadFixtures(FIXTURE);
+ setupInternalUserRegexHandler();
+
+ elExternal = document.getElementById(ID_USER_EXTERNAL);
+ elUserEmail = document.getElementById(ID_USER_EMAIL);
+ elWarningMessage = document.getElementById(ID_WARNING);
+
+ elExternal.checked = true;
+ });
+
+ const changeEmail = (val) => {
+ elUserEmail.value = val;
+ elUserEmail.dispatchEvent(new Event('input'));
+ };
+
+ const hasHiddenWarning = () => elWarningMessage.classList.contains('hidden');
+
+ describe('Behaviour of userExternal checkbox', () => {
+ it('hides warning by default', () => {
+ expect(hasHiddenWarning()).toBe(true);
+ });
+
+ describe('when matches email as internal', () => {
+ beforeEach(() => {
+ changeEmail('test@');
+ });
+
+ it('has external unchecked', () => {
+ expect(elExternal.checked).toBe(false);
+ });
+
+ it('shows warning', () => {
+ expect(hasHiddenWarning()).toBe(false);
+ });
+
+ describe('when external is checked again', () => {
+ beforeEach(() => {
+ elExternal.dispatchEvent(new Event('change'));
+ });
+
+ it('hides warning', () => {
+ expect(hasHiddenWarning()).toBe(true);
+ });
+ });
+ });
+
+ describe('when matches emails as external', () => {
+ beforeEach(() => {
+ changeEmail('test.ext@');
+ });
+
+ it('has external checked', () => {
+ expect(elExternal.checked).toBe(true);
+ });
+
+ it('hides warning', () => {
+ expect(hasHiddenWarning()).toBe(true);
+ });
+ });
+ });
+});