Skip to content
Snippets Groups Projects
Commit f8b652b9 authored by Mayra Cabrera's avatar Mayra Cabrera :zero:
Browse files

Merge branch...

Merge branch '321706-fix-error-message-inviting-to-disallowed-email-address-when-restrict-membership-by-domain-is' into 'master'

Change modal error message for restricted emails

See merge request !61425
parents 19fb82e8 670a84b6
No related branches found
No related tags found
1 merge request!61425Change modal error message for restricted emails
Pipeline #381145544 passed with warnings
Pipeline: CNG-mirror

#381154041

    Showing
    with 186 additions and 77 deletions
    ......@@ -11,9 +11,10 @@ import {
    GlFormInput,
    GlFormCheckboxGroup,
    } from '@gitlab/ui';
    import { partition, isString } from 'lodash';
    import { partition, isString, unescape } from 'lodash';
    import Api from '~/api';
    import ExperimentTracking from '~/experimentation/experiment_tracking';
    import { sanitize } from '~/lib/dompurify';
    import { BV_SHOW_MODAL } from '~/lib/utils/constants';
    import { s__, sprintf } from '~/locale';
    import {
    ......@@ -293,7 +294,7 @@ export default {
    };
    },
    conditionallyShowToastSuccess(response) {
    const message = responseMessageFromSuccess(response);
    const message = this.unescapeMsg(responseMessageFromSuccess(response));
    if (message === '') {
    this.showToastMessageSuccess();
    ......@@ -309,13 +310,17 @@ export default {
    this.closeModal();
    },
    showInvalidFeedbackMessage(response) {
    const message = this.unescapeMsg(responseMessageFromError(response));
    this.isLoading = false;
    this.invalidFeedbackMessage =
    responseMessageFromError(response) || this.$options.labels.invalidFeedbackMessageDefault;
    this.invalidFeedbackMessage = message || this.$options.labels.invalidFeedbackMessageDefault;
    },
    handleMembersTokenSelectClear() {
    this.invalidFeedbackMessage = '';
    },
    unescapeMsg(message) {
    return unescape(sanitize(message, { ALLOWED_TAGS: [] }));
    },
    },
    labels: {
    members: {
    ......
    ......@@ -18,7 +18,10 @@ function responseMessageStringForMultiple(message) {
    return message.includes(':');
    }
    function responseMessageStringFirstPart(message) {
    return message.split(' and ')[0];
    const firstPart = message.split(':')[1];
    const firstMsg = firstPart.split(/ and [\w-]*$/)[0].trim();
    return firstMsg;
    }
    export function responseMessageFromError(response) {
    ......
    ......@@ -7,15 +7,49 @@ module RestrictedSignup
    def validate_admin_signup_restrictions(email)
    return if allowed_domain?(email)
    error_type = fetch_error_type(email)
    return unless error_type.present?
    [
    signup_email_invalid_message,
    error_message[created_by_key][error_type]
    ].join(' ')
    end
    def fetch_error_type(email)
    if allowlist_present?
    return _('domain is not authorized for sign-up.')
    :allowlist
    elsif denied_domain?(email)
    return _('is not from an allowed domain.')
    :denylist
    elsif restricted_email?(email)
    return _('is not allowed. Try again with a different email address, or contact your GitLab admin.')
    :restricted
    end
    end
    def error_message
    {
    admin: {
    allowlist: html_escape_once(_("Go to the 'Admin area > Sign-up restrictions', and check 'Allowed domains for sign-ups'.")).html_safe,
    denylist: html_escape_once(_("Go to the 'Admin area > Sign-up restrictions', and check the 'Domain denylist'.")).html_safe,
    restricted: html_escape_once(_("Go to the 'Admin area > Sign-up restrictions', and check 'Email restrictions for sign-ups'.")).html_safe,
    group_setting: html_escape_once(_("Go to the group’s 'Settings > General' page, and check 'Restrict membership by email domain'.")).html_safe
    },
    nonadmin: {
    allowlist: error_nonadmin,
    denylist: error_nonadmin,
    restricted: error_nonadmin,
    group_setting: error_nonadmin
    }
    }
    end
    def error_nonadmin
    _("Check with your administrator.")
    end
    nil
    def created_by_key
    created_by&.can_admin_all_resources? ? :admin : :nonadmin
    end
    def denied_domain?(email)
    ......
    ......@@ -448,6 +448,14 @@ def signup_email_valid?
    errors.add(:user, error) if error
    end
    def signup_email_invalid_message
    if source_type == 'Project'
    _("is not allowed for this project.")
    else
    _("is not allowed for this group.")
    end
    end
    def update_highest_role?
    return unless user_id.present?
    ......
    ......@@ -2102,6 +2102,10 @@ def signup_email_valid?
    errors.add(:email, error) if error
    end
    def signup_email_invalid_message
    _('is not allowed for sign-up.')
    end
    def check_username_format
    return if username.blank? || Mime::EXTENSION_LOOKUP.keys.none? { |type| username.end_with?(".#{type}") }
    ......
    ......@@ -10,6 +10,9 @@ en:
    target: Target issue
    group:
    path: Group URL
    member:
    user: "The member's email address"
    invite_email: "The member's email address"
    project/error_tracking_setting:
    token: "Auth Token"
    project: "Project"
    ......
    ......@@ -103,8 +103,11 @@ def validate_email_verified
    end
    def email_does_not_match_any_allowed_domains(email)
    n_("email does not match the allowed domain of %{email_domains}", "email does not match the allowed domains: %{email_domains}", group_allowed_email_domains.size) %
    { email_domains: group_allowed_email_domains.map(&:domain).join(', ') }
    msg_1 = signup_email_invalid_message
    msg_2 = error_message[created_by_key][:group_setting]
    [msg_1, msg_2].join(' ')
    end
    def matches_at_least_one_group_allowed_email_domain?(email)
    ......
    ......@@ -189,7 +189,7 @@
    post :request_access, params: { group_id: group }
    expect(controller).to set_flash.to "Your request for access could not be processed: "\
    "User email 'unverified@gitlab.com' is not a verified email."
    "The member's email address email 'unverified@gitlab.com' is not a verified email."
    expect(response).to redirect_to(group_path(group))
    expect(group.requesters.exists?(user_id: requesting_user)).to be_falsey
    expect(group.users).not_to include requesting_user
    ......
    ......@@ -12,7 +12,7 @@
    let(:source) { group }
    let(:nested_source) { create(:group, parent: group) }
    it_behaves_like 'member group domain validations'
    it_behaves_like 'member group domain validations', 'group'
    end
    describe 'access level inclusion' do
    ......
    ......@@ -95,7 +95,7 @@
    let(:subgroup) { create(:group, parent: group) }
    let(:nested_source) { create(:project, namespace: subgroup) }
    it_behaves_like 'member group domain validations'
    it_behaves_like 'member group domain validations', 'project'
    it 'does not validate personal projects' do
    unconfirmed_gitlab_user = create(:user, :unconfirmed, email: 'unverified@gitlab.com')
    ......
    ......@@ -21,40 +21,37 @@
    end
    end
    shared_examples 'admin signup restrictions email error' do
    context 'when restricted by admin signup restriction - denylist' do
    before do
    stub_application_setting(domain_denylist_enabled: true)
    stub_application_setting(domain_denylist: ['example.org'])
    end
    # this response code should be changed to 4xx: https://gitlab.com/gitlab-org/gitlab/-/issues/321706
    it_behaves_like 'restricted email error', 'User is not from an allowed domain.', :created
    shared_examples 'admin signup restrictions email error - denylist' do |message, code|
    before do
    stub_application_setting(domain_denylist_enabled: true)
    stub_application_setting(domain_denylist: ['example.org'])
    end
    context 'when restricted by admin signup restriction - allowlist' do
    before do
    stub_application_setting(domain_allowlist: ['example.com'])
    end
    it_behaves_like 'restricted email error', message, code
    end
    # this response code should be changed to 4xx: https://gitlab.com/gitlab-org/gitlab/-/issues/321706
    it_behaves_like 'restricted email error', 'User domain is not authorized for sign-up.', :created
    shared_examples 'admin signup restrictions email error - allowlist' do |message, code|
    before do
    stub_application_setting(domain_allowlist: ['example.com'])
    end
    context 'when restricted by admin signup restriction - email restrictions' do
    before do
    stub_application_setting(email_restrictions_enabled: true)
    stub_application_setting(email_restrictions: '([\+]|\b(\w*example.org\w*)\b)')
    end
    it_behaves_like 'restricted email error', message, code
    end
    # this response code should be changed to 4xx: https://gitlab.com/gitlab-org/gitlab/-/issues/321706
    it_behaves_like 'restricted email error', 'User is not allowed. Try again with a different email address, or contact your GitLab admin.', :created
    shared_examples 'admin signup restrictions email error - email restrictions' do |message, code|
    before do
    stub_application_setting(email_restrictions_enabled: true)
    stub_application_setting(email_restrictions: '([\+]|\b(\w*example.org\w*)\b)')
    end
    it_behaves_like 'restricted email error', message, code
    end
    describe 'POST /groups/:id/invitations' do
    it_behaves_like 'admin signup restrictions email error - denylist', "The member's email address is not allowed for this group. Go to the 'Admin area > Sign-up restrictions', and check the 'Domain denylist'.", :created
    context 'when the group is restricted by admin signup restrictions' do
    it_behaves_like 'admin signup restrictions email error'
    it_behaves_like 'admin signup restrictions email error - allowlist', "The member's email address is not allowed for this group. Go to the 'Admin area > Sign-up restrictions', and check 'Allowed domains for sign-ups'.", :created
    it_behaves_like 'admin signup restrictions email error - email restrictions', "The member's email address is not allowed for this group. Go to the 'Admin area > Sign-up restrictions', and check 'Email restrictions for sign-ups'.", :created
    end
    context 'when the group is restricted by group signup restriction - allowed domains for signup' do
    ......@@ -63,8 +60,7 @@
    create(:allowed_email_domain, group: group, domain: 'example.com')
    end
    # this response code should be changed to 4xx: https://gitlab.com/gitlab-org/gitlab/-/issues/321706
    it_behaves_like 'restricted email error', "Invite email email does not match the allowed domain of example.com", :success
    it_behaves_like 'restricted email error', "The member's email address is not allowed for this group. Go to the group’s 'Settings > General' page, and check 'Restrict membership by email domain'.", :success
    end
    end
    ......@@ -74,7 +70,11 @@
    let(:url) { "/projects/#{project.id}/invitations" }
    context 'when the project is restricted by admin signup restrictions' do
    it_behaves_like 'admin signup restrictions email error'
    it_behaves_like 'admin signup restrictions email error - denylist', "The member's email address is not allowed for this project. Go to the 'Admin area > Sign-up restrictions', and check the 'Domain denylist'.", :created
    context 'when the group is restricted by admin signup restrictions' do
    it_behaves_like 'admin signup restrictions email error - allowlist', "The member's email address is not allowed for this project. Go to the 'Admin area > Sign-up restrictions', and check 'Allowed domains for sign-ups'.", :created
    it_behaves_like 'admin signup restrictions email error - email restrictions', "The member's email address is not allowed for this project. Go to the 'Admin area > Sign-up restrictions', and check 'Email restrictions for sign-ups'.", :created
    end
    end
    end
    end
    ......@@ -53,7 +53,7 @@
    it 'returns error message' do
    subject
    expect(json_response).to eq({ 'message' => "User email does not match the allowed domain of gitlab.com" })
    expect(json_response['message']).to eq("The member's email address is not allowed for this group. Check with your administrator.")
    end
    end
    end
    ......
    ......@@ -53,7 +53,7 @@
    end
    end
    RSpec.shared_examples 'member group domain validations' do
    RSpec.shared_examples 'member group domain validations' do |source_type|
    context 'validates group domain limitations' do
    let(:group) { create(:group) }
    let(:gitlab_user) { create(:user, email: 'test@gitlab.com') }
    ......@@ -77,11 +77,20 @@
    expect(build(member_type, source: source, user: acme_user)).to be_valid
    end
    it 'shows proper error message' do
    it 'shows proper error message when not invited by admin' do
    member = build(member_type, source: source, user: gmail_user)
    allow(member).to receive_message_chain(:created_by, :can_admin_all_resources?).and_return(false)
    expect(member).to be_invalid
    expect(member.errors[:user]).to include("email does not match the allowed domains: gitlab.com, acme.com")
    expect(member.errors[:user]).to include("is not allowed for this #{source_type}. Check with your administrator.")
    end
    it 'shows proper error message when invited by admin' do
    member = build(member_type, source: source, user: gmail_user)
    allow(member).to receive_message_chain(:created_by, :can_admin_all_resources?).and_return(true)
    expect(member).to be_invalid
    expect(member.errors[:user]).to include("is not allowed for this #{source_type}. Go to the group’s 'Settings > General' page, and check 'Restrict membership by email domain'.")
    end
    it 'shows proper error message for single domain limitation' do
    ......@@ -89,7 +98,7 @@
    member = build(member_type, source: source, user: gmail_user)
    expect(member).to be_invalid
    expect(member.errors[:user]).to include("email does not match the allowed domain of gitlab.com")
    expect(member.errors[:user]).to include("is not allowed for this #{source_type}. Check with your administrator.")
    end
    it 'invited email must match at least one of the allowed domain emails' do
    ......
    ......@@ -6546,6 +6546,9 @@ msgstr ""
    msgid "Check the elasticsearch.log file to debug why the migration was halted and make any changes before retrying the migration. When you fix the cause of the failure, click \"Retry migration\", and the migration will be scheduled to be retried in the background."
    msgstr ""
     
    msgid "Check with your administrator."
    msgstr ""
    msgid "Check your Docker images for known vulnerabilities."
    msgstr ""
     
    ......@@ -15820,9 +15823,21 @@ msgstr ""
    msgid "Go to snippets"
    msgstr ""
     
    msgid "Go to the 'Admin area > Sign-up restrictions', and check 'Allowed domains for sign-ups'."
    msgstr ""
    msgid "Go to the 'Admin area > Sign-up restrictions', and check 'Email restrictions for sign-ups'."
    msgstr ""
    msgid "Go to the 'Admin area > Sign-up restrictions', and check the 'Domain denylist'."
    msgstr ""
    msgid "Go to the activity feed"
    msgstr ""
     
    msgid "Go to the group’s 'Settings > General' page, and check 'Restrict membership by email domain'."
    msgstr ""
    msgid "Go to the milestone list"
    msgstr ""
     
    ......@@ -40025,9 +40040,6 @@ msgstr ""
    msgid "does not have a supported extension. Only %{extension_list} are supported"
    msgstr ""
     
    msgid "domain is not authorized for sign-up."
    msgstr ""
    msgid "download it"
    msgstr ""
     
    ......@@ -40045,11 +40057,6 @@ msgstr ""
    msgid "email '%{email}' is not a verified email."
    msgstr ""
     
    msgid "email does not match the allowed domain of %{email_domains}"
    msgid_plural "email does not match the allowed domains: %{email_domains}"
    msgstr[0] ""
    msgstr[1] ""
    msgid "enabled"
    msgstr ""
     
    ......@@ -40263,16 +40270,19 @@ msgstr ""
    msgid "is not a valid X509 certificate."
    msgstr ""
     
    msgid "is not allowed since the group is not top-level group."
    msgid "is not allowed for sign-up."
    msgstr ""
     
    msgid "is not allowed. Try again with a different email address, or contact your GitLab admin."
    msgid "is not allowed for this group."
    msgstr ""
     
    msgid "is not allowed. We do not currently support project-level iterations"
    msgid "is not allowed for this project."
    msgstr ""
     
    msgid "is not from an allowed domain."
    msgid "is not allowed since the group is not top-level group."
    msgstr ""
    msgid "is not allowed. We do not currently support project-level iterations"
    msgstr ""
     
    msgid "is not in the group enforcing Group Managed Account"
    ......
    ......@@ -242,7 +242,7 @@ describe('InviteMembersModal', () => {
    };
    const expectedEmailRestrictedError =
    "email 'email@example.com' does not match the allowed domains: example1.org";
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.";
    const expectedSyntaxError = 'email contains an invalid email address';
    it('calls the API with the expected focus data when an areas_of_focus checkbox is clicked', () => {
    ......@@ -421,7 +421,7 @@ describe('InviteMembersModal', () => {
    await waitForPromises();
    expect(membersFormGroupInvalidFeedback()).toBe(
    "root: User email 'admin@example.com' does not match the allowed domain of example2.com",
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.",
    );
    expect(findMembersSelect().props('validationState')).toBe(false);
    });
    ......
    ......@@ -9,7 +9,7 @@ const INVITATIONS_API_ERROR_EMAIL_INVALID = {
    const INVITATIONS_API_EMAIL_RESTRICTED = {
    message: {
    'email@example.com':
    "Invite email 'email@example.com' does not match the allowed domains: example1.org",
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.",
    },
    status: 'error',
    };
    ......@@ -17,9 +17,9 @@ const INVITATIONS_API_EMAIL_RESTRICTED = {
    const INVITATIONS_API_MULTIPLE_EMAIL_RESTRICTED = {
    message: {
    'email@example.com':
    "Invite email email 'email@example.com' does not match the allowed domains: example1.org",
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.",
    'email4@example.com':
    "Invite email email 'email4@example.com' does not match the allowed domains: example1.org",
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check the Domain denylist.",
    },
    status: 'error',
    };
    ......@@ -36,7 +36,11 @@ const MEMBERS_API_MEMBER_ALREADY_EXISTS = {
    };
    const MEMBERS_API_SINGLE_USER_RESTRICTED = {
    message: { user: ["email 'email@example.com' does not match the allowed domains: example1.org"] },
    message: {
    user: [
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.",
    ],
    },
    };
    const MEMBERS_API_SINGLE_USER_ACCESS_LEVEL = {
    ......@@ -49,7 +53,7 @@ const MEMBERS_API_SINGLE_USER_ACCESS_LEVEL = {
    const MEMBERS_API_MULTIPLE_USERS_RESTRICTED = {
    message:
    "root: User email 'admin@example.com' does not match the allowed domain of example2.com and user18: User email 'user18@example.org' does not match the allowed domain of example2.com",
    "root: The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups. and user18: The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check the Domain denylist. and john_doe31: The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Email restrictions for sign-ups.",
    status: 'error',
    };
    ......
    ......@@ -2,18 +2,20 @@ import {
    responseMessageFromSuccess,
    responseMessageFromError,
    } from '~/invite_members/utils/response_message_parser';
    import { membersApiResponse, invitationsApiResponse } from '../mock_data/api_responses';
    describe('Response message parser', () => {
    const expectedMessage = 'expected display message';
    const expectedMessage = 'expected display and message.';
    describe('parse message from successful response', () => {
    const exampleKeyedMsg = { 'email@example.com': expectedMessage };
    const exampleFirstPartMultiple = 'username1: expected display and message.';
    const exampleUserMsgMultiple =
    ' and username1: id not found and username2: email is restricted';
    ' and username2: id not found and restricted email. and username3: email is restricted.';
    it.each([
    [[{ data: { message: expectedMessage } }]],
    [[{ data: { message: expectedMessage + exampleUserMsgMultiple } }]],
    [[{ data: { message: exampleFirstPartMultiple + exampleUserMsgMultiple } }]],
    [[{ data: { error: expectedMessage } }]],
    [[{ data: { message: [expectedMessage] } }]],
    [[{ data: { message: exampleKeyedMsg } }]],
    ......@@ -33,4 +35,24 @@ describe('Response message parser', () => {
    expect(responseMessageFromError(errorResponse)).toBe(expectedMessage);
    });
    });
    describe('displaying only the first error when a response has messages for multiple users', () => {
    const expected =
    "The member's email address is not allowed for this project. Go to the Admin area > Sign-up restrictions, and check Allowed domains for sign-ups.";
    it.each([
    [[{ data: membersApiResponse.MULTIPLE_USERS_RESTRICTED }]],
    [[{ data: invitationsApiResponse.MULTIPLE_EMAIL_RESTRICTED }]],
    [[{ data: invitationsApiResponse.EMAIL_RESTRICTED }]],
    ])(`returns "${expectedMessage}" from success response: %j`, (restrictedResponse) => {
    expect(responseMessageFromSuccess(restrictedResponse)).toBe(expected);
    });
    it.each([[{ response: { data: membersApiResponse.SINGLE_USER_RESTRICTED } }]])(
    `returns "${expectedMessage}" from error response: %j`,
    (singleRestrictedResponse) => {
    expect(responseMessageFromError(singleRestrictedResponse)).toBe(expected);
    },
    );
    });
    });
    ......@@ -65,6 +65,8 @@
    end
    context 'with admin signup restrictions' do
    let(:expected_message) { _('is not allowed for this group. Check with your administrator.') }
    context 'when allowed domains for signup is enabled' do
    before do
    stub_application_setting(domain_allowlist: ['example.com'])
    ......@@ -74,7 +76,7 @@
    member = build(:group_member, :invited, invite_email: 'info@gitlab.com')
    expect(member).not_to be_valid
    expect(member.errors.messages[:user].first).to eq(_('domain is not authorized for sign-up.'))
    expect(member.errors.messages[:user].first).to eq(expected_message)
    end
    end
    ......@@ -88,7 +90,7 @@
    member = build(:group_member, :invited, invite_email: 'denylist@example.org')
    expect(member).not_to be_valid
    expect(member.errors.messages[:user].first).to eq(_('is not from an allowed domain.'))
    expect(member.errors.messages[:user].first).to eq(expected_message)
    end
    end
    ......@@ -102,7 +104,7 @@
    member = build(:group_member, :invited, invite_email: 'info@gitlab.com')
    expect(member).not_to be_valid
    expect(member.errors.messages[:user].first).to eq(_('is not allowed. Try again with a different email address, or contact your GitLab admin.'))
    expect(member.errors.messages[:user].first).to eq(expected_message)
    end
    end
    end
    ......
    ......@@ -494,6 +494,8 @@
    end
    describe 'email' do
    let(:expected_error) { _('is not allowed for sign-up. Check with your administrator.') }
    context 'when no signup domains allowed' do
    before do
    stub_application_setting(domain_allowlist: [])
    ......@@ -537,7 +539,7 @@
    it 'rejects example@test.com' do
    user = build(:user, email: "example@test.com")
    expect(user).to be_invalid
    expect(user.errors.messages[:email].first).to eq(_('domain is not authorized for sign-up.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    end
    ......@@ -554,13 +556,13 @@
    it 'rejects info@test.example.com' do
    user = build(:user, email: "info@test.example.com")
    expect(user).to be_invalid
    expect(user.errors.messages[:email].first).to eq(_('domain is not authorized for sign-up.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    it 'rejects example@test.com' do
    user = build(:user, email: "example@test.com")
    expect(user).to be_invalid
    expect(user.errors.messages[:email].first).to eq(_('domain is not authorized for sign-up.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    it 'accepts example@test.com when added by another user' do
    ......@@ -598,7 +600,7 @@
    it 'rejects info@example.com' do
    user = build(:user, email: 'info@example.com')
    expect(user).not_to be_valid
    expect(user.errors.messages[:email].first).to eq(_('is not from an allowed domain.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    it 'accepts info@example.com when added by another user' do
    ......@@ -632,7 +634,7 @@
    it 'rejects info@example.com' do
    user = build(:user, email: 'info@example.com')
    expect(user).not_to be_valid
    expect(user.errors.messages[:email].first).to eq(_('domain is not authorized for sign-up.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    end
    end
    ......@@ -673,7 +675,7 @@
    user = build(:user, email: 'info@gitlab.com')
    expect(user).not_to be_valid
    expect(user.errors.messages[:email].first).to eq(_('is not allowed. Try again with a different email address, or contact your GitLab admin.'))
    expect(user.errors.messages[:email].first).to eq(expected_error)
    end
    it 'does accept a valid email address' do
    ......
    ......@@ -80,7 +80,7 @@
    it 'does not add a member' do
    expect(execute_service[:status]).to eq(:error)
    expect(execute_service[:message]).to eq('Invite email has already been taken')
    expect(execute_service[:message]).to eq("The member's email address has already been taken")
    expect(OnboardingProgress.completed?(source.namespace, :user_added)).to be(false)
    end
    end
    ......
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment