diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-08-20 18:42:06 +0000 |
commit | 6e4e1050d9dba2b7b2523fdd1768823ab85feef4 (patch) | |
tree | 78be5963ec075d80116a932011d695dd33910b4e /spec/features | |
parent | 1ce776de4ae122aba3f349c02c17cebeaa8ecf07 (diff) | |
download | gitlab-ce-6e4e1050d9dba2b7b2523fdd1768823ab85feef4.tar.gz |
Add latest changes from gitlab-org/gitlab@13-3-stable-ee
Diffstat (limited to 'spec/features')
128 files changed, 1570 insertions, 966 deletions
diff --git a/spec/features/admin/admin_mode/login_spec.rb b/spec/features/admin/admin_mode/login_spec.rb index 4b26ceb55e2..12046518aac 100644 --- a/spec/features/admin/admin_mode/login_spec.rb +++ b/spec/features/admin/admin_mode/login_spec.rb @@ -196,6 +196,7 @@ RSpec.describe 'Admin Mode Login', :clean_gitlab_redis_shared_state, :do_not_moc 'base' => 'dc=example,dc=com' } end + let(:user) { create(:omniauth_user, :admin, :two_factor, extern_uid: uid, provider: provider) } before do diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index cbaa18509ba..522da760062 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -126,7 +126,7 @@ RSpec.describe "Admin::Projects" do expect(page).to have_content('Developer') end - find(:css, '.content-list li', text: current_user.name).find(:css, 'a.btn-remove').click + find(:css, '.content-list li', text: current_user.name).find(:css, 'a.btn-danger').click expect(page).not_to have_selector(:css, '.content-list') end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 55f6a9930ff..f5b05c76e90 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -209,8 +209,7 @@ RSpec.describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_n context 'Integrations page' do before do - stub_feature_flags(instance_level_integrations: false) - visit integrations_admin_application_settings_path + visit general_admin_application_settings_path end it 'Enable hiding third party offers' do diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb index c79b812df46..ab874408e55 100644 --- a/spec/features/atom/users_spec.rb +++ b/spec/features/atom/users_spec.rb @@ -30,6 +30,7 @@ RSpec.describe "User Feed" do author: user, description: "Houston, we have a bug!\n\n***\n\nI guess.") end + let(:note) do create(:note, noteable: issue, @@ -37,6 +38,7 @@ RSpec.describe "User Feed" do note: 'Bug confirmed :+1:', project: project) end + let(:merge_request) do create(:merge_request, title: 'Fix bug', @@ -45,6 +47,7 @@ RSpec.describe "User Feed" do target_project: project, description: "Here is the fix: ![an image](image.png)") end + let(:push_event) { create(:push_event, project: project, author: user) } let!(:push_event_payload) { create(:push_event_payload, event: push_event) } diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index 03a76d9d3fd..87d29eed68d 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -21,7 +21,7 @@ RSpec.describe 'Issue Boards', :js do end context 'un-ordered issues' do - let!(:issue4) { create(:labeled_issue, project: project, labels: [label]) } + let!(:issue4) { create(:labeled_issue, project: project, labels: [label], relative_position: nil) } before do visit project_board_path(project, board) diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index 5b78d93ae04..346f305f0d0 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -36,7 +36,7 @@ RSpec.describe 'Contributions Calendar', :js do def get_cell_date_selector(contributions, date) contribution_text = - if contributions.zero? + if contributions == 0 'No contributions' else "#{contributions} #{'contribution'.pluralize(contributions)}" diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb index 6058c35c2cf..4f7f62d00a5 100644 --- a/spec/features/clusters/cluster_detail_page_spec.rb +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -20,7 +20,7 @@ RSpec.describe 'Clusterable > Show page' do expect(page).to have_content(cluster_type_label) end - it 'allow the user to set domain' do + it 'allow the user to set domain', :js do visit cluster_path within '.js-cluster-integration-form' do @@ -28,20 +28,19 @@ RSpec.describe 'Clusterable > Show page' do click_on 'Save changes' end - expect(page.status_code).to eq(200) expect(page).to have_content('Kubernetes cluster was successfully updated.') end - context 'when there is a cluster with ingress and external ip' do + context 'when there is a cluster with ingress and external ip', :js do before do cluster.create_application_ingress!(external_ip: '192.168.1.100') visit cluster_path end - it 'shows help text with the domain as an alternative to custom domain' do + it 'shows help text with the domain as an alternative to custom domain', :js do within '.js-cluster-integration-form' do - expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector) + expect(find(cluster_ingress_help_text_selector).text).to include('192.168.1.100') end end end @@ -51,7 +50,7 @@ RSpec.describe 'Clusterable > Show page' do visit cluster_path within '.js-cluster-integration-form' do - expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector) + expect(page).not_to have_selector(cluster_ingress_help_text_selector) end end end diff --git a/spec/features/clusters/installing_applications_shared_examples.rb b/spec/features/clusters/installing_applications_shared_examples.rb index 74150c42519..c422aa2be72 100644 --- a/spec/features/clusters/installing_applications_shared_examples.rb +++ b/spec/features/clusters/installing_applications_shared_examples.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true -RSpec.shared_examples "installing applications for a cluster" do |managed_apps_local_tiller| +RSpec.shared_examples "installing applications for a cluster" do before do # Reduce interval from 10 seconds which is too long for an automated test stub_const("#{Clusters::ClustersController}::STATUS_POLLING_INTERVAL", 500) - stub_feature_flags(managed_apps_local_tiller: managed_apps_local_tiller) - visit cluster_path end @@ -31,12 +29,7 @@ RSpec.shared_examples "installing applications for a cluster" do |managed_apps_l it 'user can install applications' do wait_for_requests - application_row = - if managed_apps_local_tiller - '.js-cluster-application-row-ingress' - else - '.js-cluster-application-row-helm' - end + application_row = '.js-cluster-application-row-ingress' page.within(application_row) do expect(page).not_to have_css('.js-cluster-application-install-button[disabled]') @@ -44,50 +37,11 @@ RSpec.shared_examples "installing applications for a cluster" do |managed_apps_l end end - if managed_apps_local_tiller - it 'does not show the Helm application' do - expect(page).not_to have_selector(:css, '.js-cluster-application-row-helm') - end - else - context 'when user installs Helm' do - before do - allow(ClusterInstallAppWorker).to receive(:perform_async) - wait_for_requests - - page.within('.js-cluster-application-row-helm') do - page.find(:css, '.js-cluster-application-install-button').click - end - - wait_for_requests - end - - it 'shows the status transition' do - page.within('.js-cluster-application-row-helm') do - # FE sends request and gets the response, then the buttons is "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - Clusters::Cluster.last.application_helm.make_installing! - - # FE starts polling and update the buttons to "Installing" - expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing') - - Clusters::Cluster.last.application_helm.make_installed! - - expect(page).not_to have_css('button', exact_text: 'Install', visible: :all) - expect(page).not_to have_css('button', exact_text: 'Installing', visible: :all) - expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall') - end - - expect(page).to have_content('Helm Tiller was successfully installed on your Kubernetes cluster') - end - end + it 'does not show the Helm application' do + expect(page).not_to have_selector(:css, '.js-cluster-application-row-helm') end context 'when user installs Knative' do - before do - create(:clusters_applications_helm, :installed, cluster: cluster) unless managed_apps_local_tiller - end - context 'on an abac cluster' do let(:cluster) { create(:cluster, :provided_by_gcp, :rbac_disabled, *cluster_factory_args) } @@ -166,8 +120,6 @@ RSpec.shared_examples "installing applications for a cluster" do |managed_apps_l allow(ClusterInstallAppWorker).to receive(:perform_async) allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - - create(:clusters_applications_helm, :installed, cluster: cluster) unless managed_apps_local_tiller end it 'shows status transition' do @@ -223,8 +175,6 @@ RSpec.shared_examples "installing applications for a cluster" do |managed_apps_l before do allow(ClusterInstallAppWorker).to receive(:perform_async) - create(:clusters_applications_helm, :installed, cluster: cluster) unless managed_apps_local_tiller - page.within('.js-cluster-application-row-elastic_stack') do click_button 'Install' end @@ -255,8 +205,6 @@ RSpec.shared_examples "installing applications for a cluster" do |managed_apps_l allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_in) allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async) - create(:clusters_applications_helm, :installed, cluster: cluster) unless managed_apps_local_tiller - page.within('.js-cluster-application-row-ingress') do expect(page).to have_css('.js-cluster-application-install-button:not([disabled])') page.find(:css, '.js-cluster-application-install-button').click diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 60c37d1e125..e66a40720da 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -112,7 +112,7 @@ RSpec.describe 'Commits' do describe 'Cancel build' do it 'cancels build', :js, :sidekiq_might_not_need_inline do visit pipeline_path(pipeline) - find('.js-btn-cancel-pipeline').click + find('[data-testid="cancelPipeline"]').click expect(page).to have_content 'canceled' end end diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb index 6e9749f29c3..201dc24b359 100644 --- a/spec/features/explore/groups_spec.rb +++ b/spec/features/explore/groups_spec.rb @@ -26,10 +26,6 @@ RSpec.describe 'Explore Groups', :js do end end - before do - stub_feature_flags(vue_issuables_list: false) - end - shared_examples 'renders public and internal projects' do it do visit_page diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index c878ee7329f..0ca626381d4 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -36,7 +36,7 @@ RSpec.describe 'Global search' do end end - it 'closes the dropdown on blur', :js do + it 'closes the dropdown on blur', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/201841' do fill_in 'search', with: "a" dropdown = find('.js-dashboard-search-options') diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index aaa59108b95..4488f53a03f 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -7,8 +7,6 @@ RSpec.describe 'Group empty states' do let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user } before do - stub_feature_flags(vue_issuables_list: false) - sign_in(user) end @@ -34,42 +32,52 @@ RSpec.describe 'Group empty states' do expect(page).not_to have_selector('.empty-state') end - it "displays link to create new #{issuable} when no open #{issuable} is found" do + it "displays link to create new #{issuable} when no open #{issuable} is found", :js do create("closed_#{issuable}", project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project) + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/There are no open #{issuable.to_s.humanize.downcase}/) - expect(page).to have_selector("#new_#{issuable}_body_link") + new_issuable_path = issuable == :issue ? 'new_project_issue_path' : 'project_new_merge_request_path' + + path = public_send(new_issuable_path, project) + + expect(page.find('a')['href']).to have_content(path) end end - it 'displays link to create new issue when the current search gave no results' do + it 'displays link to create new issue when the current search gave no results', :js do create(issuable, project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project, author_username: 'foo', scope: 'all', state: 'opened') + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/Sorry, your filter produced no results/) new_issuable_path = issuable == :issue ? 'new_project_issue_path' : 'project_new_merge_request_path' path = public_send(new_issuable_path, project) - expect(page).to have_selector("#new_#{issuable}_body_link[href='#{path}']") + expect(page.find('a')['href']).to have_content(path) end end - it "displays conditional text when no closed #{issuable} is found" do + it "displays conditional text when no closed #{issuable} is found", :js do create(issuable, project_relation => project) issuable_link_fn = "project_#{issuable}s_path" visit public_send(issuable_link_fn, project, state: 'closed') + wait_for_all_requests + page.within(find('.empty-state')) do expect(page).to have_content(/There are no closed #{issuable.to_s.humanize.downcase}/) end diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 8972be45acb..60cd1ebbbd7 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -158,7 +158,7 @@ RSpec.describe 'Edit group settings' do page.within('.gs-advanced') do fill_in 'group_path', with: new_group_path - click_button 'Change group path' + click_button 'Change group URL' end end diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index c76e0c311a6..8ecd2beba68 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -11,11 +11,7 @@ RSpec.describe 'Group issues page' do let(:project_with_issues_disabled) { create(:project, :issues_disabled, group: group) } let(:path) { issues_group_path(group) } - before do - stub_feature_flags(vue_issuables_list: false) - end - - context 'with shared examples' do + context 'with shared examples', :js do let(:issuable) { create(:issue, project: project, title: "this is my created issuable")} include_examples 'project features apply to issuables', Issue @@ -30,19 +26,33 @@ RSpec.describe 'Group issues page' do user_in_group end - it_behaves_like "it has an RSS button with current_user's feed token" it_behaves_like "an autodiscoverable RSS feed with current_user's feed token" + + # Note: The one from rss_shared_example.rb uses a css pseudo-class `:has` + # which is VERY experimental and only supported in Nokogiri used by Capybara + # However,`:js` option forces Capybara to use Selenium that doesn't support`:has` + context "it has an RSS button with current_user's feed token" do + it "shows the RSS button with current_user's feed token" do + expect(find('[data-testid="rss-feed-link"]')['href']).to have_content(user.feed_token) + end + end end context 'when signed out' do let(:user) { nil } - it_behaves_like "it has an RSS button without a feed token" it_behaves_like "an autodiscoverable RSS feed without a feed token" + + # Note: please see the above + context "it has an RSS button without a feed token" do + it "shows the RSS button without a feed token" do + expect(find('[data-testid="rss-feed-link"]')['href']).not_to have_content('feed_token') + end + end end end - context 'assignee', :js do + context 'assignee' do let(:access_level) { ProjectFeature::ENABLED } let(:user) { user_in_group } let(:user2) { user_outside_group } @@ -56,7 +66,7 @@ RSpec.describe 'Group issues page' do end end - context 'issues list' do + context 'issues list', :js do let(:subgroup) { create(:group, parent: group) } let(:subgroup_project) { create(:project, :public, group: subgroup)} let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } @@ -100,8 +110,6 @@ RSpec.describe 'Group issues page' do find('.empty-state .js-lazy-loaded') find('.new-project-item-link').click - find('.select2-input').set(group.name) - page.within('.select2-results') do expect(page).to have_content(project.full_name) expect(page).not_to have_content(project_with_issues_disabled.full_name) @@ -110,7 +118,7 @@ RSpec.describe 'Group issues page' do end end - context 'manual ordering' do + context 'manual ordering', :js do let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } let!(:issue1) { create(:issue, project: project, title: 'Issue #1', relative_position: 1) } @@ -143,9 +151,11 @@ RSpec.describe 'Group issues page' do end end - it 'issues should be draggable and persist order', :js do + it 'issues should be draggable and persist order' do visit issues_group_path(group, sort: 'relative_position') + wait_for_requests + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) @@ -159,11 +169,13 @@ RSpec.describe 'Group issues page' do check_issue_order end - it 'issues should not be draggable when user is not logged in', :js do + it 'issues should not be draggable when user is not logged in' do sign_out(user_in_group) visit issues_group_path(group, sort: 'relative_position') + wait_for_requests + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) @@ -187,7 +199,7 @@ RSpec.describe 'Group issues page' do end end - context 'issues pagination' do + context 'issues pagination', :js do let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user } let!(:issues) do @@ -204,7 +216,9 @@ RSpec.describe 'Group issues page' do end it 'first pagination item is active' do - expect(page).to have_css(".js-first-button a.page-link.active") + page.within('.gl-pagination') do + expect(find('.active')).to have_content('1') + end end end end diff --git a/spec/features/groups/members/manage_groups_spec.rb b/spec/features/groups/members/manage_groups_spec.rb index f1cf04417c0..faf455e4ed9 100644 --- a/spec/features/groups/members/manage_groups_spec.rb +++ b/spec/features/groups/members/manage_groups_spec.rb @@ -20,26 +20,28 @@ RSpec.describe 'Groups > Members > Manage groups', :js do add_group(shared_with_group.id, 'Reporter') + click_groups_tab + page.within(first_row) do expect(page).to have_content(shared_with_group.name) expect(page).to have_content('Reporter') end end - it 'remove user from group' do + it 'remove group from group' do create(:group_group_link, shared_group: shared_group, shared_with_group: shared_with_group, group_access: ::Gitlab::Access::DEVELOPER) visit group_group_members_path(shared_group) + click_groups_tab + expect(page).to have_content(shared_with_group.name) accept_confirm do - find(:css, '#existing_shares li', text: shared_with_group.name).find(:css, 'a.btn-remove').click + find(:css, '#tab-groups li', text: shared_with_group.name).find(:css, 'a.btn-remove').click end - wait_for_requests - expect(page).not_to have_content(shared_with_group.name) end @@ -49,6 +51,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do visit group_group_members_path(shared_group) + click_groups_tab + page.within(first_row) do click_button('Developer') click_link('Maintainer') @@ -67,4 +71,8 @@ RSpec.describe 'Groups > Members > Manage groups', :js do click_button "Invite" end end + + def click_groups_tab + click_link "Groups" + end end diff --git a/spec/features/groups/members/manage_members_spec.rb b/spec/features/groups/members/manage_members_spec.rb index 99846ecee27..0267bea2f53 100644 --- a/spec/features/groups/members/manage_members_spec.rb +++ b/spec/features/groups/members/manage_members_spec.rb @@ -69,7 +69,7 @@ RSpec.describe 'Groups > Members > Manage members' do visit group_group_members_path(group) # Open modal - find(:css, '.project-members-page li', text: user2.name).find(:css, 'button.btn-remove').click + find(:css, '.project-members-page li', text: user2.name).find(:css, 'button.btn-danger').click expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests' @@ -101,7 +101,7 @@ RSpec.describe 'Groups > Members > Manage members' do add_user('test@example.com', 'Reporter') - click_link('Pending') + click_link('Invited') page.within('.content-list.members-list') do expect(page).to have_content('test@example.com') @@ -124,7 +124,7 @@ RSpec.describe 'Groups > Members > Manage members' do expect(page).not_to have_button 'Developer' # Can not remove user2 - expect(page).not_to have_css('a.btn-remove') + expect(page).not_to have_css('a.btn-danger') end end diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb index 2a17e7d2a5c..71c9b280ebe 100644 --- a/spec/features/groups/members/master_manages_access_requests_spec.rb +++ b/spec/features/groups/members/master_manages_access_requests_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do + let(:has_tabs) { true } let(:entity) { create(:group, :public) } let(:members_page_path) { group_group_members_path(entity) } end diff --git a/spec/features/groups/members/search_members_spec.rb b/spec/features/groups/members/search_members_spec.rb index 4c34ccf87c3..ad4f5c0b579 100644 --- a/spec/features/groups/members/search_members_spec.rb +++ b/spec/features/groups/members/search_members_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'Search group member' do end it 'renders member users' do - page.within '.user-search-form' do + page.within '[data-testid="user-search-form"]' do fill_in 'search', with: member.name find('.user-search-btn').click end diff --git a/spec/features/groups/members/tabs_spec.rb b/spec/features/groups/members/tabs_spec.rb new file mode 100644 index 00000000000..fa77d1a2ff8 --- /dev/null +++ b/spec/features/groups/members/tabs_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Groups > Members > Tabs' do + using RSpec::Parameterized::TableSyntax + + shared_examples 'active "Members" tab' do + it 'displays "Members" tab' do + expect(page).to have_selector('.nav-link.active', text: 'Members') + end + end + + shared_examples 'active "Invited" tab' do + it 'displays "Invited" tab' do + expect(page).to have_selector('.nav-link.active', text: 'Invited') + end + end + + let(:owner) { create(:user) } + let(:group) { create(:group) } + + before do + stub_const('Groups::GroupMembersController::MEMBER_PER_PAGE_LIMIT', 1) + allow_any_instance_of(Member).to receive(:send_request).and_return(true) + + group.add_owner(owner) + sign_in(owner) + + create_list(:group_member, 2, group: group) + create_list(:group_member, 2, :invited, group: group) + create_list(:group_group_link, 2, shared_group: group) + create_list(:group_member, 2, :access_request, group: group) + end + + where(:tab, :count) do + 'Members' | 3 + 'Invited' | 2 + 'Groups' | 2 + 'Access requests' | 2 + end + + with_them do + it "renders #{params[:tab]} tab" do + visit group_group_members_path(group) + + expect(page).to have_selector('.nav-link', text: "#{tab} #{count}") + end + end + + context 'displays "Members" tab by default' do + before do + visit group_group_members_path(group) + end + + it_behaves_like 'active "Members" tab' + end + + context 'when searching "Invited"', :js do + before do + visit group_group_members_path(group) + + click_link 'Invited' + + page.within '[data-testid="user-search-form"]' do + fill_in 'search_invited', with: 'email' + find('button[type="submit"]').click + end + end + + it_behaves_like 'active "Invited" tab' + + context 'and then searching "Members"' do + before do + click_link 'Members' + + page.within '[data-testid="user-search-form"]' do + fill_in 'search', with: 'test' + find('button[type="submit"]').click + end + end + + it_behaves_like 'active "Members" tab' + end + end + + context 'when using "Invited" pagination', :js do + before do + visit group_group_members_path(group) + + click_link 'Invited' + + page.within '.pagination' do + click_link '2' + end + end + + it_behaves_like 'active "Invited" tab' + + context 'and then using "Members" pagination' do + before do + click_link 'Members' + + page.within '.pagination' do + click_link '2' + end + end + + it_behaves_like 'active "Members" tab' + end + end +end diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb index 06ff33ff0eb..6803b3a5785 100644 --- a/spec/features/groups/navbar_spec.rb +++ b/spec/features/groups/navbar_spec.rb @@ -45,6 +45,8 @@ RSpec.describe 'Group navbar' do end before do + insert_package_nav(_('Kubernetes')) + stub_feature_flags(group_push_rules: false) stub_feature_flags(group_iterations: false) stub_feature_flags(group_wiki: false) @@ -62,13 +64,8 @@ RSpec.describe 'Group navbar' do before do stub_config(registry: { enabled: true }) - insert_after_nav_item( - _('Kubernetes'), - new_nav_item: { - nav_item: _('Packages & Registries'), - nav_sub_items: [_('Container Registry')] - } - ) + insert_container_nav(_('Kubernetes')) + visit group_path(group) end diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb new file mode 100644 index 00000000000..d81e4aa70cf --- /dev/null +++ b/spec/features/groups/packages_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Group Packages' do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, group: group) } + + before do + sign_in(user) + group.add_maintainer(user) + end + + context 'when feature is not available' do + context 'packages feature is disabled by config' do + before do + allow(Gitlab.config.packages).to receive(:enabled).and_return(false) + end + + it 'gives 404' do + visit_group_packages + + expect(page).to have_gitlab_http_status(:not_found) + end + end + end + + context 'when feature is available', :js do + before do + visit_group_packages + end + + it 'sidebar menu is open' do + sidebar = find('.nav-sidebar') + expect(sidebar).to have_link _('Package Registry') + end + + context 'when there are packages' do + let_it_be(:second_project) { create(:project, name: 'second-project', group: group) } + let_it_be(:conan_package) { create(:conan_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') } + let_it_be(:maven_package) { create(:maven_package, project: second_project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') } + let_it_be(:packages) { [conan_package, maven_package] } + + it_behaves_like 'packages list', check_project_name: true + + it_behaves_like 'package details link' + + it 'allows you to navigate to the project page' do + page.within('[data-qa-selector="packages-table"]') do + click_link project.name + end + + expect(page).to have_current_path(project_path(project)) + expect(page).to have_content(project.name) + end + + context 'sorting' do + it_behaves_like 'shared package sorting' do + let_it_be(:package_one) { maven_package } + let_it_be(:package_two) { conan_package } + end + + it_behaves_like 'correctly sorted packages list', 'Project' do + let(:packages) { [maven_package, conan_package] } + end + + it_behaves_like 'correctly sorted packages list', 'Project', ascending: true do + let(:packages) { [conan_package, maven_package] } + end + end + end + + it_behaves_like 'when there are no packages' + end + + def visit_group_packages + visit group_packages_path(group) + end +end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 8104ff3f987..8264ec2eddd 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'Group' do expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) expect(current_path).to eq(group_path(group)) - expect(page).to have_selector '.visibility-icon .fa-globe' + expect(page).to have_selector '.visibility-icon [data-testid="earth-icon"]' end end diff --git a/spec/features/import/manifest_import_spec.rb b/spec/features/import/manifest_import_spec.rb index 1efbc5642d4..9c359e932d5 100644 --- a/spec/features/import/manifest_import_spec.rb +++ b/spec/features/import/manifest_import_spec.rb @@ -24,7 +24,7 @@ RSpec.describe 'Import multiple repositories by uploading a manifest file', :js expect(page).to have_content('https://android-review.googlesource.com/platform/build/blueprint') end - it 'imports successfully imports a project', :sidekiq_inline do + it 'imports a project successfully', :sidekiq_inline, :js do visit new_import_manifest_path attach_file('manifest', Rails.root.join('spec/fixtures/aosp_manifest.xml')) @@ -32,7 +32,11 @@ RSpec.describe 'Import multiple repositories by uploading a manifest file', :js page.within(second_row) do click_on 'Import' + end + + wait_for_requests + page.within(second_row) do expect(page).to have_content 'Done' expect(page).to have_content("#{group.full_path}/build/blueprint") end @@ -48,6 +52,6 @@ RSpec.describe 'Import multiple repositories by uploading a manifest file', :js end def second_row - page.all('table.import-jobs tbody tr')[1] + page.all('table.import-table tbody tr')[1] end end diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb index d91fae5cdfd..e7bcd7876ea 100644 --- a/spec/features/invites_spec.rb +++ b/spec/features/invites_spec.rb @@ -48,6 +48,14 @@ RSpec.describe 'Invites', :aggregate_failures do expect(page).to have_content('To accept this invitation, sign in') end + it 'pre-fills the "Username or email" field on the sign in box with the invite_email from the invite' do + expect(find_field('Username or email').value).to eq(group_invite.invite_email) + end + + it 'pre-fills the Email field on the sign up box with the invite_email from the invite' do + expect(find_field('Email').value).to eq(group_invite.invite_email) + end + it 'sign in, grants access and redirects to group page' do fill_in_sign_in_form(user) @@ -63,6 +71,8 @@ RSpec.describe 'Invites', :aggregate_failures do it 'shows message user already a member' do visit invite_path(group_invite.raw_invite_token) + + expect(page).to have_link(owner.name, href: user_url(owner)) expect(page).to have_content('However, you are already a member of this group.') end end @@ -197,8 +207,10 @@ RSpec.describe 'Invites', :aggregate_failures do it 'declines application and redirects to dashboard' do page.click_link 'Decline' + expect(current_path).to eq(dashboard_projects_path) expect(page).to have_content('You have declined the invitation to join group Owned.') + expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound end end @@ -209,7 +221,9 @@ RSpec.describe 'Invites', :aggregate_failures do it 'declines application and redirects to sign in page' do expect(current_path).to eq(new_user_session_path) + expect(page).to have_content('You have declined the invitation to join group Owned.') + expect { group_invite.reload }.to raise_error ActiveRecord::RecordNotFound end end end @@ -223,9 +237,13 @@ RSpec.describe 'Invites', :aggregate_failures do end it 'grants access and redirects to group page' do + expect(group.users.include?(user)).to be false + page.click_link 'Accept invitation' + expect(current_path).to eq(group_path(group)) expect(page).to have_content('You have been granted Owner access to group Owned.') + expect(group.users.include?(user)).to be true end end end diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 259c09b9d11..7790d8f1c4c 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -9,15 +9,13 @@ RSpec.describe 'issuable list', :js do issuable_types = [:issue, :merge_request] before do - stub_feature_flags(vue_issuables_list: false) - # something is going on project.add_user(user, :developer) sign_in(user) issuable_types.each { |type| create_issuables(type) } end issuable_types.each do |issuable_type| - it "avoids N+1 database queries for #{issuable_type.to_s.humanize.pluralize}" do + it "avoids N+1 database queries for #{issuable_type.to_s.humanize.pluralize}", quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/231426' } do control_count = ActiveRecord::QueryRecorder.new { visit_issuable_list(issuable_type) }.count create_issuables(issuable_type) diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 91f0e983fa8..aa61aff3b05 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -14,9 +14,6 @@ RSpec.describe 'Issues > Labels bulk assignment' do context 'as an allowed user', :js do before do - # Make sure that issuables list FF is not turned on. - stub_feature_flags(vue_issuables_list: false) - project.add_maintainer(user) sign_in user diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb index 6fc648954b4..12682905559 100644 --- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb +++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb @@ -8,10 +8,14 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j let(:merge_request) { create(:merge_request, source_project: project) } let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } - def resolve_all_discussions_link_selector - text = "Resolve all threads in new issue" + def resolve_all_discussions_link_selector(title: "") url = new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) - %Q{a[title="#{text}"][href="#{url}"]} + + if title.empty? + %Q{a[href="#{url}"]} + else + %Q{a[title="#{title}"][href="#{url}"]} + end end describe 'as a user with access to the project' do @@ -23,7 +27,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j it 'shows a button to resolve all threads by creating a new issue' do within('.line-resolve-all-container') do - expect(page).to have_selector resolve_all_discussions_link_selector + expect(page).to have_selector resolve_all_discussions_link_selector( title: "Resolve all threads in new issue" ) end end @@ -34,6 +38,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j it 'hides the link for creating a new issue' do expect(page).not_to have_selector resolve_all_discussions_link_selector + expect(page).not_to have_content "Resolve all threads in new issue" end end @@ -57,7 +62,7 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'does not show a link to create a new issue' do - expect(page).not_to have_link 'Create an issue to resolve them later' + expect(page).not_to have_link 'Resolve all threads in new issue' end end @@ -67,18 +72,20 @@ RSpec.describe 'Resolving all open threads in a merge request from an issue', :j end it 'shows a warning that the merge request contains unresolved threads' do - expect(page).to have_content 'There are unresolved threads.' + expect(page).to have_content 'Before this can be merged,' end it 'has a link to resolve all threads by creating an issue' do page.within '.mr-widget-body' do - expect(page).to have_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + expect(page).to have_link 'Resolve all threads in new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) end end context 'creating an issue for threads' do before do - page.click_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + page.within '.mr-widget-body' do + page.click_link 'Resolve all threads in new issue', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid) + end end it_behaves_like 'creating an issue for a thread' diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 85b7a093536..61c1e35f3c8 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Recent searches', :js do include FilteredSearchHelpers + include MobileHelpers let(:project_1) { create(:project, :public) } let(:project_2) { create(:project, :public) } @@ -104,4 +105,24 @@ RSpec.describe 'Recent searches', :js do expect(find('.flash-alert')).to have_text('An error occurred while parsing recent searches') end + + context 'on tablet/mobile screen' do + it 'shows only the history icon in the dropdown' do + resize_screen_sm + visit project_issues_path(project_1) + + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('svg', visible: true) + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('span', text: 'Recent searches', visible: false) + end + end + + context 'on PC screen' do + it 'shows only the Recent searches text in the dropdown' do + restore_window_size + visit project_issues_path(project_1) + + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('svg', visible: false) + expect(find('.filtered-search-history-dropdown-wrapper')).to have_selector('span', text: 'Recent searches', visible: true) + end + end end diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 59588978a8e..c585d7f6194 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -53,7 +53,7 @@ RSpec.describe 'Visual tokens', :js do end it 'ends editing mode when document is clicked' do - find('#content-body').click + find('.js-navbar').click expect_filtered_search_input_empty expect(page).to have_css('#js-dropdown-author', visible: false) @@ -142,7 +142,7 @@ RSpec.describe 'Visual tokens', :js do it 'does not tokenize incomplete token' do filtered_search.send_keys('author:=') - find('body').click + find('.js-navbar').click token = page.all('.tokens-container .js-visual-token')[1] expect_filtered_search_input_empty diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 0b2e8013304..3757985f99c 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -487,7 +487,7 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - find('.tribute-container .highlight').click + find('.tribute-container .highlight', visible: true).click click_button 'Save changes' @@ -501,30 +501,36 @@ RSpec.describe 'GFM autocomplete', :js do find('#note-body').native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) end - it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do + it 'opens autocomplete menu for Issues when field starts with text with item escaping HTML characters' do + issue_xss_title = 'This will execute alert<img src=x onerror=alert(2)<img src=x onerror=alert(1)>' + create(:issue, project: project, title: issue_xss_title) + page.within '.timeline-content-form' do - find('#note-body').native.send_keys('@ev') + find('#note-body').native.send_keys('#') end wait_for_requests - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) page.within '.tribute-container ul' do - expect(find('li').text).to have_content(user_xss.username) + expect(page.all('li').first.text).to include(issue_xss_title) end end - it 'doesnt open autocomplete menu character is prefixed with text' do + it 'opens autocomplete menu for Username when field starts with text with item escaping HTML characters' do page.within '.timeline-content-form' do - find('#note-body').native.send_keys('testing') - find('#note-body').native.send_keys('@') + find('#note-body').native.send_keys('@ev') end - expect(page).not_to have_selector('.tribute-container') + wait_for_requests + + expect(page).to have_selector('.tribute-container', visible: true) + + expect(find('.tribute-container ul', visible: true).text).to have_content(user_xss.username) end it 'selects the first item for assignee dropdowns' do @@ -532,11 +538,11 @@ RSpec.describe 'GFM autocomplete', :js do find('#note-body').native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) wait_for_requests - expect(find('.tribute-container ul')).to have_selector('.highlight:first-of-type') + expect(find('.tribute-container ul', visible: true)).to have_selector('.highlight:first-of-type') end it 'includes items for assignee dropdowns with non-ASCII characters in name' do @@ -545,14 +551,26 @@ RSpec.describe 'GFM autocomplete', :js do simulate_input('#note-body', "@#{user.name[0...8]}") end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) wait_for_requests - expect(find('.tribute-container')).to have_content(user.name) + expect(find('.tribute-container ul', visible: true)).to have_content(user.name) end context 'if a selected value has special characters' do + it 'wraps the result in double quotes' do + note = find('#note-body') + page.within '.timeline-content-form' do + find('#note-body').native.send_keys('') + simulate_input('#note-body', "~#{label.title[0]}") + end + + label_item = find('.tribute-container ul', text: label.title, visible: true) + + expect_to_wrap(true, label_item, note, label.title) + end + it "shows dropdown after a new line" do note = find('#note-body') page.within '.timeline-content-form' do @@ -562,7 +580,7 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys('@') end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) end it "does not show dropdown when preceded with a special character" do @@ -571,12 +589,21 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys("@") end - expect(page).to have_selector('.tribute-container') + expect(page).to have_selector('.tribute-container', visible: true) page.within '.timeline-content-form' do note.native.send_keys("@") end + expect(page).not_to have_selector('.tribute-container') + end + + it "does not throw an error if no labels exist" do + note = find('#note-body') + page.within '.timeline-content-form' do + note.native.send_keys('~') + end + expect(page).to have_selector('.tribute-container', visible: false) end @@ -586,7 +613,7 @@ RSpec.describe 'GFM autocomplete', :js do note.native.send_keys("@#{user.username[0]}") end - user_item = find('.tribute-container li', text: user.username) + user_item = find('.tribute-container ul', text: user.username, visible: true) expect_to_wrap(false, user_item, note, user.username) end @@ -611,7 +638,7 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - user_item = find('.tribute-container li', text: user.username) + user_item = find('.tribute-container ul', text: user.username, visible: true) expect(user_item).to have_content(user.username) end end @@ -640,8 +667,139 @@ RSpec.describe 'GFM autocomplete', :js do wait_for_requests - expect(find('.tribute-container ul')).not_to have_content(user.username) - expect(find('.tribute-container ul')).to have_content(unassigned_user.username) + expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username) + expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username) + end + + it 'lists users who are currently not assigned to the issue when using /assign on the second line' do + visit project_issue_path(project, issue_assignee) + + note = find('#note-body') + page.within '.timeline-content-form' do + note.native.send_keys('/assign @user2') + note.native.send_keys(:enter) + note.native.send_keys('/assign @') + note.native.send_keys(:right) + end + + wait_for_requests + + expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username) + expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username) + end + end + + context 'labels' do + it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do + label_xss_title = 'alert label <img src=x onerror="alert(\'Hello xss\');" a' + create(:label, project: project, title: label_xss_title) + + note = find('#note-body') + + # It should show all the labels on "~". + type(note, '~') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('alert label') + end + + it 'allows colons when autocompleting scoped labels' do + create(:label, project: project, title: 'scoped:label') + + note = find('#note-body') + type(note, '~scoped:') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('scoped:label') + end + + it 'allows colons when autocompleting scoped labels with double colons' do + create(:label, project: project, title: 'scoped::label') + + note = find('#note-body') + type(note, '~scoped::') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('scoped::label') + end + + it 'autocompletes multi-word labels' do + create(:label, project: project, title: 'Accepting merge requests') + + note = find('#note-body') + type(note, '~Acceptingmerge') + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('Accepting merge requests') + end + + it 'only autocompletes the latest label' do + create(:label, project: project, title: 'documentation') + create(:label, project: project, title: 'feature') + + note = find('#note-body') + type(note, '~documentation foo bar ~feat') + note.native.send_keys(:right) + + wait_for_requests + + expect(find('.tribute-container ul', visible: true).text).to have_content('feature') + expect(find('.tribute-container ul', visible: true).text).not_to have_content('documentation') + end + + it 'does not autocomplete labels if no tilde is typed' do + create(:label, project: project, title: 'documentation') + + note = find('#note-body') + type(note, 'document') + + wait_for_requests + + expect(page).not_to have_selector('.tribute-container') + end + end + + context 'when other notes are destroyed' do + let!(:discussion) { create(:discussion_note_on_issue, noteable: issue, project: issue.project) } + + # This is meant to protect against this issue https://gitlab.com/gitlab-org/gitlab/-/issues/228729 + it 'keeps autocomplete key listeners' do + visit project_issue_path(project, issue) + note = find('#note-body') + + start_comment_with_emoji(note) + + start_and_cancel_discussion + + note.fill_in(with: '') + start_comment_with_emoji(note) + note.native.send_keys(:enter) + + expect(note.value).to eql('Hello :100: ') + end + + def start_comment_with_emoji(note) + note.native.send_keys('Hello :10') + + wait_for_requests + + find('.atwho-view li', text: '100') + end + + def start_and_cancel_discussion + click_button('Reply...') + + fill_in('note_note', with: 'Whoops!') + + page.accept_alert 'Are you sure you want to cancel creating this comment?' do + click_button('Cancel') + end + + wait_for_requests end end end diff --git a/spec/features/issues/service_desk_spec.rb b/spec/features/issues/service_desk_spec.rb index 0995aa11654..2912ac33625 100644 --- a/spec/features/issues/service_desk_spec.rb +++ b/spec/features/issues/service_desk_spec.rb @@ -7,8 +7,6 @@ RSpec.describe 'Service Desk Issue Tracker', :js do let(:user) { create(:user) } before do - stub_feature_flags(vue_issuables_list: false) - allow(Gitlab::IncomingEmail).to receive(:enabled?).and_return(true) allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?).and_return(true) @@ -78,11 +76,9 @@ RSpec.describe 'Service Desk Issue Tracker', :js do context 'when service desk has been activated' do context 'when there are no issues' do describe 'service desk info content' do - before do + it 'displays the large info box, documentation, and the address' do visit service_desk_project_issues_path(project) - end - it 'displays the large info box, documentation, and the address' do aggregate_failures do expect(page).to have_css('.empty-state') expect(page).to have_link('Read more', href: help_page_path('user/project/service_desk')) diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index dfe3a1bf1b3..eb78e4e2456 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -8,7 +8,6 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do let!(:user) { create(:user)} before do - stub_feature_flags(vue_issuables_list: false) project.add_maintainer(user) sign_in(user) end @@ -52,7 +51,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do click_update_issues_button page.within('.issue .controls') do - expect(find('.author-link')["title"]).to have_content(user.name) + expect(find('.author-link')['href']).to have_content(user.website_url) end end @@ -83,13 +82,15 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do find('.dropdown-menu-milestone a', text: milestone.title).click click_update_issues_button - expect(find('.issue')).to have_content milestone.title + expect(page.find('.issue')).to have_content milestone.title end it 'sets to no milestone' do create_with_milestone visit project_issues_path(project) + wait_for_requests + expect(first('.issue')).to have_content milestone.title click_button 'Edit issues' diff --git a/spec/features/issues/user_filters_issues_spec.rb b/spec/features/issues/user_filters_issues_spec.rb index 54a600910ef..1b246181523 100644 --- a/spec/features/issues/user_filters_issues_spec.rb +++ b/spec/features/issues/user_filters_issues_spec.rb @@ -2,13 +2,11 @@ require 'spec_helper' -RSpec.describe 'User filters issues' do +RSpec.describe 'User filters issues', :js do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project_empty_repo, :public) } before do - stub_feature_flags(vue_issuables_list: false) - %w[foobar barbaz].each do |title| create(:issue, author: user, diff --git a/spec/features/issues/user_sees_empty_state_spec.rb b/spec/features/issues/user_sees_empty_state_spec.rb index e39369b0150..b43ba01606a 100644 --- a/spec/features/issues/user_sees_empty_state_spec.rb +++ b/spec/features/issues/user_sees_empty_state_spec.rb @@ -2,14 +2,10 @@ require 'spec_helper' -RSpec.describe 'Issues > User sees empty state' do +RSpec.describe 'Issues > User sees empty state', :js do let_it_be(:project) { create(:project, :public) } let_it_be(:user) { project.creator } - before do - stub_feature_flags(vue_issuables_list: false) - end - shared_examples_for 'empty state with filters' do it 'user sees empty state with filters' do create(:issue, author: user, project: project) diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index 91c6419b464..f0bb055c6f2 100644 --- a/spec/features/issues/user_sorts_issues_spec.rb +++ b/spec/features/issues/user_sorts_issues_spec.rb @@ -16,8 +16,6 @@ RSpec.describe "User sorts issues" do let_it_be(:later_due_milestone) { create(:milestone, project: project, due_date: '2013-12-12') } before do - stub_feature_flags(vue_issuables_list: false) - create_list(:award_emoji, 2, :upvote, awardable: issue1) create_list(:award_emoji, 2, :downvote, awardable: issue2) create(:award_emoji, :downvote, awardable: issue1) @@ -48,7 +46,7 @@ RSpec.describe "User sorts issues" do expect(find('.issues-filters a.is-active')).to have_content('Milestone') end - it "sorts by popularity" do + it 'sorts by popularity', :js do find('.filter-dropdown-container .dropdown').click page.within('ul.dropdown-menu.dropdown-menu-right li') do @@ -70,14 +68,14 @@ RSpec.describe "User sorts issues" do end end - it 'sorts by newest' do + it 'sorts by newest', :js do visit project_issues_path(project, sort: sort_value_created_date) expect(first_issue).to include('foo') expect(last_issue).to include('baz') end - it 'sorts by most recently updated' do + it 'sorts by most recently updated', :js do issue3.updated_at = Time.now + 100 issue3.save visit project_issues_path(project, sort: sort_value_recently_updated) @@ -85,7 +83,7 @@ RSpec.describe "User sorts issues" do expect(first_issue).to include('baz') end - describe 'sorting by due date' do + describe 'sorting by due date', :js do before do issue1.update(due_date: 1.day.from_now) issue2.update(due_date: 6.days.from_now) @@ -122,7 +120,7 @@ RSpec.describe "User sorts issues" do end end - describe 'filtering by due date' do + describe 'filtering by due date', :js do before do issue1.update(due_date: 1.day.from_now) issue2.update(due_date: 6.days.from_now) @@ -205,7 +203,7 @@ RSpec.describe "User sorts issues" do end end - describe 'sorting by milestone' do + describe 'sorting by milestone', :js do before do issue1.milestone = newer_due_milestone issue1.save @@ -221,7 +219,7 @@ RSpec.describe "User sorts issues" do end end - describe 'combine filter and sort' do + describe 'combine filter and sort', :js do let(:user2) { create(:user) } before do diff --git a/spec/features/issues/user_views_issues_spec.rb b/spec/features/issues/user_views_issues_spec.rb index 34cea7f3b0b..165f4b10cff 100644 --- a/spec/features/issues/user_views_issues_spec.rb +++ b/spec/features/issues/user_views_issues_spec.rb @@ -10,10 +10,6 @@ RSpec.describe "User views issues" do let_it_be(:user) { create(:user) } - before do - stub_feature_flags(vue_issuables_list: false) - end - shared_examples "opens issue from list" do it "opens issue" do click_link(issue.title) @@ -112,7 +108,7 @@ RSpec.describe "User views issues" do end end - context "when signed in as developer" do + context "when signed in as developer", :js do before do project.add_developer(user) sign_in(user) @@ -122,27 +118,7 @@ RSpec.describe "User views issues" do include_examples "internal project" end - context "when not signed in" do + context "when not signed in", :js do include_examples "public project" end - - context 'when vue_issuables_list feature is enabled', :js do - before do - stub_feature_flags(vue_issuables_list: true) - end - - context 'when signed in' do - before do - project.add_developer(user) - sign_in(user) - end - - include_examples "public project" - include_examples "internal project" - end - - context 'when not signed in' do - include_examples "public project" - end - end end diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index 80dcdd08f74..57362ed2d54 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -737,6 +737,7 @@ RSpec.describe 'Copy as GFM', :js do context 'inline diff' do before do visit project_commit_path(project, sample_commit.id, view: 'inline') + wait_for_requests end it_behaves_like 'copying code from a diff' @@ -745,6 +746,7 @@ RSpec.describe 'Copy as GFM', :js do context 'parallel diff' do before do visit project_commit_path(project, sample_commit.id, view: 'parallel') + wait_for_requests end it_behaves_like 'copying code from a diff' diff --git a/spec/features/markdown/metrics_spec.rb b/spec/features/markdown/metrics_spec.rb index 3e63ae67f19..9716c660fa9 100644 --- a/spec/features/markdown/metrics_spec.rb +++ b/spec/features/markdown/metrics_spec.rb @@ -18,10 +18,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st before do clear_host_from_memoized_variables - - allow(::Gitlab.config.gitlab) - .to receive(:url) - .and_return(urls.root_url.chomp('/')) + stub_gitlab_domain project.add_developer(user) sign_in(user) @@ -86,6 +83,7 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st y_label: 'Total Cores' } end + let(:metrics_url_2) { urls.metrics_project_environment_url(project, environment, **chart_params_2) } let(:description) { "See [metrics dashboard](#{metrics_url}) for info. \n See [metrics dashboard](#{metrics_url_2}) for info." } let(:issue) { create(:issue, project: project, description: description) } @@ -144,11 +142,11 @@ RSpec.describe 'Metrics rendering', :js, :kubeclient, :use_clean_rails_memory_st { panel_groups: [{ panels: [{ - type: "line-graph", + type: 'area-chart', title: title, - y_label: "metric", + y_label: 'metric', metrics: [{ - query_range: "metric * 0.5 < 1" + query_range: 'metric * 0.5 < 1' }] }] }] diff --git a/spec/features/merge_request/user_approves_spec.rb b/spec/features/merge_request/user_approves_spec.rb index d319fdcb87b..f401dd598f3 100644 --- a/spec/features/merge_request/user_approves_spec.rb +++ b/spec/features/merge_request/user_approves_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Merge request > User approves', :js do verify_approvals_count_on_index! click_approval_button('Revoke approval') - expect(page).to have_content('No approval required; you can still approve') + expect(page).to have_content('Approval is optional') end def verify_approvals_count_on_index! diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb index 30bf82e3665..3a199951b56 100644 --- a/spec/features/merge_request/user_comments_on_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_diff_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'User comments on a diff', :js do let(:merge_request) do create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') end + let(:user) { create(:user) } before do diff --git a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb index 23df7635aa1..1d3d76d3486 100644 --- a/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb +++ b/spec/features/merge_request/user_customizes_merge_commit_message_spec.rb @@ -15,6 +15,7 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js do description: "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}" ) end + let(:textbox) { page.find(:css, '#merge-message-edit', visible: false) } let(:default_message) do [ @@ -24,6 +25,7 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js do "See merge request #{merge_request.to_reference(full: true)}" ].join("\n\n") end + let(:message_with_description) do [ "Merge branch 'feature' into 'master'", diff --git a/spec/features/merge_request/user_edits_merge_request_spec.rb b/spec/features/merge_request/user_edits_merge_request_spec.rb index 6c5f508c8c6..364af8d8a76 100644 --- a/spec/features/merge_request/user_edits_merge_request_spec.rb +++ b/spec/features/merge_request/user_edits_merge_request_spec.rb @@ -85,13 +85,24 @@ RSpec.describe 'User edits a merge request', :js do end end - it 'changes the target branch' do - expect(page).to have_content('From master into feature') + describe 'changing target branch' do + it 'allows user to change target branch' do + expect(page).to have_content('From master into feature') - select2('merge-test', from: '#merge_request_target_branch') - click_button('Save changes') + select2('merge-test', from: '#merge_request_target_branch') + click_button('Save changes') + + expect(page).to have_content("Request to merge #{merge_request.source_branch} into merge-test") + expect(page).to have_content("changed target branch from #{merge_request.target_branch} to merge-test") + end - expect(page).to have_content("Request to merge #{merge_request.source_branch} into merge-test") - expect(page).to have_content("changed target branch from #{merge_request.target_branch} to merge-test") + describe 'merged merge request' do + let(:merge_request) { create(:merge_request, source_project: project, target_project: project, state: :merged) } + + it 'does not allow user to change target branch' do + expect(page).to have_content('From master into feature') + expect(page).not_to have_selector('.select2-container') + end + end end end diff --git a/spec/features/merge_request/user_jumps_to_discussion_spec.rb b/spec/features/merge_request/user_jumps_to_discussion_spec.rb new file mode 100644 index 00000000000..9bded1c5572 --- /dev/null +++ b/spec/features/merge_request/user_jumps_to_discussion_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User jumps to the next unresolved discussion', :js do + let(:project) { create(:project, :repository) } + let(:merge_request) do + create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') + end + + let(:user) { create(:user) } + + before do + create(:discussion_note, noteable: merge_request, project: project, author: user) + + project.add_maintainer(user) + sign_in(user) + + visit(diffs_project_merge_request_path(project, merge_request)) + + wait_for_requests + end + + it 'jumps to overview tab' do + find('.discussion-next-btn').click + + expect(page).to have_css('.notes-tab.active') + end +end diff --git a/spec/features/merge_request/user_merges_immediately_spec.rb b/spec/features/merge_request/user_merges_immediately_spec.rb index 47dc09ae79f..0fb081ec507 100644 --- a/spec/features/merge_request/user_merges_immediately_spec.rb +++ b/spec/features/merge_request/user_merges_immediately_spec.rb @@ -12,6 +12,7 @@ RSpec.describe 'Merge requests > User merges immediately', :js do head_pipeline: pipeline, source_branch: pipeline.ref) end + let(:pipeline) do create(:ci_pipeline, project: project, ref: 'master', diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index d5ff31de073..3dc49fb4dea 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -11,6 +11,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do title: 'Bug NS-04', merge_params: { force_remove_source_branch: '1' }) end + let(:pipeline) do create(:ci_pipeline, project: project, sha: merge_request.diff_head_sha, @@ -115,6 +116,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do merge_user: user, title: 'MepMep') end + let!(:build) do create(:ci_build, pipeline: pipeline) end @@ -154,7 +156,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do context 'view merge request with MWPS enabled but automatically merge fails' do before do - merge_request.update( + merge_request.update!( merge_user: merge_request.author, merge_error: 'Something went wrong.' ) @@ -173,7 +175,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do context 'view merge request with MWPS enabled but automatically merge fails' do before do - merge_request.update( + merge_request.update!( merge_user: merge_request.author, merge_error: 'Something went wrong.' ) diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb index 6ecffb05009..9556142ecb8 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -193,7 +193,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do context 'when the MR only supports legacy diff notes' do before do - merge_request.merge_request_diff.update(start_commit_sha: nil) + merge_request.merge_request_diff.update!(start_commit_sha: nil) visit diffs_project_merge_request_path(project, merge_request, view: 'inline') end diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index 3c70819319d..4c079b98c90 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Merge request > User posts notes', :js do let(:merge_request) do create(:merge_request, source_project: project, target_project: project) end + let!(:note) do create(:note_on_merge_request, :with_attachment, noteable: merge_request, project: project) @@ -94,20 +95,31 @@ RSpec.describe 'Merge request > User posts notes', :js do end end - describe 'reply on a deleted conversation' do - before do - visit project_merge_request_path(project, merge_request) - end - - it 'shows an error message' do + describe 'replying to a comment' do + it 'makes the discussion resolvable' do find('.js-reply-button').click - note.delete page.within('.discussion-reply-holder') do fill_in 'note[note]', with: 'A reply' click_button 'Add comment now' - wait_for_requests - expect(page).to have_content('Your comment could not be submitted because discussion to reply to cannot be found') + + expect(page).to have_button('Resolve thread') + end + end + + context 'when comment is deleted' do + it 'shows an error message' do + find('.js-reply-button').click + + page.within('.discussion-reply-holder') do + fill_in 'note[note]', with: 'A reply' + + note.delete + + click_button 'Add comment now' + + expect(page).to have_content('Your comment could not be submitted because discussion to reply to cannot be found') + end end end end diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index aa3840b4376..f2adfd21e49 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -23,7 +23,7 @@ RSpec.describe 'Merge request > User resolves diff notes and threads', :js do before do project.add_maintainer(user) sign_in(user) - note.destroy + note.destroy! visit_merge_request end diff --git a/spec/features/merge_request/user_resolves_wip_mr_spec.rb b/spec/features/merge_request/user_resolves_wip_mr_spec.rb index 34a3490a152..a9d4c4df507 100644 --- a/spec/features/merge_request/user_resolves_wip_mr_spec.rb +++ b/spec/features/merge_request/user_resolves_wip_mr_spec.rb @@ -11,6 +11,7 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do title: 'WIP: Bug NS-04', merge_params: { force_remove_source_branch: '1' }) end + let(:pipeline) do create(:ci_pipeline, project: project, sha: merge_request.diff_head_sha, @@ -32,9 +33,9 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do it 'retains merge request data after clicking Resolve WIP status' do expect(page.find('.ci-widget-content')).to have_content("Pipeline ##{pipeline.id}") - expect(page).to have_content "This is a Work in Progress" + expect(page).to have_content "This merge request is still a work in progress." - click_button('Resolve WIP status') + click_button('Mark as ready') wait_for_requests @@ -42,7 +43,7 @@ RSpec.describe 'Merge request > User resolves Work in Progress', :js do # merge request widget refreshes, which masks missing elements # that should already be present. expect(page.find('.ci-widget-content', wait: 0)).to have_content("Pipeline ##{pipeline.id}") - expect(page).not_to have_content('This is a Work in Progress') + expect(page).not_to have_content('This merge request is still a work in progress.') end end end diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb index 415e6b29d5a..7fad805866b 100644 --- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb +++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb @@ -16,6 +16,7 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do diff_refs: merge_request.diff_refs ) end + let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } before do diff --git a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb index ec2fb856be5..7f4249336fe 100644 --- a/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb +++ b/spec/features/merge_request/user_sees_cherry_pick_modal_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'Merge request > User cherry-picks', :js do context 'without a merge commit' do before do merge_request.merge_commit_sha = nil - merge_request.save + merge_request.save! end it 'does not show a Cherry-pick button' do diff --git a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb index baef547a480..d6cdc15005b 100644 --- a/spec/features/merge_request/user_sees_closing_issues_message_spec.rb +++ b/spec/features/merge_request/user_sees_closing_issues_message_spec.rb @@ -16,6 +16,7 @@ RSpec.describe 'Merge request > User sees closing issues message', :js do title: merge_request_title ) end + let(:merge_request_description) { 'Merge Request Description' } let(:merge_request_title) { 'Merge Request Title' } diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb index ca8c4f84677..289c861739f 100644 --- a/spec/features/merge_request/user_sees_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_discussions_spec.rb @@ -13,8 +13,8 @@ RSpec.describe 'Merge request > User sees threads', :js do end describe "Diff discussions" do - let!(:old_merge_request_diff) { merge_request.merge_request_diffs.create(diff_refs: outdated_diff_refs) } - let!(:new_merge_request_diff) { merge_request.merge_request_diffs.create } + let!(:old_merge_request_diff) { merge_request.merge_request_diffs.create!(diff_refs: outdated_diff_refs) } + let!(:new_merge_request_diff) { merge_request.merge_request_diffs.create! } let!(:outdated_discussion) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position).to_discussion } let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } let(:outdated_position) do @@ -24,6 +24,7 @@ RSpec.describe 'Merge request > User sees threads', :js do diff_refs: outdated_diff_refs ) end + let(:outdated_diff_refs) { project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e").diff_refs } before do diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb index cae04dd1693..ac38b2b854c 100644 --- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb @@ -21,7 +21,7 @@ RSpec.describe 'Merge request > User sees merge button depending on unresolved t context 'with unresolved threads' do it 'does not allow to merge' do expect(page).not_to have_button 'Merge' - expect(page).to have_content('There are unresolved threads.') + expect(page).to have_content('Before this can be merged,') end end diff --git a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb index e2aa10d80dd..7b319f6aff8 100644 --- a/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb @@ -8,7 +8,6 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', let(:project) { create(:project, :public, :repository) } let(:user) { project.creator } - let(:enable_mr_tabs_position_flag) { true } let(:config) do { @@ -27,7 +26,6 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end before do - stub_feature_flags(mr_tabs_position: enable_mr_tabs_position_flag) stub_application_setting(auto_devops_enabled: false) stub_feature_flags(ci_merge_request_pipeline: true) stub_ci_pipeline_yaml_file(YAML.dump(config)) @@ -36,7 +34,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end context 'when a user created a merge request in the parent project' do - let(:merge_request) do + let!(:merge_request) do create(:merge_request, source_project: project, target_project: project, @@ -53,7 +51,6 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', Ci::CreatePipelineService.new(project, user, ref: 'feature') .execute(:merge_request_event, merge_request: merge_request) end - let(:enable_mr_tabs_position_flag) { false } before do visit project_merge_request_path(project, merge_request) @@ -70,23 +67,11 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end end - context 'when merge request tabs feature flag is disabled' do - it 'sees the latest detached merge request pipeline as the head pipeline', :sidekiq_might_not_need_inline do - page.within('.ci-widget-content') do - expect(page).to have_content("##{detached_merge_request_pipeline.id}") - end - end - end - - context 'when merge request tabs feature flag is enabled' do - let(:enable_mr_tabs_position_flag) { true } + it 'sees the latest detached merge request pipeline as the head pipeline', :sidekiq_might_not_need_inline do + click_link "Overview" - it 'sees the latest detached merge request pipeline as the head pipeline', :sidekiq_might_not_need_inline do - click_link "Overview" - - page.within('.ci-widget-content') do - expect(page).to have_content("##{detached_merge_request_pipeline.id}") - end + page.within('.ci-widget-content') do + expect(page).to have_content("##{detached_merge_request_pipeline.id}") end end @@ -144,6 +129,8 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end it 'sees the latest detached merge request pipeline as the head pipeline' do + click_link 'Overview' + page.within('.ci-widget-content') do expect(page).to have_content("##{detached_merge_request_pipeline_2.id}") end @@ -152,6 +139,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', context 'when a user merges a merge request in the parent project', :sidekiq_might_not_need_inline do before do + click_link 'Overview' click_button 'Merge when pipeline succeeds' wait_for_requests @@ -179,6 +167,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', context 'when branch pipeline succeeds' do before do + click_link 'Overview' push_pipeline.succeed! wait_for_requests @@ -214,6 +203,8 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end it 'sees the latest branch pipeline as the head pipeline', :sidekiq_might_not_need_inline do + click_link 'Overview' + page.within('.ci-widget-content') do expect(page).to have_content("##{push_pipeline.id}") end @@ -260,23 +251,11 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request', end end - context 'when merge request tabs feature flag is enabled' do - it 'sees the latest detached merge request pipeline as the head pipeline' do - click_link "Overview" + it 'sees the latest detached merge request pipeline as the head pipeline' do + click_link "Overview" - page.within('.ci-widget-content') do - expect(page).to have_content("##{detached_merge_request_pipeline.id}") - end - end - end - - context 'when merge request tabs feature flag is disabled' do - let(:enable_mr_tabs_position_flag) { false } - - it 'sees the latest detached merge request pipeline as the head pipeline' do - page.within('.ci-widget-content') do - expect(page).to have_content("##{detached_merge_request_pipeline.id}") - end + page.within('.ci-widget-content') do + expect(page).to have_content("##{detached_merge_request_pipeline.id}") end end diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index ce49e9f4141..c7d26dfc814 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -302,7 +302,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do context 'view merge request with MWPS enabled but automatically merge fails' do before do - merge_request.update( + merge_request.update!( auto_merge_enabled: true, auto_merge_strategy: AutoMergeService::STRATEGY_MERGE_WHEN_PIPELINE_SUCCEEDS, merge_user: merge_request.author, @@ -324,7 +324,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do context 'view merge request with MWPS enabled but automatically merge fails' do before do - merge_request.update( + merge_request.update!( merge_when_pipeline_succeeds: true, merge_user: merge_request.author, merge_error: 'Something went wrong' @@ -345,9 +345,9 @@ RSpec.describe 'Merge request > User sees merge widget', :js do context 'view merge request where fast-forward merge is not possible' do before do - project.update(merge_requests_ff_only_enabled: true) + project.update!(merge_requests_ff_only_enabled: true) - merge_request.update( + merge_request.update!( merge_user: merge_request.author, merge_status: :cannot_be_merged ) @@ -380,19 +380,19 @@ RSpec.describe 'Merge request > User sees merge widget', :js do end end - context 'user can merge into source project but cannot push to fork', :js do - let(:fork_project) { create(:project, :public, :repository) } + context 'user can merge into target project but cannot push to fork', :js do + let(:forked_project) { fork_project(project, nil, repository: true) } let(:user2) { create(:user) } before do project.add_maintainer(user2) sign_out(:user) sign_in(user2) - merge_request.update(target_project: fork_project) + merge_request.update!(source_project: forked_project) visit project_merge_request_path(project, merge_request) end - it 'user can merge into the source project' do + it 'user can merge into the target project', :sidekiq_inline do expect(page).to have_button('Merge', disabled: false) end @@ -409,7 +409,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do project.add_developer(user2) sign_out(:user) sign_in(user2) - merge_request.update( + merge_request.update!( source_project: forked_project, target_project: project, merge_params: { 'force_remove_source_branch' => '1' } @@ -879,7 +879,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do let!(:pipeline) { create(:ci_pipeline, status: 'success', sha: sha, project: project, ref: merge_request.source_branch) } before do - project.update( + project.update!( visibility_level: Gitlab::VisibilityLevel::PUBLIC, public_builds: false ) diff --git a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb index 56092da5136..a9fefc89d6c 100644 --- a/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb @@ -13,6 +13,7 @@ RSpec.describe 'Merge request > User sees pipelines from forked project', :js do target_project: target_project, description: 'Test merge request') end + let(:pipeline) do create(:ci_pipeline, project: forked_project, diff --git a/spec/features/merge_request/user_sees_pipelines_spec.rb b/spec/features/merge_request/user_sees_pipelines_spec.rb index d693eec91c8..5d41e49c478 100644 --- a/spec/features/merge_request/user_sees_pipelines_spec.rb +++ b/spec/features/merge_request/user_sees_pipelines_spec.rb @@ -123,14 +123,24 @@ RSpec.describe 'Merge request > User sees pipelines', :js do context 'when actor is a developer in parent project' do let(:actor) { developer_in_parent } - it 'creates a pipeline in the parent project' do + it 'creates a pipeline in the parent project when user proceeds with the warning' do visit project_merge_request_path(parent_project, merge_request) create_merge_request_pipeline + act_on_security_warning(action: 'Run Pipeline') check_pipeline(expected_project: parent_project) check_head_pipeline(expected_project: parent_project) end + + it 'does not create a pipeline in the parent project when user cancels the action' do + visit project_merge_request_path(parent_project, merge_request) + + create_merge_request_pipeline + act_on_security_warning(action: 'Cancel') + + check_no_pipelines + end end context 'when actor is a developer in fork project' do @@ -187,6 +197,19 @@ RSpec.describe 'Merge request > User sees pipelines', :js do expect(page.find('.pipeline-id')[:href]).to include(expected_project.full_path) end end + + def act_on_security_warning(action:) + page.within('#create-pipeline-for-fork-merge-request-modal') do + expect(page).to have_content('Are you sure you want to run this pipeline?') + click_button(action) + end + end + + def check_no_pipelines + page.within('.ci-table') do + expect(page).to have_selector('.commit', count: 1) + end + end end describe 'race condition' do diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index 75319c8a22d..60e054ddbee 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -5,14 +5,15 @@ require 'spec_helper' RSpec.describe 'Merge request > User sees versions', :js do let(:merge_request) do create(:merge_request).tap do |mr| - mr.merge_request_diff.destroy + mr.merge_request_diff.destroy! end end + let(:project) { merge_request.source_project } let(:user) { project.creator } - let!(:merge_request_diff1) { merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } - let!(:merge_request_diff2) { merge_request.merge_request_diffs.create(head_commit_sha: nil) } - let!(:merge_request_diff3) { merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') } + let!(:merge_request_diff1) { merge_request.merge_request_diffs.create!(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') } + let!(:merge_request_diff2) { merge_request.merge_request_diffs.create!(head_commit_sha: nil) } + let!(:merge_request_diff3) { merge_request.merge_request_diffs.create!(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') } let!(:params) { {} } before do diff --git a/spec/features/merge_request/user_sees_wip_help_message_spec.rb b/spec/features/merge_request/user_sees_wip_help_message_spec.rb index 42fe18cfc93..204df5b3995 100644 --- a/spec/features/merge_request/user_sees_wip_help_message_spec.rb +++ b/spec/features/merge_request/user_sees_wip_help_message_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe 'Merge request > User sees WIP help message' do +RSpec.describe 'Merge request > User sees draft help message' do let(:project) { create(:project, :public, :repository) } let(:user) { project.creator } @@ -11,8 +11,8 @@ RSpec.describe 'Merge request > User sees WIP help message' do sign_in(user) end - context 'with WIP commits' do - it 'shows a specific WIP hint' do + context 'with draft commits' do + it 'shows a specific draft hint' do visit project_new_merge_request_path( project, merge_request: { @@ -24,14 +24,14 @@ RSpec.describe 'Merge request > User sees WIP help message' do within_wip_explanation do expect(page).to have_text( - 'It looks like you have some WIP commits in this branch' + 'It looks like you have some draft commits in this branch' ) end end end - context 'without WIP commits' do - it 'shows the regular WIP message' do + context 'without draft commits' do + it 'shows the regular draft message' do visit project_new_merge_request_path( project, merge_request: { @@ -43,11 +43,11 @@ RSpec.describe 'Merge request > User sees WIP help message' do within_wip_explanation do expect(page).not_to have_text( - 'It looks like you have some WIP commits in this branch' + 'It looks like you have some draft commits in this branch' ) expect(page).to have_text( - "Start the title with WIP: to prevent a Work In Progress merge \ -request from being merged before it's ready" + "Start the title with Draft: or WIP: to prevent a merge request that is a \ +work in progress from being merged before it's ready." ) end end diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb index 0506d190487..39495832547 100644 --- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb +++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb @@ -22,6 +22,7 @@ RSpec.describe 'User comments on a diff', :js do let(:merge_request) do create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') end + let(:user) { create(:user) } before do diff --git a/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb index b864cb55785..96a1cd81c93 100644 --- a/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb +++ b/spec/features/merge_request/user_tries_to_access_private_project_info_through_new_mr_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Merge Request > User tries to access private project information name: 'nothing to see here', repository_access_level: ProjectFeature::PRIVATE) end + let(:owned_project) do create(:project, :public, :repository, namespace: current_user.namespace, diff --git a/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb b/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb new file mode 100644 index 00000000000..20a5910e66d --- /dev/null +++ b/spec/features/merge_request/user_views_auto_expanding_diff_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User views diffs file-by-file', :js do + let(:merge_request) do + create(:merge_request, source_branch: 'squash-large-files', source_project: project, target_project: project) + end + + let(:project) { create(:project, :repository) } + let(:user) { create(:user, view_diffs_file_by_file: true) } + + before do + allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes) + allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes) + + project.add_developer(user) + + sign_in(user) + + visit(diffs_project_merge_request_path(project, merge_request, anchor: '5091f7b9dd6202e37eaedd73d7b75d82f25fdb61')) + + wait_for_requests + end + + it 'shows diffs file-by-file' do + page.within('#diffs') do + expect(page).not_to have_content('This diff is collapsed') + + click_button 'Next' + + expect(page).not_to have_content('This diff is collapsed') + end + end +end diff --git a/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb b/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb index c254a142349..abb313cb529 100644 --- a/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb +++ b/spec/features/merge_request/user_views_diffs_file_by_file_spec.rb @@ -6,6 +6,7 @@ RSpec.describe 'User views diffs file-by-file', :js do let(:merge_request) do create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') end + let(:project) { create(:project, :repository) } let(:user) { create(:user, view_diffs_file_by_file: true) } diff --git a/spec/features/merge_request/user_views_diffs_spec.rb b/spec/features/merge_request/user_views_diffs_spec.rb index 14d10fc1c9f..537c0473fa4 100644 --- a/spec/features/merge_request/user_views_diffs_spec.rb +++ b/spec/features/merge_request/user_views_diffs_spec.rb @@ -6,6 +6,7 @@ RSpec.describe 'User views diffs', :js do let(:merge_request) do create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') end + let(:project) { create(:project, :public, :repository) } let(:view) { 'inline' } diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb index df94fe2cbd0..179bf84a729 100644 --- a/spec/features/merge_requests/user_mass_updates_spec.rb +++ b/spec/features/merge_requests/user_mass_updates_spec.rb @@ -37,6 +37,15 @@ RSpec.describe 'Merge requests > User mass updates', :js do expect(page).to have_selector('.merge-request', count: 0) end end + + it 'does not exist in merged state' do + merge_request.close + visit project_merge_requests_path(project, state: 'merged') + + click_button 'Edit merge requests' + + expect(page).not_to have_css('.js-issue-status') + end end context 'assignee' do @@ -86,7 +95,7 @@ RSpec.describe 'Merge requests > User mass updates', :js do describe 'unset milestone' do before do merge_request.milestone = milestone - merge_request.save + merge_request.save! visit project_merge_requests_path(project) end diff --git a/spec/features/merge_requests/user_views_diffs_commit_spec.rb b/spec/features/merge_requests/user_views_diffs_commit_spec.rb new file mode 100644 index 00000000000..fcaabf9b0e7 --- /dev/null +++ b/spec/features/merge_requests/user_views_diffs_commit_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User views diff by commit', :js do + let(:merge_request) do + create(:merge_request_with_diffs, source_project: project, target_project: project, source_branch: 'merge-test') + end + + let(:project) { create(:project, :public, :repository) } + + before do + stub_feature_flags(diffs_batch_load: false) + visit(diffs_project_merge_request_path(project, merge_request, commit_id: merge_request.diff_head_sha)) + end + + it 'shows full commit description by default' do + expect(page).to have_selector('.commit-row-description', visible: true) + end +end diff --git a/spec/features/populate_new_pipeline_vars_with_params_spec.rb b/spec/features/populate_new_pipeline_vars_with_params_spec.rb index f931e8497fc..37fea5331a3 100644 --- a/spec/features/populate_new_pipeline_vars_with_params_spec.rb +++ b/spec/features/populate_new_pipeline_vars_with_params_spec.rb @@ -8,6 +8,7 @@ RSpec.describe "Populate new pipeline CI variables with url params", :js do let(:page_path) { new_project_pipeline_path(project) } before do + stub_feature_flags(new_pipeline_form: false) sign_in(user) project.add_maintainer(user) diff --git a/spec/features/profiles/chat_names_spec.rb b/spec/features/profiles/chat_names_spec.rb index 80b36aa37b8..ca888018cad 100644 --- a/spec/features/profiles/chat_names_spec.rb +++ b/spec/features/profiles/chat_names_spec.rb @@ -14,6 +14,7 @@ RSpec.describe 'Profile > Chat' do let(:params) do { team_id: 'T00', team_domain: 'my_chat_team', user_id: 'U01', user_name: 'my_chat_user' } end + let!(:authorize_url) { ChatNames::AuthorizeUserService.new(service, params).execute } let(:authorize_path) { URI.parse(authorize_url).request_uri } diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb index a274f2b6d96..039966080d8 100644 --- a/spec/features/profiles/password_spec.rb +++ b/spec/features/profiles/password_spec.rb @@ -42,7 +42,7 @@ RSpec.describe 'Profile > Password' do fill_passwords('mypassword', 'mypassword') page.within('.flash-notice') do - expect(page).to have_content('Password was successfully updated. Please login with it') + expect(page).to have_content('Password was successfully updated. Please sign in again.') end end end diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 21a0d01a9bf..4438831fb76 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -100,14 +100,11 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do context "when revocation fails" do it "displays an error message" do visit profile_personal_access_tokens_path - allow_any_instance_of(PersonalAccessToken).to receive(:update!).and_return(false) - - errors = ActiveModel::Errors.new(PersonalAccessToken.new).tap { |e| e.add(:name, "cannot be nil") } - allow_any_instance_of(PersonalAccessToken).to receive(:errors).and_return(errors) + allow_any_instance_of(PersonalAccessTokens::RevokeService).to receive(:revocation_permitted?).and_return(false) accept_confirm { click_on "Revoke" } expect(active_personal_access_tokens).to have_text(personal_access_token.name) - expect(page).to have_content("Could not revoke") + expect(page).to have_content("Not permitted to revoke") end end end diff --git a/spec/features/profiles/user_edit_preferences_spec.rb b/spec/features/profiles/user_edit_preferences_spec.rb index 817228edca7..d489d92c524 100644 --- a/spec/features/profiles/user_edit_preferences_spec.rb +++ b/spec/features/profiles/user_edit_preferences_spec.rb @@ -64,7 +64,7 @@ RSpec.describe 'User edit preferences profile' do expect(page).to have_select( 'user[preferred_language]', selected: 'Spanish - español', - options: Gitlab::I18n::AVAILABLE_LANGUAGES.values, + options: Gitlab::I18n.selectable_locales.values, visible: :all ) end diff --git a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb index 2747b5894dc..56db7efff51 100644 --- a/spec/features/profiles/user_visits_profile_preferences_page_spec.rb +++ b/spec/features/profiles/user_visits_profile_preferences_page_spec.rb @@ -76,13 +76,13 @@ RSpec.describe 'User visits the profile preferences page' do it 'updates their preference' do wait_for_requests - select2('eo', from: '#user_preferred_language') + select2('pt_BR', from: '#user_preferred_language') click_button 'Save' wait_for_requests refresh - expect(page).to have_css('html[lang="eo"]') + expect(page).to have_css('html[lang="pt-BR"]') end end diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index 4c144037acd..1760ec880bc 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -63,7 +63,7 @@ RSpec.describe 'test coverage badge' do create(:ci_pipeline, opts).tap do |pipeline| yield pipeline - pipeline.update_legacy_status + ::Ci::ProcessPipelineService.new(pipeline).execute end end diff --git a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb index 6bd6634822c..a65a82fab43 100644 --- a/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb +++ b/spec/features/projects/blobs/blob_line_permalink_updater_spec.rb @@ -50,7 +50,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do visit_blob find("##{ending_fragment}").hover - find("##{ending_fragment} i").click + find("##{ending_fragment} svg").click expect(find('.js-data-file-blob-permalink-url')['href']).to eq(get_absolute_url(project_blob_path(project, tree_join(sha, path), anchor: ending_fragment))) end @@ -100,7 +100,7 @@ RSpec.describe 'Blob button line permalinks (BlobLinePermalinkUpdater)', :js do visit_blob find("##{ending_fragment}").hover - find("##{ending_fragment} i").click + find("##{ending_fragment} svg").click expect(find('.js-blob-blame-link')['href']).to eq(get_absolute_url(project_blame_path(project, tree_join('master', path), anchor: ending_fragment))) end diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb index f3845bb8dec..ba063acbe70 100644 --- a/spec/features/projects/ci/lint_spec.rb +++ b/spec/features/projects/ci/lint_spec.rb @@ -21,32 +21,48 @@ RSpec.describe 'CI Lint', :js do end describe 'YAML parsing' do - before do - click_on 'Validate' - end + shared_examples 'validates the YAML' do + before do + click_on 'Validate' + end - context 'YAML is correct' do - let(:yaml_content) do - File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + context 'YAML is correct' do + let(:yaml_content) do + File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + end + + it 'parses Yaml and displays the jobs' do + expect(page).to have_content('Status: syntax is correct') + + within "table" do + aggregate_failures do + expect(page).to have_content('Job - rspec') + expect(page).to have_content('Job - spinach') + expect(page).to have_content('Deploy Job - staging') + expect(page).to have_content('Deploy Job - production') + end + end + end end - it 'parses Yaml' do - within "table" do - expect(page).to have_content('Job - rspec') - expect(page).to have_content('Job - spinach') - expect(page).to have_content('Deploy Job - staging') - expect(page).to have_content('Deploy Job - production') + context 'YAML is incorrect' do + let(:yaml_content) { 'value: cannot have :' } + + it 'displays information about an error' do + expect(page).to have_content('Status: syntax is incorrect') + expect(page).to have_selector('.ace_content', text: yaml_content) end end end - context 'YAML is incorrect' do - let(:yaml_content) { 'value: cannot have :' } + it_behaves_like 'validates the YAML' - it 'displays information about an error' do - expect(page).to have_content('Status: syntax is incorrect') - expect(page).to have_selector('.ace_content', text: yaml_content) + context 'when Dry Run is checked' do + before do + check 'Simulate a pipeline created for the default branch' end + + it_behaves_like 'validates the YAML' end describe 'YAML revalidate' do diff --git a/spec/features/projects/classification_label_on_project_pages_spec.rb b/spec/features/projects/classification_label_on_project_pages_spec.rb index 0f07ca7635b..9522e5ce2cf 100644 --- a/spec/features/projects/classification_label_on_project_pages_spec.rb +++ b/spec/features/projects/classification_label_on_project_pages_spec.rb @@ -6,6 +6,7 @@ RSpec.describe 'Classification label on project pages' do let(:project) do create(:project, external_authorization_classification_label: 'authorized label') end + let(:user) { create(:user) } before do diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 2e6a366f77a..63e5546b43c 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -205,11 +205,10 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do let(:admin) { create(:admin) } before do - stub_feature_flags(instance_level_integrations: false) stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) - visit integrations_admin_application_settings_path + visit general_admin_application_settings_path end it 'user does not see the offer' do diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index 15fed0c2727..450eaa7f004 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -73,6 +73,7 @@ RSpec.describe 'User Cluster', :js do end it 'user sees a cluster details page' do + expect(page).to have_content('GitLab Integration') expect(page).to have_button('Save changes') end diff --git a/spec/features/projects/commit/diff_notes_spec.rb b/spec/features/projects/commit/diff_notes_spec.rb index ff86047d812..6cebff1cc9a 100644 --- a/spec/features/projects/commit/diff_notes_spec.rb +++ b/spec/features/projects/commit/diff_notes_spec.rb @@ -8,30 +8,35 @@ RSpec.describe 'Commit diff', :js do let(:user) { create(:user) } let(:project) { create(:project, :public, :repository) } - before do - project.add_maintainer(user) - sign_in user + using RSpec::Parameterized::TableSyntax + + where(:view, :async_diff_file_loading) do + 'inline' | true + 'inline' | false + 'parallel' | true + 'parallel' | false end - %w(inline parallel).each do |view| - context "#{view} view" do - before do - visit project_commit_path(project, sample_commit.id, view: view) - end + with_them do + before do + stub_feature_flags(async_commit_diff_files: async_diff_file_loading) + project.add_maintainer(user) + sign_in user + visit project_commit_path(project, sample_commit.id, view: view) + end - it "adds comment to diff" do - diff_line_num = first('.diff-line-num.new') + it "adds comment to diff" do + diff_line_num = first('.diff-line-num.new') - diff_line_num.hover - diff_line_num.find('.js-add-diff-note-button').click + diff_line_num.hover + diff_line_num.find('.js-add-diff-note-button').click - page.within(first('.diff-viewer')) do - find('.js-note-text').set 'test comment' + page.within(first('.diff-viewer')) do + find('.js-note-text').set 'test comment' - click_button 'Comment' + click_button 'Comment' - expect(page).to have_content('test comment') - end + expect(page).to have_content('test comment') end end end diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb index 9349f36282d..7bd3bce85d5 100644 --- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb +++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb @@ -12,6 +12,7 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do ref: project.default_branch, sha: project.commit.sha) end + let(:build) { create(:ci_build, pipeline: pipeline) } it 'display icon with status' do @@ -25,6 +26,8 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do build.run visit project_commit_path(project, project.commit.id) + wait_for_all_requests + expect(page).to have_selector('.mr-widget-pipeline-graph') first('.mini-pipeline-graph-dropdown-toggle').click 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 71405cf917d..89ff2f4b26d 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 @@ -30,7 +30,7 @@ RSpec.describe 'Project > Commit > View user status' do end end - describe 'status for a diff note on the commit' do + describe 'status for a diff note on the commit', :js do let(:note) { create(:diff_note_on_commit, project: project) } it_behaves_like 'showing user status' do diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb index dee964005a4..596b4773716 100644 --- a/spec/features/projects/commits/user_browses_commits_spec.rb +++ b/spec/features/projects/commits/user_browses_commits_spec.rb @@ -41,7 +41,7 @@ RSpec.describe 'User browses commits' do .and have_selector('ul.breadcrumb a', count: 4) end - it 'renders diff links to both the previous and current image' do + it 'renders diff links to both the previous and current image', :js do visit project_commit_path(project, sample_image_commit.id) links = page.all('.file-actions a') diff --git a/spec/features/projects/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb index c72f88205b5..8315c821b6d 100644 --- a/spec/features/projects/environments/environment_metrics_spec.rb +++ b/spec/features/projects/environments/environment_metrics_spec.rb @@ -28,9 +28,8 @@ RSpec.describe 'Environment > Metrics' do shared_examples 'has environment selector' do it 'has a working environment selector', :js do click_link('See metrics') - # TODO: See metrics on the sidebar still points to the old metrics URL - # https://gitlab.com/gitlab-org/gitlab/-/issues/229277 - expect(page).to have_current_path(metrics_project_environment_path(project, id: environment.id)) + + expect(page).to have_current_path(project_metrics_dashboard_path(project, environment: environment.id)) expect(page).to have_css('[data-qa-selector="environments_dropdown"]') within('[data-qa-selector="environments_dropdown"]') do diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index b3f671d57a9..a05910cd892 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -37,7 +37,7 @@ RSpec.describe 'Environments page', :js do expect(page).to have_css('.environments-container') expect(page.all('.environment-name').length).to eq(1) - expect(page.all('.ic-stop').length).to eq(1) + expect(page.all('[data-testid="stop-icon"]').length).to eq(1) end end diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index d84c39de8d8..8d3ca9d9fd1 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -186,7 +186,7 @@ RSpec.describe 'Edit Project Settings' do click_button "Save changes" end - expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 3) + expect(find(".sharing-permissions")).to have_selector(".project-feature-toggle.is-disabled", count: 4) end it "shows empty features project homepage" do diff --git a/spec/features/projects/files/user_browses_files_spec.rb b/spec/features/projects/files/user_browses_files_spec.rb index e5259bd88be..a6126fbcb33 100644 --- a/spec/features/projects/files/user_browses_files_spec.rb +++ b/spec/features/projects/files/user_browses_files_spec.rb @@ -9,6 +9,7 @@ RSpec.describe "User browses files" do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end + let(:project) { create(:project, :repository, name: "Shop") } let(:project2) { create(:project, :repository, name: "Another Project", path: "another-project") } let(:tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } diff --git a/spec/features/projects/files/user_creates_directory_spec.rb b/spec/features/projects/files/user_creates_directory_spec.rb index 47c5d667f4f..f2074c78dba 100644 --- a/spec/features/projects/files/user_creates_directory_spec.rb +++ b/spec/features/projects/files/user_creates_directory_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Projects > Files > User creates a directory', :js do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end + let(:project) { create(:project, :repository) } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb index 5abc048c135..39bc139656b 100644 --- a/spec/features/projects/files/user_creates_files_spec.rb +++ b/spec/features/projects/files/user_creates_files_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Projects > Files > User creates files', :js do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } diff --git a/spec/features/projects/files/user_deletes_files_spec.rb b/spec/features/projects/files/user_deletes_files_spec.rb index 4df23b852ff..b6e300e9e59 100644 --- a/spec/features/projects/files/user_deletes_files_spec.rb +++ b/spec/features/projects/files/user_deletes_files_spec.rb @@ -7,6 +7,7 @@ RSpec.describe 'Projects > Files > User deletes files', :js do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } diff --git a/spec/features/projects/files/user_replaces_files_spec.rb b/spec/features/projects/files/user_replaces_files_spec.rb index b11cf732c95..c9b472260bd 100644 --- a/spec/features/projects/files/user_replaces_files_spec.rb +++ b/spec/features/projects/files/user_replaces_files_spec.rb @@ -9,6 +9,7 @@ RSpec.describe 'Projects > Files > User replaces files', :js do "You're not allowed to make changes to this project directly. "\ "A fork of this project has been created that you can make changes in, so you can submit a merge request." end + let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index f0ed4013230..1e84d1552a1 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Project fork' do it 'allows user to fork project' do visit project_path(project) - expect(page).not_to have_css('a.disabled', text: 'Fork') + expect(page).not_to have_css('a.disabled', text: 'Select') end it 'disables fork button when user has exceeded project limit' do @@ -40,7 +40,7 @@ RSpec.describe 'Project fork' do visit project_path(project) expect(page).to have_css('a', text: 'Fork') - expect(page).not_to have_css('a.disabled', text: 'Fork') + expect(page).not_to have_css('a.disabled', text: 'Select') end it 'renders new project fork page' do @@ -116,7 +116,7 @@ RSpec.describe 'Project fork' do click_link 'Fork' page.within '.fork-thumbnail-container' do - click_link user.name + click_link 'Select' end expect(page).to have_content 'Forked from' @@ -156,7 +156,7 @@ RSpec.describe 'Project fork' do click_link 'Fork' page.within '.fork-thumbnail-container' do - click_link user.name + click_link 'Select' end visit project_forks_path(project) @@ -193,7 +193,7 @@ RSpec.describe 'Project fork' do click_link 'Fork' page.within '.fork-thumbnail-container' do - click_link user.name + click_link 'Select' end visit project_forks_path(project) @@ -218,7 +218,7 @@ RSpec.describe 'Project fork' do click_link 'Fork' page.within '.fork-thumbnail-container' do - click_link user.name + click_link 'Select' end expect(page).to have_content "Name has already been taken" @@ -232,39 +232,43 @@ RSpec.describe 'Project fork' do group.add_maintainer(user) end - it 'allows user to fork project to group or to user namespace' do + it 'allows user to fork project to group or to user namespace', :js do visit project_path(project) + wait_for_requests expect(page).not_to have_css('a.disabled', text: 'Fork') click_link 'Fork' - expect(page).to have_css('.fork-thumbnail', count: 2) + expect(page).to have_css('.fork-thumbnail') + expect(page).to have_css('.group-row') expect(page).not_to have_css('.fork-thumbnail.disabled') end - it 'allows user to fork project to group and not user when exceeded project limit' do + it 'allows user to fork project to group and not user when exceeded project limit', :js do user.projects_limit = 0 user.save! visit project_path(project) + wait_for_requests expect(page).not_to have_css('a.disabled', text: 'Fork') click_link 'Fork' - expect(page).to have_css('.fork-thumbnail', count: 2) expect(page).to have_css('.fork-thumbnail.disabled') + expect(page).to have_css('.group-row') end - it 'links to the fork if the project was already forked within that namespace', :sidekiq_might_not_need_inline do + it 'links to the fork if the project was already forked within that namespace', :sidekiq_might_not_need_inline, :js do forked_project = fork_project(project, user, namespace: group, repository: true) visit new_project_fork_path(project) + wait_for_requests - expect(page).to have_css('div.forked', text: group.full_name) + expect(page).to have_css('.group-row a.btn', text: 'Go to fork') - click_link group.full_name + click_link 'Go to fork' expect(current_path).to eq(project_path(forked_project)) end diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 86aeb2bc80c..7f8ded4fa43 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -19,6 +19,7 @@ RSpec.describe 'Import/Export - project export integration test', :js do key: [Project, Ci::Variable, :yaml_variables] } end + let(:safe_hashes) { { yaml_variables: %w[key value public] } } let(:project) { setup_project } diff --git a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb index 8070fee5804..29a27992a0d 100644 --- a/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb +++ b/spec/features/projects/issues/design_management/user_uploads_designs_spec.rb @@ -5,9 +5,9 @@ require 'spec_helper' RSpec.describe 'User uploads new design', :js do include DesignManagementTestHelpers - let_it_be(:project) { create(:project_empty_repo, :public) } - let_it_be(:user) { project.owner } - let_it_be(:issue) { create(:issue, project: project) } + let(:project) { create(:project_empty_repo, :public) } + let(:user) { project.owner } + let(:issue) { create(:issue, project: project) } before do sign_in(user) @@ -28,7 +28,7 @@ RSpec.describe 'User uploads new design', :js do let(:feature_enabled) { true } it 'uploads designs' do - attach_file(:design_file, logo_fixture, make_visible: true) + upload_design(logo_fixture, count: 1) expect(page).to have_selector('.js-design-list-item', count: 1) @@ -36,9 +36,12 @@ RSpec.describe 'User uploads new design', :js do expect(page).to have_content('dk.png') end - attach_file(:design_file, gif_fixture, make_visible: true) + upload_design(gif_fixture, count: 2) + # Known bug in the legacy implementation: new designs are inserted + # in the beginning on the frontend. expect(page).to have_selector('.js-design-list-item', count: 2) + expect(page.all('.js-design-list-item').map(&:text)).to eq(['banana_sample.gif', 'dk.png']) end end @@ -61,8 +64,8 @@ RSpec.describe 'User uploads new design', :js do context "when the feature is available" do let(:feature_enabled) { true } - it 'uploads designs', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/225616' do - attach_file(:design_file, logo_fixture, make_visible: true) + it 'uploads designs' do + upload_design(logo_fixture, count: 1) expect(page).to have_selector('.js-design-list-item', count: 1) @@ -70,9 +73,10 @@ RSpec.describe 'User uploads new design', :js do expect(page).to have_content('dk.png') end - attach_file(:design_file, gif_fixture, make_visible: true) + upload_design(gif_fixture, count: 2) expect(page).to have_selector('.js-design-list-item', count: 2) + expect(page.all('.js-design-list-item').map(&:text)).to eq(['dk.png', 'banana_sample.gif']) end end @@ -92,4 +96,12 @@ RSpec.describe 'User uploads new design', :js do def gif_fixture Rails.root.join('spec', 'fixtures', 'banana_sample.gif') end + + def upload_design(fixture, count:) + attach_file(:design_file, fixture, match: :first, make_visible: true) + + wait_for('designs uploaded') do + issue.reload.designs.count == count + end + end end diff --git a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb index 6feefff9207..b423543dc33 100644 --- a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb +++ b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb @@ -11,33 +11,39 @@ RSpec.describe 'viewing an issue with cross project references' do create(:project, :public, external_authorization_classification_label: 'other_label') end + let(:other_issue) do create(:issue, :closed, title: 'I am in another project', project: other_project) end + let(:other_confidential_issue) do create(:issue, :confidential, :closed, title: 'I am in another project and confidential', project: other_project) end + let(:other_merge_request) do create(:merge_request, :closed, title: 'I am a merge request in another project', source_project: other_project) end + let(:description_referencing_other_issue) do "Referencing: #{other_issue.to_reference(project)}, "\ "a confidential issue #{confidential_issue.to_reference}, "\ "a cross project confidential issue #{other_confidential_issue.to_reference(project)}, and "\ "a cross project merge request #{other_merge_request.to_reference(project)}" end + let(:project) { create(:project) } let(:issue) do create(:issue, project: project, description: description_referencing_other_issue ) end + let(:confidential_issue) do create(:issue, :confidential, :closed, title: "I am in the same project and confidential", diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index 67299e852b3..b935b99642b 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -26,7 +26,7 @@ RSpec.describe 'User browses a job', :js do # scroll to the top of the page first execute_script "window.scrollTo(0,0)" - accept_confirm { find('.js-erase-link').click } + accept_confirm { find('[data-testid="job-log-erase-link"]').click } expect(page).to have_no_css('.artifacts') expect(build).not_to have_trace diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index fc005dd4718..0a6f204454e 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -282,7 +282,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do href = new_project_issue_path(project, options) page.within('.build-sidebar') do - expect(find('.js-new-issue')['href']).to include(href) + expect(find('[data-testid="job-new-issue"]')['href']).to include(href) end end end @@ -425,7 +425,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do it do wait_for_all_requests - expect(page).to have_css('.js-raw-link-controller') + expect(page).to have_css('[data-testid="job-raw-link-controller"]') end end @@ -875,7 +875,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - page.within('.js-job-erased-block') do + page.within('[data-testid="job-erased-block"]') do expect(page).to have_content('Job has been erased') end end @@ -888,7 +888,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).not_to have_css('.js-job-erased-block') + expect(page).not_to have_css('[data-testid="job-erased-block"]') end end @@ -901,8 +901,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).to have_css('.js-job-sidebar.right-sidebar-collapsed', visible: false) - expect(page).not_to have_css('.js-job-sidebar.right-sidebar-expanded', visible: false) + expect(page).to have_css('[data-testid="job-sidebar"].right-sidebar-collapsed', visible: false) + expect(page).not_to have_css('[data-testid="job-sidebar"].right-sidebar-expanded', visible: false) end end @@ -913,8 +913,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do visit project_job_path(project, job) wait_for_requests - expect(page).to have_css('.js-job-sidebar.right-sidebar-expanded') - expect(page).not_to have_css('.js-job-sidebar.right-sidebar-collapsed') + expect(page).to have_css('[data-testid="job-sidebar"].right-sidebar-expanded') + expect(page).not_to have_css('[data-testid="job-sidebar"].right-sidebar-collapsed') end end @@ -929,7 +929,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) } it 'renders message about job being stuck because no runners are active' do - expect(page).to have_css('.js-stuck-no-active-runner') + expect(page).to have_selector('[data-testid="job-stuck-no-active-runners"]') expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.") end end @@ -939,7 +939,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) } it 'renders message about job being stuck because of no runners with the specified tags' do - expect(page).to have_css('.js-stuck-with-tags') + expect(page).to have_selector('[data-testid="job-stuck-with-tags"') expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:") end end @@ -949,7 +949,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner, tag_list: %w(docker linux)) } it 'renders message about job being stuck because of no runners with the specified tags' do - expect(page).to have_css('.js-stuck-with-tags') + expect(page).to have_selector('[data-testid="job-stuck-with-tags"') expect(page).to have_content("This job is stuck because you don't have any active runners online or available with any of these tags assigned to them:") end end @@ -957,8 +957,8 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do context 'without any runners available' do let(:job) { create(:ci_build, :pending, pipeline: pipeline) } - it 'renders message about job being stuck because not runners are available' do - expect(page).to have_css('.js-stuck-no-active-runner') + it 'renders message about job being stuck because no runners are available' do + expect(page).to have_selector('[data-testid="job-stuck-no-active-runners"]') expect(page).to have_content("This job is stuck because you don't have any active runners that can run this job.") end end @@ -968,7 +968,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) } it 'renders message about job being stuck because runners are offline' do - expect(page).to have_css('.js-stuck-no-runners') + expect(page).to have_selector('[data-testid="job-stuck-no-runners"') expect(page).to have_content("This job is stuck because the project doesn't have any runners online assigned to it.") end end diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index 56b807e08d7..b32ccb0ccef 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -65,7 +65,7 @@ RSpec.describe 'Project members list' do visit_members_page # Open modal - find(:css, 'li.project_member', text: other_user.name).find(:css, 'button.btn-remove').click + find(:css, 'li.project_member', text: other_user.name).find(:css, 'button.btn-danger').click expect(page).to have_unchecked_field 'Also unassign this user from related issues and merge requests' diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index 4c3eaa93352..2fdc75dca91 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Projects > Members > Maintainer manages access requests' do it_behaves_like 'Maintainer manages access requests' do + let(:has_tabs) { false } let(:entity) { create(:project, :public) } let(:members_page_path) { project_project_members_path(entity) } end diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 22cd832ff06..dcb901bcf11 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -12,6 +12,10 @@ RSpec.describe 'Project navbar' do let_it_be(:project) { create(:project, :repository) } before do + stub_feature_flags(project_iterations: false) + + insert_package_nav(_('Operations')) + project.add_maintainer(user) sign_in(user) end @@ -58,13 +62,8 @@ RSpec.describe 'Project navbar' do before do stub_config(registry: { enabled: true }) - insert_after_nav_item( - _('Operations'), - new_nav_item: { - nav_item: _('Packages & Registries'), - nav_sub_items: [_('Container Registry')] - } - ) + insert_container_nav(_('Operations')) + visit project_path(project) end diff --git a/spec/features/projects/package_files_spec.rb b/spec/features/projects/package_files_spec.rb new file mode 100644 index 00000000000..bea9a9929b9 --- /dev/null +++ b/spec/features/projects/package_files_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'PackageFiles' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let!(:package) { create(:maven_package, project: project) } + let!(:package_file) { package.package_files.first } + + before do + sign_in(user) + end + + context 'user with master role' do + before do + project.add_maintainer(user) + end + + it 'allows direct download by url' do + visit download_project_package_file_path(project, package_file) + + expect(status_code).to eq(200) + end + + it 'renders the download link with the correct url', :js do + visit project_package_path(project, package) + + download_url = download_project_package_file_path(project, package_file) + + expect(page).to have_link(package_file.file_name, href: download_url) + end + + it 'does not allow download of package belonging to different project' do + another_package = create(:maven_package) + another_file = another_package.package_files.first + + visit download_project_package_file_path(project, another_file) + + expect(status_code).to eq(404) + end + end + + it 'does not allow direct download when no access to the project' do + visit download_project_package_file_path(project, package_file) + + expect(status_code).to eq(404) + end + + it 'gives 404 when no package file exist' do + visit download_project_package_file_path(project, non_existing_record_id) + + expect(status_code).to eq(404) + end +end diff --git a/spec/features/projects/packages_spec.rb b/spec/features/projects/packages_spec.rb new file mode 100644 index 00000000000..e5c684bdff5 --- /dev/null +++ b/spec/features/projects/packages_spec.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Packages' do + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project) } + + before do + sign_in(user) + project.add_maintainer(user) + end + + context 'when feature is not available' do + context 'packages feature is disabled by config' do + before do + allow(Gitlab.config.packages).to receive(:enabled).and_return(false) + end + + it 'gives 404' do + visit_project_packages + + expect(status_code).to eq(404) + end + end + end + + context 'when feature is available', :js do + before do + visit_project_packages + end + + context 'when there are packages' do + let_it_be(:conan_package) { create(:conan_package, project: project, name: 'zzz', created_at: 1.day.ago, version: '1.0.0') } + let_it_be(:maven_package) { create(:maven_package, project: project, name: 'aaa', created_at: 2.days.ago, version: '2.0.0') } + let_it_be(:packages) { [conan_package, maven_package] } + + it_behaves_like 'packages list' + + it_behaves_like 'package details link' + + context 'deleting a package' do + let_it_be(:project) { create(:project) } + let_it_be(:package) { create(:package, project: project) } + + it 'allows you to delete a package' do + first('[title="Remove package"]').click + click_button('Delete package') + + expect(page).to have_content 'Package deleted successfully' + expect(page).not_to have_content(package.name) + end + end + + it_behaves_like 'shared package sorting' do + let_it_be(:package_one) { maven_package } + let_it_be(:package_two) { conan_package } + end + end + + it_behaves_like 'when there are no packages' + end + + def visit_project_packages + visit project_packages_path(project) + end +end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 2ca584ab8f6..26c46190e7d 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -137,6 +137,7 @@ RSpec.describe 'Pipeline', :js do source_project: project, source_branch: pipeline.ref) end + let!(:merge_request2) do create(:merge_request, source_project: project, @@ -363,66 +364,29 @@ RSpec.describe 'Pipeline', :js do describe 'test tabs' do let(:pipeline) { create(:ci_pipeline, :with_test_reports, :with_report_results, project: project) } - context 'with build_report_summary feature flag disabled' do - before do - stub_feature_flags(build_report_summary: false) - visit_pipeline - wait_for_requests - end - - context 'with test reports' do - it 'shows badge counter in Tests tab' do - expect(pipeline.test_reports.total_count).to eq(4) - expect(page.find('.js-test-report-badge-counter').text).to eq(pipeline.test_reports.total_count.to_s) - end - - it 'does not call test_report.json endpoint by default', :js do - expect(page).to have_selector('.js-no-tests-to-show', visible: :all) - end - - it 'does call test_report.json endpoint when tab is selected', :js do - find('.js-tests-tab-link').click - wait_for_requests - - expect(page).to have_content('Jobs') - expect(page).to have_selector('.js-tests-detail', visible: :all) - end - end - - context 'without test reports' do - let(:pipeline) { create(:ci_pipeline, project: project) } - - it 'shows zero' do - expect(page.find('.js-test-report-badge-counter', visible: :all).text).to eq("0") - end - end + before do + visit_pipeline + wait_for_requests end - context 'with build_report_summary feature flag enabled' do - before do - visit_pipeline - wait_for_requests + context 'with test reports' do + it 'shows badge counter in Tests tab' do + expect(page.find('.js-test-report-badge-counter').text).to eq(pipeline.test_report_summary.total[:count].to_s) end - context 'with test reports' do - it 'shows badge counter in Tests tab' do - expect(page.find('.js-test-report-badge-counter').text).to eq(pipeline.test_report_summary.total_count.to_s) - end - - it 'calls summary.json endpoint', :js do - find('.js-tests-tab-link').click + it 'calls summary.json endpoint', :js do + find('.js-tests-tab-link').click - expect(page).to have_content('Jobs') - expect(page).to have_selector('.js-tests-detail', visible: :all) - end + expect(page).to have_content('Jobs') + expect(page).to have_selector('.js-tests-detail', visible: :all) end + end - context 'without test reports' do - let(:pipeline) { create(:ci_pipeline, project: project) } + context 'without test reports' do + let(:pipeline) { create(:ci_pipeline, project: project) } - it 'shows zero' do - expect(page.find('.js-test-report-badge-counter', visible: :all).text).to eq("0") - end + it 'shows zero' do + expect(page.find('.js-test-report-badge-counter', visible: :all).text).to eq("0") end end end @@ -436,7 +400,7 @@ RSpec.describe 'Pipeline', :js do context 'when retrying' do before do - find('.js-retry-button').click + find('[data-testid="retryButton"]').click end it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do @@ -938,7 +902,7 @@ RSpec.describe 'Pipeline', :js do context 'when retrying' do before do - find('.js-retry-button').click + find('[data-testid="retryButton"]').click end it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 0eb92f3e679..8747b3ab54c 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -652,6 +652,7 @@ 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 @@ -718,6 +719,7 @@ 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 diff --git a/spec/features/projects/product_analytics/events_spec.rb b/spec/features/projects/product_analytics/events_spec.rb new file mode 100644 index 00000000000..12f1c4d291a --- /dev/null +++ b/spec/features/projects/product_analytics/events_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +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 + project.add_maintainer(user) + sign_in(user) + end + + it 'shows no events message' do + visit(project_product_analytics_path(project)) + + expect(page).to have_content('There are currently no events') + end + + it 'shows events' do + event + + visit(project_product_analytics_path(project)) + + expect(page).to have_content('dvce_created_tstamp') + expect(page).to have_content(event.event_id) + end +end diff --git a/spec/features/projects/product_analytics/graphs_spec.rb b/spec/features/projects/product_analytics/graphs_spec.rb new file mode 100644 index 00000000000..e2293893589 --- /dev/null +++ b/spec/features/projects/product_analytics/graphs_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Product Analytics > Graphs' do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + before do + project.add_maintainer(user) + sign_in(user) + end + + it 'shows graphs', :js do + create(:product_analytics_event, project: project) + + visit(graphs_project_product_analytics_path(project)) + + expect(page).to have_content('Showing graphs based on events') + expect(page).to have_content('platform') + expect(page).to have_content('os_timezone') + expect(page).to have_content('br_lang') + expect(page).to have_content('doc_charset') + end +end diff --git a/spec/features/projects/product_analytics/setup_spec.rb b/spec/features/projects/product_analytics/setup_spec.rb new file mode 100644 index 00000000000..45c2b67502c --- /dev/null +++ b/spec/features/projects/product_analytics/setup_spec.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Product Analytics > Setup' do + let_it_be(:project) { create(:project_empty_repo) } + let_it_be(:user) { create(:user) } + + before do + project.add_maintainer(user) + sign_in(user) + end + + it 'shows the setup instructions' do + visit(setup_project_product_analytics_path(project)) + + expect(page).to have_content('Copy the code below to implement tracking in your application') + end +end diff --git a/spec/features/projects/product_analytics/test_spec.rb b/spec/features/projects/product_analytics/test_spec.rb new file mode 100644 index 00000000000..8984fb409d1 --- /dev/null +++ b/spec/features/projects/product_analytics/test_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Product Analytics > Test' do + let_it_be(:project) { create(:project_empty_repo) } + let_it_be(:user) { create(:user) } + + before do + project.add_maintainer(user) + sign_in(user) + end + + it 'says it sends a payload' do + visit(test_project_product_analytics_path(project)) + + expect(page).to have_content('This page sends a payload.') + end + + it 'shows the last event if there is one' do + event = create(:product_analytics_event, project: project) + + visit(test_project_product_analytics_path(project)) + + expect(page).to have_content(event.event_id) + end +end diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb index 878794bd897..de7251db5c9 100644 --- a/spec/features/projects/settings/operations_settings_spec.rb +++ b/spec/features/projects/settings/operations_settings_spec.rb @@ -35,7 +35,7 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do end it 'renders form for incident management' do - expect(page).to have_selector('h3', text: 'Incidents') + expect(page).to have_selector('h4', text: 'Incidents') end it 'sets correct default values' do @@ -46,11 +46,14 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do it 'updates form values' do check(create_issue) uncheck(send_email) + click_on('No template selected') + click_on('bug') save_form click_expand_incident_management_button expect(find_field(create_issue)).to be_checked + expect(page).to have_selector(:id, 'alert-integration-settings-issue-template', text: 'bug') expect(find_field(send_email)).not_to be_checked end diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb new file mode 100644 index 00000000000..0b40cbee582 --- /dev/null +++ b/spec/features/projects/settings/packages_settings_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Projects > Settings > Packages', :js do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + sign_in(user) + project.add_maintainer(user) + end + + context 'Packages enabled in config' do + before do + allow(Gitlab.config.packages).to receive(:enabled).and_return(true) + end + + it 'displays the packages toggle button' do + visit edit_project_path(project) + + expect(page).to have_content('Packages') + 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 + + it 'does not show up in UI' do + visit edit_project_path(project) + + expect(page).not_to have_content('Packages') + end + end +end diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb index 58a2c793b7b..9d9a75c22be 100644 --- a/spec/features/projects/show/user_manages_notifications_spec.rb +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do click_notifications_button expect(find('.update-notification.is-active')).to have_content('On mention') - expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications') + expect(page).to have_css('.notifications-icon[data-testid="notifications-icon"]') end it 'changes the notification setting to disabled' do @@ -32,7 +32,7 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do wait_for_requests - expect(find('.notifications-icon use')[:'xlink:href']).to end_with('#notifications-off') + expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]') end context 'custom notification settings' do @@ -52,7 +52,8 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do :merge_merge_request, :failed_pipeline, :fixed_pipeline, - :success_pipeline + :success_pipeline, + :moved_project ] end @@ -67,20 +68,6 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do end end end - - context 'when ci_pipeline_fixed_notifications is disabled' do - before do - stub_feature_flags(ci_pipeline_fixed_notifications: false) - end - - it 'hides fixed_pipeline checkbox' do - visit project_path(project) - click_notifications_button - page.find('a[data-notification-level="custom"]').click - - expect(page).not_to have_selector("input[name='notification_setting[fixed_pipeline]']") - end - end end context 'when project emails are disabled' do diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 73d033cbdb8..3db870f229a 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -2,9 +2,28 @@ require 'spec_helper' -RSpec.shared_examples_for 'snippet editor' do +RSpec.describe 'Projects > Snippets > Create Snippet', :js do + include DropzoneHelper + + let_it_be(:user) { create(:user) } + let_it_be(:project) do + create(:project, :public, creator: user).tap do |p| + p.add_maintainer(user) + end + end + + let(:title) { 'My Snippet Title' } + let(:file_content) { 'Hello World!' } + let(:md_description) { 'My Snippet **Description**' } + let(:description) { 'My Snippet Description' } + before do + stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) + + sign_in(user) + + visit new_project_snippet_path(project) end def description_field @@ -12,137 +31,81 @@ RSpec.shared_examples_for 'snippet editor' do end def fill_form - fill_in 'project_snippet_title', with: 'My Snippet Title' + fill_in 'project_snippet_title', with: title # Click placeholder first to expand full description field description_field.click - fill_in 'project_snippet_description', with: 'My Snippet **Description**' + fill_in 'project_snippet_description', with: md_description page.within('.file-editor') do el = find('.inputarea') - el.send_keys 'Hello World!' + el.send_keys file_content end end - context 'when a user is authenticated' do - before do - stub_feature_flags(snippets_vue: false) - project.add_maintainer(user) - sign_in(user) + it 'shows collapsible description input' do + collapsed = description_field - visit project_snippets_path(project) - - # Wait for the SVG to ensure the button location doesn't shift - within('.empty-state') { find('img.js-lazy-loaded') } - click_on('New snippet') - wait_for_requests - end + expect(page).not_to have_field('project_snippet_description') + expect(collapsed).to be_visible - it 'shows collapsible description input' do - collapsed = description_field + collapsed.click - expect(page).not_to have_field('project_snippet_description') - expect(collapsed).to be_visible + expect(page).to have_field('project_snippet_description') + expect(collapsed).not_to be_visible + end - collapsed.click + it 'creates a new snippet' do + fill_form + click_button('Create snippet') + wait_for_requests - expect(page).to have_field('project_snippet_description') - expect(collapsed).not_to be_visible + expect(page).to have_content(title) + expect(page).to have_content(file_content) + page.within('.snippet-header .description') do + expect(page).to have_content(description) + expect(page).to have_selector('strong') end + end - it 'creates a new snippet' do - fill_form - click_button('Create snippet') - wait_for_requests + it 'uploads a file when dragging into textarea' do + fill_form + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') - expect(page).to have_content('My Snippet Title') - expect(page).to have_content('Hello World!') - page.within('.snippet-header .description') do - expect(page).to have_content('My Snippet Description') - expect(page).to have_selector('strong') - end - end + expect(page.find_field('project_snippet_description').value).to have_content('banana_sample') - it 'uploads a file when dragging into textarea' do - fill_form - dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') + click_button('Create snippet') + wait_for_requests - expect(page.find_field("project_snippet_description").value).to have_content('banana_sample') + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z}) + end - click_button('Create snippet') - wait_for_requests + it 'displays validation errors' do + fill_in 'project_snippet_title', with: title + click_button('Create snippet') + wait_for_requests - link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z}) - end + expect(page).to have_selector('#error_explanation') + end - it 'creates a snippet when all required fields are filled in after validation failing' do - fill_in 'project_snippet_title', with: 'My Snippet Title' - click_button('Create snippet') + context 'when the git operation fails' do + let(:error) { 'Error creating the snippet' } - expect(page).to have_selector('#error_explanation') + before do + allow_next_instance_of(Snippets::CreateService) do |instance| + allow(instance).to receive(:create_commit).and_raise(StandardError, error) + end fill_form - dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') - find("input[value='Create snippet']").send_keys(:return) + click_button('Create snippet') wait_for_requests - - expect(page).to have_content('My Snippet Title') - expect(page).to have_content('Hello World!') - page.within('.snippet-header .description') do - expect(page).to have_content('My Snippet Description') - expect(page).to have_selector('strong') - end - link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z}) - end - - context 'when the git operation fails' do - let(:error) { 'Error creating the snippet' } - - before do - allow_next_instance_of(Snippets::CreateService) do |instance| - allow(instance).to receive(:create_commit).and_raise(StandardError, error) - end - - fill_form - - click_button('Create snippet') - wait_for_requests - end - - it 'displays the error' do - expect(page).to have_content(error) - end - - it 'renders new page' do - expect(page).to have_content('New Snippet') - end end - end - - context 'when a user is not authenticated' do - before do - stub_feature_flags(snippets_vue: false) - end - - it 'shows a public snippet on the index page but not the New snippet button' do - snippet = create(:project_snippet, :public, :repository, project: project) - - visit project_snippets_path(project) - expect(page).to have_content(snippet.title) - expect(page).not_to have_content('New snippet') + it 'renders the new page and displays the error' do + expect(page).to have_content(error) + expect(page).to have_content('New Snippet') end end end - -RSpec.describe 'Projects > Snippets > Create Snippet', :js do - include DropzoneHelper - - let_it_be(:user) { create(:user) } - let_it_be(:project) { create(:project, :public) } - - it_behaves_like "snippet editor" -end diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index 0f6429d49f6..8fded3cde80 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -3,157 +3,41 @@ require 'spec_helper' RSpec.describe 'Projects > Snippets > Project snippet', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } - let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) } + let_it_be(:user) { create(:user) } + let_it_be(:project) do + create(:project, creator: user).tap do |p| + p.add_maintainer(user) + end + end + + let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) } before do stub_feature_flags(snippets_vue: false) - project.add_maintainer(user) + sign_in(user) end - context 'Ruby file' do - let(:file_name) { 'popen.rb' } - let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data } + it_behaves_like 'show and render proper snippet blob' do + let(:anchor) { nil } - before do - visit project_snippet_path(project, snippet) + subject do + visit project_snippet_path(project, snippet, anchor: anchor) wait_for_requests end - - it 'displays the blob' do - aggregate_failures do - # shows highlighted Ruby code - expect(page).to have_content("require 'fileutils'") - - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - - # shows a raw button - expect(page).to have_link('Open raw') - - # shows a download button - expect(page).to have_link('Download') - end - end end - context 'Markdown file' do - let(:file_name) { 'ruby-style-guide.md' } - let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data } - - context 'visiting directly' do - before do - visit project_snippet_path(project, snippet) - - wait_for_requests - end - - it 'displays the blob using the rich viewer' do - aggregate_failures do - # hides the simple viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false) - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows rendered Markdown - expect(page).to have_link("PEP-8") - - # shows a viewer switcher - expect(page).to have_selector('.js-blob-viewer-switcher') - - # shows a disabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn.disabled') - - # shows a raw button - expect(page).to have_link('Open raw') - - # shows a download button - expect(page).to have_link('Download') - end - end - - context 'switching to the simple viewer' do - before do - find('.js-blob-viewer-switch-btn[data-viewer=simple]').click - - wait_for_requests - end - - it 'displays the blob using the simple viewer' do - aggregate_failures do - # hides the rich viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false) - - # shows highlighted Markdown code - expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - - context 'switching to the rich viewer again' do - before do - find('.js-blob-viewer-switch-btn[data-viewer=rich]').click - - wait_for_requests - end - - it 'displays the blob using the rich viewer' do - aggregate_failures do - # hides the simple viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false) - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - end - end - end - - context 'visiting with a line number anchor' do - before do - visit project_snippet_path(project, snippet, anchor: 'L1') - - wait_for_requests - end - - it 'displays the blob using the simple viewer' do - aggregate_failures do - # hides the rich viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false) - - # highlights the line in question - expect(page).to have_selector('#LC1.hll') - - # shows highlighted Markdown code - expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") + it_behaves_like 'showing user status' do + let(:file_path) { 'files/ruby/popen.rb' } + let(:user_with_status) { snippet.author } - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - end + subject { visit project_snippet_path(project, snippet) } end - it_behaves_like 'showing user status' do - let(:file_name) { 'ruby-style-guide.md' } - let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data } - - let(:user_with_status) { snippet.author } + it_behaves_like 'does not show New Snippet button' do + let(:file_path) { 'files/ruby/popen.rb' } - subject do - visit project_snippet_path(project, snippet) - wait_for_requests - end + subject { visit project_snippet_path(project, snippet) } end end diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 05d8989d88a..fdab63a56b8 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -234,4 +234,30 @@ RSpec.describe 'User updates wiki page' do it_behaves_like 'wiki file attachments' end + + context 'when an existing page exceeds the content size limit' do + let_it_be(:project) { create(:project, :wiki_repo) } + let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, content: "one\ntwo\nthree") } + + before do + stub_application_setting(wiki_page_max_content_bytes: 10) + + visit wiki_page_path(wiki_page.wiki, wiki_page, action: :edit) + end + + it 'allows changing the title if the content does not change' do + fill_in 'Title', with: 'new title' + click_on 'Save changes' + + expect(page).to have_content('Wiki was successfully updated.') + end + + it 'shows a validation error when trying to change the content' do + fill_in 'Content', with: 'new content' + click_on 'Save changes' + + expect(page).to have_content('The form contains the following error:') + expect(page).to have_content('Content is too long (11 Bytes). The maximum size is 10 Bytes.') + end + end end diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb index fea913b8212..4f29ae0cc8a 100644 --- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb @@ -11,9 +11,11 @@ RSpec.describe 'User views wiki pages' do let!(:wiki_page1) do create(:wiki_page, wiki: project.wiki, title: '3 home', content: '3') end + let!(:wiki_page2) do create(:wiki_page, wiki: project.wiki, title: '1 home', content: '1') end + let!(:wiki_page3) do create(:wiki_page, wiki: project.wiki, title: '2 home', content: '2') end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index ab0b6725491..3577498c3b4 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -254,13 +254,13 @@ RSpec.describe 'Project' do end it 'focuses on the confirmation field' do - click_button 'Remove project' + click_button 'Delete project' expect(page).to have_selector '#confirm_name_input:focus' end - it 'removes a project', :sidekiq_might_not_need_inline do - expect { remove_with_confirm('Remove project', project.path) }.to change { Project.count }.by(-1) + it 'deletes a project', :sidekiq_might_not_need_inline do + expect { remove_with_confirm('Delete project', "Delete #{project.full_name}", 'Yes, delete project') }.to change { Project.count }.by(-1) expect(page).to have_content "Project '#{project.full_name}' is in the process of being deleted." expect(Project.all.count).to be_zero expect(project.issues).to be_empty @@ -386,9 +386,9 @@ RSpec.describe 'Project' do { form: '.rspec-merge-request-settings', input: '#project_printing_merge_request_link_enabled' }] end - def remove_with_confirm(button_text, confirm_with) + def remove_with_confirm(button_text, confirm_with, confirm_button_text = 'Confirm') click_button button_text fill_in 'confirm_name_input', with: confirm_with - click_button 'Confirm' + click_button confirm_button_text end end diff --git a/spec/features/registrations/experience_level_spec.rb b/spec/features/registrations/experience_level_spec.rb new file mode 100644 index 00000000000..06d380926cd --- /dev/null +++ b/spec/features/registrations/experience_level_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Experience level screen' do + let_it_be(:user) { create(:user, :unconfirmed) } + let_it_be(:group) { create(:group) } + + before do + group.add_owner(user) + gitlab_sign_in(user) + stub_experiment_for_user(onboarding_issues: true) + visit users_sign_up_experience_level_path(namespace_path: group.to_param) + end + + subject { page } + + it 'shows the intro content' do + is_expected.to have_content('Hello there') + is_expected.to have_content('Welcome to the guided GitLab tour') + is_expected.to have_content('What describes you best?') + end + + it 'shows the option for novice' do + is_expected.to have_content('Novice') + is_expected.to have_content('I’m not very familiar with the basics of project management and DevOps') + is_expected.to have_content('Show me everything') + end + + it 'shows the option for experienced' do + is_expected.to have_content('Experienced') + is_expected.to have_content('I’m familiar with the basics of project management and DevOps') + is_expected.to have_content('Show me more advanced stuff') + end + + it 'does not display any flash messages' do + is_expected.not_to have_selector('.flash-container') + is_expected.not_to have_content("Please check your email (#{user.email}) to verify that you own this address and unlock the power of CI/CD") + end + + it 'does not include the footer links' do + is_expected.not_to have_link('Help') + is_expected.not_to have_link('About GitLab') + end +end diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 9b2373bf28b..0dff4c28270 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -450,5 +450,19 @@ RSpec.describe 'Runners' do expect(all(:link, href: group_runner_path(group, runner)).length).to eq(1) end end + + context 'filtered search' do + it 'allows user to search by status and type', :js do + visit group_settings_ci_cd_path(group) + + find('.filtered-search').click + + page.within('#js-dropdown-hint') do + expect(page).to have_content('Status') + expect(page).to have_content('Type') + expect(page).not_to have_content('Tag') + end + end + end end end diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb index 5567dcb30ec..37e83d1e888 100644 --- a/spec/features/search/user_uses_header_search_field_spec.rb +++ b/spec/features/search/user_uses_header_search_field_spec.rb @@ -104,6 +104,14 @@ RSpec.describe 'User uses header search field', :js do let(:scope_name) { 'All GitLab' } end + it 'displays search options' do + page.within('.search-input-wrap') do + fill_in('search', with: 'test') + end + + expect(page).to have_selector(scoped_search_link('test')) + end + context 'when searching through the search field' do before do create(:issue, project: project, title: 'project issue') @@ -122,9 +130,41 @@ RSpec.describe 'User uses header search field', :js do end context 'when user is in a project scope' do - include_examples 'search field examples' do - let(:url) { project_path(project) } - let(:scope_name) { project.name } + context 'and it belongs to a group' do + let(:group) { create(:group) } + let(:project) { create(:project, namespace: group) } + + include_examples 'search field examples' do + let(:url) { project_path(project) } + let(:scope_name) { project.name } + end + + it 'displays search options' do + page.within('.search-input-wrap') do + fill_in('search', with: 'test') + end + + expect(page).to have_selector(scoped_search_link('test')) + expect(page).to have_selector(scoped_search_link('test', group_id: group.id)) + expect(page).to have_selector(scoped_search_link('test', project_id: project.id, group_id: group.id)) + end + end + + context 'and it belongs to a user' do + include_examples 'search field examples' do + let(:url) { project_path(project) } + let(:scope_name) { project.name } + end + + it 'displays search options' do + page.within('.search-input-wrap') do + fill_in('search', with: 'test') + end + + expect(page).to have_selector(scoped_search_link('test')) + expect(page).not_to have_selector(scoped_search_link('test', group_id: project.namespace_id)) + expect(page).to have_selector(scoped_search_link('test', project_id: project.id)) + end end end @@ -140,6 +180,16 @@ RSpec.describe 'User uses header search field', :js do let(:url) { group_path(group) } let(:scope_name) { group.name } end + + it 'displays search options' do + page.within('.search-input-wrap') do + fill_in('search', with: 'test') + end + + expect(page).to have_selector(scoped_search_link('test')) + expect(page).to have_selector(scoped_search_link('test', group_id: group.id)) + expect(page).not_to have_selector(scoped_search_link('test', project_id: project.id)) + end end context 'when user is in a subgroup scope' do @@ -156,5 +206,25 @@ RSpec.describe 'User uses header search field', :js do let(:url) { group_path(subgroup) } let(:scope_name) { subgroup.name } end + + it 'displays search options' do + page.within('.search-input-wrap') do + fill_in('search', with: 'test') + end + + expect(page).to have_selector(scoped_search_link('test')) + expect(page).to have_selector(scoped_search_link('test', group_id: subgroup.id)) + expect(page).not_to have_selector(scoped_search_link('test', project_id: project.id)) + end + end + + def scoped_search_link(term, project_id: nil, group_id: nil) + # search_path will accept group_id and project_id but the order does not match + # what is expected in the href, so the variable must be built manually + href = search_path(search: term) + href.concat("&project_id=#{project_id}") if project_id + href.concat("&group_id=#{group_id}") if group_id + + ".dropdown a[href='#{href}']" end end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb index 99f30d2f904..051bd601c1d 100644 --- a/spec/features/security/project/internal_access_spec.rb +++ b/spec/features/security/project/internal_access_spec.rb @@ -479,8 +479,8 @@ RSpec.describe "Internal Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } it { is_expected.to be_denied_for(:external) } it { is_expected.to be_denied_for(:visitor) } end @@ -495,8 +495,8 @@ RSpec.describe "Internal Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } it { is_expected.to be_denied_for(:external) } it { is_expected.to be_denied_for(:visitor) } end @@ -511,8 +511,8 @@ RSpec.describe "Internal Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } it { is_expected.to be_denied_for(:external) } it { is_expected.to be_denied_for(:visitor) } end diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index ea00a59dee4..75993959f6e 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -293,10 +293,10 @@ RSpec.describe "Public Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } - it { is_expected.to be_denied_for(:external) } - it { is_expected.to be_denied_for(:visitor) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } + it { is_expected.to be_allowed_for(:external) } + it { is_expected.to be_allowed_for(:visitor) } end describe "GET /:project_path/-/environments/:id" do @@ -309,10 +309,10 @@ RSpec.describe "Public Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } - it { is_expected.to be_denied_for(:external) } - it { is_expected.to be_denied_for(:visitor) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } + it { is_expected.to be_allowed_for(:external) } + it { is_expected.to be_allowed_for(:visitor) } end describe "GET /:project_path/-/environments/:id/deployments" do @@ -325,10 +325,10 @@ RSpec.describe "Public Project Access" do it { is_expected.to be_allowed_for(:maintainer).of(project) } it { is_expected.to be_allowed_for(:developer).of(project) } it { is_expected.to be_allowed_for(:reporter).of(project) } - it { is_expected.to be_denied_for(:guest).of(project) } - it { is_expected.to be_denied_for(:user) } - it { is_expected.to be_denied_for(:external) } - it { is_expected.to be_denied_for(:visitor) } + it { is_expected.to be_allowed_for(:guest).of(project) } + it { is_expected.to be_allowed_for(:user) } + it { is_expected.to be_allowed_for(:external) } + it { is_expected.to be_allowed_for(:visitor) } end describe "GET /:project_path/-/environments/new" do diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index 52ae1022a4e..0667a2fd48a 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -5,10 +5,9 @@ require 'spec_helper' RSpec.describe "Internal Project Snippets Access" do include AccessMatchers - let(:project) { create(:project, :internal) } - - let(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) } - let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) } + let_it_be(:project) { create(:project, :internal) } + let_it_be(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) } + let_it_be(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) } describe "GET /:project_path/snippets" do subject { project_snippets_path(project) } diff --git a/spec/features/snippets/embedded_snippet_spec.rb b/spec/features/snippets/embedded_snippet_spec.rb index 4f2ab598a6f..b799fb2fc00 100644 --- a/spec/features/snippets/embedded_snippet_spec.rb +++ b/spec/features/snippets/embedded_snippet_spec.rb @@ -3,11 +3,13 @@ require 'spec_helper' RSpec.describe 'Embedded Snippets' do - let(:snippet) { create(:personal_snippet, :public, file_name: 'random_dir.rb', content: content) } - let(:content) { "require 'fileutils'\nFileUtils.mkdir_p 'some/random_dir'\n" } + let_it_be(:snippet) { create(:personal_snippet, :public, :repository) } + let(:blobs) { snippet.blobs.first(3) } it 'loads snippet', :js do - script_url = "http://#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}/#{snippet_path(snippet, format: 'js')}" + expect_any_instance_of(Snippet).to receive(:blobs).and_return(blobs) + + script_url = "http://#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}#{snippet_path(snippet, format: 'js')}" embed_body = "<html><body><script src=\"#{script_url}\"></script></body></html>" rack_app = proc do @@ -19,9 +21,15 @@ RSpec.describe 'Embedded Snippets' do visit("http://#{server.host}:#{server.port}/embedded_snippet.html") - expect(page).to have_content("random_dir.rb") - expect(page).to have_content("require 'fileutils'") - expect(page).to have_link('Open raw') - expect(page).to have_link('Download') + wait_for_requests + + aggregate_failures do + blobs.each do |blob| + expect(page).to have_content(blob.path) + expect(page.find(".snippet-file-content .blob-content[data-blob-id='#{blob.id}'] code")).to have_content(blob.data.squish) + expect(page).to have_link('Open raw', href: /-\/snippets\/#{snippet.id}\/raw\/master\/#{blob.path}/) + expect(page).to have_link('Download', href: /-\/snippets\/#{snippet.id}\/raw\/master\/#{blob.path}\?inline=false/) + end + end end end diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index 55031183e10..e98bb22d3ea 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -120,6 +120,17 @@ RSpec.describe 'Comments on personal snippets', :js do # but we want to make sure expect(page).not_to have_selector('.atwho-view') end + + it_behaves_like 'personal snippet with references' do + let(:container) { 'div#notes' } + + subject do + fill_in 'note[note]', with: references + click_button 'Comment' + + wait_for_requests + end + end end context 'when editing a note' do diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb index 9125ed74273..981ed12d540 100644 --- a/spec/features/snippets/show_spec.rb +++ b/spec/features/snippets/show_spec.rb @@ -3,180 +3,33 @@ require 'spec_helper' RSpec.describe 'Snippet', :js do - let(:project) { create(:project, :repository) } - let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) } + let_it_be(:user) { create(:user) } + let_it_be(:snippet) { create(:personal_snippet, :public, :repository, author: user) } before do stub_feature_flags(snippets_vue: false) end - context 'Ruby file' do - let(:file_name) { 'popen.rb' } - let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data } + it_behaves_like 'show and render proper snippet blob' do + let(:anchor) { nil } - before do - visit snippet_path(snippet) + subject do + visit snippet_path(snippet, anchor: anchor) wait_for_requests end - - it 'displays the blob' do - aggregate_failures do - # shows highlighted Ruby code - expect(page).to have_content("require 'fileutils'") - - # does not show a viewer switcher - expect(page).not_to have_selector('.js-blob-viewer-switcher') - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - - # shows a raw button - expect(page).to have_link('Open raw') - - # shows a download button - expect(page).to have_link('Download') - end - end - end - - context 'Markdown file' do - let(:file_name) { 'ruby-style-guide.md' } - let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data } - - context 'visiting directly' do - before do - visit snippet_path(snippet) - - wait_for_requests - end - - it 'displays the blob using the rich viewer' do - aggregate_failures do - # hides the simple viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false) - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows rendered Markdown - expect(page).to have_link("PEP-8") - - # shows a viewer switcher - expect(page).to have_selector('.js-blob-viewer-switcher') - - # shows a disabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn.disabled') - - # shows a raw button - expect(page).to have_link('Open raw') - - # shows a download button - expect(page).to have_link('Download') - end - end - - context 'Markdown rendering' do - let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) } - let(:file_name) { 'test.md' } - let(:content) { "1. one\n - sublist\n" } - - context 'when rendering default markdown' do - it 'renders using CommonMark' do - expect(page).to have_content("sublist") - expect(page).not_to have_xpath("//ol//li//ul") - end - end - end - - context 'switching to the simple viewer' do - before do - find('.js-blob-viewer-switch-btn[data-viewer=simple]').click - - wait_for_requests - end - - it 'displays the blob using the simple viewer' do - aggregate_failures do - # hides the rich viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false) - - # shows highlighted Markdown code - expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - - context 'switching to the rich viewer again' do - before do - find('.js-blob-viewer-switch-btn[data-viewer=rich]').click - - wait_for_requests - end - - it 'displays the blob using the rich viewer' do - aggregate_failures do - # hides the simple viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false) - expect(page).to have_selector('.blob-viewer[data-type="rich"]') - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - end - end - end - - context 'visiting with a line number anchor' do - before do - visit snippet_path(snippet, anchor: 'L1') - - wait_for_requests - end - - it 'displays the blob using the simple viewer' do - aggregate_failures do - # hides the rich viewer - expect(page).to have_selector('.blob-viewer[data-type="simple"]') - expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false) - - # highlights the line in question - expect(page).to have_selector('#LC1.hll') - - # shows highlighted Markdown code - expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)") - - # shows an enabled copy button - expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)') - end - end - end end it_behaves_like 'showing user status' do - let(:file_name) { 'popen.rb' } - let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data } + let(:file_path) { 'files/ruby/popen.rb' } let(:user_with_status) { snippet.author } subject { visit snippet_path(snippet) } end - context 'when user cannot create snippets' do - let(:user) { create(:user, :external) } - let(:snippet) { create(:personal_snippet, :public) } - - before do - sign_in(user) - - visit snippet_path(snippet) + it_behaves_like 'does not show New Snippet button' do + let(:file_path) { 'files/ruby/popen.rb' } - wait_for_requests - end - - it 'does not show the "New Snippet" button' do - expect(page).not_to have_link('New snippet') - end + subject { visit snippet_path(snippet) } end end diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index b100e035d38..f4c6536d6d3 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -2,7 +2,17 @@ require 'spec_helper' -RSpec.shared_examples_for 'snippet editor' do +RSpec.describe 'User creates snippet', :js do + include DropzoneHelper + + let_it_be(:user) { create(:user) } + + let(:title) { 'My Snippet Title' } + let(:file_content) { 'Hello World!' } + let(:md_description) { 'My Snippet **Description**' } + let(:description) { 'My Snippet Description' } + let(:created_snippet) { Snippet.last } + before do stub_feature_flags(snippets_vue: false) stub_feature_flags(snippets_edit_vue: false) @@ -14,15 +24,15 @@ RSpec.shared_examples_for 'snippet editor' do end def fill_form - fill_in 'personal_snippet_title', with: 'My Snippet Title' + fill_in 'personal_snippet_title', with: title # Click placeholder first to expand full description field description_field.click - fill_in 'personal_snippet_description', with: 'My Snippet **Description**' + fill_in 'personal_snippet_description', with: md_description page.within('.file-editor') do el = find('.inputarea') - el.send_keys 'Hello World!' + el.send_keys file_content end end @@ -34,12 +44,12 @@ RSpec.shared_examples_for 'snippet editor' do click_button('Create snippet') wait_for_requests - expect(page).to have_content('My Snippet Title') + expect(page).to have_content(title) page.within('.snippet-header .description') do - expect(page).to have_content('My Snippet Description') + expect(page).to have_content(description) expect(page).to have_selector('strong') end - expect(page).to have_content('Hello World!') + expect(page).to have_content(file_content) end it 'previews a snippet with file' do @@ -57,7 +67,7 @@ RSpec.shared_examples_for 'snippet editor' do link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src'] expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z}) - # Adds a cache buster for checking if the image exists as Selenium is now handling the cached regquests + # Adds a cache buster for checking if the image exists as Selenium is now handling the cached requests # not anymore as requests when they come straight from memory cache. reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") } expect(reqs.first.status_code).to eq(200) @@ -99,15 +109,10 @@ RSpec.shared_examples_for 'snippet editor' do wait_for_requests end - it 'displays the error' do + it 'renders the new page and displays the error' do expect(page).to have_content(error) - end - - it 'renders new page' do expect(page).to have_content('New Snippet') - end - it 'has the correct action path' do action = find('form.snippet-form')['action'] expect(action).to match(%r{/snippets\z}) end @@ -116,46 +121,10 @@ RSpec.shared_examples_for 'snippet editor' do it 'validation fails for the first time' do visit new_snippet_path - fill_in 'personal_snippet_title', with: 'My Snippet Title' + fill_in 'personal_snippet_title', with: title click_button('Create snippet') expect(page).to have_selector('#error_explanation') - - fill_form - dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') - - click_button('Create snippet') - wait_for_requests - - expect(page).to have_content('My Snippet Title') - page.within('.snippet-header .description') do - expect(page).to have_content('My Snippet Description') - expect(page).to have_selector('strong') - end - expect(page).to have_content('Hello World!') - link = find('a.no-attachment-icon img.js-lazy-loaded[alt="banana_sample"]')['src'] - expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) - - reqs = inspect_requests { visit("#{link}?ran=#{SecureRandom.base64(20)}") } - expect(reqs.first.status_code).to eq(200) - end - - it 'Authenticated user creates a snippet with + in filename' do - visit new_snippet_path - - fill_in 'personal_snippet_title', with: 'My Snippet Title' - page.within('.file-editor') do - find(:xpath, "//input[@id='personal_snippet_file_name']").set 'snippet+file+name' - el = find('.inputarea') - el.send_keys 'Hello World!' - end - - click_button 'Create snippet' - wait_for_requests - - expect(page).to have_content('My Snippet Title') - expect(page).to have_content('snippet+file+name') - expect(page).to have_content('Hello World!') end context 'when snippets default visibility level is restricted' do @@ -172,20 +141,20 @@ RSpec.shared_examples_for 'snippet editor' do click_button('Create snippet') wait_for_requests - visit snippets_path - click_link('Internal') - - expect(page).to have_content('My Snippet Title') - created_snippet = Snippet.last expect(created_snippet.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) end end -end -RSpec.describe 'User creates snippet', :js do - include DropzoneHelper + it_behaves_like 'personal snippet with references' do + let(:container) { '.snippet-header .description' } + let(:md_description) { references } - let_it_be(:user) { create(:user) } + subject do + visit new_snippet_path + fill_form + click_button('Create snippet') - it_behaves_like "snippet editor" + wait_for_requests + end + end end diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index 3692b0d1ad8..5773904dedf 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -56,8 +56,8 @@ RSpec.describe 'User edits snippet', :js do click_button 'Save changes' wait_for_requests - expect(page).to have_no_xpath("//i[@class='fa fa-lock']") - expect(page).to have_xpath("//i[@class='fa fa-shield']") + expect(page).to have_no_selector('[data-testid="lock-icon"]') + expect(page).to have_selector('[data-testid="shield-icon"]') end it 'updates the snippet to make it public' do @@ -66,8 +66,8 @@ RSpec.describe 'User edits snippet', :js do click_button 'Save changes' wait_for_requests - expect(page).to have_no_xpath("//i[@class='fa fa-lock']") - expect(page).to have_xpath("//i[@class='fa fa-globe']") + expect(page).to have_no_selector('[data-testid="lock-icon"]') + expect(page).to have_selector('[data-testid="earth-icon"]') end context 'when the git operation fails' do diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index af2ecfec498..332be055027 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -509,4 +509,29 @@ RSpec.describe 'With experimental flow' do expect(page).to have_current_path(new_project_path) end end + + context 'when terms_opt_in experimental is enabled' do + include TermsHelper + + before do + enforce_terms + stub_experiment(signup_flow: true, terms_opt_in: true) + stub_experiment_for_user(signup_flow: true, terms_opt_in: true) + end + + it 'terms are checked by default' do + new_user = build_stubbed(:user) + visit new_user_registration_path + + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email + fill_in 'new_user_first_name', with: new_user.first_name + fill_in 'new_user_last_name', with: new_user.last_name + fill_in 'new_user_password', with: new_user.password + + click_button 'Register' + + expect(current_path).to eq users_sign_up_welcome_path + end + end end |