diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 15:44:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-19 15:44:42 +0000 |
commit | 4555e1b21c365ed8303ffb7a3325d773c9b8bf31 (patch) | |
tree | 5423a1c7516cffe36384133ade12572cf709398d /spec/features/projects | |
parent | e570267f2f6b326480d284e0164a6464ba4081bc (diff) | |
download | gitlab-ce-4555e1b21c365ed8303ffb7a3325d773c9b8bf31.tar.gz |
Add latest changes from gitlab-org/gitlab@13-12-stable-eev13.12.0-rc42
Diffstat (limited to 'spec/features/projects')
53 files changed, 1142 insertions, 723 deletions
diff --git a/spec/features/projects/active_tabs_spec.rb b/spec/features/projects/active_tabs_spec.rb index 9de43e7d18c..96a321037a9 100644 --- a/spec/features/projects/active_tabs_spec.rb +++ b/spec/features/projects/active_tabs_spec.rb @@ -3,11 +3,11 @@ require 'spec_helper' RSpec.describe 'Project active tab' do - let(:user) { create :user } - let(:project) { create(:project, :repository) } + let_it_be(:project) { create(:project, :repository) } + + let(:user) { project.owner } before do - project.add_maintainer(user) sign_in(user) end @@ -18,15 +18,28 @@ RSpec.describe 'Project active tab' do end context 'on project Home' do - before do - visit project_path(project) + context 'when feature flag :sidebar_refactor is enabled' do + before do + visit project_path(project) + end + + it_behaves_like 'page has active tab', 'Project' end - it_behaves_like 'page has active tab', 'Project' - it_behaves_like 'page has active sub tab', 'Details' + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) + + visit project_path(project) + end + + it_behaves_like 'page has active tab', 'Project' + it_behaves_like 'page has active sub tab', 'Details' + end context 'on project Home/Activity' do before do + visit project_path(project) click_tab('Activity') end @@ -56,20 +69,37 @@ RSpec.describe 'Project active tab' do end context 'on project Issues' do + let(:feature_flag_value) { true } + before do + stub_feature_flags(sidebar_refactor: feature_flag_value) + visit project_issues_path(project) end it_behaves_like 'page has active tab', 'Issues' - %w(Milestones Labels).each do |sub_menu| - context "on project Issues/#{sub_menu}" do - before do - click_tab(sub_menu) - end + context "on project Issues/Milestones" do + before do + click_tab('Milestones') + end - it_behaves_like 'page has active tab', 'Issues' - it_behaves_like 'page has active sub tab', sub_menu + it_behaves_like 'page has active tab', 'Issues' + it_behaves_like 'page has active sub tab', 'Milestones' + end + + context 'when feature flag is disabled' do + let(:feature_flag_value) { false } + + %w(Milestones Labels).each do |sub_menu| + context "on project Issues/#{sub_menu}" do + before do + click_tab(sub_menu) + end + + it_behaves_like 'page has active tab', 'Issues' + it_behaves_like 'page has active sub tab', sub_menu + end end end end diff --git a/spec/features/projects/badges/pipeline_badge_spec.rb b/spec/features/projects/badges/pipeline_badge_spec.rb index c24ab5c4058..bfc924b5d9b 100644 --- a/spec/features/projects/badges/pipeline_badge_spec.rb +++ b/spec/features/projects/badges/pipeline_badge_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Pipeline Badge' do let_it_be(:project) { create(:project, :repository, :public) } + let(:ref) { project.default_branch } context 'when the project has a pipeline' do diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb index 7c564d76f70..3598aa2f423 100644 --- a/spec/features/projects/blobs/blob_show_spec.rb +++ b/spec/features/projects/blobs/blob_show_spec.rb @@ -119,6 +119,81 @@ RSpec.describe 'File blob', :js do end end + context 'when ref switch' do + def switch_ref_to(ref_name) + first('.qa-branches-select').click + + page.within '.project-refs-form' do + click_link ref_name + wait_for_requests + end + end + + it 'displays single highlighted line number of different ref' do + visit_blob('files/js/application.js', anchor: 'L1') + + switch_ref_to('feature') + + page.within '.blob-content' do + expect(find_by_id('LC1')[:class]).to include("hll") + end + end + + it 'displays multiple highlighted line numbers of different ref' do + visit_blob('files/js/application.js', anchor: 'L1-3') + + switch_ref_to('feature') + + page.within '.blob-content' do + expect(find_by_id('LC1')[:class]).to include("hll") + expect(find_by_id('LC2')[:class]).to include("hll") + expect(find_by_id('LC3')[:class]).to include("hll") + end + end + + it 'displays no highlighted number of different ref' do + Files::UpdateService.new( + project, + project.owner, + commit_message: 'Update', + start_branch: 'feature', + branch_name: 'feature', + file_path: 'files/js/application.js', + file_content: 'new content' + ).execute + + project.commit('feature').diffs.diff_files.first + + visit_blob('files/js/application.js', anchor: 'L3') + switch_ref_to('feature') + + page.within '.blob-content' do + expect(page).not_to have_css('.hll') + end + end + + context 'sucessfully change ref of similar name' do + before do + project.repository.create_branch('dev') + project.repository.create_branch('development') + end + + it 'switch ref from longer to shorter ref name' do + visit_blob('files/js/application.js', ref: 'development') + switch_ref_to('dev') + + expect(page.find('.file-title-name').text).to eq('application.js') + end + + it 'switch ref from shorter to longer ref name' do + visit_blob('files/js/application.js', ref: 'dev') + switch_ref_to('development') + + expect(page.find('.file-title-name').text).to eq('application.js') + end + end + end + context 'visiting with a line number anchor' do before do visit_blob('files/markdown/ruby-style-guide.md', anchor: 'L1') diff --git a/spec/features/projects/branches/user_deletes_branch_spec.rb b/spec/features/projects/branches/user_deletes_branch_spec.rb index bebb4bb679b..53994ec018e 100644 --- a/spec/features/projects/branches/user_deletes_branch_spec.rb +++ b/spec/features/projects/branches/user_deletes_branch_spec.rb @@ -4,6 +4,7 @@ require "spec_helper" RSpec.describe "User deletes branch", :js do let_it_be(:user) { create(:user) } + let(:project) { create(:project, :repository) } before do diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index 00ec9d49a10..7b10f72006f 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -30,7 +30,7 @@ RSpec.describe 'project commit pipelines', :js do wait_for_requests page.within('.merge-request-info') do - expect(page).not_to have_selector '.spinner' + expect(page).not_to have_selector '.gl-spinner' expect(page).to have_content 'No related merge requests found' end end diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb index cd944436228..fce9fa4fb62 100644 --- a/spec/features/projects/commit/cherry_pick_spec.rb +++ b/spec/features/projects/commit/cherry_pick_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe 'Cherry-pick Commits', :js do let_it_be(:user) { create(:user) } let_it_be(:sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' } + let!(:project) { create_default(:project, :repository, namespace: user.namespace) } let(:master_pickable_commit) { project.commit(sha) } diff --git a/spec/features/projects/commit/user_comments_on_commit_spec.rb b/spec/features/projects/commit/user_comments_on_commit_spec.rb index 0fa4975bb25..6997c2d8338 100644 --- a/spec/features/projects/commit/user_comments_on_commit_spec.rb +++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb @@ -8,6 +8,7 @@ RSpec.describe "User comments on commit", :js do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } + let(:comment_text) { "XML attached" } before_all do diff --git a/spec/features/projects/commit/user_reverts_commit_spec.rb b/spec/features/projects/commit/user_reverts_commit_spec.rb index ad327b86aa7..1c6cf5eb258 100644 --- a/spec/features/projects/commit/user_reverts_commit_spec.rb +++ b/spec/features/projects/commit/user_reverts_commit_spec.rb @@ -6,6 +6,7 @@ RSpec.describe 'User reverts a commit', :js do include RepoHelpers let_it_be(:user) { create(:user) } + let!(:project) { create_default(:project, :repository, namespace: user.namespace) } before do diff --git a/spec/features/projects/commit/user_views_user_status_on_commit_spec.rb b/spec/features/projects/commit/user_views_user_status_on_commit_spec.rb index 89ff2f4b26d..cc3c70e66ce 100644 --- a/spec/features/projects/commit/user_views_user_status_on_commit_spec.rb +++ b/spec/features/projects/commit/user_views_user_status_on_commit_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Project > Commit > View user status' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } + let(:commit_author) { create(:user, email: sample_commit.author_email) } before do diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 64e9968061c..bc3ef2af9b0 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -118,6 +118,34 @@ RSpec.describe "Compare", :js do end end end + + context "pagination" do + before do + stub_const("Projects::CompareController::COMMIT_DIFFS_PER_PAGE", 1) + end + + it "shows an adjusted count for changed files on this page" do + visit project_compare_index_path(project, from: "feature", to: "master") + + click_button('Compare') + + expect(page).to have_content("Showing 1 changed file") + end + + it "shows commits list only on the first page" do + visit project_compare_index_path(project, from: "feature", to: "master") + click_button('Compare') + + expect(page).to have_content 'Commits (29)' + + # go to the second page + within(".files .gl-pagination") do + click_on("2") + end + + expect(page).not_to have_content 'Commits (29)' + end + end end describe "tags" do diff --git a/spec/features/projects/confluence/user_views_confluence_page_spec.rb b/spec/features/projects/confluence/user_views_confluence_page_spec.rb index d39c97291db..7ec724ed55d 100644 --- a/spec/features/projects/confluence/user_views_confluence_page_spec.rb +++ b/spec/features/projects/confluence/user_views_confluence_page_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'User views the Confluence page' do let_it_be(:user) { create(:user) } + let(:project) { create(:project, :public) } before do diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb index 6218578cac6..bf705cf875b 100644 --- a/spec/features/projects/deploy_keys_spec.rb +++ b/spec/features/projects/deploy_keys_spec.rb @@ -19,10 +19,11 @@ RSpec.describe 'Project deploy keys', :js do it 'removes association between project and deploy key' do visit project_settings_repository_path(project) - page.within(find('.qa-deploy-keys-settings')) do + page.within(find('.rspec-deploy-keys-settings')) do expect(page).to have_selector('.deploy-key', count: 1) - accept_confirm { find('[data-testid="remove-icon"]').click } + click_button 'Remove' + click_button 'Remove deploy key' wait_for_requests diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb index 747277e2562..e47f36c4b7a 100644 --- a/spec/features/projects/diffs/diff_show_spec.rb +++ b/spec/features/projects/diffs/diff_show_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Diff file viewer', :js do +RSpec.describe 'Diff file viewer', :js, :with_clean_rails_cache do let(:project) { create(:project, :public, :repository) } def visit_commit(sha, anchor: nil) diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index ab82a4750d3..363fe8c35fe 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -54,17 +54,30 @@ RSpec.describe 'Edit Project Settings' do end context 'When external issue tracker is enabled and issues disabled on project settings' do - it 'hides issues tab and show labels tab' do + before do project.issues_enabled = false project.save! allow_next_instance_of(Project) do |instance| allow(instance).to receive(:external_issue_tracker).and_return(JiraService.new) end + end + it 'hides issues tab' do visit project_path(project) expect(page).not_to have_selector('.shortcuts-issues') - expect(page).to have_selector('.shortcuts-labels') + expect(page).not_to have_selector('.shortcuts-labels') + end + + context 'when feature flag :sidebar_refactor is disabled' do + it 'hides issues tab and show labels tab' do + stub_feature_flags(sidebar_refactor: false) + + visit project_path(project) + + expect(page).not_to have_selector('.shortcuts-issues') + expect(page).to have_selector('.shortcuts-labels') + end end end diff --git a/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb deleted file mode 100644 index cd796d45aba..00000000000 --- a/spec/features/projects/files/gitlab_ci_syntax_yml_dropdown_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file' do - include Spec::Support::Helpers::Features::EditorLiteSpecHelpers - - let_it_be(:namespace) { create(:namespace) } - let(:project) { create(:project, :repository, namespace: namespace) } - - before do - sign_in project.owner - stub_experiment(ci_syntax_templates_b: experiment_active) - stub_experiment_for_subject(ci_syntax_templates_b: in_experiment_group) - - visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml') - end - - context 'when experiment is not active' do - let(:experiment_active) { false } - let(:in_experiment_group) { false } - - it 'does not show the "Learn CI/CD syntax" template dropdown' do - expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector') - end - end - - context 'when experiment is active' do - let(:experiment_active) { true } - - context 'when the user is in the control group' do - let(:in_experiment_group) { false } - - it 'does not show the "Learn CI/CD syntax" template dropdown' do - expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector') - end - end - - context 'when the user is in the experimental group' do - let(:in_experiment_group) { true } - - it 'allows the user to pick a "Learn CI/CD syntax" template from the dropdown', :js do - expect(page).to have_css('.gitlab-ci-syntax-yml-selector') - - find('.js-gitlab-ci-syntax-yml-selector').click - - wait_for_requests - - within '.gitlab-ci-syntax-yml-selector' do - find('.dropdown-input-field').set('Artifacts example') - find('.dropdown-content .is-focused', text: 'Artifacts example').click - end - - wait_for_requests - - expect(page).to have_css('.gitlab-ci-syntax-yml-selector .dropdown-toggle-text', text: 'Learn CI/CD syntax') - expect(editor_get_value).to have_content('You can use artifacts to pass data to jobs in later stages.') - end - - context 'when the group is created longer than 90 days ago' do - let(:namespace) { create(:namespace, created_at: 91.days.ago) } - - it 'does not show the "Learn CI/CD syntax" template dropdown' do - expect(page).not_to have_css('.gitlab-ci-syntax-yml-selector') - end - end - end - end -end diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index c18ff9ddbbc..453cc14c267 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -131,8 +131,8 @@ RSpec.describe 'Projects > Files > User edits files', :js do expect(page).to have_selector(:link_or_button, 'Fork') expect(page).to have_selector(:link_or_button, 'Cancel') expect(page).to have_content( - "You're not allowed to edit files in this project directly. "\ - "Please fork this project, make your changes there, and submit a merge request." + "You can’t edit files directly in this project. "\ + "Fork this project and submit a merge request with your changes." ) end diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 2b7ea70fe5a..9a6d1961a02 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -6,7 +6,7 @@ RSpec.describe 'Project fork' do include ProjectForksHelper let(:user) { create(:user) } - let(:project) { create(:project, :public, :repository) } + let(:project) { create(:project, :public, :repository, description: 'some description') } before do sign_in(user) @@ -228,7 +228,7 @@ RSpec.describe 'Project fork' do click_link 'Fork' page.within('.fork-thumbnail-container') do - expect(page).to have_css('div.identicon') + expect(page).to have_css('span.identicon') end end diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb index 72df84bf905..7e039a087c7 100644 --- a/spec/features/projects/graph_spec.rb +++ b/spec/features/projects/graph_spec.rb @@ -75,7 +75,7 @@ RSpec.describe 'Project Graph', :js do expect(page).to have_content 'Last week' expect(page).to have_content 'Last month' expect(page).to have_content 'Last year' - expect(page).to have_content 'Duration for the last 30 commits' + expect(page).to have_content 'Pipeline durations for the last 30 commits' end end end diff --git a/spec/features/projects/services/user_activates_asana_spec.rb b/spec/features/projects/integrations/user_activates_asana_spec.rb index cf2290383e8..cf2290383e8 100644 --- a/spec/features/projects/services/user_activates_asana_spec.rb +++ b/spec/features/projects/integrations/user_activates_asana_spec.rb diff --git a/spec/features/projects/services/user_activates_assembla_spec.rb b/spec/features/projects/integrations/user_activates_assembla_spec.rb index 63cc424a641..63cc424a641 100644 --- a/spec/features/projects/services/user_activates_assembla_spec.rb +++ b/spec/features/projects/integrations/user_activates_assembla_spec.rb diff --git a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb b/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb index 91db375be3a..91db375be3a 100644 --- a/spec/features/projects/services/user_activates_atlassian_bamboo_ci_spec.rb +++ b/spec/features/projects/integrations/user_activates_atlassian_bamboo_ci_spec.rb diff --git a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb index 4a4c33cb881..c3aefe05f75 100644 --- a/spec/features/projects/issues/design_management/user_views_design_images_spec.rb +++ b/spec/features/projects/issues/design_management/user_views_design_images_spec.rb @@ -8,6 +8,7 @@ RSpec.describe 'Users views raw design image files' do let_it_be(:project) { create(:project, :public) } let_it_be(:issue) { create(:issue, project: project) } let_it_be(:design) { create(:design, :with_file, issue: issue, versions_count: 2) } + let(:newest_version) { design.versions.ordered.first } let(:oldest_version) { design.versions.ordered.last } diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 18a6ad12240..a1416f3f563 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -136,7 +136,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).to have_selector('.build-job.active') + expect(page).to have_selector('[data-testid="active-job"]') end end @@ -255,7 +255,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do end it 'renders escaped tooltip name' do - page.find('.active.build-job a').hover + page.find('[data-testid="active-job"]').hover expect(page).to have_content('<img src=x onerror=alert(document.domain)> - passed') end end diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 0a373b0d51a..4a25e28a14e 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -33,14 +33,14 @@ RSpec.describe 'Issue prioritization' do sign_in user visit project_issues_path(project, sort: 'label_priority') + wait_for_requests + # Ensure we are indicating that issues are sorted by priority - expect(page).to have_selector('.dropdown', text: 'Label priority') + expect(page).to have_button 'Label priority' - page.within('.issues-holder') do - issue_titles = all('.issues-list .issue-title-text').map(&:text) + issue_titles = all('.issues-list .issue-title-text').map(&:text) - expect(issue_titles).to eq(%w(issue_4 issue_3 issue_5 issue_2 issue_1)) - end + expect(issue_titles).to eq(%w(issue_4 issue_3 issue_5 issue_2 issue_1)) end end @@ -72,15 +72,15 @@ RSpec.describe 'Issue prioritization' do sign_in user visit project_issues_path(project, sort: 'label_priority') - expect(page).to have_selector('.dropdown', text: 'Label priority') + wait_for_requests + + expect(page).to have_button 'Label priority' - page.within('.issues-holder') do - issue_titles = all('.issues-list .issue-title-text').map(&:text) + issue_titles = all('.issues-list .issue-title-text').map(&:text) - expect(issue_titles[0..1]).to contain_exactly('issue_5', 'issue_8') - expect(issue_titles[2..4]).to contain_exactly('issue_1', 'issue_3', 'issue_7') - expect(issue_titles[5..-1]).to eq(%w(issue_2 issue_4 issue_6)) - end + expect(issue_titles[0..1]).to contain_exactly('issue_5', 'issue_8') + expect(issue_titles[2..4]).to contain_exactly('issue_1', 'issue_3', 'issue_7') + expect(issue_titles[5..-1]).to eq(%w(issue_2 issue_4 issue_6)) end end end diff --git a/spec/features/projects/labels/user_sees_links_to_issuables_spec.rb b/spec/features/projects/labels/user_sees_links_to_issuables_spec.rb index 11aa53fd963..6f98883a412 100644 --- a/spec/features/projects/labels/user_sees_links_to_issuables_spec.rb +++ b/spec/features/projects/labels/user_sees_links_to_issuables_spec.rb @@ -51,6 +51,7 @@ RSpec.describe 'Projects > Labels > User sees links to issuables' do context 'with a group label' do let_it_be(:group) { create(:group) } + let(:label) { create(:group_label, group: group, title: 'bug') } context 'when merge requests and issues are enabled for the project' do diff --git a/spec/features/projects/labels/user_views_labels_spec.rb b/spec/features/projects/labels/user_views_labels_spec.rb index da8520ca8fb..7a6942b6259 100644 --- a/spec/features/projects/labels/user_views_labels_spec.rb +++ b/spec/features/projects/labels/user_views_labels_spec.rb @@ -5,6 +5,7 @@ require "spec_helper" RSpec.describe "User views labels" do let_it_be(:project) { create(:project_empty_repo, :public) } let_it_be(:user) { create(:user) } + let(:label_titles) { %w[bug enhancement feature] } let!(:prioritized_label) { create(:label, project: project, title: 'prioritized-label-name', priority: 1) } diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb index 83ba2533a73..4caf3e947c7 100644 --- a/spec/features/projects/members/invite_group_spec.rb +++ b/spec/features/projects/members/invite_group_spec.rb @@ -6,25 +6,48 @@ RSpec.describe 'Project > Members > Invite group', :js do include Select2Helper include ActionView::Helpers::DateHelper include Spec::Support::Helpers::Features::MembersHelpers + include Spec::Support::Helpers::Features::InviteMembersModalHelper let(:maintainer) { create(:user) } - before do - stub_feature_flags(invite_members_group_modal: false) + using RSpec::Parameterized::TableSyntax + + where(:invite_members_group_modal_enabled, :expected_invite_group_selector) do + true | 'button[data-qa-selector="invite_a_group_button"]' + false | '#invite-group-tab' + end + + with_them do + before do + stub_feature_flags(invite_members_group_modal: invite_members_group_modal_enabled) + end + + it 'displays either the invite group button or the form with tabs based on the feature flag' do + project = create(:project, namespace: create(:group)) + + project.add_maintainer(maintainer) + sign_in(maintainer) + + visit project_project_members_path(project) + + expect(page).to have_selector(expected_invite_group_selector) + end end describe 'Share with group lock' do + let(:invite_group_selector) { 'button[data-qa-selector="invite_a_group_button"]' } + shared_examples 'the project can be shared with groups' do - it 'the "Invite group" tab exists' do + it 'the "Invite a group" button exists' do visit project_project_members_path(project) - expect(page).to have_selector('#invite-group-tab') + expect(page).to have_selector(invite_group_selector) end end shared_examples 'the project cannot be shared with groups' do - it 'the "Invite group" tab does not exist' do + it 'the "Invite a group" button does not exist' do visit project_project_members_path(project) - expect(page).not_to have_selector('#invite-group-tab') + expect(page).not_to have_selector(invite_group_selector) end end @@ -41,7 +64,9 @@ RSpec.describe 'Project > Members > Invite group', :js do context 'when the group has "Share with group lock" disabled' do it_behaves_like 'the project can be shared with groups' - it 'the project can be shared with another group' do + it 'the project can be shared with another group when the feature flag invite_members_group_modal is disabled' do + stub_feature_flags(invite_members_group_modal: false) + visit project_project_members_path(project) expect(page).not_to have_link 'Groups' @@ -56,6 +81,22 @@ RSpec.describe 'Project > Members > Invite group', :js do expect(members_table).to have_content(group_to_share_with.name) end + + it 'the project can be shared with another group when the feature flag invite_members_group_modal is enabled' do + stub_feature_flags(invite_members_group_modal: true) + + visit project_project_members_path(project) + + expect(page).not_to have_link 'Groups' + + invite_group(group_to_share_with.name) + + visit project_project_members_path(project) + + click_link 'Groups' + + expect(members_table).to have_content(group_to_share_with.name) + end end context 'when the group has "Share with group lock" enabled' do @@ -127,13 +168,7 @@ RSpec.describe 'Project > Members > Invite group', :js do visit project_project_members_path(project) - click_on 'invite-group-tab' - - select2 group.id, from: '#link_group_id' - - fill_in 'expires_at_groups', with: 5.days.from_now.strftime('%Y-%m-%d') - click_on 'invite-group-tab' - find('.btn-confirm').click + invite_group(group.name, role: 'Guest', expires_at: 5.days.from_now) end it 'the group link shows the expiration time with a warning class' do @@ -149,29 +184,23 @@ RSpec.describe 'Project > Members > Invite group', :js do context 'with multiple groups to choose from' do let(:project) { create(:project) } - before do + it 'includes multiple groups' do project.add_maintainer(maintainer) sign_in(maintainer) - create(:group).add_owner(maintainer) - create(:group).add_owner(maintainer) + group1 = create(:group) + group1.add_owner(maintainer) + group2 = create(:group) + group2.add_owner(maintainer) visit project_project_members_path(project) - click_link 'Invite group' + click_on 'Invite a group' + click_on 'Select a group' + wait_for_requests - find('.ajax-groups-select.select2-container') - - execute_script 'GROUP_SELECT_PER_PAGE = 1;' - open_select2 '#link_group_id' - end - - it 'infinitely scrolls' do - expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 1) - - scroll_select2_to_bottom('.select2-drop .select2-results:visible') - - expect(find('.select2-drop .select2-results')).to have_selector('.select2-result', count: 2) + expect(page).to have_button(group1.name) + expect(page).to have_button(group2.name) end end @@ -188,16 +217,19 @@ RSpec.describe 'Project > Members > Invite group', :js do group_to_share_with.add_maintainer(maintainer) end - it 'the groups dropdown does not show ancestors' do + # This behavior should be changed to exclude the ancestor and project + # group from the options once issue is fixed for the modal: + # https://gitlab.com/gitlab-org/gitlab/-/issues/329835 + it 'the groups dropdown does show ancestors and the project group' do visit project_project_members_path(project) - click_on 'invite-group-tab' - click_link 'Search for a group' + click_on 'Invite a group' + click_on 'Select a group' + wait_for_requests - page.within '.select2-drop' do - expect(page).to have_content(group_to_share_with.name) - expect(page).not_to have_content(group.name) - end + expect(page).to have_button(group_to_share_with.name) + expect(page).to have_button(group.name) + expect(page).to have_button(nested_group.name) end end end diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index 384b8ae9929..f1fc579bb8a 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' RSpec.describe 'Project members list', :js do - include Select2Helper include Spec::Support::Helpers::Features::MembersHelpers + include Spec::Support::Helpers::Features::InviteMembersModalHelper let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } @@ -12,8 +12,6 @@ RSpec.describe 'Project members list', :js do let(:project) { create(:project, :internal, namespace: group) } before do - stub_feature_flags(invite_members_group_modal: true) - sign_in(user1) group.add_owner(user1) end @@ -52,7 +50,7 @@ RSpec.describe 'Project members list', :js do it 'add user to project' do visit_members_page - add_user(user2.name, 'Reporter') + invite_member(user2.name, role: 'Reporter') page.within find_member_row(user2) do expect(page).to have_button('Reporter') @@ -100,7 +98,7 @@ RSpec.describe 'Project members list', :js do it 'invite user to project' do visit_members_page - add_user('test@example.com', 'Reporter') + invite_member('test@example.com', role: 'Reporter') click_link 'Invited' @@ -171,25 +169,6 @@ RSpec.describe 'Project members list', :js do private - def add_user(id, role) - click_on 'Invite members' - - page.within '#invite-members-modal' do - fill_in 'Select members or type email addresses', with: id - - wait_for_requests - click_button id - - click_button 'Guest' - wait_for_requests - click_button role - - click_button 'Invite' - end - - page.refresh - end - def visit_members_page visit project_project_members_path(project) end diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index d22097a2f6f..c1b14cf60e7 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -3,12 +3,13 @@ require 'spec_helper' RSpec.describe 'Projects > Members > Maintainer adds member with expiration date', :js do - include Select2Helper include ActiveSupport::Testing::TimeHelpers include Spec::Support::Helpers::Features::MembersHelpers + include Spec::Support::Helpers::Features::InviteMembersModalHelper let_it_be(:maintainer) { create(:user) } let_it_be(:project) { create(:project) } + let(:new_member) { create(:user) } before do @@ -19,18 +20,9 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date end it 'expiration date is displayed in the members list' do - stub_feature_flags(invite_members_group_modal: false) - visit project_project_members_path(project) - page.within '.invite-users-form' do - select2(new_member.id, from: '#user_ids', multiple: true) - - fill_in 'expires_at', with: 5.days.from_now.to_date - find_field('expires_at').native.send_keys :enter - - click_on 'Invite' - end + invite_member(new_member.name, role: 'Guest', expires_at: 5.days.from_now.to_date) page.within find_member_row(new_member) do expect(page).to have_content(/in \d days/) diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb index 93bbabcc3f8..335ae6794b7 100644 --- a/spec/features/projects/merge_request_button_spec.rb +++ b/spec/features/projects/merge_request_button_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Merge Request button' do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public, :repository) } + let(:forked_project) { fork_project(project, user, repository: true) } shared_examples 'Merge request button only shown when allowed' do diff --git a/spec/features/projects/milestones/gfm_autocomplete_spec.rb b/spec/features/projects/milestones/gfm_autocomplete_spec.rb new file mode 100644 index 00000000000..547a5d11dec --- /dev/null +++ b/spec/features/projects/milestones/gfm_autocomplete_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'GFM autocomplete', :js do + let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } + let_it_be(:group) { create(:group, name: 'Ancestor') } + let_it_be(:project) { create(:project, :repository, group: group) } + let_it_be(:issue) { create(:issue, project: project, assignees: [user], title: 'My special issue') } + let_it_be(:label) { create(:label, project: project, title: 'special+') } + let_it_be(:milestone) { create(:milestone, resource_parent: project, title: "project milestone") } + let_it_be(:merge_request) { create(:merge_request, source_project: project) } + + shared_examples 'displays autocomplete menu for all entities' do + it 'autocompletes all available entities' do + fill_in 'Description', with: User.reference_prefix + wait_for_requests + expect(find_autocomplete_menu).to be_visible + expect_autocomplete_entry(user.name) + + fill_in 'Description', with: Label.reference_prefix + wait_for_requests + expect(find_autocomplete_menu).to be_visible + expect_autocomplete_entry(label.title) + + fill_in 'Description', with: Milestone.reference_prefix + wait_for_requests + expect(find_autocomplete_menu).to be_visible + expect_autocomplete_entry(milestone.title) + + fill_in 'Description', with: Issue.reference_prefix + wait_for_requests + expect(find_autocomplete_menu).to be_visible + expect_autocomplete_entry(issue.title) + + fill_in 'Description', with: MergeRequest.reference_prefix + wait_for_requests + expect(find_autocomplete_menu).to be_visible + expect_autocomplete_entry(merge_request.title) + end + end + + before_all do + group.add_maintainer(user) + end + + describe 'new milestone page' do + before do + sign_in(user) + visit new_project_milestone_path(project) + + wait_for_requests + end + + it_behaves_like 'displays autocomplete menu for all entities' + end + + describe 'update milestone page' do + before do + sign_in(user) + visit edit_project_milestone_path(project, milestone) + + wait_for_requests + end + + it_behaves_like 'displays autocomplete menu for all entities' + end + + private + + def find_autocomplete_menu + find('.atwho-view ul', visible: true) + end + + def expect_autocomplete_entry(entry) + page.within('.atwho-container') do + expect(page).to have_content(entry) + end + end +end diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 7dc3ee63669..ee5bf99fd75 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -8,62 +8,168 @@ RSpec.describe 'Project navbar' do include_context 'project navbar structure' - let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } - before do - insert_package_nav(_('Operations')) - insert_infrastructure_registry_nav - stub_config(registry: { enabled: false }) + let(:user) { project.owner } - project.add_maintainer(user) + before do sign_in(user) end - it_behaves_like 'verified navigation bar' do + context 'when sidebar refactor feature flag is disabled' do before do - visit project_path(project) + stub_feature_flags(sidebar_refactor: false) + insert_package_nav(_('Operations')) + insert_infrastructure_registry_nav + + insert_after_sub_nav_item( + _('Boards'), + within: _('Issues'), + new_sub_nav_item_name: _('Labels') + ) + + insert_after_nav_item( + _('Snippets'), + new_nav_item: { + nav_item: _('Members'), + nav_sub_items: [] + } + ) + + stub_config(registry: { enabled: false }) end - end - context 'when value stream is available' do - before do - visit project_path(project) + it_behaves_like 'verified navigation bar' do + before do + visit project_path(project) + end end - it 'redirects to value stream when Analytics item is clicked' do - page.within('.sidebar-top-level-items') do - find('[data-qa-selector=analytics_anchor]').click + context 'when value stream is available' do + before do + visit project_path(project) end - wait_for_requests + it 'redirects to value stream when Analytics item is clicked' do + page.within('.sidebar-top-level-items') do + find('.shortcuts-analytics').click + end + + wait_for_requests - expect(page).to have_current_path(project_cycle_analytics_path(project)) + expect(page).to have_current_path(project_cycle_analytics_path(project)) + end end - end - context 'when pages are available' do - before do - stub_config(pages: { enabled: true }) + context 'when pages are available' do + before do + stub_config(pages: { enabled: true }) - insert_after_sub_nav_item( - _('Operations'), - within: _('Settings'), - new_sub_nav_item_name: _('Pages') - ) + insert_after_sub_nav_item( + _('Operations'), + within: _('Settings'), + new_sub_nav_item_name: _('Pages') + ) - visit project_path(project) + visit project_path(project) + end + + it_behaves_like 'verified navigation bar' end - it_behaves_like 'verified navigation bar' + context 'when container registry is available' do + before do + stub_config(registry: { enabled: true }) + + insert_container_nav + + visit project_path(project) + end + + it_behaves_like 'verified navigation bar' + end end - context 'when container registry is available' do + context 'when sidebar refactor feature flag is enabled' do + let(:monitor_nav_item) do + { + nav_item: _('Monitor'), + nav_sub_items: monitor_menu_items + } + end + + let(:monitor_menu_items) do + [ + _('Metrics'), + _('Logs'), + _('Tracing'), + _('Error Tracking'), + _('Alerts'), + _('Incidents'), + _('Product Analytics') + ] + end + + let(:project_information_nav_item) do + { + nav_item: _('Project information'), + nav_sub_items: [ + _('Activity'), + _('Labels'), + _('Members') + ] + } + end + + let(:settings_menu_items) do + [ + _('General'), + _('Integrations'), + _('Webhooks'), + _('Access Tokens'), + _('Repository'), + _('CI/CD'), + _('Monitor') + ] + end + before do + stub_feature_flags(sidebar_refactor: true) stub_config(registry: { enabled: true }) - + insert_package_nav(_('Monitor')) + insert_infrastructure_registry_nav insert_container_nav + insert_after_sub_nav_item( + _('Monitor'), + within: _('Settings'), + new_sub_nav_item_name: _('Packages & Registries') + ) + + insert_after_nav_item( + _('Monitor'), + new_nav_item: { + nav_item: _('Infrastructure'), + nav_sub_items: [ + _('Kubernetes clusters'), + _('Serverless platform'), + _('Terraform') + ] + } + ) + + insert_after_nav_item( + _('Security & Compliance'), + new_nav_item: { + nav_item: _('Deployments'), + nav_sub_items: [ + _('Feature Flags'), + _('Environments'), + _('Releases') + ] + } + ) + visit project_path(project) end diff --git a/spec/features/projects/new_project_from_template_spec.rb b/spec/features/projects/new_project_from_template_spec.rb new file mode 100644 index 00000000000..1c8647d859a --- /dev/null +++ b/spec/features/projects/new_project_from_template_spec.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'New project from template', :js do + let(:user) { create(:user) } + + before do + sign_in(user) + + visit new_project_path + end + + context 'create from template' do + before do + page.find('a[href="#create_from_template"]').click + wait_for_requests + end + + it 'shows template tabs' do + page.within('#create-from-template-pane') do + expect(page).to have_link('Built-in', href: '#built-in') + end + end + end +end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index 7119039d5ff..a1523f9eb08 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -5,50 +5,48 @@ require 'spec_helper' RSpec.describe 'New project', :js do include Select2Helper - context 'as a user' do - let(:user) { create(:user) } + shared_examples 'combined_menu: feature flag examples' do + context 'as a user' do + let(:user) { create(:user) } - before do - sign_in(user) - end - - context 'new repo experiment', :experiment do - it 'when in control renders "project"' do - stub_experiments(new_repo: :control) + before do + sign_in(user) + end - visit new_project_path + context 'new repo experiment', :experiment do + it 'when in control renders "project"' do + stub_experiments(new_repo: :control) - find('li.header-new.dropdown').click + visit new_project_path - page.within('li.header-new.dropdown') do - expect(page).to have_selector('a', text: 'New project') - expect(page).to have_no_selector('a', text: 'New project/repository') - end + find('li.header-new.dropdown').click - expect(page).to have_selector('.blank-state-title', text: 'Create blank project') - expect(page).to have_no_selector('.blank-state-title', text: 'Create blank project/repository') - end + page.within('li.header-new.dropdown') do + expect(page).to have_selector('a', text: 'New project') + expect(page).to have_no_selector('a', text: 'New project/repository') + end - it 'when in candidate renders "project/repository"' do - stub_experiments(new_repo: :candidate) + expect(page).to have_selector('h3', text: 'Create blank project') + expect(page).to have_no_selector('h3', text: 'Create blank project/repository') + end - visit new_project_path + it 'when in candidate renders "project/repository"' do + stub_experiments(new_repo: :candidate) - find('li.header-new.dropdown').click + visit new_project_path - page.within('li.header-new.dropdown') do - expect(page).to have_selector('a', text: 'New project/repository') - end + find('li.header-new.dropdown').click - expect(page).to have_selector('.blank-state-title', text: 'Create blank project/repository') - end + page.within('li.header-new.dropdown') do + expect(page).to have_selector('a', text: 'New project/repository') + end - context 'with combined_menu feature disabled' do - before do - stub_feature_flags(combined_menu: false) + expect(page).to have_selector('h3', text: 'Create blank project/repository') end it 'when in control it renders "project" in the new projects dropdown' do + pending_on_combined_menu_flag + stub_experiments(new_repo: :control) visit new_project_path @@ -64,6 +62,8 @@ RSpec.describe 'New project', :js do end it 'when in candidate it renders "project/repository" in the new projects dropdown' do + pending_on_combined_menu_flag + stub_experiments(new_repo: :candidate) visit new_project_path @@ -76,337 +76,373 @@ RSpec.describe 'New project', :js do end end end - end - it 'shows a message if multiple levels are restricted' do - Gitlab::CurrentSettings.update!( - restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::INTERNAL] - ) + it 'shows a message if multiple levels are restricted' do + Gitlab::CurrentSettings.update!( + restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE, Gitlab::VisibilityLevel::INTERNAL] + ) - visit new_project_path - find('[data-qa-selector="blank_project_link"]').click - - expect(page).to have_content 'Other visibility settings have been disabled by the administrator.' - end + visit new_project_path + find('[data-qa-selector="blank_project_link"]').click - it 'shows a message if all levels are restricted' do - Gitlab::CurrentSettings.update!( - restricted_visibility_levels: Gitlab::VisibilityLevel.values - ) + expect(page).to have_content 'Other visibility settings have been disabled by the administrator.' + end - visit new_project_path - find('[data-qa-selector="blank_project_link"]').click + it 'shows a message if all levels are restricted' do + Gitlab::CurrentSettings.update!( + restricted_visibility_levels: Gitlab::VisibilityLevel.values + ) - expect(page).to have_content 'Visibility settings have been disabled by the administrator.' - end - end - - context 'as an admin' do - let(:user) { create(:admin) } + visit new_project_path + find('[data-qa-selector="blank_project_link"]').click - before do - sign_in(user) + expect(page).to have_content 'Visibility settings have been disabled by the administrator.' + end end - it 'shows "New project" page', :js do - visit new_project_path - find('[data-qa-selector="blank_project_link"]').click - - expect(page).to have_content('Project name') - expect(page).to have_content('Project URL') - expect(page).to have_content('Project slug') - - click_link('New project') - find('[data-qa-selector="import_project_link"]').click + context 'as an admin' do + let(:user) { create(:admin) } - expect(page).to have_link('GitHub') - expect(page).to have_link('Bitbucket') - expect(page).to have_link('GitLab.com') - expect(page).to have_button('Repo by URL') - expect(page).to have_link('GitLab export') - end - - describe 'manifest import option' do before do + sign_in(user) + end + + it 'shows "New project" page', :js do visit new_project_path + find('[data-qa-selector="blank_project_link"]').click - find('[data-qa-selector="import_project_link"]').click - end + expect(page).to have_content('Project name') + expect(page).to have_content('Project URL') + expect(page).to have_content('Project slug') - it { expect(page).to have_link('Manifest file') } - end + click_link('New project') + find('[data-qa-selector="import_project_link"]').click - context 'Visibility level selector', :js do - Gitlab::VisibilityLevel.options.each do |key, level| - it "sets selector to #{key}" do - stub_application_setting(default_project_visibility: level) + expect(page).to have_link('GitHub') + expect(page).to have_link('Bitbucket') + expect(page).to have_link('GitLab.com') + expect(page).to have_button('Repo by URL') + expect(page).to have_link('GitLab export') + end + describe 'manifest import option' do + before do visit new_project_path - find('[data-qa-selector="blank_project_link"]').click - page.within('#blank-project-pane') do - expect(find_field("project_visibility_level_#{level}")).to be_checked - end - end - it "saves visibility level #{level} on validation error" do - visit new_project_path - find('[data-qa-selector="blank_project_link"]').click + find('[data-qa-selector="import_project_link"]').click + end - choose(key) - click_button('Create project') - page.within('#blank-project-pane') do - expect(find_field("project_visibility_level_#{level}")).to be_checked - end + it 'has Manifest file' do + expect(page).to have_link('Manifest file') end end - context 'when group visibility is private but default is internal' do - let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } + context 'Visibility level selector', :js do + Gitlab::VisibilityLevel.options.each do |key, level| + it "sets selector to #{key}" do + stub_application_setting(default_project_visibility: level) - before do - stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL) - end + visit new_project_path + find('[data-qa-selector="blank_project_link"]').click + page.within('#blank-project-pane') do + expect(find_field("project_visibility_level_#{level}")).to be_checked + end + end - context 'when admin mode is enabled', :enable_admin_mode do - it 'has private selected' do - visit new_project_path(namespace_id: group.id) + it "saves visibility level #{level} on validation error" do + visit new_project_path find('[data-qa-selector="blank_project_link"]').click + choose(key) + click_button('Create project') page.within('#blank-project-pane') do - expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked + expect(find_field("project_visibility_level_#{level}")).to be_checked end end end - context 'when admin mode is disabled' do - it 'is not allowed' do - visit new_project_path(namespace_id: group.id) + context 'when group visibility is private but default is internal' do + let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } - expect(page).to have_content('Not Found') + before do + stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL) end - end - end - context 'when group visibility is public but user requests private' do - let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + context 'when admin mode is enabled', :enable_admin_mode do + it 'has private selected' do + visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click - before do - stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL) - end + page.within('#blank-project-pane') do + expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked + end + end + end - context 'when admin mode is enabled', :enable_admin_mode do - it 'has private selected' do - visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) - find('[data-qa-selector="blank_project_link"]').click + context 'when admin mode is disabled' do + it 'is not allowed' do + visit new_project_path(namespace_id: group.id) - page.within('#blank-project-pane') do - expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked + expect(page).to have_content('Not Found') end end end - context 'when admin mode is disabled' do - it 'is not allowed' do - visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) + context 'when group visibility is public but user requests private' do + let_it_be(:group) { create(:group, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } - expect(page).to have_content('Not Found') + before do + stub_application_setting(default_project_visibility: Gitlab::VisibilityLevel::INTERNAL) end - end - end - end - context 'Readme selector' do - it 'shows the initialize with Readme checkbox on "Blank project" tab' do - visit new_project_path - find('[data-qa-selector="blank_project_link"]').click + context 'when admin mode is enabled', :enable_admin_mode do + it 'has private selected' do + visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) + find('[data-qa-selector="blank_project_link"]').click - expect(page).to have_css('input#project_initialize_with_readme') - expect(page).to have_content('Initialize repository with a README') - end + page.within('#blank-project-pane') do + expect(find_field("project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).to be_checked + end + end + end - it 'does not show the initialize with Readme checkbox on "Create from template" tab' do - visit new_project_path - find('[data-qa-selector="create_from_template_link"]').click - first('.choose-template').click + context 'when admin mode is disabled' do + it 'is not allowed' do + visit new_project_path(namespace_id: group.id, project: { visibility_level: Gitlab::VisibilityLevel::PRIVATE }) - page.within '.project-fields-form' do - expect(page).not_to have_css('input#project_initialize_with_readme') - expect(page).not_to have_content('Initialize repository with a README') + expect(page).to have_content('Not Found') + end + end end end - it 'does not show the initialize with Readme checkbox on "Import project" tab' do - visit new_project_path - find('[data-qa-selector="import_project_link"]').click - first('.js-import-git-toggle-button').click + context 'Readme selector' do + it 'shows the initialize with Readme checkbox on "Blank project" tab' do + visit new_project_path + find('[data-qa-selector="blank_project_link"]').click - page.within '.toggle-import-form' do - expect(page).not_to have_css('input#project_initialize_with_readme') - expect(page).not_to have_content('Initialize repository with a README') + expect(page).to have_css('input#project_initialize_with_readme') + expect(page).to have_content('Initialize repository with a README') end - end - end - context 'Namespace selector' do - context 'with user namespace' do - before do + it 'does not show the initialize with Readme checkbox on "Create from template" tab' do visit new_project_path - find('[data-qa-selector="blank_project_link"]').click + find('[data-qa-selector="create_from_template_link"]').click + first('.choose-template').click + + page.within '.project-fields-form' do + expect(page).not_to have_css('input#project_initialize_with_readme') + expect(page).not_to have_content('Initialize repository with a README') + end end - it 'selects the user namespace' do - page.within('#blank-project-pane') do - expect(page).to have_select('project[namespace_id]', visible: false, selected: user.username) + it 'does not show the initialize with Readme checkbox on "Import project" tab' do + visit new_project_path + find('[data-qa-selector="import_project_link"]').click + first('.js-import-git-toggle-button').click + + page.within '#import-project-pane' do + expect(page).not_to have_css('input#project_initialize_with_readme') + expect(page).not_to have_content('Initialize repository with a README') end end end - context 'with group namespace' do - let(:group) { create(:group, :private) } + context 'Namespace selector' do + context 'with user namespace' do + before do + visit new_project_path + find('[data-qa-selector="blank_project_link"]').click + end - before do - group.add_owner(user) - visit new_project_path(namespace_id: group.id) - find('[data-qa-selector="blank_project_link"]').click + it 'selects the user namespace' do + page.within('#blank-project-pane') do + expect(page).to have_select('project[namespace_id]', visible: false, selected: user.username) + end + end end - it 'selects the group namespace' do - page.within('#blank-project-pane') do - expect(page).to have_select('project[namespace_id]', visible: false, selected: group.name) + context 'with group namespace' do + let(:group) { create(:group, :private) } + + before do + group.add_owner(user) + visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click + end + + it 'selects the group namespace' do + page.within('#blank-project-pane') do + expect(page).to have_select('project[namespace_id]', visible: false, selected: group.name) + end end end - end - context 'with subgroup namespace' do - let(:group) { create(:group) } - let(:subgroup) { create(:group, parent: group) } + context 'with subgroup namespace' do + let(:group) { create(:group) } + let(:subgroup) { create(:group, parent: group) } - before do - group.add_maintainer(user) - visit new_project_path(namespace_id: subgroup.id) - find('[data-qa-selector="blank_project_link"]').click - end + before do + group.add_maintainer(user) + visit new_project_path(namespace_id: subgroup.id) + find('[data-qa-selector="blank_project_link"]').click + end - it 'selects the group namespace' do - page.within('#blank-project-pane') do - expect(page).to have_select('project[namespace_id]', visible: false, selected: subgroup.full_path) + it 'selects the group namespace' do + page.within('#blank-project-pane') do + expect(page).to have_select('project[namespace_id]', visible: false, selected: subgroup.full_path) + end end end - end - context 'when changing namespaces dynamically', :js do - let(:public_group) { create(:group, :public) } - let(:internal_group) { create(:group, :internal) } - let(:private_group) { create(:group, :private) } + context 'when changing namespaces dynamically', :js do + let(:public_group) { create(:group, :public) } + let(:internal_group) { create(:group, :internal) } + let(:private_group) { create(:group, :private) } - before do - public_group.add_owner(user) - internal_group.add_owner(user) - private_group.add_owner(user) - visit new_project_path(namespace_id: public_group.id) - find('[data-qa-selector="blank_project_link"]').click - end + before do + public_group.add_owner(user) + internal_group.add_owner(user) + private_group.add_owner(user) + visit new_project_path(namespace_id: public_group.id) + find('[data-qa-selector="blank_project_link"]').click + end - it 'enables the correct visibility options' do - select2(user.namespace_id, from: '#project_namespace_id') - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled - - select2(public_group.id, from: '#project_namespace_id') - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled - - select2(internal_group.id, from: '#project_namespace_id') - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled - - select2(private_group.id, from: '#project_namespace_id') - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).to be_disabled - expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled + it 'enables the correct visibility options' do + select2(user.namespace_id, from: '#project_namespace_id') + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled + + select2(public_group.id, from: '#project_namespace_id') + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).not_to be_disabled + + select2(internal_group.id, from: '#project_namespace_id') + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled + + select2(private_group.id, from: '#project_namespace_id') + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PRIVATE}")).not_to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::INTERNAL}")).to be_disabled + expect(find("#project_visibility_level_#{Gitlab::VisibilityLevel::PUBLIC}")).to be_disabled + end end end - end - context 'Import project options', :js do - before do - visit new_project_path - find('[data-qa-selector="import_project_link"]').click - end - - context 'from git repository url, "Repo by URL"' do + context 'Import project options', :js do before do - first('.js-import-git-toggle-button').click + visit new_project_path + find('[data-qa-selector="import_project_link"]').click end - it 'does not autocomplete sensitive git repo URL' do - autocomplete = find('#project_import_url')['autocomplete'] + context 'from git repository url, "Repo by URL"' do + before do + first('.js-import-git-toggle-button').click + end - expect(autocomplete).to eq('off') - end + it 'does not autocomplete sensitive git repo URL' do + autocomplete = find('#project_import_url')['autocomplete'] - it 'shows import instructions' do - git_import_instructions = first('.js-toggle-content') + expect(autocomplete).to eq('off') + end - expect(git_import_instructions).to be_visible - expect(git_import_instructions).to have_content 'Git repository URL' - end + it 'shows import instructions' do + git_import_instructions = first('.js-toggle-content') - it 'keeps "Import project" tab open after form validation error' do - collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace) + expect(git_import_instructions).to be_visible + expect(git_import_instructions).to have_content 'Git repository URL' + end - fill_in 'project_import_url', with: collision_project.http_url_to_repo - fill_in 'project_name', with: collision_project.name + it 'reports error if repo URL does not end with .git' do + fill_in 'project_import_url', with: 'http://foo/bar' + fill_in 'project_name', with: 'import-project-without-git-suffix' + fill_in 'project_path', with: 'import-project-without-git-suffix' - click_on 'Create project' + click_button 'Create project' - expect(page).to have_css('#import-project-pane.active') - expect(page).not_to have_css('.toggle-import-form.hide') - end - end + expect(page).to have_text('Please provide a valid URL ending with .git') + end - context 'from GitHub' do - before do - first('.js-import-github').click - end + it 'keeps "Import project" tab open after form validation error' do + collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace) + + fill_in 'project_import_url', with: collision_project.http_url_to_repo + fill_in 'project_name', with: collision_project.name + + click_on 'Create project' - it 'shows import instructions' do - expect(page).to have_content('Authenticate with GitHub') - expect(current_path).to eq new_import_github_path + expect(page).to have_css('#import-project-pane.active') + expect(page).not_to have_css('.toggle-import-form.hide') + end end - end - context 'from manifest file' do - before do - first('.import_manifest').click + context 'from GitHub' do + before do + first('.js-import-github').click + end + + it 'shows import instructions' do + expect(page).to have_content('Authenticate with GitHub') + expect(current_path).to eq new_import_github_path + end end - it 'shows import instructions' do - expect(page).to have_content('Manifest file import') - expect(current_path).to eq new_import_manifest_path + context 'from manifest file' do + before do + first('.import_manifest').click + end + + it 'shows import instructions' do + expect(page).to have_content('Manifest file import') + expect(current_path).to eq new_import_manifest_path + end end end - end - context 'Namespace selector' do - context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do - let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) } + context 'Namespace selector' do + context 'with group with DEVELOPER_MAINTAINER_PROJECT_ACCESS project_creation_level' do + let(:group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) } - before do - group.add_developer(user) - visit new_project_path(namespace_id: group.id) - find('[data-qa-selector="blank_project_link"]').click - end + before do + group.add_developer(user) + visit new_project_path(namespace_id: group.id) + find('[data-qa-selector="blank_project_link"]').click + end - it 'selects the group namespace' do - page.within('#blank-project-pane') do - expect(page).to have_select('project[namespace_id]', visible: false, selected: group.full_path) + it 'selects the group namespace' do + page.within('#blank-project-pane') do + expect(page).to have_select('project[namespace_id]', visible: false, selected: group.full_path) + end end end end end end + + context 'with combined_menu: feature flag on' do + let(:needs_rewrite_for_combined_menu_flag_on) { true } + + before do + stub_feature_flags(combined_menu: true) + end + + it_behaves_like 'combined_menu: feature flag examples' + end + + context 'with combined_menu feature flag off' do + let(:needs_rewrite_for_combined_menu_flag_on) { false } + + before do + stub_feature_flags(combined_menu: false) + end + + it_behaves_like 'combined_menu: feature flag examples' + end + + def pending_on_combined_menu_flag + pending 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56587' if needs_rewrite_for_combined_menu_flag_on + end end diff --git a/spec/features/projects/pages/user_adds_domain_spec.rb b/spec/features/projects/pages/user_adds_domain_spec.rb index 24c9edb79e5..de9effe3dc7 100644 --- a/spec/features/projects/pages/user_adds_domain_spec.rb +++ b/spec/features/projects/pages/user_adds_domain_spec.rb @@ -5,6 +5,7 @@ RSpec.describe 'User adds pages domain', :js do include LetsEncryptHelpers let_it_be(:project) { create(:project, pages_https_only: false) } + let(:user) { create(:user) } before do diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 4a0581bb5cf..70dc0bd04e8 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -739,6 +739,7 @@ RSpec.describe 'Pipeline', :js do context 'when build requires resource', :sidekiq_inline do let_it_be(:project) { create(:project, :repository) } + let(:pipeline) { create(:ci_pipeline, project: project) } let(:resource_group) { create(:ci_resource_group, project: project) } diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index e375bc10dbf..f1672af1019 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -457,22 +457,8 @@ RSpec.describe 'Pipelines', :js do visit_project_pipelines end - it 'has artifacts' do - expect(page).to have_selector('.build-artifacts') - end - - it 'has artifacts download dropdown' do - find('.js-pipeline-dropdown-download').click - - expect(page).to have_link(with_artifacts.file_type) - end - - it 'has download attribute on download links' do - find('.js-pipeline-dropdown-download').click - expect(page).to have_selector('a', text: 'Download') - page.all('.build-artifacts a', text: 'Download').each do |link| - expect(link[:download]).to eq '' - end + it 'has artifacts dropdown' do + expect(page).to have_selector('[data-testid="pipeline-multi-actions-dropdown"]') end end @@ -488,7 +474,7 @@ RSpec.describe 'Pipelines', :js do visit_project_pipelines end - it { expect(page).not_to have_selector('.build-artifacts') } + it { expect(page).not_to have_selector('[data-testid="artifact-item"]') } end context 'without artifacts' do @@ -503,7 +489,7 @@ RSpec.describe 'Pipelines', :js do visit_project_pipelines end - it { expect(page).not_to have_selector('.build-artifacts') } + it { expect(page).not_to have_selector('[data-testid="artifact-item"]') } end context 'with trace artifact' do @@ -514,7 +500,7 @@ RSpec.describe 'Pipelines', :js do end it 'does not show trace artifact as artifacts' do - expect(page).not_to have_selector('.build-artifacts') + expect(page).not_to have_selector('[data-testid="artifact-item"]') end end end @@ -657,26 +643,28 @@ RSpec.describe 'Pipelines', :js do let(:project) { create(:project, :repository) } before do - stub_feature_flags(new_pipeline_form: false) visit new_project_pipeline_path(project) end context 'for valid commit', :js do before do click_button project.default_branch + wait_for_requests - page.within '.dropdown-menu' do - click_link 'master' - end + find('p', text: 'master').click + wait_for_requests end - context 'with gitlab-ci.yml' do + context 'with gitlab-ci.yml', :js do before do stub_ci_pipeline_to_return_yaml_file end it 'creates a new pipeline' do - expect { click_on 'Run pipeline' } + expect do + click_on 'Run pipeline' + wait_for_requests + end .to change { Ci::Pipeline.count }.by(1) expect(Ci::Pipeline.last).to be_web @@ -684,12 +672,15 @@ RSpec.describe 'Pipelines', :js do context 'when variables are specified' do it 'creates a new pipeline with variables' do - page.within '.ci-variable-row-body' do - fill_in "Input variable key", with: "key_name" - fill_in "Input variable value", with: "value" + page.within(find("[data-testid='ci-variable-row']")) do + find("[data-testid='pipeline-form-ci-variable-key']").set('key_name') + find("[data-testid='pipeline-form-ci-variable-value']").set('value') end - expect { click_on 'Run pipeline' } + expect do + click_on 'Run pipeline' + wait_for_requests + end .to change { Ci::Pipeline.count }.by(1) expect(Ci::Pipeline.last.variables.map { |var| var.slice(:key, :secret_value) }) @@ -701,19 +692,17 @@ RSpec.describe 'Pipelines', :js do context 'without gitlab-ci.yml' do before do click_on 'Run pipeline' + wait_for_requests end it { expect(page).to have_content('Missing CI config file') } it 'creates a pipeline after first request failed and a valid gitlab-ci.yml file is available when trying again' do - click_button project.default_branch - stub_ci_pipeline_to_return_yaml_file - page.within '.dropdown-menu' do - click_link 'master' + expect do + click_on 'Run pipeline' + wait_for_requests end - - expect { click_on 'Run pipeline' } .to change { Ci::Pipeline.count }.by(1) end end @@ -760,14 +749,13 @@ RSpec.describe 'Pipelines', :js do let(:project) { create(:project, :repository) } before do - stub_feature_flags(new_pipeline_form: false) visit new_project_pipeline_path(project) end describe 'new pipeline page' do it 'has field to add a new pipeline' do - expect(page).to have_selector('.js-branch-select') - expect(find('.js-branch-select')).to have_content project.default_branch + expect(page).to have_selector('[data-testid="ref-select"]') + expect(find('[data-testid="ref-select"]')).to have_content project.default_branch expect(page).to have_content('Run for') end end @@ -776,10 +764,10 @@ RSpec.describe 'Pipelines', :js do it 'shows filtered pipelines', :js do click_button project.default_branch - page.within '.dropdown-menu' do - find('.dropdown-input-field').native.send_keys('fix') + page.within '[data-testid="ref-select"]' do + find('[data-testid="search-refs"]').native.send_keys('fix') - page.within '.dropdown-content' do + page.within '.gl-new-dropdown-contents' do expect(page).to have_content('fix') end end diff --git a/spec/features/projects/product_analytics/events_spec.rb b/spec/features/projects/product_analytics/events_spec.rb index 12f1c4d291a..05d12e12acb 100644 --- a/spec/features/projects/product_analytics/events_spec.rb +++ b/spec/features/projects/product_analytics/events_spec.rb @@ -5,6 +5,7 @@ require 'spec_helper' RSpec.describe 'Product Analytics > Events' do let_it_be(:project) { create(:project_empty_repo) } let_it_be(:user) { create(:user) } + let(:event) { create(:product_analytics_event, project: project) } before do diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb index aabbc8cea7b..d8a55fc7f3b 100644 --- a/spec/features/projects/releases/user_views_releases_spec.rb +++ b/spec/features/projects/releases/user_views_releases_spec.rb @@ -19,143 +19,129 @@ RSpec.describe 'User views releases', :js do project.add_guest(guest) end - shared_examples 'releases page' do - context('when the user is a maintainer') do - before do - sign_in(maintainer) + context('when the user is a maintainer') do + before do + sign_in(maintainer) + + visit project_releases_path(project) + end - visit project_releases_path(project) + it 'sees the release' do + page.within("##{release_v1.tag}") do + expect(page).to have_content(release_v1.name) + expect(page).to have_content(release_v1.tag) + expect(page).not_to have_content('Upcoming Release') end + end - it 'sees the release' do - page.within("##{release_v1.tag}") do - expect(page).to have_content(release_v1.name) - expect(page).to have_content(release_v1.tag) - expect(page).not_to have_content('Upcoming Release') + context 'when there is a link as an asset' do + let!(:release_link) { create(:release_link, release: release_v1, url: url ) } + let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } + let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" } + + it 'sees the link' do + page.within("##{release_v1.tag} .js-assets-list") do + expect(page).to have_link release_link.name, href: direct_asset_link + expect(page).not_to have_css('[data-testid="external-link-indicator"]') end end - context 'when there is a link as an asset' do - let!(:release_link) { create(:release_link, release: release_v1, url: url ) } + context 'when there is a link redirect' do + let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release_v1) << "/downloads#{release_link.filepath}" } - it 'sees the link' do + it 'sees the link', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329301' do page.within("##{release_v1.tag} .js-assets-list") do expect(page).to have_link release_link.name, href: direct_asset_link expect(page).not_to have_css('[data-testid="external-link-indicator"]') end end + end - context 'when there is a link redirect' do - let!(:release_link) { create(:release_link, release: release_v1, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } - let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - - it 'sees the link' do - page.within("##{release_v1.tag} .js-assets-list") do - expect(page).to have_link release_link.name, href: direct_asset_link - expect(page).not_to have_css('[data-testid="external-link-indicator"]') - end - end - end - - context 'when url points to external resource' do - let(:url) { 'http://google.com/download' } + context 'when url points to external resource' do + let(:url) { 'http://google.com/download' } - it 'sees that the link is external resource' do - page.within("##{release_v1.tag} .js-assets-list") do - expect(page).to have_css('[data-testid="external-link-indicator"]') - end + it 'sees that the link is external resource', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/329302' do + page.within("##{release_v1.tag} .js-assets-list") do + expect(page).to have_css('[data-testid="external-link-indicator"]') end end end + end - context 'with an upcoming release' do - it 'sees the upcoming tag' do - page.within("##{release_v3.tag}") do - expect(page).to have_content('Upcoming Release') - end + context 'with an upcoming release' do + it 'sees the upcoming tag' do + page.within("##{release_v3.tag}") do + expect(page).to have_content('Upcoming Release') end end + end - context 'with a tag containing a slash' do - it 'sees the release' do - page.within("##{release_v2.tag.parameterize}") do - expect(page).to have_content(release_v2.name) - expect(page).to have_content(release_v2.tag) - end + context 'with a tag containing a slash' do + it 'sees the release' do + page.within("##{release_v2.tag.parameterize}") do + expect(page).to have_content(release_v2.name) + expect(page).to have_content(release_v2.tag) end end + end - context 'sorting' do - def sort_page(by:, direction:) - within '[data-testid="releases-sort"]' do - find('.dropdown-toggle').click - - click_button(by, class: 'dropdown-item') - - find('.sorting-direction-button').click if direction == :ascending - end - end - - shared_examples 'releases sort order' do - it "sorts the releases #{description}" do - card_titles = page.all('.release-block .card-title', minimum: expected_releases.count) - - card_titles.each_with_index do |title, index| - expect(title).to have_content(expected_releases[index].name) - end - end - end + context 'sorting' do + def sort_page(by:, direction:) + within '[data-testid="releases-sort"]' do + find('.dropdown-toggle').click - context "when the page is sorted by the default sort order" do - let(:expected_releases) { [release_v3, release_v2, release_v1] } + click_button(by, class: 'dropdown-item') - it_behaves_like 'releases sort order' + find('.sorting-direction-button').click if direction == :ascending end + end - context "when the page is sorted by created_at ascending " do - let(:expected_releases) { [release_v2, release_v1, release_v3] } + shared_examples 'releases sort order' do + it "sorts the releases #{description}" do + card_titles = page.all('.release-block .card-title', minimum: expected_releases.count) - before do - sort_page by: 'Created date', direction: :ascending + card_titles.each_with_index do |title, index| + expect(title).to have_content(expected_releases[index].name) end - - it_behaves_like 'releases sort order' end end - end - context('when the user is a guest') do - before do - sign_in(guest) - end + context "when the page is sorted by the default sort order" do + let(:expected_releases) { [release_v3, release_v2, release_v1] } - it 'renders release info except for Git-related data' do - visit project_releases_path(project) + it_behaves_like 'releases sort order' + end - within('.release-block', match: :first) do - expect(page).to have_content(release_v3.description) + context "when the page is sorted by created_at ascending " do + let(:expected_releases) { [release_v2, release_v1, release_v3] } - # The following properties (sometimes) include Git info, - # so they are not rendered for Guest users - expect(page).not_to have_content(release_v3.name) - expect(page).not_to have_content(release_v3.tag) - expect(page).not_to have_content(release_v3.commit.short_id) + before do + sort_page by: 'Created date', direction: :ascending end + + it_behaves_like 'releases sort order' end end end - context 'when the graphql_releases_page feature flag is enabled' do - it_behaves_like 'releases page' - end - - context 'when the graphql_releases_page feature flag is disabled' do + context('when the user is a guest') do before do - stub_feature_flags(graphql_releases_page: false) + sign_in(guest) end - it_behaves_like 'releases page' + it 'renders release info except for Git-related data' do + visit project_releases_path(project) + + within('.release-block', match: :first) do + expect(page).to have_content(release_v3.description) + + # The following properties (sometimes) include Git info, + # so they are not rendered for Guest users + expect(page).not_to have_content(release_v3.name) + expect(page).not_to have_content(release_v3.tag) + expect(page).not_to have_content(release_v3.commit.short_id) + end + end end end diff --git a/spec/features/projects/services/user_activates_issue_tracker_spec.rb b/spec/features/projects/services/user_activates_issue_tracker_spec.rb index 1aec8883395..019d50a497b 100644 --- a/spec/features/projects/services/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/services/user_activates_issue_tracker_spec.rb @@ -87,6 +87,6 @@ RSpec.describe 'User activates issue tracker', :js do it_behaves_like 'external issue tracker activation', tracker: 'Redmine' it_behaves_like 'external issue tracker activation', tracker: 'YouTrack', skip_new_issue_url: true it_behaves_like 'external issue tracker activation', tracker: 'Bugzilla' - it_behaves_like 'external issue tracker activation', tracker: 'Custom Issue Tracker' + it_behaves_like 'external issue tracker activation', tracker: 'Custom issue tracker' it_behaves_like 'external issue tracker activation', tracker: 'EWM', skip_test: true end diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb index 8083c851bb7..76d5d7308d1 100644 --- a/spec/features/projects/settings/access_tokens_spec.rb +++ b/spec/features/projects/settings/access_tokens_spec.rb @@ -99,7 +99,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do visit project_settings_access_tokens_path(personal_project) expect(page).to have_selector('#new_project_access_token') - expect(page).to have_text('You can generate an access token scoped to this project for each application to use the GitLab API.') + expect(page).to have_text('Generate project access tokens scoped to this project for your applications that need access to the GitLab API.') end end diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb index ca976997142..64138e0aeca 100644 --- a/spec/features/projects/settings/operations_settings_spec.rb +++ b/spec/features/projects/settings/monitor_settings_spec.rb @@ -3,25 +3,35 @@ require 'spec_helper' RSpec.describe 'Projects > Settings > For a forked project', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :repository, create_templates: :issue) } - let(:role) { :maintainer } + let_it_be(:project) { create(:project, :repository, create_templates: :issue) } + + let(:user) { project.owner} before do sign_in(user) - project.add_role(user, role) end - describe 'Sidebar > Operations' do - it 'renders the settings link in the sidebar' do + describe 'Sidebar > Monitor' do + it 'renders the menu in the sidebar' do visit project_path(project) wait_for_requests - expect(page).to have_selector('a[title="Operations"]', visible: false) + expect(page).to have_selector('.sidebar-sub-level-items a[aria-label="Monitor"]', text: 'Monitor', visible: false) + end + + context 'when feature flag sidebar_refactor is disabled' do + it 'renders the menu "Operations" in the sidebar' do + stub_feature_flags(sidebar_refactor: false) + + visit project_path(project) + wait_for_requests + + expect(page).to have_selector('.sidebar-sub-level-items a[aria-label="Operations"]', text: 'Operations', visible: false) + end end end - describe 'Settings > Operations' do + describe 'Settings > Monitor' do describe 'Incidents' do let(:create_issue) { 'Create an incident. Incidents are created for each alert triggered.' } let(:send_email) { 'Send a single email notification to Owners and Maintainers for new alerts.' } diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb index 0b40cbee582..62f31fd027b 100644 --- a/spec/features/projects/settings/packages_settings_spec.rb +++ b/spec/features/projects/settings/packages_settings_spec.rb @@ -3,36 +3,32 @@ require 'spec_helper' RSpec.describe 'Projects > Settings > Packages', :js do - let(:project) { create(:project) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + let(:user) { project.owner } before do sign_in(user) - project.add_maintainer(user) + + stub_config(packages: { enabled: packages_enabled }) + + visit edit_project_path(project) end context 'Packages enabled in config' do - before do - allow(Gitlab.config.packages).to receive(:enabled).and_return(true) - end + let(:packages_enabled) { true } it 'displays the packages toggle button' do - visit edit_project_path(project) - - expect(page).to have_content('Packages') + expect(page).to have_button('Packages', class: 'gl-toggle') expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true) end end context 'Packages disabled in config' do - before do - allow(Gitlab.config.packages).to receive(:enabled).and_return(false) - end + let(:packages_enabled) { false } it 'does not show up in UI' do - visit edit_project_path(project) - - expect(page).not_to have_content('Packages') + expect(page).not_to have_button('Packages', class: 'gl-toggle') end end end diff --git a/spec/features/projects/settings/project_settings_spec.rb b/spec/features/projects/settings/project_settings_spec.rb index cd1c9ecde9c..71b319d192c 100644 --- a/spec/features/projects/settings/project_settings_spec.rb +++ b/spec/features/projects/settings/project_settings_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Projects settings' do let_it_be(:project) { create(:project) } + let(:user) { project.owner } let(:panel) { find('.general-settings', match: :first) } let(:button) { panel.find('.btn.gl-button.js-settings-toggle') } diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index bc60cdd2f8e..6a2769d11fd 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -11,105 +11,125 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p let(:container_registry_enabled) { true } let(:container_registry_enabled_on_project) { true } - subject { visit project_settings_ci_cd_path(project) } + shared_examples 'an expiration policy form' do + before do + project.update!(container_registry_enabled: container_registry_enabled_on_project) + project.container_expiration_policy.update!(enabled: true) - before do - project.update!(container_registry_enabled: container_registry_enabled_on_project) - project.container_expiration_policy.update!(enabled: true) + sign_in(user) + stub_container_registry_config(enabled: container_registry_enabled) + end - sign_in(user) - stub_container_registry_config(enabled: container_registry_enabled) - end + context 'as owner' do + it 'shows available section' do + subject - context 'as owner' do - it 'shows available section' do - subject + settings_block = find('#js-registry-policies') + expect(settings_block).to have_text 'Clean up image tags' + end - settings_block = find('#js-registry-policies') - expect(settings_block).to have_text 'Clean up image tags' - end + it 'saves cleanup policy submit the form' do + subject - it 'saves cleanup policy submit the form' do - subject + within '#js-registry-policies' do + select('Every day', from: 'Run cleanup') + select('50 tags per image name', from: 'Keep the most recent:') + fill_in('Keep tags matching:', with: 'stable') + select('7 days', from: 'Remove tags older than:') + fill_in('Remove tags matching:', with: '.*-production') + + submit_button = find('[data-testid="save-button"') + expect(submit_button).not_to be_disabled + submit_button.click + end - within '#js-registry-policies' do - select('Every day', from: 'Run cleanup') - select('50 tags per image name', from: 'Keep the most recent:') - fill_in('Keep tags matching:', with: 'stable') - select('7 days', from: 'Remove tags older than:') - fill_in('Remove tags matching:', with: '.*-production') + expect(find('.gl-toast')).to have_content('Cleanup policy successfully saved.') + end - submit_button = find('[data-testid="save-button"') - expect(submit_button).not_to be_disabled - submit_button.click + it 'does not save cleanup policy submit form with invalid regex' do + subject + + within '#js-registry-policies' do + fill_in('Remove tags matching:', with: '*-production') + + submit_button = find('[data-testid="save-button"') + expect(submit_button).not_to be_disabled + submit_button.click + end + + expect(find('.gl-toast')).to have_content('Something went wrong while updating the cleanup policy.') end - toast = find('.gl-toast') - expect(toast).to have_content('Cleanup policy successfully saved.') end - it 'does not save cleanup policy submit form with invalid regex' do - subject + context 'with a project without expiration policy' do + where(:application_setting, :feature_flag, :result) do + true | true | :available_section + true | false | :available_section + false | true | :available_section + false | false | :disabled_message + end - within '#js-registry-policies' do - fill_in('Remove tags matching:', with: '*-production') + with_them do + before do + project.container_expiration_policy.destroy! + stub_feature_flags(container_expiration_policies_historic_entry: false) + stub_application_setting(container_expiration_policies_enable_historic_entries: application_setting) + stub_feature_flags(container_expiration_policies_historic_entry: project) if feature_flag + end - submit_button = find('[data-testid="save-button"') - expect(submit_button).not_to be_disabled - submit_button.click + it 'displays the expected result' do + subject + + within '#js-registry-policies' do + case result + when :available_section + expect(find('[data-testid="enable-toggle"]')).to have_content('Disabled - Tags will not be automatically deleted.') + when :disabled_message + expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') + end + end + end end - toast = find('.gl-toast') - expect(toast).to have_content('Something went wrong while updating the cleanup policy.') end - end - context 'with a project without expiration policy' do - where(:application_setting, :feature_flag, :result) do - true | true | :available_section - true | false | :available_section - false | true | :available_section - false | false | :disabled_message - end + context 'when registry is disabled' do + let(:container_registry_enabled) { false } + + it 'does not exists' do + subject - with_them do - before do - project.container_expiration_policy.destroy! - stub_feature_flags(container_expiration_policies_historic_entry: false) - stub_application_setting(container_expiration_policies_enable_historic_entries: application_setting) - stub_feature_flags(container_expiration_policies_historic_entry: project) if feature_flag + expect(page).not_to have_selector('#js-registry-policies') end + end - it 'displays the expected result' do + context 'when container registry is disabled on project' do + let(:container_registry_enabled_on_project) { false } + + it 'does not exists' do subject - within '#js-registry-policies' do - case result - when :available_section - expect(find('[data-testid="enable-toggle"]')).to have_content('Disabled - Tags will not be automatically deleted.') - when :disabled_message - expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') - end - end + expect(page).not_to have_selector('#js-registry-policies') end end end - context 'when registry is disabled' do - let(:container_registry_enabled) { false } + context 'with sidebar feature flag off' do + subject { visit project_settings_ci_cd_path(project) } - it 'does not exists' do - subject - - expect(page).not_to have_selector('#js-registry-policies') + before do + stub_feature_flags(sidebar_refactor: false) end - end - context 'when container registry is disabled on project' do - let(:container_registry_enabled_on_project) { false } + it_behaves_like 'an expiration policy form' + end - it 'does not exists' do - subject + context 'with sidebar feature flag on' do + subject { visit project_settings_packages_and_registries_path(project) } - expect(page).not_to have_selector('#js-registry-policies') + before do + stub_feature_flags(sidebar_refactor: true) end + + it_behaves_like 'an expiration policy form' end end diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 2f257d299d8..f420a8a76b9 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -42,6 +42,7 @@ RSpec.describe 'Projects > Settings > Repository settings' do context 'Deploy Keys', :js do let_it_be(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) } let_it_be(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) } + let(:new_ssh_key) { attributes_for(:key)[:key] } it 'get list of keys' do @@ -116,7 +117,8 @@ RSpec.describe 'Projects > Settings > Repository settings' do project.deploy_keys << private_deploy_key visit project_settings_repository_path(project) - accept_confirm { find('.deploy-key', text: private_deploy_key.title).find('[data-testid="remove-icon"]').click } + click_button 'Remove' + click_button 'Remove deploy key' expect(page).not_to have_content(private_deploy_key.title) end diff --git a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb index ebda5c9ff59..bf90e86c263 100644 --- a/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb @@ -163,7 +163,8 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do click_on('Save changes') end - find('.flash-notice') + wait_for_requests + radio = find_field('project_project_setting_attributes_squash_option_default_on') expect(radio).to be_checked @@ -178,7 +179,8 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do click_on('Save changes') end - find('.flash-notice') + wait_for_requests + radio = find_field('project_project_setting_attributes_squash_option_always') expect(radio).to be_checked @@ -193,7 +195,8 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do click_on('Save changes') end - find('.flash-notice') + wait_for_requests + radio = find_field('project_project_setting_attributes_squash_option_never') expect(radio).to be_checked @@ -220,7 +223,8 @@ RSpec.describe 'Projects > Settings > User manages merge request settings' do click_on('Save changes') end - find('.flash-notice') + wait_for_requests + radio = find_field('project_project_setting_attributes_mr_default_target_self_true') expect(radio).to be_checked diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb index b237e7e8ce7..be4b6d6b82d 100644 --- a/spec/features/projects/settings/user_manages_project_members_spec.rb +++ b/spec/features/projects/settings/user_manages_project_members_spec.rb @@ -38,16 +38,12 @@ RSpec.describe 'Projects > Settings > User manages project members' do end it 'imports a team from another project', :js do - stub_feature_flags(invite_members_group_modal: false) - project2.add_maintainer(user) project2.add_reporter(user_mike) visit(project_project_members_path(project)) - page.within('.invite-users-form') do - click_link('Import') - end + click_link('Import a project') select2(project2.id, from: '#source_project_id') click_button('Import project members') @@ -55,6 +51,28 @@ RSpec.describe 'Projects > Settings > User manages project members' do expect(find_member_row(user_mike)).to have_content('Reporter') end + describe 'when the :invite_members_group_modal is disabled' do + before do + stub_feature_flags(invite_members_group_modal: false) + end + + it 'imports a team from another project', :js do + project2.add_maintainer(user) + project2.add_reporter(user_mike) + + visit(project_project_members_path(project)) + + page.within('.invite-users-form') do + click_link('Import') + end + + select2(project2.id, from: '#source_project_id') + click_button('Import project members') + + expect(find_member_row(user_mike)).to have_content('Reporter') + end + end + it 'shows all members of project shared group', :js do group.add_owner(user) group.add_developer(user_dmitriy) diff --git a/spec/features/projects/snippets/user_views_snippets_spec.rb b/spec/features/projects/snippets/user_views_snippets_spec.rb index bc8cba1dc31..40539b43ed5 100644 --- a/spec/features/projects/snippets/user_views_snippets_spec.rb +++ b/spec/features/projects/snippets/user_views_snippets_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Projects > Snippets > User views snippets' do let_it_be(:project) { create(:project) } + let(:user) { create(:user) } def visit_project_snippets diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb index 6935ad4be02..39b8cddd005 100644 --- a/spec/features/projects/user_changes_project_visibility_spec.rb +++ b/spec/features/projects/user_changes_project_visibility_spec.rb @@ -28,7 +28,9 @@ RSpec.describe 'User changes public project visibility', :js do click_button 'Reduce project visibility' end - expect(page).to have_text("Project '#{project.name}' was successfully updated") + wait_for_requests + + expect(project.reload).to be_private end end diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb index ff6217d02a7..e2498928fa0 100644 --- a/spec/features/projects/user_sees_sidebar_spec.rb +++ b/spec/features/projects/user_sees_sidebar_spec.rb @@ -198,7 +198,7 @@ RSpec.describe 'Projects > User sees sidebar' do expect(page).to have_content 'Project' expect(page).to have_content 'Issues' expect(page).to have_content 'Wiki' - expect(page).to have_content 'Operations' + expect(page).to have_content 'Monitor' expect(page).not_to have_content 'Repository' expect(page).not_to have_content 'CI/CD' diff --git a/spec/features/projects/user_sees_user_popover_spec.rb b/spec/features/projects/user_sees_user_popover_spec.rb index e357824a533..db451578ff8 100644 --- a/spec/features/projects/user_sees_user_popover_spec.rb +++ b/spec/features/projects/user_sees_user_popover_spec.rb @@ -6,6 +6,7 @@ RSpec.describe 'User sees user popover', :js do include Spec::Support::Helpers::Features::NotesHelpers let_it_be(:project) { create(:project, :repository) } + let(:user) { project.creator } let(:merge_request) do create(:merge_request, source_project: project, target_project: project) diff --git a/spec/features/projects/user_uses_shortcuts_spec.rb b/spec/features/projects/user_uses_shortcuts_spec.rb index b6fde19e0d4..1350ecf6e75 100644 --- a/spec/features/projects/user_uses_shortcuts_spec.rb +++ b/spec/features/projects/user_uses_shortcuts_spec.rb @@ -68,14 +68,27 @@ RSpec.describe 'User uses shortcuts', :js do end context 'when navigating to the Project pages' do - it 'redirects to the details page' do + it 'redirects to the project page' do visit project_issues_path(project) find('body').native.send_key('g') find('body').native.send_key('p') expect(page).to have_active_navigation('Project') - expect(page).to have_active_sub_navigation('Details') + end + + context 'when feature flag :sidebar_refactor is disabled' do + it 'redirects to the details page' do + stub_feature_flags(sidebar_refactor: false) + + visit project_issues_path(project) + + find('body').native.send_key('g') + find('body').native.send_key('p') + + expect(page).to have_active_navigation('Project') + expect(page).to have_active_sub_navigation('Details') + end end it 'redirects to the activity page' do @@ -165,28 +178,62 @@ RSpec.describe 'User uses shortcuts', :js do end end - context 'when navigating to the Operations pages' do + context 'when navigating to the Deployments page' do + it 'redirects to the Environments page' do + find('body').native.send_key('g') + find('body').native.send_key('e') + + expect(page).to have_active_navigation('Deployments') + expect(page).to have_active_sub_navigation('Environments') + end + end + + context 'when navigating to the Monitor pages' do it 'redirects to the Metrics page' do find('body').native.send_key('g') find('body').native.send_key('l') - expect(page).to have_active_navigation('Operations') + expect(page).to have_active_navigation('Monitor') expect(page).to have_active_sub_navigation('Metrics') end - it 'redirects to the Environments page' do - find('body').native.send_key('g') - find('body').native.send_key('e') + context 'when feature flag :sidebar_refactor is disabled' do + before do + stub_feature_flags(sidebar_refactor: false) + end - expect(page).to have_active_navigation('Operations') - expect(page).to have_active_sub_navigation('Environments') + it 'redirects to the Operations page' do + find('body').native.send_key('g') + find('body').native.send_key('l') + + expect(page).to have_active_navigation('Operations') + expect(page).to have_active_sub_navigation('Metrics') + end + + it 'redirects to the Kubernetes page with active Operations' do + find('body').native.send_key('g') + find('body').native.send_key('k') + + expect(page).to have_active_navigation('Operations') + expect(page).to have_active_sub_navigation('Kubernetes') + end + + it 'redirects to the Environments page' do + find('body').native.send_key('g') + find('body').native.send_key('e') + + expect(page).to have_active_navigation('Operations') + expect(page).to have_active_sub_navigation('Environments') + end end + end + context 'when navigating to the Infrastructure pages' do it 'redirects to the Kubernetes page' do find('body').native.send_key('g') find('body').native.send_key('k') - expect(page).to have_active_navigation('Operations') + expect(page).to have_active_navigation('Infrastructure') expect(page).to have_active_sub_navigation('Kubernetes') end end |