diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 11:10:13 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-06-20 11:10:13 +0000 |
commit | 0ea3fcec397b69815975647f5e2aa5fe944a8486 (patch) | |
tree | 7979381b89d26011bcf9bdc989a40fcc2f1ed4ff /spec/features | |
parent | 72123183a20411a36d607d70b12d57c484394c8e (diff) | |
download | gitlab-ce-0ea3fcec397b69815975647f5e2aa5fe944a8486.tar.gz |
Add latest changes from gitlab-org/gitlab@15-1-stable-eev15.1.0-rc42
Diffstat (limited to 'spec/features')
125 files changed, 1427 insertions, 1191 deletions
diff --git a/spec/features/admin/admin_disables_two_factor_spec.rb b/spec/features/admin/admin_disables_two_factor_spec.rb index f65e85b4cb6..4463dbb1eb0 100644 --- a/spec/features/admin/admin_disables_two_factor_spec.rb +++ b/spec/features/admin/admin_disables_two_factor_spec.rb @@ -3,8 +3,9 @@ require 'spec_helper' RSpec.describe 'Admin disables 2FA for a user' do + include Spec::Support::Helpers::ModalHelpers + it 'successfully', :js do - stub_feature_flags(bootstrap_confirmation_modals: false) admin = create(:admin) sign_in(admin) gitlab_enable_admin_mode_sign_in(admin) @@ -12,9 +13,11 @@ RSpec.describe 'Admin disables 2FA for a user' do edit_user(user) page.within('.two-factor-status') do - accept_confirm { click_link 'Disable' } + click_link 'Disable' end + accept_gl_confirm(button_text: 'Disable') + page.within('.two-factor-status') do expect(page).to have_content 'Disabled' expect(page).not_to have_button 'Disable' diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index 90dde7340d5..2d541a34f62 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -28,7 +28,7 @@ RSpec.describe 'Admin Groups' do end end - describe 'create a group' do + describe 'create a group', :js do describe 'with expected fields' do it 'renders from as expected', :aggregate_failures do visit new_admin_group_path @@ -60,8 +60,7 @@ RSpec.describe 'Admin Groups' do expect(page).to have_current_path admin_group_path(Group.find_by(path: path_component)), ignore_query: true content = page.find('#content-body') - h3_texts = content.all('h3').collect(&:text).join("\n") - expect(h3_texts).to match group_name + expect(page).to have_content group_name li_texts = content.all('li').collect(&:text).join("\n") expect(li_texts).to match group_name expect(li_texts).to match path_component @@ -76,7 +75,7 @@ RSpec.describe 'Admin Groups' do expect_selected_visibility(internal) end - it 'when entered in group name, it auto filled the group path', :js do + it 'when entered in group name, it auto filled the group path' do visit admin_groups_path click_link "New group" group_name = 'gitlab' @@ -85,7 +84,7 @@ RSpec.describe 'Admin Groups' do expect(path_field.value).to eq group_name end - it 'auto populates the group path with the group name', :js do + it 'auto populates the group path with the group name' do visit admin_groups_path click_link "New group" group_name = 'my gitlab project' @@ -94,7 +93,7 @@ RSpec.describe 'Admin Groups' do expect(path_field.value).to eq 'my-gitlab-project' end - it 'when entering in group path, group name does not change anymore', :js do + it 'when entering in group path, group name does not change anymore' do visit admin_groups_path click_link "New group" group_path = 'my-gitlab-project' diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index fd51fd71fea..6caf2b24555 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -41,4 +41,18 @@ RSpec.describe 'Admin::HookLogs' do expect(page).to have_current_path(edit_admin_hook_path(system_hook), ignore_query: true) end + + context 'response data is too large' do + let(:hook_log) { create(:web_hook_log, web_hook: system_hook, request_data: WebHookLog::OVERSIZE_REQUEST_DATA) } + + it 'shows request data as too large and disables retry function' do + visit(admin_hook_hook_log_path(system_hook, hook_log)) + + expect(page).to have_content('Request data is too large') + expect(page).not_to have_button( + _('Resent request'), + disabled: true, class: 'has-tooltip', title: _("Request data is too large") + ) + end + end end diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 388ab02d8e8..901315752d6 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Admin::Hooks' do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:admin) } before do @@ -79,7 +81,6 @@ RSpec.describe 'Admin::Hooks' do let(:hook_url) { generate(:url) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) create(:system_hook, url: hook_url) end @@ -87,7 +88,7 @@ RSpec.describe 'Admin::Hooks' do it 'from hooks list page' do visit admin_hooks_path - accept_confirm { click_link 'Delete' } + accept_gl_confirm(button_text: 'Delete webhook') { click_link 'Delete' } expect(page).not_to have_content(hook_url) end @@ -95,7 +96,7 @@ RSpec.describe 'Admin::Hooks' do visit admin_hooks_path click_link 'Edit' - accept_confirm { click_link 'Delete' } + accept_gl_confirm(button_text: 'Delete webhook') { click_link 'Delete' } expect(page).not_to have_content(hook_url) end end diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb index ba0870a53ae..fa5c94aa66e 100644 --- a/spec/features/admin/admin_labels_spec.rb +++ b/spec/features/admin/admin_labels_spec.rb @@ -16,7 +16,6 @@ RSpec.describe 'admin issues labels' do describe 'list' do before do - stub_feature_flags(bootstrap_confirmation_modals: false) visit admin_labels_path end @@ -38,11 +37,9 @@ RSpec.describe 'admin issues labels' do end it 'deletes all labels', :js do - page.within '.labels' do - page.all('.js-remove-label').each do |remove| - accept_confirm { remove.click } - wait_for_requests - end + page.all('.labels .js-remove-label').each do |remove| + accept_gl_confirm(button_text: 'Delete label') { remove.click } + wait_for_requests end wait_for_requests diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index e1a1e2bbb2d..d312965f6cf 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -115,13 +115,17 @@ RSpec.describe "Admin Runners" do expect(page).not_to have_content("runner-bar") end - it 'shows no runner when description does not match' do - input_filtered_search_keys('runner-baz') + context 'when description does not match' do + before do + input_filtered_search_keys('runner-baz') + end - expect(page).to have_link('All 0') - expect(page).to have_link('Instance 0') + it_behaves_like 'shows no runners found' - expect(page).to have_text 'No runners found' + it 'shows no runner' do + expect(page).to have_link('All 0') + expect(page).to have_link('Instance 0') + end end end @@ -190,14 +194,6 @@ RSpec.describe "Admin Runners" do expect(page).not_to have_content 'runner-never-contacted' end - it 'shows no runner when status does not match' do - input_filtered_search_filter_is_only('Status', 'Stale') - - expect(page).to have_link('All 0') - - expect(page).to have_text 'No runners found' - end - it 'shows correct runner when status is selected and search term is entered' do input_filtered_search_filter_is_only('Status', 'Online') input_filtered_search_keys('runner-1') @@ -225,6 +221,18 @@ RSpec.describe "Admin Runners" do expect(page).to have_selector '.badge', text: 'never contacted' end end + + context 'when status does not match' do + before do + input_filtered_search_filter_is_only('Status', 'Stale') + end + + it_behaves_like 'shows no runners found' + + it 'shows no runner' do + expect(page).to have_link('All 0') + end + end end describe 'filter by type' do @@ -273,21 +281,6 @@ RSpec.describe "Admin Runners" do end end - it 'shows no runner when type does not match' do - visit admin_runners_path - - page.within('[data-testid="runner-type-tabs"]') do - click_on 'Instance' - - expect(page).to have_link('Instance', class: 'active') - end - - expect(page).not_to have_content 'runner-project' - expect(page).not_to have_content 'runner-group' - - expect(page).to have_text 'No runners found' - end - it 'shows correct runner when type is selected and search term is entered' do create(:ci_runner, :project, description: 'runner-2-project', projects: [project]) @@ -327,6 +320,24 @@ RSpec.describe "Admin Runners" do expect(page).not_to have_content 'runner-group' expect(page).not_to have_content 'runner-paused-project' end + + context 'when type does not match' do + before do + visit admin_runners_path + page.within('[data-testid="runner-type-tabs"]') do + click_on 'Instance' + + expect(page).to have_link('Instance', class: 'active') + end + end + + it_behaves_like 'shows no runners found' + + it 'shows no runner' do + expect(page).not_to have_content 'runner-project' + expect(page).not_to have_content 'runner-group' + end + end end describe 'filter by tag' do @@ -358,15 +369,6 @@ RSpec.describe "Admin Runners" do expect(page).not_to have_content 'runner-red' end - it 'shows no runner when tag does not match' do - visit admin_runners_path - - input_filtered_search_filter_is_only('Tags', 'green') - - expect(page).not_to have_content 'runner-blue' - expect(page).to have_text 'No runners found' - end - it 'shows correct runner when tag is selected and search term is entered' do create(:ci_runner, :instance, description: 'runner-2-blue', tag_list: ['blue']) @@ -384,6 +386,19 @@ RSpec.describe "Admin Runners" do expect(page).not_to have_content 'runner-blue' expect(page).not_to have_content 'runner-red' end + + context 'when tag does not match' do + before do + visit admin_runners_path + input_filtered_search_filter_is_only('Tags', 'green') + end + + it_behaves_like 'shows no runners found' + + it 'shows no runner' do + expect(page).not_to have_content 'runner-blue' + end + end end it 'sorts by last contact date' do @@ -419,7 +434,7 @@ RSpec.describe "Admin Runners" do visit admin_runners_path end - it_behaves_like "shows no runners" + it_behaves_like 'shows no runners registered' it 'shows tabs with total counts equal to 0' do expect(page).to have_link('All 0') diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 79b3f049047..8843e13026b 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -61,7 +61,7 @@ RSpec.describe 'Admin updates settings' do expect(current_settings.import_sources).to be_empty page.within('.as-visibility-access') do - check "Repo by URL" + check "Repository by URL" click_button 'Save changes' end @@ -280,6 +280,18 @@ RSpec.describe 'Admin updates settings' do expect(current_settings.gitpod_enabled).to be(true) end end + + context 'GitLab for Jira App settings' do + it 'changes the setting' do + page.within('#js-jira_connect-settings') do + fill_in 'Jira Connect Application ID', with: '1234' + click_button 'Save changes' + end + + expect(current_settings.jira_connect_application_key).to eq('1234') + expect(page).to have_content "Application settings saved successfully" + end + end end context 'Integrations page' do diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 15bc2318022..7e57cffc791 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Admin > Users > Impersonation Tokens', :js do + include Spec::Support::Helpers::ModalHelpers + let(:admin) { create(:admin) } let!(:user) { create(:user) } @@ -74,10 +76,9 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do let!(:impersonation_token) { create(:personal_access_token, :impersonation, user: user) } it "allows revocation of an active impersonation token" do - stub_feature_flags(bootstrap_confirmation_modals: false) visit admin_user_impersonation_tokens_path(user_id: user.username) - accept_confirm { click_on "Revoke" } + accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" } expect(page).to have_selector(".settings-message") expect(no_personal_access_tokens_message).to have_text("This user has no active impersonation tokens.") diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 4e6aae7c46f..2dffef93600 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -4,11 +4,11 @@ require 'spec_helper' RSpec.describe 'Admin uses repository checks', :request_store do include StubENV + include Spec::Support::Helpers::ModalHelpers let(:admin) { create(:admin) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') sign_in(admin) end @@ -57,7 +57,9 @@ RSpec.describe 'Admin uses repository checks', :request_store do expect(RepositoryCheck::ClearWorker).to receive(:perform_async) - accept_confirm { find(:link, 'Clear all repository checks').send_keys(:return) } + accept_gl_confirm(button_text: 'Clear repository checks') do + find(:link, 'Clear all repository checks').send_keys(:return) + end expect(page).to have_content('Started asynchronous removal of all repository check states.') end diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb index 7e8dee9cc0b..18bb03f4617 100644 --- a/spec/features/admin/users/user_spec.rb +++ b/spec/features/admin/users/user_spec.rb @@ -10,7 +10,6 @@ RSpec.describe 'Admin::Users::User' do let_it_be(:current_user) { create(:admin) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(current_user) gitlab_enable_admin_mode_sign_in(current_user) end @@ -354,7 +353,7 @@ RSpec.describe 'Admin::Users::User' do expect(page).to have_content("Secondary email: #{secondary_email.email}") - accept_confirm { find("#remove_email_#{secondary_email.id}").click } + accept_gl_confirm { find("#remove_email_#{secondary_email.id}").click } expect(page).not_to have_content(secondary_email.email) end diff --git a/spec/features/admin/users/users_spec.rb b/spec/features/admin/users/users_spec.rb index a05e1531949..e5df6cc0fd3 100644 --- a/spec/features/admin/users/users_spec.rb +++ b/spec/features/admin/users/users_spec.rb @@ -10,7 +10,6 @@ RSpec.describe 'Admin::Users' do let_it_be(:current_user) { create(:admin) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(current_user) gitlab_enable_admin_mode_sign_in(current_user) end @@ -492,9 +491,7 @@ RSpec.describe 'Admin::Users' do within(:css, '.gl-mb-3 + .card') do click_link group.name end - within(:css, 'h3.page-title') do - expect(page).to have_content "Group: #{group.name}" - end + expect(page).to have_content "Group: #{group.name}" expect(page).to have_content project.name end @@ -506,8 +503,11 @@ RSpec.describe 'Admin::Users' do it 'allows group membership to be revoked', :js do page.within(first('.group_member')) do - accept_confirm { find('.btn[data-testid="remove-user"]').click } + find('.btn[data-testid="remove-user"]').click end + + accept_gl_confirm(button_text: 'Remove') + wait_for_requests expect(page).not_to have_selector('.group_member') diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index bf976168bbe..e8321adeb42 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -521,7 +521,6 @@ RSpec.describe 'Project issue boards', :js do let_it_be(:user_guest) { create(:user) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_guest(user_guest) sign_in(user_guest) visit project_board_path(project, board) diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb index 09e042b00cc..06e3e00db7d 100644 --- a/spec/features/clusters/cluster_detail_page_spec.rb +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -36,20 +36,6 @@ RSpec.describe 'Clusterable > Show page' do expect(page).not_to have_selector('[data-testid="cluster-environments-tab"]') end - - context 'content-security policy' do - it 'has AWS domains in the CSP' do - visit cluster_path - - expect(response_headers['Content-Security-Policy']).to include(::Clusters::ClustersController::AWS_CSP_DOMAINS.join(' ')) - end - - it 'keeps existing connect-src in the CSP' do - visit cluster_path - - expect(response_headers['Content-Security-Policy']).to include("connect-src #{Gitlab::ContentSecurityPolicy::Directives.connect_src}") - end - end end shared_examples 'editing a GCP cluster' do diff --git a/spec/features/clusters/create_agent_spec.rb b/spec/features/clusters/create_agent_spec.rb index c7326204bf6..b879ae645f7 100644 --- a/spec/features/clusters/create_agent_spec.rb +++ b/spec/features/clusters/create_agent_spec.rb @@ -35,6 +35,7 @@ RSpec.describe 'Cluster agent registration', :js do expect(page).to have_content('You cannot see this token again after you close this window.') expect(page).to have_content('example-agent-token') expect(page).to have_content('helm upgrade --install') + expect(page).to have_content('example-agent-2') within find('.modal-footer') do click_button('Close') diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 4b38df175e2..db841ffc627 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -10,7 +10,6 @@ RSpec.describe 'Commits' do before do sign_in(user) stub_ci_pipeline_to_return_yaml_file - stub_feature_flags(pipeline_tabs_vue: false) end let(:creator) { create(:user, developer_projects: [project]) } @@ -94,7 +93,6 @@ RSpec.describe 'Commits' do context 'Download artifacts', :js do before do - stub_feature_flags(pipeline_tabs_vue: false) create(:ci_job_artifact, :archive, file: artifacts_file, job: build) end @@ -124,7 +122,6 @@ RSpec.describe 'Commits' do context "when logged as reporter", :js do before do - stub_feature_flags(pipeline_tabs_vue: false) project.add_reporter(user) create(:ci_job_artifact, :archive, file: artifacts_file, job: build) visit builds_project_pipeline_path(project, pipeline) diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index 04e78b59ab4..adb43d60306 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -55,7 +55,8 @@ RSpec.describe 'Dashboard Todos' do expect(link).not_to be_nil expect(link['data-iid']).to eq(referenced_mr.iid.to_s) expect(link['data-project-path']).to eq(referenced_mr.project.full_path) - expect(link['data-mr-title']).to eq(referenced_mr.title) + expect(link['title']).to eq(referenced_mr.title) + expect(link['data-reference-type']).to eq('merge_request') end end diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb index c7d37205b71..9af9baeb5bb 100644 --- a/spec/features/group_variables_spec.rb +++ b/spec/features/group_variables_spec.rb @@ -12,8 +12,18 @@ RSpec.describe 'Group variables', :js do group.add_owner(user) gitlab_sign_in(user) wait_for_requests - visit page_path end - it_behaves_like 'variable list' + context 'with disabled ff `ci_variable_settings_graphql' do + before do + stub_feature_flags(ci_variable_settings_graphql: false) + visit page_path + end + + it_behaves_like 'variable list' + end + + # TODO: Uncomment when the new graphQL app for variable settings + # is enabled. + # it_behaves_like 'variable list' end diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb index 74ea72b238f..6b512323d4d 100644 --- a/spec/features/groups/clusters/user_spec.rb +++ b/spec/features/groups/clusters/user_spec.rb @@ -112,9 +112,9 @@ RSpec.describe 'User Cluster', :js do context 'when user destroys the cluster' do before do click_link 'Advanced Settings' - click_button 'Remove integration and resources' + find('[data-testid="remove-integration-button"]').click fill_in 'confirm_cluster_name_input', with: cluster.name - click_button 'Remove integration' + find('[data-testid="remove-integration-modal-button"]').click end it 'user sees creation form with the successful message' do diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index 71f38401fa1..f11e5c56545 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_issues_list: true) - sign_in(user) end diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb index 1d821edefa3..a60b8a60da0 100644 --- a/spec/features/groups/group_runners_spec.rb +++ b/spec/features/groups/group_runners_spec.rb @@ -33,7 +33,7 @@ RSpec.describe "Group Runners" do visit group_runners_path(group) end - it_behaves_like "shows no runners" + it_behaves_like 'shows no runners registered' it 'shows tabs with total counts equal to 0' do expect(page).to have_link('All 0') @@ -70,6 +70,18 @@ RSpec.describe "Group Runners" do expect(find_link('Edit')[:href]).to end_with(edit_group_runner_path(group, group_runner)) end end + + context 'when description does not match' do + before do + input_filtered_search_keys('runner-baz') + end + + it_behaves_like 'shows no runners found' + + it 'shows no runner' do + expect(page).not_to have_content 'runner-foo' + end + end end context "with an online project runner" do @@ -137,31 +149,37 @@ RSpec.describe "Group Runners" do create(:ci_runner, :group, groups: [group], description: 'runner-foo', contacted_at: Time.zone.now) end - it 'user edits the runner to be protected' do - visit edit_group_runner_path(group, runner) + context 'when group_runner_view_ui is disabled' do + before do + stub_feature_flags(group_runner_view_ui: false) + end - expect(page.find_field('runner[access_level]')).not_to be_checked + it 'user edits the runner to be protected' do + visit edit_group_runner_path(group, runner) - check 'runner_access_level' - click_button 'Save changes' + expect(page.find_field('runner[access_level]')).not_to be_checked - expect(page).to have_content 'Protected Yes' - end + check 'runner_access_level' + click_button 'Save changes' - context 'when a runner has a tag' do - before do - runner.update!(tag_list: ['tag']) + expect(page).to have_content 'Protected Yes' end - it 'user edits runner not to run untagged jobs' do - visit edit_group_runner_path(group, runner) + context 'when a runner has a tag' do + before do + runner.update!(tag_list: ['tag']) + end - expect(page.find_field('runner[run_untagged]')).to be_checked + it 'user edits runner not to run untagged jobs' do + visit edit_group_runner_path(group, runner) - uncheck 'runner_run_untagged' - click_button 'Save changes' + expect(page.find_field('runner[run_untagged]')).to be_checked - expect(page).to have_content 'Can run untagged jobs No' + uncheck 'runner_run_untagged' + click_button 'Save changes' + + expect(page).to have_content 'Can run untagged jobs No' + end end end end diff --git a/spec/features/groups/import_export/connect_instance_spec.rb b/spec/features/groups/import_export/connect_instance_spec.rb index 552b599a3f3..ae03e64cf59 100644 --- a/spec/features/groups/import_export/connect_instance_spec.rb +++ b/spec/features/groups/import_export/connect_instance_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'Import/Export - Connect to another instance', :js do click_on 'Connect instance' - expect(page).to have_content 'Showing 1-1 of 42 groups from %{url}' % { url: source_url } + expect(page).to have_content 'Showing 1-1 of 42 groups that you own from %{url}' % { url: source_url } expect(page).to have_content 'stub-group' visit '/' diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index ef3346b9763..c86705832b1 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -11,10 +11,6 @@ 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_issues_list: true) - end - context 'with shared examples', :js do let(:issuable) { create(:issue, project: project, title: "this is my created issuable")} @@ -140,8 +136,6 @@ RSpec.describe 'Group issues page' do let!(:issue3) { create(:issue, project: project, title: 'Issue #3', relative_position: 3) } before do - stub_feature_flags(vue_issues_list: false) - sign_in(user_in_group) end @@ -164,45 +158,36 @@ RSpec.describe 'Group issues page' do end it 'issues should be draggable and persist order' do - visit issues_group_path(group, sort: 'relative_position') - - wait_for_requests + visit issues_group_path(group) + select_manual_sort - drag_to(selector: '.manual-ordering', - from_index: 0, - to_index: 2) + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) - wait_for_requests + expect_issue_order - check_issue_order - - visit issues_group_path(group, sort: 'relative_position') + visit issues_group_path(group) - check_issue_order + expect_issue_order end 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 + visit issues_group_path(group) + select_manual_sort - drag_to(selector: '.manual-ordering', - from_index: 0, - to_index: 2) + drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2) - wait_for_requests + expect(page).to have_text 'An error occurred while reordering issues.' + end - # Issue order should remain the same - page.within('.manual-ordering') do - expect(find('.issue:nth-child(1) .title')).to have_content('Issue #1') - expect(find('.issue:nth-child(2) .title')).to have_content('Issue #2') - expect(find('.issue:nth-child(3) .title')).to have_content('Issue #3') - end + def select_manual_sort + click_button 'Created date' + click_button 'Manual' + wait_for_requests end - def check_issue_order + def expect_issue_order expect(page).to have_css('.issue:nth-child(1) .title', text: 'Issue #2') expect(page).to have_css('.issue:nth-child(2) .title', text: 'Issue #3') expect(page).to have_css('.issue:nth-child(3) .title', text: 'Issue #1') diff --git a/spec/features/groups/members/leave_group_spec.rb b/spec/features/groups/members/leave_group_spec.rb index 50d5db46cee..66f251c859a 100644 --- a/spec/features/groups/members/leave_group_spec.rb +++ b/spec/features/groups/members/leave_group_spec.rb @@ -4,13 +4,13 @@ require 'spec_helper' RSpec.describe 'Groups > Members > Leave group' do include Spec::Support::Helpers::Features::MembersHelpers + include Spec::Support::Helpers::ModalHelpers let(:user) { create(:user) } let(:other_user) { create(:user) } let(:group) { create(:group) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -32,7 +32,7 @@ RSpec.describe 'Groups > Members > Leave group' do visit group_path(group, leave: 1) - page.accept_confirm + accept_gl_confirm(button_text: 'Leave group') wait_for_all_requests expect(page).to have_current_path(dashboard_groups_path, ignore_query: true) diff --git a/spec/features/groups/navbar_spec.rb b/spec/features/groups/navbar_spec.rb index e4b44d65438..b4faa3ce0dd 100644 --- a/spec/features/groups/navbar_spec.rb +++ b/spec/features/groups/navbar_spec.rb @@ -15,7 +15,6 @@ RSpec.describe 'Group navbar' do before do insert_package_nav(_('Kubernetes')) - stub_feature_flags(customer_relations: false) stub_config(dependency_proxy: { enabled: false }) stub_config(registry: { enabled: false }) stub_feature_flags(harbor_registry_integration: false) @@ -42,12 +41,10 @@ RSpec.describe 'Group navbar' do it_behaves_like 'verified navigation bar' end - context 'when customer_relations feature and flag is enabled' do + context 'when customer_relations feature is enabled' do let(:group) { create(:group, :crm_enabled) } before do - stub_feature_flags(customer_relations: true) - if Gitlab.ee? insert_customer_relations_nav(_('Analytics')) else @@ -60,12 +57,10 @@ RSpec.describe 'Group navbar' do it_behaves_like 'verified navigation bar' end - context 'when customer_relations feature and flag is enabled but subgroup' do + context 'when customer_relations feature is enabled but subgroup' do let(:group) { create(:group, :crm_enabled, parent: create(:group)) } before do - stub_feature_flags(customer_relations: true) - visit group_path(group) end diff --git a/spec/features/groups/settings/access_tokens_spec.rb b/spec/features/groups/settings/access_tokens_spec.rb index 20787c4c2f5..198d3a40df2 100644 --- a/spec/features/groups/settings/access_tokens_spec.rb +++ b/spec/features/groups/settings/access_tokens_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Group > Settings > Access Tokens', :js do + include Spec::Support::Helpers::ModalHelpers + let_it_be(:user) { create(:user) } let_it_be(:bot_user) { create(:user, :project_bot) } let_it_be(:group) { create(:group) } @@ -13,7 +15,6 @@ RSpec.describe 'Group > Settings > Access Tokens', :js do end before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index eb62b6fa8ee..fa8db1befb5 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -72,6 +72,58 @@ RSpec.describe 'Group show page' do end end end + + context 'subgroups and projects empty state', :js do + context 'when user has permissions to create new subgroups or projects' do + before do + group.add_owner(user) + sign_in(user) + visit path + end + + it 'shows `Create new subgroup` link' do + expect(page).to have_link( + s_('GroupsEmptyState|Create new subgroup'), + href: new_group_path(parent_id: group.id) + ) + end + + it 'shows `Create new project` link' do + expect(page).to have_link( + s_('GroupsEmptyState|Create new project'), + href: new_project_path(namespace_id: group.id) + ) + end + end + end + + context 'when user does not have permissions to create new subgroups or projects', :js do + before do + group.add_reporter(user) + sign_in(user) + visit path + end + + it 'does not show `Create new subgroup` link' do + expect(page).not_to have_link( + s_('GroupsEmptyState|Create new subgroup'), + href: new_group_path(parent_id: group.id) + ) + end + + it 'does not show `Create new project` link' do + expect(page).not_to have_link( + s_('GroupsEmptyState|Create new project'), + href: new_project_path(namespace_id: group.id) + ) + end + + it 'shows empty state' do + expect(page).to have_content(s_('GroupsEmptyState|No subgroups or projects.')) + expect(page).to have_content(s_('GroupsEmptyState|You do not have necessary permissions to create a subgroup' \ + ' or project in this group. Please contact an owner of this group to create a new subgroup or project.')) + end + end end context 'when signed out' do diff --git a/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb b/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb index 9fe11070187..4e4c0e509b0 100644 --- a/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb +++ b/spec/features/groups/user_sees_users_dropdowns_in_issuables_list_spec.rb @@ -2,23 +2,50 @@ require 'spec_helper' -RSpec.describe 'Groups > User sees users dropdowns in issuables list' do - let(:entity) { create(:group) } +RSpec.describe 'Groups > User sees users dropdowns in issuables list', :js do + include FilteredSearchHelpers + + let(:group) { create(:group) } let(:user_in_dropdown) { create(:user) } let!(:user_not_in_dropdown) { create(:user) } - let!(:project) { create(:project, group: entity) } + let!(:project) { create(:project, group: group) } before do - entity.add_developer(user_in_dropdown) + group.add_developer(user_in_dropdown) + sign_in(user_in_dropdown) end - it_behaves_like 'issuable user dropdown behaviors' do - let(:issuable) { create(:issue, project: project) } - let(:issuables_path) { issues_group_path(entity) } + describe 'issues' do + let!(:issuable) { create(:issue, project: project) } + + %w[Author Assignee].each do |dropdown| + describe "#{dropdown} dropdown" do + it 'only includes members of the project/group' do + visit issues_group_path(group) + + select_tokens dropdown, '=', submit: false + + expect_suggestion(user_in_dropdown.name) + expect_no_suggestion(user_not_in_dropdown.name) + end + end + end end - it_behaves_like 'issuable user dropdown behaviors' do - let(:issuable) { create(:merge_request, source_project: project) } - let(:issuables_path) { merge_requests_group_path(entity) } + describe 'merge requests' do + let!(:issuable) { create(:merge_request, source_project: project) } + + %w[author assignee].each do |dropdown| + describe "#{dropdown} dropdown" do + it 'only includes members of the project/group' do + visit merge_requests_group_path(group) + + filtered_search.set("#{dropdown}:=") + + expect(find("#js-dropdown-#{dropdown} .filter-dropdown")).to have_content(user_in_dropdown.name) + expect(find("#js-dropdown-#{dropdown} .filter-dropdown")).not_to have_content(user_not_in_dropdown.name) + end + end + end end end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index ceb4af03f89..31390b110e7 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -22,7 +22,7 @@ RSpec.describe 'Group' do end describe 'as a non-admin' do - it 'creates a group and persists visibility radio selection', :js do + it 'creates a group and persists visibility radio selection', :js, :saas do stub_application_setting(default_group_visibility: :private) fill_in 'Group name', with: 'test-group' @@ -127,7 +127,7 @@ RSpec.describe 'Group' do describe 'Mattermost team creation' do before do - stub_mattermost_setting(enabled: mattermost_enabled) + stub_mattermost_setting(enabled: mattermost_enabled, host: 'https://mattermost.test') visit new_group_path click_link 'Create group' @@ -145,13 +145,14 @@ RSpec.describe 'Group' do end it 'updates the team URL on graph path update', :js do - out_span = find('span[data-bind-out="create_chat_team"]', visible: false) + label = find('#group_create_chat_team ~ label[for=group_create_chat_team]') + url = 'https://mattermost.test/test-group' - expect(out_span.text).to be_empty + expect(label.text).not_to match(url) fill_in('group_path', with: 'test-group') - expect(out_span.text).to eq('test-group') + expect(label.text).to match(url) end end @@ -497,7 +498,9 @@ RSpec.describe 'Group' do let_it_be(:group) { create(:group) } let_it_be_with_refind(:user) { create(:user) } - before_all do + before do + stub_feature_flags(namespace_storage_limit_bypass_date_check: false) + group.add_owner(user) sign_in(user) end diff --git a/spec/features/incidents/incidents_list_spec.rb b/spec/features/incidents/incidents_list_spec.rb index 789cc89e083..3241e71f537 100644 --- a/spec/features/incidents/incidents_list_spec.rb +++ b/spec/features/incidents/incidents_list_spec.rb @@ -44,18 +44,5 @@ RSpec.describe 'Incident Management index', :js do expect(table).to have_content('Date created') expect(table).to have_content('Assignees') end - - context 'when :incident_escalations feature is disabled' do - before do - stub_feature_flags(incident_escalations: false) - end - - it 'does not include the Status columns' do - visit project_incidents_path(project) - wait_for_requests - - expect(page.find('.gl-table')).not_to have_content('Status') - end - end end end diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 7edf5fdc5ff..0fa2d238b0a 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -9,8 +9,6 @@ RSpec.describe 'issuable list', :js do issuable_types = [:issue, :merge_request] before do - stub_feature_flags(vue_issues_list: true) - project.add_user(user, :developer) sign_in(user) issuable_types.each { |type| create_issuables(type) } diff --git a/spec/features/issue_rebalancing_spec.rb b/spec/features/issue_rebalancing_spec.rb index 8a05aeec7ec..686aa5eb1b6 100644 --- a/spec/features/issue_rebalancing_spec.rb +++ b/spec/features/issue_rebalancing_spec.rb @@ -15,10 +15,6 @@ RSpec.describe 'Issue rebalancing' do group.add_developer(user) end - before do - stub_feature_flags(vue_issues_list: true) - end - context 'when issue rebalancing is in progress' do before do sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 18b70c9622a..05eb656461e 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -9,10 +9,6 @@ RSpec.describe 'Dropdown assignee', :js do let_it_be(:user) { create(:user) } let_it_be(:issue) { create(:issue, project: project) } - before do - stub_feature_flags(vue_issues_list: true) - end - describe 'behavior' do before do project.add_maintainer(user) diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index 07e2bd3b7e4..36a8f1f3902 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -10,8 +10,6 @@ RSpec.describe 'Dropdown author', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_base_spec.rb b/spec/features/issues/filtered_search/dropdown_base_spec.rb index 5fdab288b2d..9e3e3d394cd 100644 --- a/spec/features/issues/filtered_search/dropdown_base_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_base_spec.rb @@ -10,8 +10,6 @@ RSpec.describe 'Dropdown base', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb index d6d59b89a8c..78450a9c3f7 100644 --- a/spec/features/issues/filtered_search/dropdown_emoji_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_emoji_spec.rb @@ -11,8 +11,6 @@ RSpec.describe 'Dropdown emoji', :js do let_it_be(:award_emoji_star) { create(:award_emoji, name: 'star', user: user, awardable: issue) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) create_list(:award_emoji, 2, user: user, name: 'thumbsup') create_list(:award_emoji, 1, user: user, name: 'thumbsdown') diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index c64247b2b15..dcbab308efa 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -10,8 +10,6 @@ RSpec.describe 'Dropdown hint', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) end diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index 67e3792a04c..0ff56909ad1 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -11,8 +11,6 @@ RSpec.describe 'Dropdown label', :js do let_it_be(:label) { create(:label, project: project, title: 'bug-label') } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 19a4c8853f1..37d604106f1 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -12,8 +12,6 @@ RSpec.describe 'Dropdown milestone', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/dropdown_release_spec.rb b/spec/features/issues/filtered_search/dropdown_release_spec.rb index 50ac9068b26..08e20563c8e 100644 --- a/spec/features/issues/filtered_search/dropdown_release_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_release_spec.rb @@ -12,8 +12,6 @@ RSpec.describe 'Dropdown release', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) - project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 13bce49e6d1..8d96bbc38cb 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -19,7 +19,6 @@ RSpec.describe 'Filter issues', :js do end before do - stub_feature_flags(vue_issues_list: true) project.add_maintainer(user) create(:issue, project: project, author: user2, title: "Bug report 1") diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index bb5964258be..cb17349dd43 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -13,8 +13,6 @@ RSpec.describe 'Recent searches', :js do let(:project_1_local_storage_key) { "#{project_1.full_path}-issue-recent-searches" } before do - stub_feature_flags(vue_issues_list: true) - # Visit any fast-loading page so we can clear local storage without a DOM exception visit '/404' remove_recent_searches diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index 8639ec2a227..e075547e326 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -10,7 +10,6 @@ RSpec.describe 'Search bar', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index 9fb6a4cc2af..7a367723609 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -15,7 +15,6 @@ RSpec.describe 'Visual tokens', :js do let_it_be(:issue) { create(:issue, project: project) } before do - stub_feature_flags(vue_issues_list: true) project.add_user(user, :maintainer) project.add_user(user_rock, :maintainer) sign_in(user) diff --git a/spec/features/issues/incident_issue_spec.rb b/spec/features/issues/incident_issue_spec.rb index a2519a44604..d6ec7f1c539 100644 --- a/spec/features/issues/incident_issue_spec.rb +++ b/spec/features/issues/incident_issue_spec.rb @@ -26,6 +26,7 @@ RSpec.describe 'Incident Detail', :js do context 'when user displays the incident' do before do + stub_feature_flags(incident_timeline: project) project.add_developer(user) sign_in(user) @@ -72,6 +73,12 @@ RSpec.describe 'Incident Detail', :js do expect(hidden_items).to all(be_visible) end end + + it 'shows the edit title and description button' do + edit_button = find_all('[aria-label="Edit title and description"]') + + expect(edit_button).to all(be_visible) + end end context 'when on alert details tab' do @@ -87,6 +94,61 @@ RSpec.describe 'Incident Detail', :js do expect(hidden_items.count).to eq(0) end end + + it 'does not show the edit title and description button' do + edit_button = find_all('[aria-label="Edit title and description"]') + + expect(edit_button.count).to eq(0) + end + end + + context 'when on timeline events tab from incident route' do + before do + visit project_issues_incident_path(project, incident) + wait_for_requests + click_link 'Timeline' + end + + it 'does not show the linked issues and notes/comment components' do + page.within('.issuable-details') do + hidden_items = find_all('.js-issue-widgets') + + # Linked Issues/MRs and comment box are hidden on page + expect(hidden_items.count).to eq(0) + end + end + end + + context 'when on timeline events tab from issue route' do + before do + visit project_issue_path(project, incident) + wait_for_requests + click_link 'Timeline' + end + + it 'does not show the linked issues and notes/comment commponents' do + page.within('.issuable-details') do + hidden_items = find_all('.js-issue-widgets') + + # Linked Issues/MRs and comment box are hidden on page + expect(hidden_items.count).to eq(0) + end + end + end + + context 'when incident_timeline feature flag is disabled' do + before do + stub_feature_flags(incident_timeline: false) + + visit project_issue_path(project, incident) + wait_for_requests + end + + it 'does not show Timeline tab' do + tabs = find('[data-testid="incident-tabs"]') + + expect(tabs).not_to have_content('Timeline') + end end end end diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index 88709d66887..2af54e51bb7 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -140,13 +140,9 @@ RSpec.describe 'Issue Detail', :js do end context 'by non-member author' do - it 'routes the user to the issue details page when the `issue_type` is set to issue' do - open_issue_edit_form - - page.within('[data-testid="issuable-form"]') do - update_type_select('Incident', 'Issue') - - expect(page).to have_current_path(project_issue_path(project, incident)) + it 'cannot edit issuable' do + page.within('.content') do + expect(page).to have_no_button('Edit title and description') end end end diff --git a/spec/features/issues/rss_spec.rb b/spec/features/issues/rss_spec.rb index bdc5f282875..e3faed81c73 100644 --- a/spec/features/issues/rss_spec.rb +++ b/spec/features/issues/rss_spec.rb @@ -13,10 +13,6 @@ RSpec.describe 'Project Issues RSS', :js do group.add_developer(user) end - before do - stub_feature_flags(vue_issues_list: true) - end - context 'when signed in' do let_it_be(:user) { create(:user) } diff --git a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb index 27377f6e1fd..4837d13574c 100644 --- a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb @@ -15,10 +15,6 @@ RSpec.describe 'Issues > Labels bulk assignment' do let(:issue_1_selector) { "#issuable_#{issue1.id}" } let(:issue_2_selector) { "#issuable_#{issue2.id}" } - before do - stub_feature_flags(vue_issues_list: true) - end - context 'as an allowed user', :js do before do project.add_maintainer(user) diff --git a/spec/features/issues/user_bulk_edits_issues_spec.rb b/spec/features/issues/user_bulk_edits_issues_spec.rb index 625303f89e4..0533f1688e2 100644 --- a/spec/features/issues/user_bulk_edits_issues_spec.rb +++ b/spec/features/issues/user_bulk_edits_issues_spec.rb @@ -107,10 +107,6 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do describe 'select all issues' do let!(:issue_2) { create(:issue, project: project) } - before do - stub_feature_flags(vue_issues_list: true) - end - it 'after selecting all issues, unchecking one issue only unselects that one issue' do visit project_issues_path(project) diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb index a719263f092..a1e7c007b90 100644 --- a/spec/features/issues/user_comments_on_issue_spec.rb +++ b/spec/features/issues/user_comments_on_issue_spec.rb @@ -10,7 +10,6 @@ RSpec.describe "User comments on issue", :js do let(:user) { create(:user) } before do - stub_feature_flags(sandboxed_mermaid: false) project.add_guest(user) sign_in(user) @@ -42,17 +41,6 @@ RSpec.describe "User comments on issue", :js do expect(page.find('pre code').text).to eq code_block_content end - it "renders HTML content as text in Mermaid" do - html_content = "<img onerror=location=`javascript\\u003aalert\\u0028document.domain\\u0029` src=x>" - mermaid_content = "graph LR\n B-->D(#{html_content});" - comment = "```mermaid\n#{mermaid_content}\n```" - - add_note(comment) - - expect(page.find('svg.mermaid')).not_to have_content 'javascript' - within('svg.mermaid') { expect(page).not_to have_selector('img') } - end - it 'opens autocomplete menu for quick actions and have `/label` first choice' do project.add_maintainer(user) create(:label, project: project, title: 'label') @@ -67,7 +55,7 @@ RSpec.describe "User comments on issue", :js do it "edits comment" do add_note("# Comment with a header") - page.within(".note-body > .note-text") do + page.within(".note-body .note-text") do expect(page).to have_content("Comment with a header").and have_no_css("#comment-with-a-header") end diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb index 3bba041dab7..151d3c60fa2 100644 --- a/spec/features/issues/user_creates_issue_spec.rb +++ b/spec/features/issues/user_creates_issue_spec.rb @@ -8,10 +8,6 @@ RSpec.describe "User creates issue" do let_it_be(:project) { create(:project_empty_repo, :public) } let_it_be(:user) { create(:user) } - before do - stub_feature_flags(vue_issues_list: true) - end - context "when unauthenticated" do before do sign_out(:user) diff --git a/spec/features/issues/user_filters_issues_spec.rb b/spec/features/issues/user_filters_issues_spec.rb index 42c2b5d32c1..2941ea6ec36 100644 --- a/spec/features/issues/user_filters_issues_spec.rb +++ b/spec/features/issues/user_filters_issues_spec.rb @@ -7,8 +7,6 @@ RSpec.describe 'User filters issues', :js do let_it_be(:project) { create(:project_empty_repo, :public) } before do - stub_feature_flags(vue_issues_list: true) - %w[foobar barbaz].each do |title| create(:issue, author: user, diff --git a/spec/features/issues/user_sees_breadcrumb_links_spec.rb b/spec/features/issues/user_sees_breadcrumb_links_spec.rb index 1577d7d5ce8..4ec13533a8d 100644 --- a/spec/features/issues/user_sees_breadcrumb_links_spec.rb +++ b/spec/features/issues/user_sees_breadcrumb_links_spec.rb @@ -8,8 +8,6 @@ RSpec.describe 'New issue breadcrumb' do let(:user) { project.creator } before do - stub_feature_flags(vue_issues_list: true) - sign_in(user) visit(new_project_issue_path(project)) end diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb index 4af313576ed..7add6c782f7 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_issues_list: true) - create_list(:award_emoji, 2, :upvote, awardable: issue1) create_list(:award_emoji, 2, :downvote, awardable: issue2) create(:award_emoji, :downvote, awardable: issue1) diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb index ea888d4b254..2f22ac8b395 100644 --- a/spec/features/labels_hierarchy_spec.rb +++ b/spec/features/labels_hierarchy_spec.rb @@ -17,8 +17,6 @@ RSpec.describe 'Labels Hierarchy', :js do let!(:project_label_1) { create(:label, project: project_1, title: 'Label_4') } before do - stub_feature_flags(vue_issues_list: true) - grandparent.add_owner(user) sign_in(user) diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb index fa23fac2f96..1f219886818 100644 --- a/spec/features/markdown/math_spec.rb +++ b/spec/features/markdown/math_spec.rb @@ -67,4 +67,24 @@ RSpec.describe 'Math rendering', :js do expect(page).to have_selector('.js-lazy-render-math') end end + + it 'renders without any limits on wiki page', :js do + description = <<~MATH + ```math + \Huge \sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{\sqrt{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} + ``` + MATH + + wiki_page = build(:wiki_page, { container: project, content: description }) + wiki_page.create message: 'math test commit' # rubocop:disable Rails/SaveBang + wiki_page = project.wiki.find_page(wiki_page.slug) + + visit project_wiki_path(project, wiki_page) + + wait_for_requests + + page.within '.js-wiki-page-content' do + expect(page).not_to have_selector('.js-lazy-render-math') + end + end end diff --git a/spec/features/markdown/mermaid_spec.rb b/spec/features/markdown/mermaid_spec.rb deleted file mode 100644 index 322b5306a00..00000000000 --- a/spec/features/markdown/mermaid_spec.rb +++ /dev/null @@ -1,361 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Mermaid rendering', :js do - let_it_be(:project) { create(:project, :public) } - - let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') } - let(:modifier_key) { is_mac ? :command : :control } - - before do - stub_feature_flags(sandboxed_mermaid: false) - end - - it 'renders Mermaid diagrams correctly' do - description = <<~MERMAID - ```mermaid - graph TD; - A-->B; - A-->C; - B-->D; - C-->D; - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - %w[A B C D].each do |label| - expect(page).to have_selector('svg text', text: label) - end - end - - it 'renders linebreaks in Mermaid diagrams' do - description = <<~MERMAID - ```mermaid - graph TD; - A(Line 1<br>Line 2)-->B(Line 1<br/>Line 2); - C(Line 1<br />Line 2)-->D(Line 1<br />Line 2); - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - # From # From https://github.com/mermaid-js/mermaid/blob/170ed89e9ef3e33dc84f8656eed1725379d505df/src/dagre-wrapper/createLabel.js#L39-L42 - expected = %(<div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">Line 1<br>Line 2</div>) - expect(page.html.scan(expected).count).to be(4) - end - - it 'does not allow XSS in HTML labels' do - description = <<~MERMAID - ```mermaid - graph LR; - A-->CLICK_HERE_AND_GET_BONUS; - click A alert "aaa" - click CLICK_HERE_AND_GET_BONUS "javascript:alert%28%64%6f%63%75%6d%65%6e%74%2e%64%6f%6d%61%69%6e%29" "Here is the XSS" - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - # From https://github.com/mermaid-js/mermaid/blob/170ed89e9ef3e33dc84f8656eed1725379d505df/src/dagre-wrapper/createLabel.js#L39-L42 - expected = %(<div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml">CLICK_HERE_AND_GET_BONUS</div>) - expect(page.html).to include(expected) - end - - it 'renders only 2 Mermaid blocks and', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' do - description = <<~MERMAID - ```mermaid - graph LR - A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B; - ``` - ```mermaid - graph LR - A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B; - ``` - ```mermaid - graph LR - A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B;B-->A;A-->B; - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - page.within('.description') do - expect(page).to have_selector('svg') - expect(page).to have_selector('pre.mermaid') - end - end - - it 'correctly sizes mermaid diagram inside <details> block' do - description = <<~MERMAID - <details> - <summary>Click to show diagram</summary> - - ```mermaid - graph TD; - A-->B; - A-->C; - B-->D; - C-->D; - ``` - - </details> - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - page.within('.description') do - page.find('summary').click - svg = page.find('svg.mermaid') - - expect(svg[:style]).to match(/max-width/) - expect(svg[:width].to_i).to eq(100) - expect(svg[:height].to_i).to be_within(5).of(236) - end - end - - it 'renders V2 state diagrams' do - description = <<~MERMAID - ```mermaid - stateDiagram-v2 - [*] --> Idle - Idle --> Active : CONTINUE - state Active { - [*] --> Run - Run--> Stop: CONTINUE - Stop--> Run: CONTINUE - - Run: Run - Run: entry/start - Run: check - } - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - page.within('.description') do - expect(page).to have_selector('svg') - end - end - - it 'correctly sizes mermaid diagram block' do - description = <<~MERMAID - ```mermaid - graph TD; - A-->B; - A-->C; - B-->D; - C-->D; - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - expect(page).to have_css('svg.mermaid[style*="max-width"][width="100%"]') - end - - it 'display button when diagram exceeds length', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/287806' do - graph_edges = "A-->B;B-->A;" * 420 - - description = <<~MERMAID - ```mermaid - graph LR - #{graph_edges} - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - page.within('.description') do - expect(page).not_to have_selector('svg') - - expect(page).to have_selector('pre.mermaid') - - expect(page).to have_selector('.lazy-alert-shown') - - expect(page).to have_selector('.js-lazy-render-mermaid-container') - end - - wait_for_requests - wait_for_mermaid - - find('.js-lazy-render-mermaid').click - - page.within('.description') do - expect(page).to have_selector('svg') - - expect(page).not_to have_selector('.js-lazy-render-mermaid-container') - end - end - - it 'does not render more than 50 mermaid blocks', :js, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/234081' } do - graph_edges = "A-->B;B-->A;" - - description = <<~MERMAID - ```mermaid - graph LR - #{graph_edges} - ``` - MERMAID - - description *= 51 - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - page.within('.description') do - expect(page).to have_selector('svg') - - expect(page).to have_selector('.lazy-alert-shown') - - expect(page).to have_selector('.js-lazy-render-mermaid-container') - end - end - - it 'renders without any limits on wiki page', :js do - graph_edges = "A-->B;B-->A;" - - description = <<~MERMAID - ```mermaid - graph LR - #{graph_edges} - ``` - MERMAID - - description *= 51 - - wiki_page = build(:wiki_page, { container: project, content: description }) - wiki_page.create message: 'mermaid test commit' # rubocop:disable Rails/SaveBang - wiki_page = project.wiki.find_page(wiki_page.slug) - - visit project_wiki_path(project, wiki_page) - - wait_for_requests - wait_for_mermaid - - page.within('.js-wiki-page-content') do - expect(page).not_to have_selector('.lazy-alert-shown') - - expect(page).not_to have_selector('.js-lazy-render-mermaid-container') - end - end - - it 'does not allow HTML injection' do - description = <<~MERMAID - ```mermaid - %%{init: {"flowchart": {"htmlLabels": "false"}} }%% - flowchart - A["<iframe></iframe>"] - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - page.within('.description') do - expect(page).not_to have_xpath("//iframe") - end - end - - it 'correctly copies and pastes to/from the clipboard' do - stub_feature_flags(sandboxed_mermaid: true) - - description = <<~MERMAID - ```mermaid - graph TD; - A-->B; - A-->C; - ``` - MERMAID - - issue = create(:issue, project: project, description: description) - - user = create(:user) - sign_in(user) - visit project_issue_path(project, issue) - - wait_for_requests - wait_for_mermaid - - find('pre.language-mermaid').hover - find('copy-code button').click - - sleep 2 - - find('#note-body').send_keys [modifier_key, 'v'] - - wait_for_requests - - # The codefences do actually get included, but we can't get spec to pass - # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83202#note_880621264 - expect(find('#note-body').value.strip).to eq("graph TD;\n A-->B;\n A-->C;") - end -end - -def wait_for_mermaid - run_idle_callback = <<~RUN_IDLE_CALLBACK - window.requestIdleCallback(() => { - window.__CAPYBARA_IDLE_CALLBACK_EXEC__ = 1; - }) - RUN_IDLE_CALLBACK - - page.evaluate_script(run_idle_callback) - - Timeout.timeout(Capybara.default_max_wait_time) do - loop until finished_rendering? - end -end - -def finished_rendering? - check_idle_callback = <<~CHECK_IDLE_CALLBACK - window.__CAPYBARA_IDLE_CALLBACK_EXEC__ - CHECK_IDLE_CALLBACK - page.evaluate_script(check_idle_callback) == 1 -end diff --git a/spec/features/merge_request/batch_comments_spec.rb b/spec/features/merge_request/batch_comments_spec.rb index 9b54d95be6b..f03c812ebb5 100644 --- a/spec/features/merge_request/batch_comments_spec.rb +++ b/spec/features/merge_request/batch_comments_spec.rb @@ -13,224 +13,221 @@ RSpec.describe 'Merge request > Batch comments', :js do end before do - stub_feature_flags(paginated_notes: false) - project.add_maintainer(user) sign_in(user) + + visit_diffs end - context 'Feature is enabled' do - before do - visit_diffs - end + it 'adds draft note' do + write_diff_comment - it 'adds draft note' do - write_diff_comment + expect(find('.draft-note-component')).to have_content('Line is wrong') - expect(find('.draft-note-component')).to have_content('Line is wrong') + expect(page).to have_selector('[data-testid="review_bar_component"]') - expect(page).to have_selector('[data-testid="review_bar_component"]') + expect(find('[data-testid="review_bar_component"] .gl-badge')).to have_content('1') + end + + it 'publishes review' do + write_diff_comment - expect(find('[data-testid="review_bar_component"] .btn-confirm')).to have_content('1') + page.within('.review-bar-content') do + click_button 'Finish review' + click_button 'Submit review' end - it 'publishes review' do - write_diff_comment + wait_for_requests - page.within('.review-bar-content') do - click_button 'Submit review' - end + expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') - wait_for_requests + expect(page).to have_selector('.note:not(.draft-note)', text: 'Line is wrong') + end - expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') + it 'publishes single comment' do + write_diff_comment - expect(page).to have_selector('.note:not(.draft-note)', text: 'Line is wrong') - end + click_button 'Add comment now' - it 'publishes single comment' do - write_diff_comment + wait_for_requests - click_button 'Add comment now' + expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') - wait_for_requests + expect(page).to have_selector('.note:not(.draft-note)', text: 'Line is wrong') + end + + it 'deletes draft note' do + write_diff_comment - expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') + find('.js-note-delete').click - expect(page).to have_selector('.note:not(.draft-note)', text: 'Line is wrong') + page.within('.modal') do + click_button('Delete Comment', match: :first) end - it 'deletes draft note' do - write_diff_comment + wait_for_requests - find('.js-note-delete').click + expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') + end - page.within('.modal') do - click_button('Delete Comment', match: :first) - end + it 'edits draft note' do + write_diff_comment - wait_for_requests + find('.js-note-edit').click - expect(page).not_to have_selector('.draft-note-component', text: 'Line is wrong') - end + # make sure comment form is in view + execute_script("window.scrollBy(0, 200)") - it 'edits draft note' do - write_diff_comment + write_comment(text: 'Testing update', button_text: 'Save comment') - find('.js-note-edit').click + expect(page).to have_selector('.draft-note-component', text: 'Testing update') + end - # make sure comment form is in view - execute_script("window.scrollBy(0, 200)") + context 'with image and file draft note' do + let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project) } + let!(:draft_on_text) { create(:draft_note_on_text_diff, merge_request: merge_request, author: user, path: 'README.md', note: 'Lorem ipsum on text...') } + let!(:draft_on_image) { create(:draft_note_on_image_diff, merge_request: merge_request, author: user, path: 'files/images/ee_repo_logo.png', note: 'Lorem ipsum on an image...') } - write_comment(text: 'Testing update', button_text: 'Save comment') + it 'does not show in overview' do + visit_overview - expect(page).to have_selector('.draft-note-component', text: 'Testing update') + expect(page).to have_no_text(draft_on_text.note) + expect(page).to have_no_text(draft_on_image.note) end + end - context 'with image and file draft note' do - let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project) } - let!(:draft_on_text) { create(:draft_note_on_text_diff, merge_request: merge_request, author: user, path: 'README.md', note: 'Lorem ipsum on text...') } - let!(:draft_on_image) { create(:draft_note_on_image_diff, merge_request: merge_request, author: user, path: 'files/images/ee_repo_logo.png', note: 'Lorem ipsum on an image...') } - - it 'does not show in overview' do - visit_overview + context 'adding single comment to review' do + before do + visit_overview + end - expect(page).to have_no_text(draft_on_text.note) - expect(page).to have_no_text(draft_on_image.note) - end + it 'at first does not show `Add to review` and `Add comment now` buttons' do + expect(page).to have_no_button('Add to review') + expect(page).to have_no_button('Add comment now') end - context 'adding single comment to review' do + context 'when review has started' do before do - visit_overview - end - - it 'at first does not show `Add to review` and `Add comment now` buttons' do - expect(page).to have_no_button('Add to review') - expect(page).to have_no_button('Add comment now') - end - - context 'when review has started' do - before do - visit_diffs + visit_diffs - write_diff_comment + write_diff_comment - visit_overview - end + visit_overview + end - it 'can add comment to review' do - write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a draft comment', button_text: 'Add to review') + it 'can add comment to review' do + write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a draft comment', button_text: 'Add to review') - expect(page).to have_selector('.draft-note-component', text: 'Its a draft comment') + expect(page).to have_selector('.draft-note-component', text: 'Its a draft comment') - click_button('Pending comments') + click_button('Pending comments') - expect(page).to have_text('2 pending comments') - end + expect(page).to have_text('2 pending comments') + end - it 'can add comment right away' do - write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a regular comment', button_text: 'Add comment now') + it 'can add comment right away' do + write_comment(selector: '.js-main-target-form', field: 'note-body', text: 'Its a regular comment', button_text: 'Add comment now') - expect(page).to have_selector('.note:not(.draft-note)', text: 'Its a regular comment') + expect(page).to have_selector('.note:not(.draft-note)', text: 'Its a regular comment') - click_button('Pending comments') + click_button('Pending comments') - expect(page).to have_text('1 pending comment') - end + expect(page).to have_text('1 pending comment') end end + end - context 'in parallel diff' do - before do - find('.js-show-diff-settings').click - click_button 'Side-by-side' - find('.js-show-diff-settings').click - end + context 'in parallel diff' do + before do + find('.js-show-diff-settings').click + click_button 'Side-by-side' + find('.js-show-diff-settings').click + end - it 'adds draft comments to both sides' do - write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9') - write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9', button_text: 'Add to review', text: 'Another wrong line') + it 'adds draft comments to both sides' do + write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9') + write_parallel_comment('2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9', button_text: 'Add to review', text: 'Another wrong line') - expect(find('.new .draft-note-component')).to have_content('Line is wrong') - expect(find('.old .draft-note-component')).to have_content('Another wrong line') + expect(find('.new .draft-note-component')).to have_content('Line is wrong') + expect(find('.old .draft-note-component')).to have_content('Another wrong line') - expect(find('.review-bar-content .btn-confirm')).to have_content('2') - end + expect(find('.review-bar-content .gl-badge')).to have_content('2') end + end - context 'thread is unresolved' do - let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } + context 'thread is unresolved' do + let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } - before do - visit_diffs - end + before do + visit_diffs + end - it 'publishes comment right away and resolves the thread' do - expect(active_discussion.resolved?).to eq(false) + it 'publishes comment right away and resolves the thread' do + expect(active_discussion.resolved?).to eq(false) - write_reply_to_discussion(button_text: 'Add comment now', resolve: true) + write_reply_to_discussion(button_text: 'Add comment now', resolve: true) - page.within '.discussions-counter' do - expect(page).to have_content('All threads resolved') - end + page.within '.discussions-counter' do + expect(page).to have_content('All threads resolved') end + end - it 'publishes review and resolves the thread' do - expect(active_discussion.resolved?).to eq(false) + it 'publishes review and resolves the thread' do + expect(active_discussion.resolved?).to eq(false) - write_reply_to_discussion(resolve: true) + write_reply_to_discussion(resolve: true) - page.within('.review-bar-content') do - click_button 'Submit review' - end + page.within('.review-bar-content') do + click_button 'Finish review' + click_button 'Submit review' + end - wait_for_requests + wait_for_requests - page.within '.discussions-counter' do - expect(page).to have_content('All threads resolved') - end + page.within '.discussions-counter' do + expect(page).to have_content('All threads resolved') end end + end - context 'thread is resolved' do - let!(:active_discussion) { create(:diff_note_on_merge_request, :resolved, noteable: merge_request, project: project).to_discussion } + context 'thread is resolved' do + let!(:active_discussion) { create(:diff_note_on_merge_request, :resolved, noteable: merge_request, project: project).to_discussion } - before do - active_discussion.resolve!(@current_user) + before do + active_discussion.resolve!(@current_user) - visit_diffs + visit_diffs - page.find('.js-diff-comment-avatar').click - end + page.find('.js-diff-comment-avatar').click + end - it 'publishes comment right away and unresolves the thread' do - expect(active_discussion.resolved?).to eq(true) + it 'publishes comment right away and unresolves the thread' do + expect(active_discussion.resolved?).to eq(true) - write_reply_to_discussion(button_text: 'Add comment now', unresolve: true) + write_reply_to_discussion(button_text: 'Add comment now', unresolve: true) - page.within '.discussions-counter' do - expect(page).to have_content('1 unresolved thread') - end + page.within '.discussions-counter' do + expect(page).to have_content('1 unresolved thread') end + end - it 'publishes review and unresolves the thread' do - expect(active_discussion.resolved?).to eq(true) + it 'publishes review and unresolves the thread' do + expect(active_discussion.resolved?).to eq(true) - wait_for_requests + wait_for_requests - write_reply_to_discussion(button_text: 'Start a review', unresolve: true) + write_reply_to_discussion(button_text: 'Start a review', unresolve: true) - page.within('.review-bar-content') do - click_button 'Submit review' - end + page.within('.review-bar-content') do + click_button 'Finish review' + click_button 'Submit review' + end - wait_for_requests + wait_for_requests - page.within '.discussions-counter' do - expect(page).to have_content('1 unresolved thread') - end + page.within '.discussions-counter' do + expect(page).to have_content('1 unresolved thread') end end end 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 99756da51e4..06b29969775 100644 --- a/spec/features/merge_request/user_comments_on_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_diff_spec.rb @@ -14,7 +14,6 @@ RSpec.describe 'User comments on a diff', :js do let(:user) { create(:user) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/merge_request/user_creates_merge_request_spec.rb b/spec/features/merge_request/user_creates_merge_request_spec.rb index a3dc3079374..2bf8e9ba6a4 100644 --- a/spec/features/merge_request/user_creates_merge_request_spec.rb +++ b/spec/features/merge_request/user_creates_merge_request_spec.rb @@ -30,7 +30,6 @@ RSpec.describe "User creates a merge request", :js do it "shows merge request form" do page.within('.merge-request-form') do - expect(page.find('#merge_request_title')['placeholder']).to eq 'Title' expect(page.find('#merge_request_description')['placeholder']).to eq 'Describe the goal of the changes and what reviewers should be aware of.' end end @@ -100,7 +99,7 @@ RSpec.describe "User creates a merge request", :js do click_button("Compare branches and continue") - expect(page).to have_css("h3.page-title", text: "New merge request") + expect(page).to have_text _('New merge request') page.within("form#new_merge_request") do fill_in("Title", with: title) 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 64715f9234a..8a310aba77b 100644 --- a/spec/features/merge_request/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'Merge request > User posts diff notes', :js do project.add_developer(user) sign_in(user) - stub_feature_flags(bootstrap_confirmation_modals: false) + stub_const('Gitlab::QueryLimiting::Transaction::THRESHOLD', 104) end context 'when hovering over a parallel view diff file' do diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index ad602afe68a..844ef6133c8 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -18,7 +18,6 @@ RSpec.describe 'Merge request > User posts notes', :js do end before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_maintainer(user) sign_in(user) @@ -158,7 +157,7 @@ RSpec.describe 'Merge request > User posts notes', :js do page.within("#note_#{note.id}") do expect(find('.current-note-edit-form', visible: true)).to be_visible expect(find('.note-edit-form', visible: true)).to be_visible - expect(find(:css, '.note-body > .note-text', visible: false)).not_to be_visible + expect(find(:css, '.note-body .note-text', visible: false)).not_to be_visible end end diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb index 982e75760d7..a04ca4e789c 100644 --- a/spec/features/merge_request/user_resolves_conflicts_spec.rb +++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb @@ -178,23 +178,6 @@ RSpec.describe 'Merge request > User resolves conflicts', :js do end end - context 'sidebar' do - let(:merge_request) { create_merge_request('conflict-resolvable') } - - before do - project.add_developer(user) - sign_in(user) - - visit conflicts_project_merge_request_path(project, merge_request) - end - - it 'displays reviewers' do - page.within '.issuable-sidebar' do - expect(page).to have_selector('[data-testid="reviewer"]', count: 1) - end - end - end - unresolvable_conflicts = { 'conflict-too-large' => 'when the conflicts contain a large file', 'conflict-binary-file' => 'when the conflicts contain a binary file', 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 fca40dc7edc..0e9ff98c3e1 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 @@ -83,7 +83,6 @@ RSpec.describe 'Merge request > User sees avatars on diff notes', :js do %w(parallel).each do |view| context "#{view} view" do before do - stub_feature_flags(bootstrap_confirmation_modals: false) visit diffs_project_merge_request_path(project, merge_request, view: view) wait_for_requests diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb index 01cc58777ba..81034caaee2 100644 --- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb +++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb @@ -109,10 +109,12 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do end context 'with stop action' do - let(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } + let(:manual) do + create(:ci_build, :manual, pipeline: pipeline, + name: 'close_app', environment: environment.name) + end before do - stub_feature_flags(bootstrap_confirmation_modals: false) build.success! deployment.update!(on_stop: manual.name) visit project_merge_request_path(project, merge_request) diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb index d79763ba5e0..cc477e363a4 100644 --- a/spec/features/merge_request/user_sees_discussions_spec.rb +++ b/spec/features/merge_request/user_sees_discussions_spec.rb @@ -62,7 +62,7 @@ RSpec.describe 'Merge request > User sees threads', :js do within(".discussion[data-discussion-id='#{discussion_id}']") do find_field('Reply…').click fill_in 'note[note]', with: 'Test!' - click_button 'Comment' + click_button 'Reply' expect(page).to have_css('.note', count: 2) end diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index 2b856811e02..4465d7e29be 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -101,6 +101,7 @@ RSpec.describe 'Merge request > User sees versions', :js do outdated_diff_note.save! refresh + wait_for_requests expect(page).to have_css(".diffs .notes[data-discussion-id='#{outdated_diff_note.discussion_id}']") end diff --git a/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb b/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb index f637186ec67..b214486b3c1 100644 --- a/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb +++ b/spec/features/merge_request/user_views_user_status_on_merge_request_spec.rb @@ -10,16 +10,6 @@ RSpec.describe 'Project > Merge request > View user status' do subject { visit merge_request_path(merge_request) } - describe 'the status of the merge request author' do - before do - stub_feature_flags(updated_mr_header: false) - end - - it_behaves_like 'showing user status' do - let(:user_with_status) { merge_request.author } - end - end - context 'for notes', :js do describe 'the status of the author of a note on a merge request' do let(:note) { create(:note, noteable: merge_request, project: project, author: create(:user)) } diff --git a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb index 459145d3ef0..4a124299c61 100644 --- a/spec/features/merge_requests/user_sorts_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_sorts_merge_requests_spec.rb @@ -17,8 +17,6 @@ RSpec.describe 'User sorts merge requests', :js do let_it_be(:project) { create(:project, :public, group: group) } before do - stub_feature_flags(vue_issues_list: true) - sign_in(user) visit(project_merge_requests_path(project)) diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index b9594293996..5bbd89f1b88 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -64,7 +64,7 @@ RSpec.describe 'Milestone' do end find('input[name="commit"]').click - expect(find('.alert-danger')).to have_content('already being used for another group or project milestone.') + expect(find('.gl-alert-danger')).to have_content('already being used for another group or project milestone.') end end @@ -122,8 +122,8 @@ RSpec.describe 'Milestone' do click_link 'Reopen Milestone' - expect(page).not_to have_selector('.status-box-closed') - expect(page).to have_selector('.status-box-open') + expect(page).not_to have_selector('.gl-bg-red-500') + expect(page).to have_selector('.gl-bg-green-500') end end @@ -133,8 +133,8 @@ RSpec.describe 'Milestone' do click_link 'Reopen Milestone' - expect(page).not_to have_selector('.status-box-closed') - expect(page).to have_selector('.status-box-open') + expect(page).not_to have_selector('.gl-bg-red-500') + expect(page).to have_selector('.gl-bg-green-500') end end end diff --git a/spec/features/nav/top_nav_responsive_spec.rb b/spec/features/nav/top_nav_responsive_spec.rb index 5c6a12a37a3..d571327e4b5 100644 --- a/spec/features/nav/top_nav_responsive_spec.rb +++ b/spec/features/nav/top_nav_responsive_spec.rb @@ -41,7 +41,7 @@ RSpec.describe 'top nav responsive', :js do end it 'has new dropdown', :aggregate_failures do - click_button('New...') + click_button('Create new') expect(page).to have_link('New project', href: new_project_path) expect(page).to have_link('New group', href: new_group_path) diff --git a/spec/features/nav/top_nav_tooltip_spec.rb b/spec/features/nav/top_nav_tooltip_spec.rb new file mode 100644 index 00000000000..58bfe1caf65 --- /dev/null +++ b/spec/features/nav/top_nav_tooltip_spec.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'top nav tooltips', :js do + let_it_be(:user) { create(:user) } + + before do + sign_in(user) + visit explore_projects_path + end + + it 'clicking new dropdown hides tooltip', :aggregate_failures do + btn = '#js-onboarding-new-project-link' + + page.find(btn).hover + + expect(page).to have_content('Create new') + + page.find(btn).click + + expect(page).not_to have_content('Create new') + end +end diff --git a/spec/features/oauth_registration_spec.rb b/spec/features/oauth_registration_spec.rb new file mode 100644 index 00000000000..18dd10755b1 --- /dev/null +++ b/spec/features/oauth_registration_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'OAuth Registration', :js, :allow_forgery_protection do + include DeviseHelpers + include LoginHelpers + include TermsHelper + using RSpec::Parameterized::TableSyntax + + around do |example| + with_omniauth_full_host { example.run } + end + + context 'when the user registers using single-sign on provider' do + let(:uid) { 'my-uid' } + let(:email) { 'user@example.com' } + + where(:provider, :additional_info) do + :github | {} + :twitter | {} + :bitbucket | {} + :gitlab | {} + :google_oauth2 | {} + :facebook | {} + :cas3 | {} + :auth0 | {} + :authentiq | {} + :salesforce | { extra: { email_verified: true } } + :dingtalk | {} + :alicloud | {} + end + + with_them do + before do + stub_omniauth_provider(provider) + stub_feature_flags(update_oauth_registration_flow: true) + end + + context 'when block_auto_created_users is true' do + before do + stub_omniauth_setting(block_auto_created_users: true) + end + + it 'redirects back to the sign-in page' do + register_via(provider, uid, email, additional_info: additional_info) + + expect(page).to have_current_path new_user_session_path + expect(page).to have_content('Your account is pending approval') + end + end + + context 'when block_auto_created_users is false' do + before do + stub_omniauth_setting(block_auto_created_users: false) + end + + it 'redirects to the initial welcome path' do + register_via(provider, uid, email, additional_info: additional_info) + + expect(page).to have_current_path users_sign_up_welcome_path + expect(page).to have_content('Welcome to GitLab, mockuser!') + end + + context 'when terms are enforced' do + before do + enforce_terms + end + + it 'auto accepts terms and redirects to the initial welcome path' do + register_via(provider, uid, email, additional_info: additional_info) + + expect(page).to have_current_path users_sign_up_welcome_path + expect(page).to have_content('Welcome to GitLab, mockuser!') + end + end + + context 'when provider does not send a verified email address' do + let(:email) { 'temp-email-for-oauth@email.com' } + + it 'redirects to the profile path' do + register_via(provider, uid, email, additional_info: additional_info) + + expect(page).to have_current_path profile_path + expect(page).to have_content('Please complete your profile with email address') + end + end + end + end + end +end diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb index 36657406303..1013937ebb9 100644 --- a/spec/features/profile_spec.rb +++ b/spec/features/profile_spec.rb @@ -3,10 +3,11 @@ require 'spec_helper' RSpec.describe 'Profile account page', :js do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:user) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -65,11 +66,17 @@ RSpec.describe 'Profile account page', :js do it 'allows resetting of feed token' do visit profile_personal_access_tokens_path + previous_token = '' + within('[data-testid="feed-token-container"]') do previous_token = find_field('Feed token').value - accept_confirm { click_link('reset this token') } + click_link('reset this token') + end + accept_gl_confirm + + within('[data-testid="feed-token-container"]') do click_button('Click to reveal') expect(find_field('Feed token').value).not_to eq(previous_token) @@ -81,11 +88,17 @@ RSpec.describe 'Profile account page', :js do visit profile_personal_access_tokens_path + previous_token = '' + within('[data-testid="incoming-email-token-container"]') do previous_token = find_field('Incoming email token').value - accept_confirm { click_link('reset this token') } + click_link('reset this token') + end + + accept_gl_confirm + within('[data-testid="incoming-email-token-container"]') do click_button('Click to reveal') expect(find_field('Incoming email token').value).not_to eq(previous_token) diff --git a/spec/features/profiles/active_sessions_spec.rb b/spec/features/profiles/active_sessions_spec.rb index a515c7b1c1f..24c9225532b 100644 --- a/spec/features/profiles/active_sessions_spec.rb +++ b/spec/features/profiles/active_sessions_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do + include Spec::Support::Helpers::ModalHelpers + let(:user) do create(:user).tap do |user| user.current_sign_in_at = Time.current @@ -11,10 +13,6 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do let(:admin) { create(:admin) } - before do - stub_feature_flags(bootstrap_confirmation_modals: false) - end - it 'user sees their active sessions' do travel_to(Time.zone.parse('2018-03-12 09:06')) do Capybara::Session.new(:session1) @@ -101,7 +99,9 @@ RSpec.describe 'Profile > Active Sessions', :clean_gitlab_redis_shared_state do expect(page).to have_link('Revoke', count: 1) - accept_confirm { click_on 'Revoke' } + accept_gl_confirm(button_text: 'Revoke') do + click_on 'Revoke' + end expect(page).not_to have_link('Revoke') end diff --git a/spec/features/profiles/oauth_applications_spec.rb b/spec/features/profiles/oauth_applications_spec.rb index 9d79041dc9d..ee1daf69f62 100644 --- a/spec/features/profiles/oauth_applications_spec.rb +++ b/spec/features/profiles/oauth_applications_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe 'Profile > Applications' do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:user) } let(:application) { create(:oauth_application, owner: user) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -25,9 +26,11 @@ RSpec.describe 'Profile > Applications' do page.within('.oauth-applications') do expect(page).to have_content('Your applications (1)') - accept_confirm { click_button 'Destroy' } + click_button 'Destroy' end + accept_gl_confirm(button_text: 'Destroy') + expect(page).to have_content('The application was deleted successfully') expect(page).to have_content('Your applications (0)') expect(page).to have_content('Authorized applications (0)') @@ -39,9 +42,11 @@ RSpec.describe 'Profile > Applications' do page.within('.oauth-authorized-applications') do expect(page).to have_content('Authorized applications (1)') - accept_confirm { click_button 'Revoke' } + click_button 'Revoke' end + accept_gl_confirm(button_text: 'Revoke application') + expect(page).to have_content('The application was revoked access.') expect(page).to have_content('Your applications (0)') expect(page).to have_content('Authorized applications (0)') diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 8cbc0491441..bca1bc4df4d 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -3,34 +3,24 @@ require 'spec_helper' RSpec.describe 'Profile > Personal Access Tokens', :js do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:user) } let(:pat_create_service) { double('PersonalAccessTokens::CreateService', execute: ServiceResponse.error(message: 'error', payload: { personal_access_token: PersonalAccessToken.new })) } def active_personal_access_tokens - find(".table.active-tokens") - end - - def no_personal_access_tokens_message - find(".settings-message") + find("[data-testid='active-tokens']") end def created_personal_access_token - find("#created-personal-access-token").value + find_field('new-access-token').value end def feed_token_description "Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs." end - def disallow_personal_access_token_saves! - allow(PersonalAccessTokens::CreateService).to receive(:new).and_return(pat_create_service) - - 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) - end - before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -51,6 +41,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do check "read_user" click_on "Create personal access token" + wait_for_all_requests expect(active_personal_access_tokens).to have_text(name) expect(active_personal_access_tokens).to have_text('in') @@ -61,13 +52,16 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do context "when creation fails" do it "displays an error message" do - disallow_personal_access_token_saves! + number_tokens_before = PersonalAccessToken.count visit profile_personal_access_tokens_path fill_in "Token name", with: 'My PAT' - expect { click_on "Create personal access token" }.not_to change { PersonalAccessToken.count } - expect(page).to have_content("Name cannot be nil") - expect(page).not_to have_selector("#created-personal-access-token") + click_on "Create personal access token" + wait_for_all_requests + + expect(number_tokens_before).to equal(PersonalAccessToken.count) + expect(page).to have_content(_("Scopes can't be blank")) + expect(page).not_to have_selector("[data-testid='new-access-tokens']") end end end @@ -101,31 +95,27 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do it "allows revocation of an active token" do visit profile_personal_access_tokens_path - accept_confirm { click_on "Revoke" } + accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" } - expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active personal access tokens.") + expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.") end it "removes expired tokens from 'active' section" do personal_access_token.update!(expires_at: 5.days.ago) visit profile_personal_access_tokens_path - expect(page).to have_selector(".settings-message") - expect(no_personal_access_tokens_message).to have_text("This user has no active personal access tokens.") + expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.") end context "when revocation fails" do it "displays an error message" do - visit profile_personal_access_tokens_path - allow_next_instance_of(PersonalAccessTokens::RevokeService) do |instance| allow(instance).to receive(:revocation_permitted?).and_return(false) end + visit profile_personal_access_tokens_path - accept_confirm { click_on "Revoke" } + accept_gl_confirm(button_text: "Revoke") { click_on "Revoke" } expect(active_personal_access_tokens).to have_text(personal_access_token.name) - expect(page).to have_content("Not permitted to revoke") end end end diff --git a/spec/features/profiles/user_visits_profile_spec.rb b/spec/features/profiles/user_visits_profile_spec.rb index 7d545711997..8b1af283765 100644 --- a/spec/features/profiles/user_visits_profile_spec.rb +++ b/spec/features/profiles/user_visits_profile_spec.rb @@ -89,6 +89,10 @@ RSpec.describe 'User visits their profile' do end describe 'storage_enforcement_banner', :js do + before do + stub_feature_flags(namespace_storage_limit_bypass_date_check: false) + end + context 'with storage_enforcement_date set' do let_it_be(:storage_enforcement_date) { Date.today + 30 } diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb index cc59fea173b..89dbd1afc6b 100644 --- a/spec/features/project_variables_spec.rb +++ b/spec/features/project_variables_spec.rb @@ -12,28 +12,36 @@ RSpec.describe 'Project variables', :js do sign_in(user) project.add_maintainer(user) project.variables << variable - visit page_path end - it_behaves_like 'variable list' - - it 'adds a new variable with an environment scope' do - click_button('Add variable') + # TODO: Add same tests but with FF enabled context when + # the new graphQL app for variable settings is enabled. + context 'with disabled ff `ci_variable_settings_graphql' do + before do + stub_feature_flags(ci_variable_settings_graphql: false) + visit page_path + end - page.within('#add-ci-variable') do - fill_in 'Key', with: 'akey' - find('#ci-variable-value').set('akey_value') - find('[data-testid="environment-scope"]').click - find('[data-testid="ci-environment-search"]').set('review/*') - find('[data-testid="create-wildcard-button"]').click + it_behaves_like 'variable list' + it 'adds a new variable with an environment scope' do click_button('Add variable') - end - wait_for_requests + page.within('#add-ci-variable') do + fill_in 'Key', with: 'akey' + find('#ci-variable-value').set('akey_value') + find('[data-testid="environment-scope"]').click + find('[data-testid="ci-environment-search"]').set('review/*') + find('[data-testid="create-wildcard-button"]').click + + click_button('Add variable') + end + + wait_for_requests - page.within('[data-testid="ci-variable-table"]') do - expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*') + page.within('[data-testid="ci-variable-table"]') do + expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*') + end end end end diff --git a/spec/features/projects/branches/user_deletes_branch_spec.rb b/spec/features/projects/branches/user_deletes_branch_spec.rb index 0d08e7ea10d..a89fed3a78a 100644 --- a/spec/features/projects/branches/user_deletes_branch_spec.rb +++ b/spec/features/projects/branches/user_deletes_branch_spec.rb @@ -3,6 +3,8 @@ require "spec_helper" RSpec.describe "User deletes branch", :js do + include Spec::Support::Helpers::ModalHelpers + let_it_be(:user) { create(:user) } let(:project) { create(:project, :repository) } @@ -24,9 +26,7 @@ RSpec.describe "User deletes branch", :js do find('.js-delete-branch-button').click end - page.within '.modal-footer' do - click_button 'Yes, delete branch' - end + accept_gl_confirm(button_text: 'Yes, delete branch') wait_for_requests diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb index 2f960c09936..8197fe46c7b 100644 --- a/spec/features/projects/ci/editor_spec.rb +++ b/spec/features/projects/ci/editor_spec.rb @@ -12,8 +12,6 @@ RSpec.describe 'Pipeline Editor', :js do let(:other_branch) { 'test' } before do - stub_feature_flags(pipeline_editor_file_tree: false) - sign_in(user) project.add_developer(user) @@ -70,14 +68,8 @@ RSpec.describe 'Pipeline Editor', :js do expect(page).to have_content('Pipeline Editor') end - describe 'Branch Switcher (pipeline_editor_file_tree disabled)' do - it_behaves_like 'default branch switcher behavior' - end - - describe 'Branch Switcher (pipeline_editor_file_tree enabled)' do + describe 'Branch Switcher' do before do - stub_feature_flags(pipeline_editor_file_tree: true) - visit project_ci_pipeline_editor_path(project) wait_for_requests diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index a8a23ba1c85..5c54b7fda7c 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -66,9 +66,9 @@ RSpec.describe 'Gcp Cluster', :js do context 'when user destroys the cluster' do before do click_link 'Advanced Settings' - click_button 'Remove integration and resources' + find('[data-testid="remove-integration-button"]').click fill_in 'confirm_cluster_name_input', with: cluster.name - click_button 'Remove integration' + find('[data-testid="remove-integration-modal-button"]').click click_link 'Certificate' end diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index b6bfaa3a9b9..527d038f975 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -100,9 +100,9 @@ RSpec.describe 'User Cluster', :js do context 'when user destroys the cluster' do before do click_link 'Advanced Settings' - click_button 'Remove integration and resources' + find('[data-testid="remove-integration-button"]').click fill_in 'confirm_cluster_name_input', with: cluster.name - click_button 'Remove integration' + find('[data-testid="remove-integration-modal-button"]').click click_link 'Certificate' end diff --git a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb index 67d3276fc14..9059f9e4857 100644 --- a/spec/features/projects/commit/comments/user_deletes_comments_spec.rb +++ b/spec/features/projects/commit/comments/user_deletes_comments_spec.rb @@ -4,6 +4,7 @@ require "spec_helper" RSpec.describe "User deletes comments on a commit", :js do include Spec::Support::Helpers::Features::NotesHelpers + include Spec::Support::Helpers::ModalHelpers include RepoHelpers let(:comment_text) { "XML attached" } @@ -11,7 +12,6 @@ RSpec.describe "User deletes comments on a commit", :js do let(:user) { create(:user) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) project.add_developer(user) @@ -32,9 +32,11 @@ RSpec.describe "User deletes comments on a commit", :js do find(".more-actions").click find(".more-actions .dropdown-menu li", match: :first) - accept_confirm { find(".js-note-delete").click } + find(".js-note-delete").click end + accept_gl_confirm(button_text: 'Delete comment') + expect(page).not_to have_css(".note") end end diff --git a/spec/features/projects/commit/user_comments_on_commit_spec.rb b/spec/features/projects/commit/user_comments_on_commit_spec.rb index b0be6edb245..a7f23f093a3 100644 --- a/spec/features/projects/commit/user_comments_on_commit_spec.rb +++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb @@ -4,6 +4,7 @@ require "spec_helper" RSpec.describe "User comments on commit", :js do include Spec::Support::Helpers::Features::NotesHelpers + include Spec::Support::Helpers::ModalHelpers include RepoHelpers let_it_be(:project) { create(:project, :repository) } @@ -93,8 +94,6 @@ RSpec.describe "User comments on commit", :js do context "when deleting comment" do before do - stub_feature_flags(bootstrap_confirmation_modals: false) - visit(project_commit_path(project, sample_commit.id)) add_note(comment_text) @@ -112,9 +111,11 @@ RSpec.describe "User comments on commit", :js do find(".more-actions").click find(".more-actions .dropdown-menu li", match: :first) - accept_confirm { find(".js-note-delete").click } + find(".js-note-delete").click end + accept_gl_confirm(button_text: 'Delete comment') + expect(page).not_to have_css(".note") end end diff --git a/spec/features/projects/commits/multi_view_diff_spec.rb b/spec/features/projects/commits/multi_view_diff_spec.rb index 009dd05c6d1..282112a3767 100644 --- a/spec/features/projects/commits/multi_view_diff_spec.rb +++ b/spec/features/projects/commits/multi_view_diff_spec.rb @@ -18,71 +18,77 @@ RSpec.describe 'Multiple view Diffs', :js do let(:feature_flag_on) { false } before do - stub_feature_flags(rendered_diffs_viewer: feature_flag_on ? project : false) - visit path wait_for_all_requests end - context 'when :rendered_diffs_viewer is off' do - context 'and diff does not have ipynb' do - it_behaves_like "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b' + context 'diff does not include ipynb' do + it_behaves_like "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b' + + context 'and in inline diff' do + let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' } + + it 'does not change display for non-ipynb' do + expect(page).to have_selector line_with_content('new', 1) + end end - context 'and diff has ipynb' do - it_behaves_like "no multiple viewers", '5d6ed1503801ca9dc28e95eeb85a7cf863527aee' + context 'and in parallel diff' do + let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' } + + it 'does not change display for non-ipynb' do + page.find('#parallel-diff-btn').click + + expect(page).to have_selector line_with_content('new', 1) + end end end - context 'when :rendered_diffs_viewer is on' do - let(:feature_flag_on) { true } + context 'opening a diff with ipynb' do + it 'loads the rendered diff as hidden' do + diff = page.find('.diff-file, .file-holder', match: :first) - context 'and diff does not include ipynb' do - it_behaves_like "no multiple viewers", 'ddd0f15ae83993f5cb66a927a28673882e99100b' + expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' + expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' - context 'and in inline diff' do - let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' } + expect(classes_for_element(diff, 'toHide', visible: false)).to include('hidden') + expect(classes_for_element(diff, 'toShow')).not_to include('hidden') - it 'does not change display for non-ipynb' do - expect(page).to have_selector line_with_content('new', 1) - end - end + expect(classes_for_element(diff, 'toShowBtn')).to include('selected') + expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') + end - context 'and in parallel diff' do - let(:ref) { '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' } + it 'displays the rendered diff and hides after selection changes' do + diff = page.find('.diff-file, .file-holder', match: :first) + diff.find('[data-diff-toggle-entity="toShowBtn"]').click - it 'does not change display for non-ipynb' do - page.find('#parallel-diff-btn').click + expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' + expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' - expect(page).to have_selector line_with_content('new', 1) - end - end + expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') + expect(classes_for_element(diff, 'toShowBtn')).to include('selected') end - context 'and opening a diff with ipynb' do - it 'loads the rendered diff as hidden' do - diff = page.find('.diff-file, .file-holder', match: :first) - - expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' - expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' + it 'transforms the diff' do + diff = page.find('.diff-file, .file-holder', match: :first) - expect(classes_for_element(diff, 'toHide', visible: false)).to include('hidden') - expect(classes_for_element(diff, 'toShow')).not_to include('hidden') + expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:') + end - expect(classes_for_element(diff, 'toShowBtn')).to include('selected') - expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') + context 'on parallel view' do + before do + page.find('#parallel-diff-btn').click end - it 'displays the rendered diff and hides after selection changes' do - diff = page.find('.diff-file, .file-holder', match: :first) - diff.find('[data-diff-toggle-entity="toShowBtn"]').click - - expect(diff).to have_selector '[data-diff-toggle-entity="toShow"]' - expect(diff).not_to have_selector '[data-diff-toggle-entity="toHide"]' + it 'lines without mapping cannot receive comments' do + expect(page).not_to have_selector('td.line_content.nomappinginraw ~ td.diff-line-num > .add-diff-note') + expect(page).to have_selector('td.line_content:not(.nomappinginraw) ~ td.diff-line-num > .add-diff-note') + end - expect(classes_for_element(diff, 'toHideBtn')).not_to include('selected') - expect(classes_for_element(diff, 'toShowBtn')).to include('selected') + it 'lines numbers without mapping are empty' do + expect(page).not_to have_selector('td.nomappinginraw + td.diff-line-num') + expect(page).to have_selector('td.nomappinginraw + td.diff-line-num', visible: false) end it 'transforms the diff' do @@ -90,40 +96,18 @@ RSpec.describe 'Multiple view Diffs', :js do expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:') end + end - context 'on parallel view' do - before do - page.find('#parallel-diff-btn').click - end - - it 'lines without mapping cannot receive comments' do - expect(page).not_to have_selector('td.line_content.nomappinginraw ~ td.diff-line-num > .add-diff-note') - expect(page).to have_selector('td.line_content:not(.nomappinginraw) ~ td.diff-line-num > .add-diff-note') - end - - it 'lines numbers without mapping are empty' do - expect(page).not_to have_selector('td.nomappinginraw + td.diff-line-num') - expect(page).to have_selector('td.nomappinginraw + td.diff-line-num', visible: false) - end - - it 'transforms the diff' do - diff = page.find('.diff-file, .file-holder', match: :first) - - expect(diff['innerHTML']).to include('%% Cell type:markdown id:0aac5da7-745c-4eda-847a-3d0d07a1bb9b tags:') - end + context 'on inline view' do + it 'lines without mapping cannot receive comments' do + expect(page).not_to have_selector('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num > .add-diff-note') + expect(page).to have_selector('tr.line_holder:not([class$="nomappinginraw"]) > td.diff-line-num > .add-diff-note') end - context 'on inline view' do - it 'lines without mapping cannot receive comments' do - expect(page).not_to have_selector('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num > .add-diff-note') - expect(page).to have_selector('tr.line_holder:not([class$="nomappinginraw"]) > td.diff-line-num > .add-diff-note') - end - - it 'lines numbers without mapping are empty' do - elements = page.all('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num').map { |e| e.text(:all) } + it 'lines numbers without mapping are empty' do + elements = page.all('tr.line_holder[class$="nomappinginraw"] > td.diff-line-num').map { |e| e.text(:all) } - expect(elements).to all(be == "") - end + expect(elements).to all(be == "") end end end diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb index 17eb421191f..54685441300 100644 --- a/spec/features/projects/container_registry_spec.rb +++ b/spec/features/projects/container_registry_spec.rb @@ -122,7 +122,7 @@ RSpec.describe 'Container Registry', :js do it 'renders the tags list correctly' do expect(page).to have_content('latest') expect(page).to have_content('stable') - expect(page).to have_content('Digest: N/A') + expect(page).to have_content('Digest: Not applicable.') end end diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index bfd54b9c6da..951b24eafac 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -157,7 +157,7 @@ RSpec.describe 'Environment' do context 'with related deployable present' do let(:pipeline) { create(:ci_pipeline, project: project) } - let(:build) { create(:ci_build, pipeline: pipeline) } + let(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) } let(:deployment) do create(:deployment, :success, environment: environment, deployable: build) @@ -261,9 +261,12 @@ RSpec.describe 'Environment' do context 'when environment is available' do context 'with stop action' do + let(:build) { create(:ci_build, :success, pipeline: pipeline, environment: environment.name) } + let(:action) do create(:ci_build, :manual, pipeline: pipeline, - name: 'close_app') + name: 'close_app', + environment: environment.name) end let(:deployment) do @@ -283,7 +286,6 @@ RSpec.describe 'Environment' do click_button('Stop') click_button('Stop environment') # confirm modal wait_for_all_requests - expect(page).to have_button('Delete') end end @@ -361,8 +363,6 @@ RSpec.describe 'Environment' do end visit_environment(environment) - - expect(page).not_to have_button('Stop') end ## diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 6cf59394af7..9ec41cd8f8d 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -132,8 +132,6 @@ RSpec.describe 'Environments page', :js do create(:environment, project: project, state: :available) end - stub_feature_flags(bootstrap_confirmation_modals: false) - context 'when there are no deployments' do before do visit_environments(project) diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 23fcc1fe444..649c21d4459 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -189,7 +189,7 @@ RSpec.describe 'Edit Project Settings' do click_button "Save changes" end - expect(find(".sharing-permissions")).to have_selector(".gl-toggle.is-disabled", minimum: 4) + expect(find(".sharing-permissions")).to have_selector(".gl-toggle.is-disabled", minimum: 3) end it "shows empty features project homepage" do diff --git a/spec/features/projects/hook_logs/user_reads_log_spec.rb b/spec/features/projects/hook_logs/user_reads_log_spec.rb index 8513a9374d1..9b7ec14c36f 100644 --- a/spec/features/projects/hook_logs/user_reads_log_spec.rb +++ b/spec/features/projects/hook_logs/user_reads_log_spec.rb @@ -3,21 +3,80 @@ require 'spec_helper' RSpec.describe 'Hook logs' do - let(:web_hook_log) { create(:web_hook_log, response_body: '<script>') } - let(:project) { web_hook_log.web_hook.project } + let(:project) { create(:project) } + let(:project_hook) { create(:project_hook, project: project) } + let(:web_hook_log) { create(:web_hook_log, web_hook: project_hook, response_body: 'Hello World') } let(:user) { create(:user) } before do + web_hook_log project.add_maintainer(user) sign_in(user) end - it 'user reads log without getting XSS' do - visit( - project_hook_hook_log_path( - project, web_hook_log.web_hook, web_hook_log)) + it 'shows list of hook logs' do + visit edit_project_hook_path(project, project_hook) - expect(page).to have_content('<script>') + expect(page).to have_content('Recent events') + expect(page).to have_link('View details', href: project_hook_hook_log_path(project, project_hook, web_hook_log)) + end + + it 'shows hook log details' do + visit edit_project_hook_path(project, project_hook) + click_link 'View details' + + expect(page).to have_content("POST #{web_hook_log.url}") + expect(page).to have_content(web_hook_log.response_body) + expect(page).to have_content('Resend Request') + end + + it 'retries hook log' do + WebMock.stub_request(:post, project_hook.url) + + visit edit_project_hook_path(project, project_hook) + click_link 'View details' + click_link 'Resend Request' + + expect(page).to have_current_path(edit_project_hook_path(project, project_hook), ignore_query: true) + end + + context 'request gets internal error' do + let(:web_hook_log) { create(:web_hook_log, web_hook: project_hook, internal_error_message: 'Some error') } + + it 'shows hook log details with internal error message' do + visit edit_project_hook_path(project, project_hook) + click_link 'View details' + + expect(page).to have_content("POST #{web_hook_log.url}") + expect(page).to have_content(web_hook_log.internal_error_message) + expect(page).to have_content('Resend Request') + end + end + + context 'response body contains XSS string' do + let(:web_hook_log) { create(:web_hook_log, web_hook: project_hook, response_body: '<script>') } + + it 'displays log without getting XSS' do + visit(project_hook_hook_log_path(project, project_hook, web_hook_log)) + + expect(page).to have_content('<script>') + end + end + + context 'response data is too large' do + let(:web_hook_log) do + create(:web_hook_log, web_hook: project_hook, request_data: WebHookLog::OVERSIZE_REQUEST_DATA) + end + + it 'shows request data as too large and disables retry function' do + visit(project_hook_hook_log_path(project, project_hook, web_hook_log)) + + expect(page).to have_content('Request data is too large') + expect(page).not_to have_button( + _('Resent request'), + disabled: true, class: 'has-tooltip', title: _("Request data is too large") + ) + end end end diff --git a/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb index 2821f35f6a6..e7d4ed58549 100644 --- a/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb +++ b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'User activates issue tracker', :js do it 'activates the integration' do expect(page).to have_content("#{tracker} settings saved and active.") - expect(page).to have_current_path(edit_project_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) end it 'shows the link in the menu' do @@ -58,7 +58,7 @@ RSpec.describe 'User activates issue tracker', :js do end expect(page).to have_content("#{tracker} settings saved and active.") - expect(page).to have_current_path(edit_project_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) end end end @@ -73,7 +73,7 @@ RSpec.describe 'User activates issue tracker', :js do it 'saves but does not activate the integration' do expect(page).to have_content("#{tracker} settings saved, but not active.") - expect(page).to have_current_path(edit_project_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, tracker.parameterize(separator: '_')), ignore_query: true) end it 'does not show the external tracker link in the menu' do diff --git a/spec/features/projects/integrations/user_activates_jira_spec.rb b/spec/features/projects/integrations/user_activates_jira_spec.rb index f855d6befe7..dad201ffbb6 100644 --- a/spec/features/projects/integrations/user_activates_jira_spec.rb +++ b/spec/features/projects/integrations/user_activates_jira_spec.rb @@ -20,7 +20,7 @@ RSpec.describe 'User activates Jira', :js do it 'activates the Jira integration' do expect(page).to have_content('Jira settings saved and active.') - expect(page).to have_current_path(edit_project_integration_path(project, :jira), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, :jira), ignore_query: true) end unless Gitlab.ee? @@ -55,13 +55,13 @@ RSpec.describe 'User activates Jira', :js do click_test_then_save_integration expect(page).to have_content('Jira settings saved and active.') - expect(page).to have_current_path(edit_project_integration_path(project, :jira), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, :jira), ignore_query: true) end end end describe 'user disables the Jira integration' do - include JiraServiceHelper + include JiraIntegrationHelpers before do stub_jira_integration_test @@ -72,7 +72,7 @@ RSpec.describe 'User activates Jira', :js do it 'saves but does not activate the Jira integration' do expect(page).to have_content('Jira settings saved, but not active.') - expect(page).to have_current_path(edit_project_integration_path(project, :jira), ignore_query: true) + expect(page).to have_current_path(edit_project_settings_integration_path(project, :jira), ignore_query: true) end it 'does not show the Jira link in the menu' do diff --git a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb index ed0877ab0e9..54c9ec0f62e 100644 --- a/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb +++ b/spec/features/projects/integrations/user_activates_mattermost_slash_command_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Set up Mattermost slash commands', :js do let(:mattermost_enabled) { true } describe 'activation' do - let(:edit_path) { edit_project_integration_path(project, :mattermost_slash_commands) } + let(:edit_path) { edit_project_settings_integration_path(project, :mattermost_slash_commands) } include_examples 'user activates the Mattermost Slash Command integration' end diff --git a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb index 616469c5df8..e89f6e309ea 100644 --- a/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb +++ b/spec/features/projects/integrations/user_activates_slack_notifications_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'User activates Slack notifications', :js do pipeline_channel: 6, wiki_page_channel: 7) - visit(edit_project_integration_path(project, integration)) + visit(edit_project_settings_integration_path(project, integration)) end it 'filters events by channel' do diff --git a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb index 0b4c9620bdf..df8cd84ffdb 100644 --- a/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb +++ b/spec/features/projects/integrations/user_activates_slack_slash_command_spec.rb @@ -24,7 +24,11 @@ RSpec.describe 'Slack slash commands', :js do click_active_checkbox click_on 'Save' - expect(page).to have_current_path(edit_project_integration_path(project, :slack_slash_commands), ignore_query: true) + expect(page).to have_current_path( + edit_project_settings_integration_path(project, :slack_slash_commands), + ignore_query: true + ) + expect(page).to have_content('Slack slash commands settings saved, but not active.') end @@ -32,7 +36,11 @@ RSpec.describe 'Slack slash commands', :js do fill_in 'Token', with: 'token' click_on 'Save' - expect(page).to have_current_path(edit_project_integration_path(project, :slack_slash_commands), ignore_query: true) + expect(page).to have_current_path( + edit_project_settings_integration_path(project, :slack_slash_commands), + ignore_query: true + ) + expect(page).to have_content('Slack slash commands settings saved and active.') end diff --git a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb index fcb04c338a9..8a2881c95dc 100644 --- a/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb +++ b/spec/features/projects/integrations/user_uses_inherited_settings_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'User uses inherited settings', :js do - include JiraServiceHelper + include JiraIntegrationHelpers include_context 'project integration activation' diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index e2dc760beda..6a2d2c36521 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'User browses a job', :js do + include Spec::Support::Helpers::ModalHelpers + let(:user) { create(:user) } let(:user_access_level) { :developer } let(:project) { create(:project, :repository, namespace: user.namespace) } @@ -12,7 +14,6 @@ RSpec.describe 'User browses a job', :js do before do project.add_maintainer(user) project.enable_ci - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -26,7 +27,11 @@ 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('[data-testid="job-log-erase-link"]').click } + accept_gl_confirm(button_text: 'Erase job log') do + find('[data-testid="job-log-erase-link"]').click + end + + wait_for_requests 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 befaf85fc1e..f0d41c1dd11 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -987,7 +987,9 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do it 'renders message about job being stuck because of no runners with the specified tags' do 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:") + expect(page).to have_content("This job is stuck because of one of the following problems. There are no active runners online, no runners for the ") + expect(page).to have_content("protected branch") + expect(page).to have_content(", or no runners that match all of the job's tags:") end end @@ -997,7 +999,9 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do it 'renders message about job being stuck because of no runners with the specified tags' do 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:") + expect(page).to have_content("This job is stuck because of one of the following problems. There are no active runners online, no runners for the ") + expect(page).to have_content("protected branch") + expect(page).to have_content(", or no runners that match all of the job's tags:") end end diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb index 0f4120e88e0..8d229530ef5 100644 --- a/spec/features/projects/members/manage_members_spec.rb +++ b/spec/features/projects/members/manage_members_spec.rb @@ -48,20 +48,48 @@ RSpec.describe 'Projects > Members > Manage members', :js do end end - it 'uses ProjectMember access_level_roles for the invite members modal access option', :aggregate_failures do - visit_members_page + context 'when owner' do + it 'uses ProjectMember access_level_roles for the invite members modal access option', :aggregate_failures do + visit_members_page - click_on 'Invite members' + click_on 'Invite members' - click_on 'Guest' - wait_for_requests + click_on 'Guest' + wait_for_requests - page.within '.dropdown-menu' do - expect(page).to have_button('Guest') - expect(page).to have_button('Reporter') - expect(page).to have_button('Developer') - expect(page).to have_button('Maintainer') - expect(page).not_to have_button('Owner') + page.within '.dropdown-menu' do + expect(page).to have_button('Guest') + expect(page).to have_button('Reporter') + expect(page).to have_button('Developer') + expect(page).to have_button('Maintainer') + expect(page).to have_button('Owner') + end + end + end + + context 'when maintainer' do + let(:maintainer) { create(:user) } + + before do + project.add_maintainer(maintainer) + sign_in(maintainer) + end + + it 'uses ProjectMember access_level_roles for the invite members modal access option', :aggregate_failures do + visit_members_page + + click_on 'Invite members' + + click_on 'Guest' + wait_for_requests + + page.within '.dropdown-menu' do + expect(page).to have_button('Guest') + expect(page).to have_button('Reporter') + expect(page).to have_button('Developer') + expect(page).to have_button('Maintainer') + expect(page).not_to have_button('Owner') + end end end diff --git a/spec/features/projects/members/member_leaves_project_spec.rb b/spec/features/projects/members/member_leaves_project_spec.rb index 67c40c1dbee..db227f3701d 100644 --- a/spec/features/projects/members/member_leaves_project_spec.rb +++ b/spec/features/projects/members/member_leaves_project_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Projects > Members > Member leaves project' do include Spec::Support::Helpers::Features::MembersHelpers + include Spec::Support::Helpers::ModalHelpers let(:user) { create(:user) } let(:project) { create(:project, :repository, :with_namespace_settings) } @@ -11,7 +12,6 @@ RSpec.describe 'Projects > Members > Member leaves project' do before do project.add_developer(user) sign_in(user) - stub_feature_flags(bootstrap_confirmation_modals: false) end it 'user leaves project' do @@ -26,7 +26,7 @@ RSpec.describe 'Projects > Members > Member leaves project' do it 'user leaves project by url param', :js do visit project_path(project, leave: 1) - page.accept_confirm + accept_gl_confirm(button_text: 'Leave project') wait_for_all_requests expect(page).to have_current_path(dashboard_projects_path, ignore_query: true) diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb index 370d7b49832..be124502c32 100644 --- a/spec/features/projects/members/user_requests_access_spec.rb +++ b/spec/features/projects/members/user_requests_access_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Projects > Members > User requests access', :js do + include Spec::Support::Helpers::ModalHelpers + let_it_be(:user) { create(:user) } let_it_be(:maintainer) { create(:user) } let_it_be(:project) { create(:project, :public, :repository) } @@ -13,7 +15,6 @@ RSpec.describe 'Projects > Members > User requests access', :js do sign_in(user) project.add_maintainer(maintainer) visit project_path(project) - stub_feature_flags(bootstrap_confirmation_modals: false) end it 'request access feature is disabled' do @@ -67,7 +68,7 @@ RSpec.describe 'Projects > Members > User requests access', :js do expect(project.requesters.exists?(user_id: user)).to be_truthy - accept_confirm { click_link 'Withdraw Access Request' } + accept_gl_confirm { click_link 'Withdraw Access Request' } expect(page).not_to have_content 'Withdraw Access Request' expect(page).to have_content 'Request Access' diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index 0046dfe436f..c323e60bb71 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -57,10 +57,37 @@ RSpec.describe 'New project', :js do expect(page).to have_link('GitHub') expect(page).to have_link('Bitbucket') expect(page).to have_link('GitLab.com') - expect(page).to have_button('Repo by URL') + expect(page).to have_button('Repository by URL') expect(page).to have_link('GitLab export') end + describe 'github import option' do + context 'with user namespace' do + before do + visit new_project_path + click_link 'Import project' + end + + it 'renders link to github importer' do + expect(page).to have_link(href: new_import_github_path) + end + end + + context 'with group namespace' do + let(:group) { create(:group, :private) } + + before do + group.add_owner(user) + visit new_project_path(namespace_id: group.id) + click_link 'Import project' + end + + it 'renders link to github importer including namespace id' do + expect(page).to have_link(href: new_import_github_path(namespace_id: group.id)) + end + end + end + describe 'manifest import option' do before do visit new_project_path @@ -175,7 +202,7 @@ RSpec.describe 'New project', :js do it 'does not show the initialize with Readme checkbox on "Import project" tab' do visit new_project_path click_link 'Import project' - click_button 'Repo by URL' + click_button 'Repository by URL' page.within '#import-project-pane' do expect(page).not_to have_css('input#project_initialize_with_readme') @@ -277,7 +304,7 @@ RSpec.describe 'New project', :js do click_link 'Import project' end - context 'from git repository url, "Repo by URL"' do + context 'from git repository url, "Repository by URL"' do before do first('.js-import-git-toggle-button').click end diff --git a/spec/features/projects/pages/user_adds_domain_spec.rb b/spec/features/projects/pages/user_adds_domain_spec.rb index 71bf1c24655..afa3f29ce0d 100644 --- a/spec/features/projects/pages/user_adds_domain_spec.rb +++ b/spec/features/projects/pages/user_adds_domain_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' RSpec.describe 'User adds pages domain', :js do include LetsEncryptHelpers + include Spec::Support::Helpers::ModalHelpers let_it_be(:project) { create(:project, pages_https_only: false) } @@ -14,8 +15,6 @@ RSpec.describe 'User adds pages domain', :js do project.add_maintainer(user) sign_in(user) - - stub_feature_flags(bootstrap_confirmation_modals: false) end context 'when pages are exposed on external HTTP address', :http_pages_enabled do @@ -95,7 +94,7 @@ RSpec.describe 'User adds pages domain', :js do fill_in 'Domain', with: 'my.test.domain.com' - find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click + find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click fill_in 'Certificate (PEM)', with: certificate_pem fill_in 'Key (PEM)', with: certificate_key @@ -168,7 +167,7 @@ RSpec.describe 'User adds pages domain', :js do within('#content-body') { click_link 'Edit' } - accept_confirm { click_link 'Remove' } + accept_gl_confirm(button_text: 'Remove certificate') { click_link 'Remove' } expect(page).to have_field('Certificate (PEM)', with: '') expect(page).to have_field('Key (PEM)', with: '') diff --git a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb index bdf280f4fe4..4c633bea64e 100644 --- a/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb +++ b/spec/features/projects/pages/user_edits_lets_encrypt_settings_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do include LetsEncryptHelpers + include Spec::Support::Helpers::ModalHelpers let(:project) { create(:project, pages_https_only: false) } let(:user) { create(:user) } @@ -14,7 +15,6 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do before do allow(Gitlab.config.pages).to receive(:enabled).and_return(true) stub_lets_encrypt_settings - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_role(user, role) sign_in(user) @@ -50,7 +50,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do expect(page).to have_selector '.card-header', text: 'Certificate' expect(page).to have_text domain.subject - find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click + find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'true' expect(page).not_to have_selector '.card-header', text: 'Certificate' @@ -74,7 +74,7 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do expect(page).not_to have_field 'Certificate (PEM)', type: 'textarea' expect(page).not_to have_field 'Key (PEM)', type: 'textarea' - find('.js-auto-ssl-toggle-container .js-project-feature-toggle').click + find('.js-auto-ssl-toggle-container .js-project-feature-toggle button').click expect(find("#pages_domain_auto_ssl_enabled", visible: false).value).to eq 'false' expect(page).to have_field 'Certificate (PEM)', type: 'textarea' @@ -139,7 +139,8 @@ RSpec.describe "Pages with Let's Encrypt", :https_pages_enabled do expect(page).to have_selector '.card-header', text: 'Certificate' expect(page).to have_text domain.subject - within('.card') { accept_confirm { click_on 'Remove' } } + within('.card') { click_on 'Remove' } + accept_gl_confirm(button_text: 'Remove certificate') expect(page).to have_field 'Certificate (PEM)', with: '' expect(page).to have_field 'Key (PEM)', with: '' end diff --git a/spec/features/projects/pages/user_edits_settings_spec.rb b/spec/features/projects/pages/user_edits_settings_spec.rb index 1226e1dc2ed..bd163f4a109 100644 --- a/spec/features/projects/pages/user_edits_settings_spec.rb +++ b/spec/features/projects/pages/user_edits_settings_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' RSpec.describe 'Pages edits pages settings', :js do + include Spec::Support::Helpers::ModalHelpers + let(:project) { create(:project, pages_https_only: false) } let(:user) { create(:user) } @@ -176,7 +178,6 @@ RSpec.describe 'Pages edits pages settings', :js do describe 'Remove page' do context 'when pages are deployed' do before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.mark_pages_as_deployed end @@ -185,7 +186,7 @@ RSpec.describe 'Pages edits pages settings', :js do expect(page).to have_link('Remove pages') - accept_confirm { click_link 'Remove pages' } + accept_gl_confirm(button_text: 'Remove pages') { click_link 'Remove pages' } expect(page).to have_content('Pages were scheduled for removal') expect(project.reload.pages_deployed?).to be_falsey diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index 7cb14feabd2..8cf6d5bd29b 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -3,15 +3,16 @@ require 'spec_helper' RSpec.describe 'Pipeline Schedules', :js do + include Spec::Support::Helpers::ModalHelpers + let!(:project) { create(:project, :repository) } let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) } let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) } let(:scope) { nil } let!(:user) { create(:user) } - context 'logged in as the pipeline scheduler owner' do + context 'logged in as the pipeline schedule owner' do before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_developer(user) pipeline_schedule.update!(owner: user) gitlab_sign_in(user) @@ -81,7 +82,6 @@ RSpec.describe 'Pipeline Schedules', :js do context 'logged in as a project maintainer' do before do - stub_feature_flags(bootstrap_confirmation_modals: false) project.add_maintainer(user) gitlab_sign_in(user) end @@ -117,7 +117,9 @@ RSpec.describe 'Pipeline Schedules', :js do end it 'deletes the pipeline' do - accept_confirm { click_link 'Delete' } + click_link 'Delete' + + accept_gl_confirm(button_text: 'Delete pipeline schedule') expect(page).not_to have_css(".pipeline-schedule-table-row") end diff --git a/spec/features/projects/pipelines/legacy_pipeline_spec.rb b/spec/features/projects/pipelines/legacy_pipeline_spec.rb index a29cef393a8..db6feecba03 100644 --- a/spec/features/projects/pipelines/legacy_pipeline_spec.rb +++ b/spec/features/projects/pipelines/legacy_pipeline_spec.rb @@ -1070,4 +1070,202 @@ RSpec.describe 'Pipeline', :js do end end end + + describe 'GET /:project/-/pipelines/:id/builds' do + include_context 'pipeline builds' + + let_it_be(:project) { create(:project, :repository) } + + let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } + + before do + visit builds_project_pipeline_path(project, pipeline) + end + + it 'shows a list of jobs' do + expect(page).to have_content('Test') + expect(page).to have_content(build_passed.id) + expect(page).to have_content('Deploy') + expect(page).to have_content(build_failed.id) + expect(page).to have_content(build_running.id) + expect(page).to have_content(build_external.id) + expect(page).to have_content('Retry') + expect(page).to have_content('Cancel running') + expect(page).to have_button('Play') + end + + context 'page tabs' do + it 'shows Pipeline, Jobs and DAG tabs with link' do + expect(page).to have_link('Pipeline') + expect(page).to have_link('Jobs') + expect(page).to have_link('Needs') + end + + it 'shows counter in Jobs tab' do + expect(page.find('.js-builds-counter').text).to eq(pipeline.total_size.to_s) + end + end + + context 'retrying jobs' do + it { expect(page).not_to have_content('retried') } + + context 'when retrying' do + before do + find('[data-testid="retry"]', match: :first).click + end + + it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do + expect(page).not_to have_content('Retry') + end + end + end + + context 'canceling jobs' do + it { expect(page).not_to have_selector('.ci-canceled') } + + context 'when canceling' do + before do + click_on 'Cancel running' + end + + it 'does not show a "Cancel running" button', :sidekiq_might_not_need_inline do + expect(page).not_to have_content('Cancel running') + end + end + end + + context 'playing manual job' do + before do + within '[data-testid="jobs-tab-table"]' do + click_button('Play') + + wait_for_requests + end + end + + it { expect(build_manual.reload).to be_pending } + end + + context 'when user unschedules a delayed job' do + before do + within '[data-testid="jobs-tab-table"]' do + click_button('Unschedule') + end + end + + it 'unschedules the delayed job and shows play button as a manual job' do + expect(page).to have_button('Play') + expect(page).not_to have_button('Unschedule') + end + end + end + + describe 'GET /:project/-/pipelines/:id/failures' do + let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: '1234') } + let(:pipeline_failures_page) { failures_project_pipeline_path(project, pipeline) } + let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline) } + + subject { visit pipeline_failures_page } + + context 'with failed build' do + before do + failed_build.trace.set('4 examples, 1 failure') + end + + it 'lists failed builds' do + subject + + expect(page).to have_content(failed_build.name) + expect(page).to have_content(failed_build.stage) + end + + it 'shows build failure logs' do + subject + + expect(page).to have_content('4 examples, 1 failure') + end + + it 'shows the failure reason' do + subject + + expect(page).to have_content('There is an unknown failure, please try again') + end + + context 'when user does not have permission to retry build' do + it 'shows retry button for failed build' do + subject + + page.within(find('#js-tab-failures', match: :first)) do + expect(page).not_to have_button('Retry') + end + end + end + + context 'when user does have permission to retry build' do + before do + create(:protected_branch, :developers_can_merge, + name: pipeline.ref, project: project) + end + + it 'shows retry button for failed build' do + subject + + page.within(find('#js-tab-failures', match: :first)) do + expect(page).to have_button('Retry') + end + end + end + end + + context 'when missing build logs' do + it 'lists failed builds' do + subject + + expect(page).to have_content(failed_build.name) + expect(page).to have_content(failed_build.stage) + end + + it 'does not show log' do + subject + + expect(page).to have_content('No job log') + end + end + + context 'without permission to access builds' do + let(:role) { :guest } + + before do + project.update!(public_builds: false) + end + + context 'when accessing failed jobs page' do + it 'renders a 404 page' do + requests = inspect_requests { subject } + + expect(page).to have_title('Not Found') + expect(requests.first.status_code).to eq(404) + end + end + end + + context 'without failures' do + before do + failed_build.update!(status: :success) + end + + it 'does not show the failure tab' do + subject + + expect(page).not_to have_content('Failed Jobs') + end + + it 'displays the pipeline graph' do + subject + + expect(page).to have_current_path(pipeline_path(pipeline), ignore_query: true) + expect(page).to have_selector('.js-pipeline-graph') + end + end + end end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 9eda05f695d..a83d4191f38 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -414,16 +414,6 @@ RSpec.describe 'Pipeline', :js do expect(page).to have_selector('button[aria-label="Retry downstream pipeline"]') end - context 'and the FF downstream_retry_action is disabled' do - before do - stub_feature_flags(downstream_retry_action: false) - end - - it 'does not show the retry action' do - expect(page).not_to have_selector('button[aria-label="Retry downstream pipeline"]') - end - end - context 'when retrying' do before do find('button[aria-label="Retry downstream pipeline"]').click @@ -508,8 +498,7 @@ RSpec.describe 'Pipeline', :js do end it 'shows counter in Jobs tab' do - skip('Enable in jobs `pipeline_tabs_vue` MR') - expect(page.find('.js-builds-counter').text).to eq(pipeline.total_size.to_s) + expect(page.find('[data-testid="builds-counter"]').text).to eq(pipeline.total_size.to_s) end context 'without permission to access builds' do @@ -889,7 +878,6 @@ RSpec.describe 'Pipeline', :js do describe 'GET /:project/-/pipelines/:id/builds' do before do - stub_feature_flags(pipeline_tabs_vue: false) visit builds_project_pipeline_path(project, pipeline) end @@ -1042,7 +1030,6 @@ RSpec.describe 'Pipeline', :js do let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) } before do - stub_feature_flags(pipeline_tabs_vue: false) visit builds_project_pipeline_path(project, pipeline) end @@ -1066,8 +1053,7 @@ RSpec.describe 'Pipeline', :js do end it 'shows counter in Jobs tab' do - skip('unskip when jobs tab is implemented with ff `pipeline_tabs_vue`') - expect(page.find('.js-builds-counter').text).to eq(pipeline.total_size.to_s) + expect(page.find('[data-testid="builds-counter"]').text).to eq(pipeline.total_size.to_s) end end @@ -1130,10 +1116,6 @@ RSpec.describe 'Pipeline', :js do let(:pipeline_failures_page) { failures_project_pipeline_path(project, pipeline) } let!(:failed_build) { create(:ci_build, :failed, pipeline: pipeline) } - before do - stub_feature_flags(pipeline_tabs_vue: false) - end - subject { visit pipeline_failures_page } context 'with failed build' do @@ -1160,42 +1142,11 @@ RSpec.describe 'Pipeline', :js do expect(page).to have_content('There is an unknown failure, please try again') end - context 'when failed_jobs_tab_vue feature flag is disabled' do - before do - stub_feature_flags(failed_jobs_tab_vue: false) - end - - context 'when user does not have permission to retry build' do - it 'shows retry button for failed build' do - subject - - page.within(find('.build-failures', match: :first)) do - expect(page).not_to have_link('Retry') - end - end - end - - context 'when user does have permission to retry build' do - before do - create(:protected_branch, :developers_can_merge, - name: pipeline.ref, project: project) - end - - it 'shows retry button for failed build' do - subject - - page.within(find('.build-failures', match: :first)) do - expect(page).to have_link('Retry') - end - end - end - end - context 'when user does not have permission to retry build' do it 'shows retry button for failed build' do subject - page.within(find('#js-tab-failures', match: :first)) do + page.within(find('[data-testid="tab-failures"]', match: :first)) do expect(page).not_to have_button('Retry') end end @@ -1210,7 +1161,7 @@ RSpec.describe 'Pipeline', :js do it 'shows retry button for failed build' do subject - page.within(find('#js-tab-failures', match: :first)) do + page.within(find('[data-testid="tab-failures"]', match: :first)) do expect(page).to have_button('Retry') end end @@ -1255,7 +1206,6 @@ RSpec.describe 'Pipeline', :js do end it 'does not show the failure tab' do - skip('unskip when the failure tab has been implemented in ff `pipeline_tabs_vue`') subject expect(page).not_to have_content('Failed Jobs') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index a18bf7c5caf..785edc69623 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -311,7 +311,6 @@ RSpec.describe 'Pipelines', :js do end before do - stub_feature_flags(bootstrap_confirmation_modals: false) visit_project_pipelines end diff --git a/spec/features/projects/releases/user_views_edit_release_spec.rb b/spec/features/projects/releases/user_views_edit_release_spec.rb index f08f5529472..6551b254643 100644 --- a/spec/features/projects/releases/user_views_edit_release_spec.rb +++ b/spec/features/projects/releases/user_views_edit_release_spec.rb @@ -30,10 +30,12 @@ RSpec.describe 'User edits Release', :js do it 'renders the breadcrumbs' do within('.breadcrumbs') do - expect(page).to have_content("#{project.creator.name} #{project.name} Edit Release") + expect(page).to have_content("#{project.creator.name} #{project.name} Releases #{release.name} Edit Release") expect(page).to have_link(project.creator.name, href: user_path(project.creator)) expect(page).to have_link(project.name, href: project_path(project)) + expect(page).to have_link(_('Releases'), href: project_releases_path(project)) + expect(page).to have_link(release.name, href: project_release_path(project, release)) expect(page).to have_link('Edit Release', href: edit_project_release_path(project, release)) end end diff --git a/spec/features/projects/settings/access_tokens_spec.rb b/spec/features/projects/settings/access_tokens_spec.rb index 122bf267021..88f9a50b093 100644 --- a/spec/features/projects/settings/access_tokens_spec.rb +++ b/spec/features/projects/settings/access_tokens_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Project > Settings > Access Tokens', :js do + include Spec::Support::Helpers::ModalHelpers + let_it_be(:user) { create(:user) } let_it_be(:bot_user) { create(:user, :project_bot) } let_it_be(:group) { create(:group) } @@ -14,7 +16,6 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do end before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end @@ -24,6 +25,11 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do create(:personal_access_token, user: bot_user) end + def role_dropdown_options + role_dropdown = page.find_by_id('resource_access_token_access_level') + role_dropdown.all('option').map(&:text) + end + context 'when user is not a project maintainer' do before do project.add_developer(user) @@ -33,37 +39,68 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do end describe 'token creation' do - it_behaves_like 'resource access tokens creation', 'project' + context 'when user is a project owner' do + before do + project.add_owner(user) + end - context 'when token creation is not allowed' do - it_behaves_like 'resource access tokens creation disallowed', 'Project access token creation is disabled in this group. You can still use and manage existing tokens.' + it_behaves_like 'resource access tokens creation', 'project' - context 'with a project in a personal namespace' do - let(:personal_project) { create(:project) } + it 'shows Owner option' do + visit resource_settings_access_tokens_path - before do - personal_project.add_maintainer(user) - end + expect(role_dropdown_options).to include('Owner') + end + end - it 'shows access token creation form and text' do - visit project_settings_access_tokens_path(personal_project) + context 'when user is a project maintainer' do + before_all do + project.add_maintainer(user) + end + + it_behaves_like 'resource access tokens creation', 'project' + + it 'does not show Owner option for a maintainer' do + visit resource_settings_access_tokens_path - expect(page).to have_selector('#new_resource_access_token') - expect(page).to have_text('Generate project access tokens scoped to this project for your applications that need access to the GitLab API.') - end + expect(role_dropdown_options).not_to include('Owner') end end end - describe 'active tokens' do - let!(:resource_access_token) { create_resource_access_token } + context 'when token creation is not allowed' do + it_behaves_like 'resource access tokens creation disallowed', 'Project access token creation is disabled in this group. You can still use and manage existing tokens.' - it_behaves_like 'active resource access tokens' + context 'with a project in a personal namespace' do + let(:personal_project) { create(:project) } + + before do + personal_project.add_maintainer(user) + end + + it 'shows access token creation form and text' do + visit project_settings_access_tokens_path(personal_project) + + expect(page).to have_selector('#js-new-access-token-form') + end + end end - describe 'inactive tokens' do - let!(:resource_access_token) { create_resource_access_token } + describe 'viewing tokens' do + before_all do + project.add_maintainer(user) + end + + describe 'active tokens' do + let!(:resource_access_token) { create_resource_access_token } + + it_behaves_like 'active resource access tokens' + end - it_behaves_like 'inactive resource access tokens', 'This project has no active access tokens.' + describe 'inactive tokens' do + let!(:resource_access_token) { create_resource_access_token } + + it_behaves_like 'inactive resource access tokens', 'This project has no active access tokens.' + end end end diff --git a/spec/features/projects/settings/branch_rules_settings_spec.rb b/spec/features/projects/settings/branch_rules_settings_spec.rb new file mode 100644 index 00000000000..5cc35f108b5 --- /dev/null +++ b/spec/features/projects/settings/branch_rules_settings_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Projects > Settings > Repository > Branch rules settings' do + let(:project) { create(:project_empty_repo) } + let(:user) { create(:user) } + let(:role) { :developer } + + subject(:request) { visit project_settings_repository_branch_rules_path(project) } + + before do + project.add_role(user, role) + sign_in(user) + end + + context 'for developer' do + let(:role) { :developer } + + it 'is not allowed to view' do + request + + expect(page).to have_gitlab_http_status(:not_found) + end + end + + context 'for maintainer' do + let(:role) { :maintainer } + + context 'Branch rules', :js do + it 'renders branch rules page' do + request + + expect(page).to have_content('Branch rules') + end + end + + context 'branch_rules feature flag disabled' do + it 'does not render branch rules content' do + stub_feature_flags(branch_rules: false) + request + + expect(page).to have_gitlab_http_status(:not_found) + end + end + end +end diff --git a/spec/features/projects/settings/packages_settings_spec.rb b/spec/features/projects/settings/packages_settings_spec.rb index 057e6b635fe..1c2b0faa215 100644 --- a/spec/features/projects/settings/packages_settings_spec.rb +++ b/spec/features/projects/settings/packages_settings_spec.rb @@ -11,6 +11,7 @@ RSpec.describe 'Projects > Settings > Packages', :js do sign_in(user) stub_config(packages: { enabled: packages_enabled }) + stub_feature_flags(package_registry_access_level: package_registry_access_level) visit edit_project_path(project) end @@ -18,14 +19,31 @@ RSpec.describe 'Projects > Settings > Packages', :js do context 'Packages enabled in config' do let(:packages_enabled) { true } - it 'displays the packages toggle button' do - expect(page).to have_selector('[data-testid="toggle-label"]', text: 'Packages') - expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true) + context 'with feature flag disabled' do + let(:package_registry_access_level) { false } + + it 'displays the packages toggle button' do + expect(page).to have_selector('[data-testid="toggle-label"]', text: 'Packages') + expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true) + end + end + + context 'with feature flag enabled' do + let(:package_registry_access_level) { true } + + it 'displays the packages access level setting' do + expect(page).to have_selector('[data-testid="package-registry-access-level"] > label', text: 'Package registry') + expect(page).to have_selector( + 'input[name="project[project_feature_attributes][package_registry_access_level]"]', + visible: false + ) + end end end context 'Packages disabled in config' do let(:packages_enabled) { false } + let(:package_registry_access_level) { false } it 'does not show up in UI' do expect(page).not_to have_selector('[data-testid="toggle-label"]', text: 'Packages') diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 4e1b55d3d70..cfdd3d9224d 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -39,6 +39,22 @@ RSpec.describe 'Projects > Settings > Repository settings' do end end + context 'Branch rules', :js do + it 'renders branch rules settings' do + visit project_settings_repository_path(project) + expect(page).to have_content('Branch rules') + end + + context 'branch_rules feature flag disabled', :js do + it 'does not render branch rules settings' do + stub_feature_flags(branch_rules: false) + visit project_settings_repository_path(project) + + expect(page).not_to have_content('Branch rules') + end + end + end + context 'Deploy Keys', :js do let_it_be(:private_deploy_key) { create(:deploy_key, title: 'private_deploy_key', public: false) } let_it_be(:public_deploy_key) { create(:another_deploy_key, title: 'public_deploy_key', public: true) } diff --git a/spec/features/projects/settings/user_searches_in_settings_spec.rb b/spec/features/projects/settings/user_searches_in_settings_spec.rb index 44b5464a1b0..7ed96d01189 100644 --- a/spec/features/projects/settings/user_searches_in_settings_spec.rb +++ b/spec/features/projects/settings/user_searches_in_settings_spec.rb @@ -7,7 +7,6 @@ RSpec.describe 'User searches project settings', :js do let_it_be(:project) { create(:project, :repository, namespace: user.namespace, pages_https_only: false) } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) end diff --git a/spec/features/promotion_spec.rb b/spec/features/promotion_spec.rb index 8692930376f..903d6244a4c 100644 --- a/spec/features/promotion_spec.rb +++ b/spec/features/promotion_spec.rb @@ -27,7 +27,7 @@ RSpec.describe 'Promotions', :js do visit edit_project_path(project) within('#promote_service_desk') do - find('.close').click + find('.js-close').click end wait_for_requests diff --git a/spec/features/refactor_blob_viewer_disabled/projects/files/user_replaces_files_spec.rb b/spec/features/refactor_blob_viewer_disabled/projects/files/user_replaces_files_spec.rb deleted file mode 100644 index 5561cf15a66..00000000000 --- a/spec/features/refactor_blob_viewer_disabled/projects/files/user_replaces_files_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Projects > Files > User replaces files', :js do - include DropzoneHelper - - let(:fork_message) 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) } - let(:project2_tree_path_root_ref) { project_tree_path(project2, project2.repository.root_ref) } - let(:user) { create(:user) } - - before do - stub_feature_flags(refactor_blob_viewer: false) - sign_in(user) - end - - context 'when an user has write access' do - before do - project.add_maintainer(user) - visit(project_tree_path_root_ref) - wait_for_requests - end - - it 'replaces an existed file with a new one' do - click_link('.gitignore') - - expect(page).to have_content('.gitignore') - - click_on('Replace') - drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt')) - - page.within('#modal-upload-blob') do - fill_in(:commit_message, with: 'Replacement file commit message') - end - - click_button('Replace file') - - expect(page).to have_content('Lorem ipsum dolor sit amet') - expect(page).to have_content('Sed ut perspiciatis unde omnis') - expect(page).to have_content('Replacement file commit message') - end - end - - context 'when an user does not have write access' do - before do - project2.add_reporter(user) - visit(project2_tree_path_root_ref) - wait_for_requests - end - - it 'replaces an existed file with a new one in a forked project', :sidekiq_might_not_need_inline do - click_link('.gitignore') - - expect(page).to have_content('.gitignore') - - click_on('Replace') - - expect(page).to have_link('Fork') - expect(page).to have_button('Cancel') - - click_link('Fork') - - expect(page).to have_content(fork_message) - - click_on('Replace') - drop_in_dropzone(File.join(Rails.root, 'spec', 'fixtures', 'doc_sample.txt')) - - page.within('#modal-upload-blob') do - fill_in(:commit_message, with: 'Replacement file commit message') - end - - click_button('Replace file') - - expect(page).to have_content('Replacement file commit message') - - fork = user.fork_of(project2.reload) - - expect(page).to have_current_path(project_new_merge_request_path(fork), ignore_query: true) - - click_link('Changes') - - expect(page).to have_content('Lorem ipsum dolor sit amet') - expect(page).to have_content('Sed ut perspiciatis unde omnis') - 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 6bd31d7314c..8d55a7a64f4 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Comments on personal snippets', :js do include NoteInteractionHelpers + include Spec::Support::Helpers::ModalHelpers let_it_be(:snippet) { create(:personal_snippet, :public) } let_it_be(:other_note) { create(:note_on_personal_snippet) } @@ -18,7 +19,6 @@ RSpec.describe 'Comments on personal snippets', :js do end before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in user visit snippet_path(snippet) @@ -124,7 +124,7 @@ RSpec.describe 'Comments on personal snippets', :js do page.within('.current-note-edit-form') do fill_in 'note[note]', with: 'new content' - find('.btn-success').click + find('.btn-confirm').click end page.within("#notes-list li#note_#{snippet_notes[0].id}") do @@ -142,9 +142,11 @@ RSpec.describe 'Comments on personal snippets', :js do open_more_actions_dropdown(snippet_notes[0]) page.within("#notes-list li#note_#{snippet_notes[0].id}") do - accept_confirm { click_on 'Delete comment' } + click_on 'Delete comment' end + accept_gl_confirm(button_text: 'Delete comment') + wait_for_requests expect(page).not_to have_selector("#notes-list li#note_#{snippet_notes[0].id}") diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index c682ad06977..628468a2abe 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -16,7 +16,6 @@ RSpec.describe 'User creates snippet', :js do let(:snippet_title_field) { 'snippet-title' } before do - stub_feature_flags(bootstrap_confirmation_modals: false) sign_in(user) visit new_snippet_path diff --git a/spec/features/tags/developer_deletes_tag_spec.rb b/spec/features/tags/developer_deletes_tag_spec.rb index 6b669695f7b..efd4b42c136 100644 --- a/spec/features/tags/developer_deletes_tag_spec.rb +++ b/spec/features/tags/developer_deletes_tag_spec.rb @@ -10,6 +10,7 @@ RSpec.describe 'Developer deletes tag', :js do before do project.add_developer(user) sign_in(user) + create(:protected_tag, project: project, name: 'v1.1.1') visit project_tags_path(project) end @@ -22,6 +23,16 @@ RSpec.describe 'Developer deletes tag', :js do expect(page).not_to have_content 'v1.1.0' end + + context 'protected tags' do + it 'can not delete protected tags' do + expect(page).to have_content 'v1.1.1' + + container = page.find('.content .flex-row', text: 'v1.1.1') + expect(container).to have_button('Only a project maintainer or owner can delete a protected tag', + disabled: true) + end + end end context 'from a specific tag page' do @@ -33,7 +44,7 @@ RSpec.describe 'Developer deletes tag', :js do container = page.find('.nav-controls') delete_tag container - expect(page).to have_current_path("#{project_tags_path(project)}/", ignore_query: true) + expect(page).to have_current_path(project_tags_path(project), ignore_query: true) expect(page).not_to have_content 'v1.0.0' end end @@ -55,9 +66,9 @@ RSpec.describe 'Developer deletes tag', :js do end def delete_tag(container) - container.find('.js-remove-tag').click + container.find('.js-delete-tag-button').click - page.within('.modal') { click_button('Delete tag') } + page.within('.modal') { click_button('Yes, delete tag') } wait_for_requests end end diff --git a/spec/features/tags/maintainer_deletes_protected_tag_spec.rb b/spec/features/tags/maintainer_deletes_protected_tag_spec.rb new file mode 100644 index 00000000000..0bf9645c2fb --- /dev/null +++ b/spec/features/tags/maintainer_deletes_protected_tag_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Maintainer deletes protected tag', :js do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:project) { create(:project, :repository, namespace: group) } + let(:tag_name) { 'v1.1.1' } + + before do + project.add_maintainer(user) + sign_in(user) + create(:protected_tag, project: project, name: tag_name) + visit project_tags_path(project) + end + + context 'from the tags list page' do + it 'deletes the tag' do + expect(page).to have_content "#{tag_name} protected" + + page.find('.content .flex-row', text: tag_name).find('.js-delete-tag-button').click + assert_modal_content(tag_name) + confirm_delete_tag(tag_name) + + expect(page).not_to have_content tag_name + end + end + + context 'from a specific tag page' do + before do + click_on tag_name + end + + it 'deletes the tag' do + expect(page).to have_current_path(project_tag_path(project, tag_name), ignore_query: true) + + page.find('.js-delete-tag-button').click + assert_modal_content(tag_name) + confirm_delete_tag(tag_name) + + expect(page).to have_current_path(project_tags_path(project), ignore_query: true) + expect(page).not_to have_content tag_name + end + end + + def assert_modal_content(tag_name) + within '.modal' do + expect(page).to have_content("Please type the following to confirm: #{tag_name}") + expect(page).to have_field('delete_tag_input') + expect(page).to have_button('Yes, delete protected tag', disabled: true) + end + end + + def confirm_delete_tag(tag_name) + within '.modal' do + fill_in('delete_tag_input', with: tag_name) + click_button('Yes, delete protected tag') + wait_for_requests + end + end +end diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index 7f5cf2359a3..eb497715df7 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Triggers', :js do + include Spec::Support::Helpers::ModalHelpers + let(:trigger_title) { 'trigger desc' } let(:user) { create(:user) } let(:user2) { create(:user) } @@ -74,7 +76,6 @@ RSpec.describe 'Triggers', :js do describe 'trigger "Revoke" workflow' do before do - stub_feature_flags(bootstrap_confirmation_modals: false) create(:ci_trigger, owner: user2, project: @project, description: trigger_title) visit project_settings_ci_cd_path(@project) end @@ -86,7 +87,7 @@ RSpec.describe 'Triggers', :js do it 'revoke trigger' do # See if "Revoke" on trigger works post trigger creation - page.accept_confirm do + accept_gl_confirm(button_text: 'Revoke') do find('[data-testid="trigger_revoke_button"]').send_keys(:return) end diff --git a/spec/features/user_sorts_things_spec.rb b/spec/features/user_sorts_things_spec.rb index bcf3defe9c6..c6a1cfdc146 100644 --- a/spec/features/user_sorts_things_spec.rb +++ b/spec/features/user_sorts_things_spec.rb @@ -16,8 +16,6 @@ RSpec.describe "User sorts things", :js do let_it_be(:merge_request) { create(:merge_request, target_project: project, source_project: project, author: current_user) } before do - stub_feature_flags(vue_issues_list: true) - project.add_developer(current_user) sign_in(current_user) end diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index 3eae4955167..30441dac7b6 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -341,6 +341,7 @@ RSpec.describe 'Signup' do end it 'redirects to step 2 of the signup process, sets the role and redirects back' do + stub_feature_flags(about_your_company_registration_flow: false) visit new_user_registration_path fill_in_signup_form diff --git a/spec/features/users/zuora_csp_spec.rb b/spec/features/users/zuora_csp_spec.rb new file mode 100644 index 00000000000..f3fd27d6495 --- /dev/null +++ b/spec/features/users/zuora_csp_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Zuora content security policy' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:pipeline) { create(:ci_pipeline, project: project) } + + before do + project.add_developer(user) + sign_in(user) + end + + it 'has proper Content Security Policy headers' do + visit pipeline_path(pipeline) + + expect(response_headers['Content-Security-Policy']).to include('https://*.zuora.com') + end +end |