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
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/registrations_controller_spec.rb5
-rw-r--r--spec/features/invites_spec.rb16
-rw-r--r--spec/features/projects/snippets/create_snippet_spec.rb2
-rw-r--r--spec/features/uploads/user_uploads_file_to_note_spec.rb2
-rw-r--r--spec/features/users/signup_spec.rb20
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js59
-rw-r--r--spec/frontend/integrations/edit/store/actions_spec.js27
-rw-r--r--spec/frontend/integrations/edit/store/getters_spec.js32
-rw-r--r--spec/frontend/integrations/edit/store/mutations_spec.js24
-rw-r--r--spec/frontend/integrations/edit/store/state_spec.js1
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js15
-rw-r--r--spec/requests/api/invitations_spec.rb98
-rw-r--r--spec/requests/api/settings_spec.rb2
13 files changed, 292 insertions, 11 deletions
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index fdcea33b0be..2fb17e56f37 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe RegistrationsController do
before do
stub_feature_flags(invisible_captcha: false)
+ stub_application_setting(require_admin_approval_after_user_signup: false)
end
describe '#new' do
@@ -76,10 +77,6 @@ RSpec.describe RegistrationsController do
end
context 'when the `require_admin_approval_after_user_signup` setting is turned off' do
- before do
- stub_application_setting(require_admin_approval_after_user_signup: false)
- end
-
it 'signs up the user in `active` state' do
subject
created_user = User.find_by(email: 'new@user.com')
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index d1520a5a53a..2ceffa896eb 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
let(:group_invite) { group.group_members.invite.last }
before do
+ stub_application_setting(require_admin_approval_after_user_signup: false)
project.add_maintainer(owner)
group.add_owner(owner)
group.add_developer('user@example.com', owner)
@@ -97,6 +98,21 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
click_link 'Register now'
end
+ context 'with admin appoval required enabled' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
+
+ let(:send_email_confirmation) { true }
+
+ it 'does not sign the user in' do
+ fill_in_sign_up_form(new_user)
+
+ expect(current_path).to eq(new_user_session_path)
+ expect(page).to have_content('You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator')
+ end
+ end
+
context 'email confirmation disabled' do
let(:send_email_confirmation) { false }
diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb
index 28fe0a0b7e1..0ed9e23c7f8 100644
--- a/spec/features/projects/snippets/create_snippet_spec.rb
+++ b/spec/features/projects/snippets/create_snippet_spec.rb
@@ -62,7 +62,7 @@ RSpec.describe 'Projects > Snippets > Create Snippet', :js do
click_button('Create snippet')
wait_for_requests
- link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
+ link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src']
expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z})
end
diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb
index 1eb3b016152..589cc9f9b02 100644
--- a/spec/features/uploads/user_uploads_file_to_note_spec.rb
+++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb
@@ -78,7 +78,7 @@ RSpec.describe 'User uploads file to note' do
click_button 'Comment'
wait_for_requests
- expect(find('a.no-attachment-icon img[alt="dk"]')['src'])
+ expect(find('a.no-attachment-icon img.js-lazy-loaded[alt="dk"]')['src'])
.to match(%r{/#{project.full_path}/uploads/\h{32}/dk\.png$})
end
end
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index bb2b465a69a..bfdd1e1bdb7 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -43,6 +43,10 @@ end
RSpec.describe 'Signup' do
include TermsHelper
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: false)
+ end
+
let(:new_user) { build_stubbed(:user) }
def fill_in_signup_form
@@ -228,6 +232,22 @@ RSpec.describe 'Signup' do
expect(current_path).to eq users_sign_up_welcome_path
end
end
+
+ context 'with required admin approval enabled' do
+ before do
+ stub_application_setting(require_admin_approval_after_user_signup: true)
+ end
+
+ it 'creates the user but does not sign them in' do
+ visit new_user_registration_path
+
+ fill_in_signup_form
+
+ expect { click_button 'Register' }.to change { User.count }.by(1)
+ expect(current_path).to eq new_user_session_path
+ expect(page).to have_content("You have signed up successfully. However, we could not sign you in because your account is awaiting approval from your GitLab administrator")
+ end
+ end
end
context 'with errors' do
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index 4dd38c959f8..97e77ac87ab 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -5,6 +5,7 @@ import IntegrationForm from '~/integrations/edit/components/integration_form.vue
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
+import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue';
import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_fields.vue';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
@@ -44,6 +45,8 @@ describe('IntegrationForm', () => {
const findOverrideDropdown = () => wrapper.find(OverrideDropdown);
const findActiveCheckbox = () => wrapper.find(ActiveCheckbox);
const findConfirmationModal = () => wrapper.find(ConfirmationModal);
+ const findResetConfirmationModal = () => wrapper.find(ResetConfirmationModal);
+ const findResetButton = () => wrapper.find('[data-testid="reset-button"]');
const findJiraTriggerFields = () => wrapper.find(JiraTriggerFields);
const findJiraIssuesFields = () => wrapper.find(JiraIssuesFields);
const findTriggerFields = () => wrapper.find(TriggerFields);
@@ -75,6 +78,29 @@ describe('IntegrationForm', () => {
expect(findConfirmationModal().exists()).toBe(true);
});
+
+ describe('resetPath is empty', () => {
+ it('does not render ResetConfirmationModal and button', () => {
+ createComponent({
+ integrationLevel: integrationLevels.INSTANCE,
+ });
+
+ expect(findResetButton().exists()).toBe(false);
+ expect(findResetConfirmationModal().exists()).toBe(false);
+ });
+ });
+
+ describe('resetPath is present', () => {
+ it('renders ResetConfirmationModal and button', () => {
+ createComponent({
+ integrationLevel: integrationLevels.INSTANCE,
+ resetPath: 'resetPath',
+ });
+
+ expect(findResetButton().exists()).toBe(true);
+ expect(findResetConfirmationModal().exists()).toBe(true);
+ });
+ });
});
describe('integrationLevel is group', () => {
@@ -85,6 +111,29 @@ describe('IntegrationForm', () => {
expect(findConfirmationModal().exists()).toBe(true);
});
+
+ describe('resetPath is empty', () => {
+ it('does not render ResetConfirmationModal and button', () => {
+ createComponent({
+ integrationLevel: integrationLevels.GROUP,
+ });
+
+ expect(findResetButton().exists()).toBe(false);
+ expect(findResetConfirmationModal().exists()).toBe(false);
+ });
+ });
+
+ describe('resetPath is present', () => {
+ it('renders ResetConfirmationModal and button', () => {
+ createComponent({
+ integrationLevel: integrationLevels.GROUP,
+ resetPath: 'resetPath',
+ });
+
+ expect(findResetButton().exists()).toBe(true);
+ expect(findResetConfirmationModal().exists()).toBe(true);
+ });
+ });
});
describe('integrationLevel is project', () => {
@@ -95,6 +144,16 @@ describe('IntegrationForm', () => {
expect(findConfirmationModal().exists()).toBe(false);
});
+
+ it('does not render ResetConfirmationModal and button', () => {
+ createComponent({
+ integrationLevel: 'project',
+ resetPath: 'resetPath',
+ });
+
+ expect(findResetButton().exists()).toBe(false);
+ expect(findResetConfirmationModal().exists()).toBe(false);
+ });
});
describe('type is "slack"', () => {
diff --git a/spec/frontend/integrations/edit/store/actions_spec.js b/spec/frontend/integrations/edit/store/actions_spec.js
index 5356c0a411b..5b5c8d6f76e 100644
--- a/spec/frontend/integrations/edit/store/actions_spec.js
+++ b/spec/frontend/integrations/edit/store/actions_spec.js
@@ -1,6 +1,11 @@
import testAction from 'helpers/vuex_action_helper';
import createState from '~/integrations/edit/store/state';
-import { setOverride } from '~/integrations/edit/store/actions';
+import {
+ setOverride,
+ setIsSaving,
+ setIsTesting,
+ setIsResetting,
+} from '~/integrations/edit/store/actions';
import * as types from '~/integrations/edit/store/mutation_types';
describe('Integration form store actions', () => {
@@ -15,4 +20,24 @@ describe('Integration form store actions', () => {
return testAction(setOverride, true, state, [{ type: types.SET_OVERRIDE, payload: true }]);
});
});
+
+ describe('setIsSaving', () => {
+ it('should commit isSaving mutation', () => {
+ return testAction(setIsSaving, true, state, [{ type: types.SET_IS_SAVING, payload: true }]);
+ });
+ });
+
+ describe('setIsTesting', () => {
+ it('should commit isTesting mutation', () => {
+ return testAction(setIsTesting, true, state, [{ type: types.SET_IS_TESTING, payload: true }]);
+ });
+ });
+
+ describe('setIsResetting', () => {
+ it('should commit isResetting mutation', () => {
+ return testAction(setIsResetting, true, state, [
+ { type: types.SET_IS_RESETTING, payload: true },
+ ]);
+ });
+ });
});
diff --git a/spec/frontend/integrations/edit/store/getters_spec.js b/spec/frontend/integrations/edit/store/getters_spec.js
index 3353e0c84cc..7d4532a1059 100644
--- a/spec/frontend/integrations/edit/store/getters_spec.js
+++ b/spec/frontend/integrations/edit/store/getters_spec.js
@@ -1,5 +1,12 @@
-import { currentKey, isInheriting, propsSource } from '~/integrations/edit/store/getters';
+import {
+ currentKey,
+ isInheriting,
+ isDisabled,
+ propsSource,
+} from '~/integrations/edit/store/getters';
import createState from '~/integrations/edit/store/state';
+import mutations from '~/integrations/edit/store/mutations';
+import * as types from '~/integrations/edit/store/mutation_types';
import { mockIntegrationProps } from '../mock_data';
describe('Integration form store getters', () => {
@@ -45,6 +52,29 @@ describe('Integration form store getters', () => {
});
});
+ describe('isDisabled', () => {
+ it.each`
+ isSaving | isTesting | isResetting | expected
+ ${false} | ${false} | ${false} | ${false}
+ ${true} | ${false} | ${false} | ${true}
+ ${false} | ${true} | ${false} | ${true}
+ ${false} | ${false} | ${true} | ${true}
+ ${false} | ${true} | ${true} | ${true}
+ ${true} | ${false} | ${true} | ${true}
+ ${true} | ${true} | ${false} | ${true}
+ ${true} | ${true} | ${true} | ${true}
+ `(
+ 'when isSaving = $isSaving, isTesting = $isTesting, isResetting = $isResetting then isDisabled = $expected',
+ ({ isSaving, isTesting, isResetting, expected }) => {
+ mutations[types.SET_IS_SAVING](state, isSaving);
+ mutations[types.SET_IS_TESTING](state, isTesting);
+ mutations[types.SET_IS_RESETTING](state, isResetting);
+
+ expect(isDisabled(state)).toBe(expected);
+ },
+ );
+ });
+
describe('propsSource', () => {
beforeEach(() => {
state.defaultState = defaultState;
diff --git a/spec/frontend/integrations/edit/store/mutations_spec.js b/spec/frontend/integrations/edit/store/mutations_spec.js
index 4b733726d44..4707b4b3714 100644
--- a/spec/frontend/integrations/edit/store/mutations_spec.js
+++ b/spec/frontend/integrations/edit/store/mutations_spec.js
@@ -16,4 +16,28 @@ describe('Integration form store mutations', () => {
expect(state.override).toBe(true);
});
});
+
+ describe(`${types.SET_IS_SAVING}`, () => {
+ it('sets isSaving', () => {
+ mutations[types.SET_IS_SAVING](state, true);
+
+ expect(state.isSaving).toBe(true);
+ });
+ });
+
+ describe(`${types.SET_IS_TESTING}`, () => {
+ it('sets isTesting', () => {
+ mutations[types.SET_IS_TESTING](state, true);
+
+ expect(state.isTesting).toBe(true);
+ });
+ });
+
+ describe(`${types.SET_IS_RESETTING}`, () => {
+ it('sets isResetting', () => {
+ mutations[types.SET_IS_RESETTING](state, true);
+
+ expect(state.isResetting).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/integrations/edit/store/state_spec.js b/spec/frontend/integrations/edit/store/state_spec.js
index fc193850a94..4d0f4a1da71 100644
--- a/spec/frontend/integrations/edit/store/state_spec.js
+++ b/spec/frontend/integrations/edit/store/state_spec.js
@@ -7,6 +7,7 @@ describe('Integration form state factory', () => {
customState: {},
isSaving: false,
isTesting: false,
+ isResetting: false,
override: false,
});
});
diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js
index 6fef5f6b63c..d7cedb939d2 100644
--- a/spec/frontend/lib/utils/text_utility_spec.js
+++ b/spec/frontend/lib/utils/text_utility_spec.js
@@ -325,4 +325,19 @@ describe('text_utility', () => {
expect(textUtils.hasContent(txt)).toEqual(result);
});
});
+
+ describe('isValidSha1Hash', () => {
+ const validSha1Hash = '92d10c15';
+ const stringOver40 = new Array(42).join('a');
+
+ it.each`
+ hash | valid
+ ${validSha1Hash} | ${true}
+ ${'__characters'} | ${false}
+ ${'abc'} | ${false}
+ ${stringOver40} | ${false}
+ `(`returns $valid for $hash`, ({ hash, valid }) => {
+ expect(textUtils.isValidSha1Hash(hash)).toBe(valid);
+ });
+ });
});
diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb
index 9befd4f533a..75586970abb 100644
--- a/spec/requests/api/invitations_spec.rb
+++ b/spec/requests/api/invitations_spec.rb
@@ -7,7 +7,8 @@ RSpec.describe API::Invitations do
let(:developer) { create(:user) }
let(:access_requester) { create(:user) }
let(:stranger) { create(:user) }
- let(:email) { 'email@example.org' }
+ let(:email) { 'email1@example.com' }
+ let(:email2) { 'email2@example.com' }
let(:project) do
create(:project, :public, creator_id: maintainer.id, namespace: maintainer.namespace) do |project|
@@ -75,7 +76,7 @@ RSpec.describe API::Invitations do
it 'invites a list of new email addresses' do
expect do
- email_list = 'email1@example.com,email2@example.com'
+ email_list = [email, email2].join(',')
post api("/#{source_type.pluralize}/#{source.id}/invitations", maintainer),
params: { email: email_list, access_level: Member::DEVELOPER }
@@ -204,4 +205,97 @@ RSpec.describe API::Invitations do
let(:source) { group }
end
end
+
+ shared_examples 'GET /:source_type/:id/invitations' do |source_type|
+ context "with :source_type == #{source_type.pluralize}" do
+ it_behaves_like 'a 404 response when source is private' do
+ let(:route) { get invitations_url(source, stranger) }
+ end
+
+ %i[maintainer developer access_requester stranger].each do |type|
+ context "when authenticated as a #{type}" do
+ it 'returns 200' do
+ user = public_send(type)
+
+ get invitations_url(source, user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(0)
+ end
+ end
+ end
+
+ it 'avoids N+1 queries' do
+ # Establish baseline
+ get invitations_url(source, maintainer)
+
+ control = ActiveRecord::QueryRecorder.new do
+ get invitations_url(source, maintainer)
+ end
+
+ invite_member_by_email(source, source_type, email, maintainer)
+
+ expect do
+ get invitations_url(source, maintainer)
+ end.not_to exceed_query_limit(control)
+ end
+
+ it 'does not find confirmed members' do
+ get invitations_url(source, developer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.size).to eq(0)
+ expect(json_response.map { |u| u['id'] }).not_to match_array [maintainer.id, developer.id]
+ end
+
+ it 'finds all members with no query string specified' do
+ invite_member_by_email(source, source_type, email, developer)
+ invite_member_by_email(source, source_type, email2, developer)
+
+ get invitations_url(source, developer), params: { query: '' }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(2)
+ expect(json_response.map { |u| u['invite_email'] }).to match_array [email, email2]
+ end
+
+ it 'finds the invitation by invite_email with query string' do
+ invite_member_by_email(source, source_type, email, developer)
+ invite_member_by_email(source, source_type, email2, developer)
+
+ get invitations_url(source, developer), params: { query: email }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['invite_email']).to eq(email)
+ expect(json_response.first['created_by_name']).to eq(developer.name)
+ expect(json_response.first['user_name']).to eq(nil)
+ end
+
+ def invite_member_by_email(source, source_type, email, created_by)
+ create(:"#{source_type}_member", invite_token: '123', invite_email: email, source: source, user: nil, created_by: created_by)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/invitations' do
+ it_behaves_like 'GET /:source_type/:id/invitations', 'project' do
+ let(:source) { project }
+ end
+ end
+
+ describe 'GET /groups/:id/invitations' do
+ it_behaves_like 'GET /:source_type/:id/invitations', 'group' do
+ let(:source) { group }
+ end
+ end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index e03c0d37f3d..da6eaf0ae23 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe API::Settings, 'Settings' do
expect(json_response['spam_check_endpoint_enabled']).to be_falsey
expect(json_response['spam_check_endpoint_url']).to be_nil
expect(json_response['wiki_page_max_content_bytes']).to be_a(Integer)
- expect(json_response['require_admin_approval_after_user_signup']).to eq(false)
+ expect(json_response['require_admin_approval_after_user_signup']).to eq(true)
end
end