diff options
Diffstat (limited to 'spec/features/projects')
65 files changed, 1618 insertions, 1916 deletions
diff --git a/spec/features/projects/activity/user_sees_design_comment_spec.rb b/spec/features/projects/activity/user_sees_design_comment_spec.rb index e60deba65f0..3a8e2790858 100644 --- a/spec/features/projects/activity/user_sees_design_comment_spec.rb +++ b/spec/features/projects/activity/user_sees_design_comment_spec.rb @@ -12,7 +12,7 @@ RSpec.describe 'Projects > Activity > User sees design comment', :js do let_it_be(:design) { create(:design, issue: issue) } let(:design_activity) do - "#{commenter.name} #{commenter.to_reference} commented on design" + "#{commenter.name} #{commenter.to_reference} commented on design #{design.to_reference}" end let(:issue_activity) do diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index 3382bdcd65f..d1e635f11c0 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -17,10 +17,10 @@ RSpec.describe 'list of badges' do expect(page).to have_content 'Markdown' expect(page).to have_content 'HTML' expect(page).to have_content 'AsciiDoc' - expect(page).to have_css('.highlight', count: 3) + expect(page).to have_css('.js-syntax-highlight', count: 3) expect(page).to have_xpath("//img[@alt='pipeline status']") - page.within('.highlight', match: :first) do + page.within('.js-syntax-highlight', match: :first) do expect(page).to have_content 'badges/master/pipeline.svg' end end @@ -32,10 +32,10 @@ RSpec.describe 'list of badges' do expect(page).to have_content 'Markdown' expect(page).to have_content 'HTML' expect(page).to have_content 'AsciiDoc' - expect(page).to have_css('.highlight', count: 3) + expect(page).to have_css('.js-syntax-highlight', count: 3) expect(page).to have_xpath("//img[@alt='coverage report']") - page.within('.highlight', match: :first) do + page.within('.js-syntax-highlight', match: :first) do expect(page).to have_content 'badges/master/coverage.svg' end end diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 5aca994f53e..c30c8dda852 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe 'Editing file blob', :js do include TreeHelper + include BlobSpecHelpers let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') } @@ -20,9 +21,18 @@ RSpec.describe 'Editing file blob', :js do sign_in(user) end - def edit_and_commit(commit_changes: true) + def edit_and_commit(commit_changes: true, is_diff: false) + set_default_button('edit') + refresh wait_for_requests - find('.js-edit-blob').click + + if is_diff + first('.js-diff-more-actions').click + click_link('Edit in single-file editor') + else + click_link('Edit') + end + fill_editor(content: 'class NextFeature\\nend\\n') if commit_changes @@ -38,7 +48,7 @@ RSpec.describe 'Editing file blob', :js do context 'from MR diff' do before do visit diffs_project_merge_request_path(project, merge_request) - edit_and_commit + edit_and_commit(is_diff: true) end it 'returns me to the mr' do diff --git a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb index a271a4f43a8..fda2992af8d 100644 --- a/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb +++ b/spec/features/projects/blobs/user_creates_new_blob_in_new_project_spec.rb @@ -2,7 +2,9 @@ require 'spec_helper' -RSpec.describe 'User creates blob in new project', :js do +RSpec.describe 'User creates new blob', :js do + include WebIdeSpecHelpers + let(:user) { create(:user) } let(:project) { create(:project, :empty_repo) } @@ -12,16 +14,19 @@ RSpec.describe 'User creates blob in new project', :js do visit project_path(project) end - it 'allows the user to add a new file' do + it 'allows the user to add a new file in Web IDE' do click_link 'New file' - execute_script("monaco.editor.getModels()[0].setValue('Hello world')") + wait_for_requests + + ide_create_new_file('dummy-file', content: "Hello world\n") - fill_in(:file_name, with: 'dummy-file') + ide_commit - click_button('Commit changes') + click_button('Commit') - expect(page).to have_content('The file has been successfully created') + expect(page).to have_content('All changes are committed') + expect(project.repository.blob_at('master', 'dummy-file').data).to eql("Hello world\n") end end diff --git a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb index 8b43687c71c..023e00a3e02 100644 --- a/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb +++ b/spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb @@ -10,7 +10,7 @@ RSpec.describe 'User follows pipeline suggest nudge spec when feature is enabled describe 'viewing the new blob page' do before do - stub_feature_flags(suggest_pipeline: true) + stub_experiment_for_user(suggest_pipeline: true) sign_in(user) end diff --git a/spec/features/projects/branches/user_deletes_branch_spec.rb b/spec/features/projects/branches/user_deletes_branch_spec.rb index 21a1d31bad4..c480c41709c 100644 --- a/spec/features/projects/branches/user_deletes_branch_spec.rb +++ b/spec/features/projects/branches/user_deletes_branch_spec.rb @@ -17,7 +17,7 @@ RSpec.describe "User deletes branch", :js do fill_in("branch-search", with: "improve/awesome").native.send_keys(:enter) page.within(".js-branch-improve\\/awesome") do - accept_alert { find(".btn-remove").click } + accept_alert { find(".btn-danger").click } end wait_for_requests diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb index 0e2444c5434..dcad7ee66a3 100644 --- a/spec/features/projects/branches_spec.rb +++ b/spec/features/projects/branches_spec.rb @@ -21,11 +21,11 @@ RSpec.describe 'Branches' do before do # Add 4 stale branches (1..4).reverse_each do |i| - Timecop.freeze((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") } + travel_to((threshold + i).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") } end # Add 6 active branches (1..6).each do |i| - Timecop.freeze((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") } + travel_to((threshold - i).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") } end end @@ -101,7 +101,7 @@ RSpec.describe 'Branches' do visit project_branches_filtered_path(project, state: 'all') expect(all('.all-branches').last).to have_selector('li', count: 20) - accept_confirm { first('.js-branch-item .btn-remove').click } + accept_confirm { first('.js-branch-item .btn-danger').click } expect(all('.all-branches').last).to have_selector('li', count: 19) end @@ -163,7 +163,7 @@ RSpec.describe 'Branches' do expect(page).to have_content('fix') expect(find('.all-branches')).to have_selector('li', count: 1) - accept_confirm { find('.js-branch-fix .btn-remove').click } + accept_confirm { find('.js-branch-fix .btn-danger').click } expect(page).not_to have_content('fix') expect(find('.all-branches')).to have_selector('li', count: 0) diff --git a/spec/features/projects/ci/lint_spec.rb b/spec/features/projects/ci/lint_spec.rb index ce435151b84..eb2efb4357d 100644 --- a/spec/features/projects/ci/lint_spec.rb +++ b/spec/features/projects/ci/lint_spec.rb @@ -8,117 +8,88 @@ RSpec.describe 'CI Lint', :js do let(:project) { create(:project, :repository) } let(:user) { create(:user) } - shared_examples 'correct ci linting process' do - describe 'YAML parsing' do - shared_examples 'validates the YAML' do - before do - stub_feature_flags(ci_lint_vue: false) - click_on 'Validate' - end + let(:content_selector) { '.content .view-lines' } - context 'YAML is correct' do - let(:yaml_content) do - File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) - end + before do + stub_feature_flags(ci_lint_vue: false) + project.add_developer(user) + sign_in(user) - it 'parses Yaml and displays the jobs' do - expect(page).to have_content('Status: syntax is correct') + visit project_ci_lint_path(project) + editor_set_value(yaml_content) - within "table" do - aggregate_failures do - expect(page).to have_content('Job - rspec') - expect(page).to have_content('Job - spinach') - expect(page).to have_content('Deploy Job - staging') - expect(page).to have_content('Deploy Job - production') - end - end - end - end + wait_for('YAML content') do + find(content_selector).text.present? + end + end - context 'YAML is incorrect' do - let(:yaml_content) { 'value: cannot have :' } + describe 'YAML parsing' do + shared_examples 'validates the YAML' do + before do + stub_feature_flags(ci_lint_vue: false) + click_on 'Validate' + end - it 'displays information about an error' do - expect(page).to have_content('Status: syntax is incorrect') - expect(page).to have_selector(content_selector, text: yaml_content) - end + context 'YAML is correct' do + let(:yaml_content) do + File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) end - end - it_behaves_like 'validates the YAML' + it 'parses Yaml and displays the jobs' do + expect(page).to have_content('Status: syntax is correct') - context 'when Dry Run is checked' do - before do - check 'Simulate a pipeline created for the default branch' + within "table" do + aggregate_failures do + expect(page).to have_content('Job - rspec') + expect(page).to have_content('Job - spinach') + expect(page).to have_content('Deploy Job - staging') + expect(page).to have_content('Deploy Job - production') + end + end end - - it_behaves_like 'validates the YAML' end - describe 'YAML revalidate' do - let(:yaml_content) { 'my yaml content' } + context 'YAML is incorrect' do + let(:yaml_content) { 'value: cannot have :' } - it 'loads previous YAML content after validation' do - expect(page).to have_field('content', with: 'my yaml content', visible: false, type: 'textarea') + it 'displays information about an error' do + expect(page).to have_content('Status: syntax is incorrect') + expect(page).to have_selector(content_selector, text: yaml_content) end end end - describe 'YAML clearing' do + it_behaves_like 'validates the YAML' + + context 'when Dry Run is checked' do before do - click_on 'Clear' + check 'Simulate a pipeline created for the default branch' end - context 'YAML is present' do - let(:yaml_content) do - File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) - end - - it 'YAML content is cleared' do - expect(page).to have_field('content', with: '', visible: false, type: 'textarea') - end - end + it_behaves_like 'validates the YAML' end - end - context 'with ACE editor' do - it_behaves_like 'correct ci linting process' do - let(:content_selector) { '.ace_content' } + describe 'YAML revalidate' do + let(:yaml_content) { 'my yaml content' } - before do - stub_feature_flags(monaco_ci: false) - stub_feature_flags(ci_lint_vue: false) - project.add_developer(user) - sign_in(user) - - visit project_ci_lint_path(project) - find('#ci-editor') - execute_script("ace.edit('ci-editor').setValue(#{yaml_content.to_json});") - - # Ace editor updates a hidden textarea and it happens asynchronously - wait_for('YAML content') do - find(content_selector).text.present? - end + it 'loads previous YAML content after validation' do + expect(page).to have_field('content', with: 'my yaml content', visible: false, type: 'textarea') end end end - context 'with Editor Lite' do - it_behaves_like 'correct ci linting process' do - let(:content_selector) { '.content .view-lines' } - - before do - stub_feature_flags(monaco_ci: true) - stub_feature_flags(ci_lint_vue: false) - project.add_developer(user) - sign_in(user) + describe 'YAML clearing' do + before do + click_on 'Clear' + end - visit project_ci_lint_path(project) - editor_set_value(yaml_content) + context 'YAML is present' do + let(:yaml_content) do + File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + end - wait_for('YAML content') do - find(content_selector).text.present? - end + it 'YAML content is cleared' do + expect(page).to have_field('content', with: '', visible: false, type: 'textarea') end end end diff --git a/spec/features/projects/clusters/eks_spec.rb b/spec/features/projects/clusters/eks_spec.rb index c5feef6c6f3..9f3f331cfab 100644 --- a/spec/features/projects/clusters/eks_spec.rb +++ b/spec/features/projects/clusters/eks_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'AWS EKS Cluster', :js do before do visit project_clusters_path(project) - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' end context 'when user creates a cluster on AWS EKS' do diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb index 04339d20d77..a0519d88532 100644 --- a/spec/features/projects/clusters/gcp_spec.rb +++ b/spec/features/projects/clusters/gcp_spec.rb @@ -33,7 +33,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do before do visit project_clusters_path(project) - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' click_link 'Create new cluster' click_link 'Google GKE' end @@ -143,7 +143,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do before do visit project_clusters_path(project) - click_link 'Add Kubernetes cluster' + click_link 'Connect cluster with certificate' click_link 'Connect existing cluster' end @@ -162,7 +162,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do it 'user sees creation form with the successful message' do expect(page).to have_content('Kubernetes cluster integration was successfully removed.') - expect(page).to have_link('Add Kubernetes cluster') + expect(page).to have_link('Integrate with a cluster certificate') end end end @@ -178,7 +178,7 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do end it 'user sees offer on cluster create page' do - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' expect(page).to have_css('.gcp-signup-offer') end @@ -192,10 +192,10 @@ RSpec.describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do it 'user does not see offer after dismissing' do expect(page).to have_css('.gcp-signup-offer') - find('.gcp-signup-offer .close').click + find('.gcp-signup-offer .js-close').click wait_for_requests - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' expect(page).not_to have_css('.gcp-signup-offer') end diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb index 9d0dc65093e..748eba558aa 100644 --- a/spec/features/projects/clusters/user_spec.rb +++ b/spec/features/projects/clusters/user_spec.rb @@ -25,7 +25,7 @@ RSpec.describe 'User Cluster', :js do before do visit project_clusters_path(project) - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' click_link 'Connect existing cluster' end @@ -52,6 +52,10 @@ RSpec.describe 'User Cluster', :js do it 'user sees RBAC is enabled by default' do expect(page).to have_checked_field('RBAC-enabled cluster') end + + it 'user sees namespace per environment is enabled by default' do + expect(page).to have_checked_field('Namespace per environment') + end end context 'when user filled form with invalid parameters' do @@ -112,7 +116,7 @@ RSpec.describe 'User Cluster', :js do it 'user sees creation form with the successful message' do expect(page).to have_content('Kubernetes cluster integration was successfully removed.') - expect(page).to have_link('Add Kubernetes cluster') + expect(page).to have_link('Integrate with a cluster certificate') end end end diff --git a/spec/features/projects/clusters_spec.rb b/spec/features/projects/clusters_spec.rb index d674fbc457e..6c6e65005f6 100644 --- a/spec/features/projects/clusters_spec.rb +++ b/spec/features/projects/clusters_spec.rb @@ -11,7 +11,6 @@ RSpec.describe 'Clusters', :js do before do project.add_maintainer(user) gitlab_sign_in(user) - stub_feature_flags(clusters_list_redesign: false) end context 'when user does not have a cluster and visits cluster index page' do @@ -20,7 +19,7 @@ RSpec.describe 'Clusters', :js do end it 'sees empty state' do - expect(page).to have_link('Add Kubernetes cluster') + expect(page).to have_link('Integrate with a cluster certificate') expect(page).to have_selector('.empty-state') end end @@ -42,7 +41,7 @@ RSpec.describe 'Clusters', :js do context 'when user filled form with environment scope' do before do - click_link 'Add Kubernetes cluster' + click_link 'Connect cluster with certificate' click_link 'Connect existing cluster' fill_in 'cluster_name', with: 'staging-cluster' fill_in 'cluster_environment_scope', with: 'staging/*' @@ -71,7 +70,7 @@ RSpec.describe 'Clusters', :js do context 'when user updates duplicated environment scope' do before do - click_link 'Add Kubernetes cluster' + click_link 'Connect cluster with certificate' click_link 'Connect existing cluster' fill_in 'cluster_name', with: 'staging-cluster' fill_in 'cluster_environment_scope', with: '*' @@ -117,7 +116,7 @@ RSpec.describe 'Clusters', :js do context 'when user filled form with environment scope' do before do - click_link 'Add Kubernetes cluster' + click_link 'Connect cluster with certificate' click_link 'Create new cluster' click_link 'Google GKE' @@ -162,7 +161,7 @@ RSpec.describe 'Clusters', :js do context 'when user updates duplicated environment scope' do before do - click_link 'Add Kubernetes cluster' + click_link 'Connect cluster with certificate' click_link 'Create new cluster' click_link 'Google GKE' @@ -196,8 +195,7 @@ RSpec.describe 'Clusters', :js do end it 'user sees a table with one cluster' do - # One is the header row, the other the cluster row - expect(page).to have_selector('.gl-responsive-table-row', count: 2) + expect(page).to have_selector('[data-testid="cluster_list_table"] tbody tr', count: 1) end context 'when user clicks on a cluster' do @@ -216,7 +214,7 @@ RSpec.describe 'Clusters', :js do before do visit project_clusters_path(project) - click_link 'Add Kubernetes cluster' + click_link 'Integrate with a cluster certificate' click_link 'Create new cluster' end diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index f97abc5bd8b..00ec9d49a10 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -19,7 +19,7 @@ RSpec.describe 'project commit pipelines', :js do context 'when no builds triggered yet' do it 'shows the ID of the first pipeline' do - page.within('.table-holder') do + page.within('.pipelines .ci-table') do expect(page).to have_content project.ci_pipelines[0].id # pipeline ids 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 87a022d74a3..0fa4975bb25 100644 --- a/spec/features/projects/commit/user_comments_on_commit_spec.rb +++ b/spec/features/projects/commit/user_comments_on_commit_spec.rb @@ -6,19 +6,22 @@ RSpec.describe "User comments on commit", :js do include Spec::Support::Helpers::Features::NotesHelpers include RepoHelpers - let(:project) { create(:project, :repository) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user) } let(:comment_text) { "XML attached" } - before do - sign_in(user) + before_all do project.add_developer(user) + end - visit(project_commit_path(project, sample_commit.id)) + before do + sign_in(user) end context "when adding new comment" do it "adds comment" do + visit(project_commit_path(project, sample_commit.id)) + emoji_code = ":+1:" page.within(".js-main-target-form") do @@ -57,6 +60,8 @@ RSpec.describe "User comments on commit", :js do context "when editing comment" do before do + visit(project_commit_path(project, sample_commit.id)) + add_note(comment_text) end @@ -87,6 +92,8 @@ RSpec.describe "User comments on commit", :js do context "when deleting comment" do before do + visit(project_commit_path(project, sample_commit.id)) + add_note(comment_text) end @@ -108,4 +115,35 @@ RSpec.describe "User comments on commit", :js do expect(page).not_to have_css(".note") end end + + context 'when checking task lists' do + let(:note_with_task) do + <<-EOT.strip_heredoc + + - [ ] Task 1 + EOT + end + + before do + create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user) + create(:note_on_commit, project: project, commit_id: sample_commit.id, note: note_with_task, author: user) + + visit(project_commit_path(project, sample_commit.id)) + end + + it 'allows the tasks to be checked' do + expect(page).to have_selector('li.task-list-item', count: 2) + expect(page).to have_selector('li.task-list-item input[checked]', count: 0) + + all('.task-list-item-checkbox').each do |checkbox| + checkbox.click + end + wait_for_requests + + visit(project_commit_path(project, sample_commit.id)) + + expect(page).to have_selector('li.task-list-item', count: 2) + expect(page).to have_selector('li.task-list-item input[checked]', count: 2) + end + end end diff --git a/spec/features/projects/compare_spec.rb b/spec/features/projects/compare_spec.rb index 865ae3ad8cb..e387ea4d473 100644 --- a/spec/features/projects/compare_spec.rb +++ b/spec/features/projects/compare_spec.rb @@ -113,7 +113,7 @@ RSpec.describe "Compare", :js do click_button('Compare') - page.within('.alert') do + page.within('.gl-alert') do expect(page).to have_text("Too many changes to show. To preserve performance only 3 of 3+ files are displayed.") end end diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index fa10e429af2..1d7be7fa7a3 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -333,7 +333,7 @@ RSpec.describe 'Environment' do visit project_branches_filtered_path(project, state: 'all', search: 'feature') remove_branch_with_hooks(project, user, 'feature') do - page.within('.js-branch-feature') { find('a.btn-remove').click } + page.within('.js-branch-feature') { find('a.btn-danger').click } end visit_environment(environment) diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 7f2ef61bcbe..8c032660726 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -372,7 +372,7 @@ RSpec.describe 'Environments page', :js do let(:role) { :developer } it 'developer creates a new environment with a valid name' do - within(".top-area") { click_link 'New environment' } + within(".environments-section") { click_link 'New environment' } fill_in('Name', with: 'production') click_on 'Save' @@ -380,7 +380,7 @@ RSpec.describe 'Environments page', :js do end it 'developer creates a new environmetn with invalid name' do - within(".top-area") { click_link 'New environment' } + within(".environments-section") { click_link 'New environment' } fill_in('Name', with: 'name,with,commas') click_on 'Save' diff --git a/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb b/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb new file mode 100644 index 00000000000..2a81c706525 --- /dev/null +++ b/spec/features/projects/feature_flag_user_lists/user_deletes_feature_flag_user_list_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User deletes feature flag user list', :js do + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user) } + + before do + project.add_developer(developer) + sign_in(developer) + end + + context 'with a list' do + before do + create(:operations_feature_flag_user_list, project: project, name: 'My List') + end + + it 'deletes the list' do + visit(project_feature_flags_path(project, scope: 'userLists')) + + delete_user_list_button.click + delete_user_list_modal_confirmation_button.click + + expect(page).to have_text('Lists 0') + end + end + + context 'with a list that is in use' do + before do + list = create(:operations_feature_flag_user_list, project: project, name: 'My List') + feature_flag = create(:operations_feature_flag, :new_version_flag, project: project) + create(:operations_strategy, feature_flag: feature_flag, name: 'gitlabUserList', user_list: list) + end + + it 'does not delete the list' do + visit(project_feature_flags_path(project, scope: 'userLists')) + + delete_user_list_button.click + delete_user_list_modal_confirmation_button.click + + expect(page).to have_text('User list is associated with a strategy') + expect(page).to have_text('Lists 1') + expect(page).to have_text('My List') + + alert_dismiss_button.click + + expect(page).not_to have_text('User list is associated with a strategy') + end + end + + def delete_user_list_button + find("button[data-testid='delete-user-list']") + end + + def delete_user_list_modal_confirmation_button + find("button[data-testid='modal-confirm']") + end + + def alert_dismiss_button + find("div[data-testid='serverErrors'] button") + end +end diff --git a/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb b/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb new file mode 100644 index 00000000000..b37c2780827 --- /dev/null +++ b/spec/features/projects/feature_flag_user_lists/user_edits_feature_flag_user_list_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User edits feature flag user list', :js do + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user) } + + before do + project.add_developer(developer) + sign_in(developer) + end + + it 'prefills the edit form with the list name' do + list = create(:operations_feature_flag_user_list, project: project, name: 'My List Name') + + visit(edit_project_feature_flags_user_list_path(project, list)) + + expect(page).to have_field 'Name', with: 'My List Name' + end +end diff --git a/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb b/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb new file mode 100644 index 00000000000..dfebe6408bd --- /dev/null +++ b/spec/features/projects/feature_flag_user_lists/user_sees_feature_flag_user_list_details_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User sees feature flag user list details', :js do + let_it_be(:project) { create(:project) } + let_it_be(:developer) { create(:user) } + + before do + project.add_developer(developer) + sign_in(developer) + end + + it 'displays the list name' do + list = create(:operations_feature_flag_user_list, project: project, name: 'My List') + + visit(project_feature_flags_user_list_path(project, list)) + + expect(page).to have_text('My List') + end +end diff --git a/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb new file mode 100644 index 00000000000..830dda737b0 --- /dev/null +++ b/spec/features/projects/feature_flags/user_creates_feature_flag_spec.rb @@ -0,0 +1,200 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User creates feature flag', :js do + include FeatureFlagHelpers + + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + before do + project.add_developer(user) + stub_feature_flags(feature_flag_permissions: false) + sign_in(user) + end + + it 'user creates a flag enabled for user ids' do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('test_feature', 'Test feature') + within_strategy_row(1) do + select 'User IDs', from: 'Type' + fill_in 'User IDs', with: 'user1, user2' + environment_plus_button.click + environment_search_input.set('production') + environment_search_results.first.click + end + click_button 'Create feature flag' + + expect_user_to_see_feature_flags_index_page + expect(page).to have_text('test_feature') + end + + it 'user creates a flag with default environment scopes' do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('test_flag', 'Test flag') + within_strategy_row(1) do + select 'All users', from: 'Type' + end + click_button 'Create feature flag' + + expect_user_to_see_feature_flags_index_page + expect(page).to have_text('test_flag') + + edit_feature_flag_button.click + + within_strategy_row(1) do + expect(page).to have_text('All users') + expect(page).to have_text('All environments') + end + end + + it 'removes the correct strategy when a strategy is deleted' do + visit(new_project_feature_flag_path(project)) + click_button 'Add strategy' + within_strategy_row(1) do + select 'All users', from: 'Type' + end + within_strategy_row(2) do + select 'Percent of users', from: 'Type' + end + within_strategy_row(1) do + delete_strategy_button.click + end + + within_strategy_row(1) do + expect(page).to have_select('Type', selected: 'Percent of users') + end + end + + context 'with new version flags disabled' do + before do + stub_feature_flags(feature_flags_new_version: false) + end + + context 'when creates without changing scopes' do + before do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('ci_live_trace', 'For live trace') + click_button 'Create feature flag' + expect(page).to have_current_path(project_feature_flags_path(project)) + end + + it 'shows the created feature flag' do + within_feature_flag_row(1) do + expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') + end + end + end + end + + context 'when creates with disabling the default scope' do + before do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('ci_live_trace', 'For live trace') + + within_scope_row(1) do + within_status { find('.project-feature-toggle').click } + end + + click_button 'Create feature flag' + end + + it 'shows the created feature flag' do + within_feature_flag_row(1) do + expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*') + end + end + end + end + + context 'when creates with an additional scope' do + before do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('mr_train', '') + + within_scope_row(2) do + within_environment_spec do + find('.js-env-search > input').set("review/*") + find('.js-create-button').click + end + end + + within_scope_row(2) do + within_status { find('.project-feature-toggle').click } + end + + click_button 'Create feature flag' + end + + it 'shows the created feature flag' do + within_feature_flag_row(1) do + expect(page.find('.feature-flag-name')).to have_content('mr_train') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(2)')).to have_content('review/*') + end + end + end + end + + context 'when searches an environment name for scope creation' do + let!(:environment) { create(:environment, name: 'production', project: project) } + + before do + visit(new_project_feature_flag_path(project)) + set_feature_flag_info('mr_train', '') + + within_scope_row(2) do + within_environment_spec do + find('.js-env-search > input').set('prod') + click_button 'production' + end + end + + click_button 'Create feature flag' + end + + it 'shows the created feature flag' do + within_feature_flag_row(1) do + expect(page.find('.feature-flag-name')).to have_content('mr_train') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') + expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(2)')).to have_content('production') + end + end + end + end + end + + private + + def set_feature_flag_info(name, description) + fill_in 'Name', with: name + fill_in 'Description', with: description + end + + def environment_plus_button + find('.js-new-environments-dropdown') + end + + def environment_search_input + find('.js-new-environments-dropdown input') + end + + def environment_search_results + all('.js-new-environments-dropdown button.dropdown-item') + end +end diff --git a/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb new file mode 100644 index 00000000000..581709aacee --- /dev/null +++ b/spec/features/projects/feature_flags/user_deletes_feature_flag_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User deletes feature flag', :js do + include FeatureFlagHelpers + + let(:user) { create(:user) } + let(:project) { create(:project, namespace: user.namespace) } + + let!(:feature_flag) do + create_flag(project, 'ci_live_trace', false, + description: 'For live trace feature') + end + + before do + project.add_developer(user) + stub_feature_flags(feature_flag_permissions: false) + sign_in(user) + + visit(project_feature_flags_path(project)) + + find('.js-feature-flag-delete-button').click + click_button('Delete feature flag') + expect(page).to have_current_path(project_feature_flags_path(project)) + end + + it 'user does not see feature flag' do + expect(page).to have_no_content('ci_live_trace') + end +end diff --git a/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb new file mode 100644 index 00000000000..750f4dc5ef4 --- /dev/null +++ b/spec/features/projects/feature_flags/user_sees_feature_flag_list_spec.rb @@ -0,0 +1,147 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User sees feature flag list', :js do + include FeatureFlagHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, namespace: user.namespace) } + + before_all do + project.add_developer(user) + end + + before do + sign_in(user) + end + + context 'with legacy feature flags' do + before do + create_flag(project, 'ci_live_trace', false).tap do |feature_flag| + create_scope(feature_flag, 'review/*', true) + end + create_flag(project, 'drop_legacy_artifacts', false) + create_flag(project, 'mr_train', true).tap do |feature_flag| + create_scope(feature_flag, 'production', false) + end + stub_feature_flags(feature_flags_legacy_read_only_override: false) + end + + it 'user sees the first flag' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(1) do + expect(page.find('.js-feature-flag-id')).to have_content('^1') + expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') + expect_status_toggle_button_not_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*') + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(2)')).to have_content('review/*') + end + end + end + + it 'user sees the second flag' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(2) do + expect(page.find('.js-feature-flag-id')).to have_content('^2') + expect(page.find('.feature-flag-name')).to have_content('drop_legacy_artifacts') + expect_status_toggle_button_not_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(1)')).to have_content('*') + end + end + end + + it 'user sees the third flag' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(3) do + expect(page.find('.js-feature-flag-id')).to have_content('^3') + expect(page.find('.feature-flag-name')).to have_content('mr_train') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('[data-qa-selector="feature-flag-scope-info-badge"]:nth-child(1)')).to have_content('*') + expect(page.find('[data-qa-selector="feature-flag-scope-muted-badge"]:nth-child(2)')).to have_content('production') + end + end + end + + it 'user sees the status toggle disabled' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(1) do + expect_status_toggle_button_to_be_disabled + end + end + + context 'when legacy feature flags are not read-only' do + before do + stub_feature_flags(feature_flags_legacy_read_only: false) + end + + it 'user updates the status toggle' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(1) do + status_toggle_button.click + + expect_status_toggle_button_to_be_checked + end + end + end + + context 'when legacy feature flags are read-only but the override is active for a project' do + before do + stub_feature_flags( + feature_flags_legacy_read_only: true, + feature_flags_legacy_read_only_override: project + ) + end + + it 'user updates the status toggle' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(1) do + status_toggle_button.click + + expect_status_toggle_button_to_be_checked + end + end + end + end + + context 'with new version flags' do + before do + create(:operations_feature_flag, :new_version_flag, project: project, + name: 'my_flag', active: false) + end + + it 'user updates the status toggle' do + visit(project_feature_flags_path(project)) + + within_feature_flag_row(1) do + status_toggle_button.click + + expect_status_toggle_button_to_be_checked + end + end + end + + context 'when there are no feature flags' do + before do + visit(project_feature_flags_path(project)) + end + + it 'shows empty page' do + expect(page).to have_text 'Get started with feature flags' + expect(page).to have_selector('.btn-success', text: 'New feature flag') + expect(page).to have_selector('[data-qa-selector="configure_feature_flags_button"]', text: 'Configure') + end + end +end diff --git a/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb new file mode 100644 index 00000000000..bc2d63e1953 --- /dev/null +++ b/spec/features/projects/feature_flags/user_updates_feature_flag_spec.rb @@ -0,0 +1,195 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User updates feature flag', :js do + include FeatureFlagHelpers + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, namespace: user.namespace) } + + before_all do + project.add_developer(user) + end + + before do + stub_feature_flags( + feature_flag_permissions: false, + feature_flags_legacy_read_only_override: false + ) + sign_in(user) + end + + context 'with a new version feature flag' do + let!(:feature_flag) do + create_flag(project, 'test_flag', false, version: Operations::FeatureFlag.versions['new_version_flag'], + description: 'For testing') + end + + let!(:strategy) do + create(:operations_strategy, feature_flag: feature_flag, + name: 'default', parameters: {}) + end + + let!(:scope) do + create(:operations_scope, strategy: strategy, environment_scope: '*') + end + + it 'user adds a second strategy' do + visit(edit_project_feature_flag_path(project, feature_flag)) + + wait_for_requests + + click_button 'Add strategy' + within_strategy_row(2) do + select 'Percent of users', from: 'Type' + fill_in 'Percentage', with: '15' + end + click_button 'Save changes' + + edit_feature_flag_button.click + + within_strategy_row(1) do + expect(page).to have_text 'All users' + expect(page).to have_text 'All environments' + end + within_strategy_row(2) do + expect(page).to have_text 'Percent of users' + expect(page).to have_field 'Percentage', with: '15' + expect(page).to have_text 'All environments' + end + end + + it 'user toggles the flag on' do + visit(edit_project_feature_flag_path(project, feature_flag)) + status_toggle_button.click + click_button 'Save changes' + + within_feature_flag_row(1) do + expect_status_toggle_button_to_be_checked + end + end + end + + context 'with a legacy feature flag' do + let!(:feature_flag) do + create_flag(project, 'ci_live_trace', true, + description: 'For live trace feature') + end + + let!(:scope) { create_scope(feature_flag, 'review/*', true) } + + context 'when legacy flags are editable' do + before do + stub_feature_flags(feature_flags_legacy_read_only: false) + + visit(edit_project_feature_flag_path(project, feature_flag)) + end + + it 'user sees persisted default scope' do + within_scope_row(1) do + within_environment_spec do + expect(page).to have_content('* (All Environments)') + end + + within_status do + expect(find('.project-feature-toggle')['aria-label']) + .to eq('Toggle Status: ON') + end + end + end + + context 'when user updates the status of a scope' do + before do + within_scope_row(2) do + within_status { find('.project-feature-toggle').click } + end + + click_button 'Save changes' + expect(page).to have_current_path(project_feature_flags_path(project)) + end + + it 'shows the updated feature flag' do + within_feature_flag_row(1) do + expect(page.find('.feature-flag-name')).to have_content('ci_live_trace') + expect_status_toggle_button_to_be_checked + + within_feature_flag_scopes do + expect(page.find('.badge:nth-child(1)')).to have_content('*') + expect(page.find('.badge:nth-child(1)')['class']).to include('badge-info') + expect(page.find('.badge:nth-child(2)')).to have_content('review/*') + expect(page.find('.badge:nth-child(2)')['class']).to include('badge-muted') + end + end + end + end + + context 'when user adds a new scope' do + before do + within_scope_row(3) do + within_environment_spec do + find('.js-env-search > input').set('production') + find('.js-create-button').click + end + end + + click_button 'Save changes' + expect(page).to have_current_path(project_feature_flags_path(project)) + end + + it 'shows the newly created scope' do + within_feature_flag_row(1) do + within_feature_flag_scopes do + expect(page.find('.badge:nth-child(3)')).to have_content('production') + expect(page.find('.badge:nth-child(3)')['class']).to include('badge-muted') + end + end + end + end + + context 'when user deletes a scope' do + before do + within_scope_row(2) do + within_delete { find('.js-delete-scope').click } + end + + click_button 'Save changes' + expect(page).to have_current_path(project_feature_flags_path(project)) + end + + it 'shows the updated feature flag' do + within_feature_flag_row(1) do + within_feature_flag_scopes do + expect(page).to have_css('.badge:nth-child(1)') + expect(page).not_to have_css('.badge:nth-child(2)') + end + end + end + end + end + + context 'when legacy flags are read-only' do + it 'the user cannot edit the flag' do + visit(edit_project_feature_flag_path(project, feature_flag)) + + expect(page).to have_text 'This feature flag is read-only, and it will be removed in 14.0.' + expect(page).to have_css('button.js-ff-submit.disabled') + end + end + + context 'when legacy flags are read-only, but the override is active for one project' do + it 'the user can edit the flag' do + stub_feature_flags(feature_flags_legacy_read_only_override: project) + + visit(edit_project_feature_flag_path(project, feature_flag)) + status_toggle_button.click + click_button 'Save changes' + + expect(page).to have_current_path(project_feature_flags_path(project)) + within_feature_flag_row(1) do + expect_status_toggle_button_not_to_be_checked + end + end + end + end +end diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 8d3ca9d9fd1..467adb25a17 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -201,7 +201,7 @@ RSpec.describe 'Edit Project Settings' do visit project_path(project) - expect(page).to have_content "Customize your workflow!" + expect(page).to have_content "joined project" end it "hides project activity tabs" do diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index eed1e7aaf1b..d28e31c08dc 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Projects > Files > Project owner sees a link to create a license file in empty project', :js do + include WebIdeSpecHelpers + let(:project) { create(:project_empty_repo) } let(:project_maintainer) { project.owner } @@ -10,36 +12,35 @@ RSpec.describe 'Projects > Files > Project owner sees a link to create a license sign_in(project_maintainer) end - it 'project maintainer creates a license file from a template' do + it 'allows project maintainer creates a license file from a template in Web IDE' do visit project_path(project) click_on 'Add LICENSE' - expect(page).to have_content('New file') - expect(current_path).to eq( - project_new_blob_path(project, 'master')) - expect(find('#file_name').value).to eq('LICENSE') - expect(page).to have_selector('.license-selector') + expect(current_path).to eq("/-/ide/project/#{project.full_path}/edit/master/-/LICENSE") + + expect(page).to have_selector('.qa-file-templates-bar') select_template('MIT License') - file_content = first('.file-editor') - expect(file_content).to have_content('MIT License') - expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") + expect(ide_editor_value).to have_content('MIT License') + expect(ide_editor_value).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") + + ide_commit + + click_button('Commit') + + expect(current_path).to eq("/-/ide/project/#{project.full_path}/tree/master/-/") - fill_in :commit_message, with: 'Add a LICENSE file', visible: true - click_button 'Commit changes' + expect(page).to have_content('All changes are committed') - expect(current_path).to eq( - project_blob_path(project, 'master/LICENSE')) - expect(page).to have_content('MIT License') - expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") + license_file = project.repository.blob_at('master', 'LICENSE').data + expect(license_file).to have_content('MIT License') + expect(license_file).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") end def select_template(template) - page.within('.js-license-selector-wrap') do - click_button 'Apply a template' - click_link template - wait_for_requests - end + click_button 'Choose a template...' + click_button template + wait_for_requests end end diff --git a/spec/features/projects/files/user_browses_lfs_files_spec.rb b/spec/features/projects/files/user_browses_lfs_files_spec.rb index ecc56b794b2..3be5ab64834 100644 --- a/spec/features/projects/files/user_browses_lfs_files_spec.rb +++ b/spec/features/projects/files/user_browses_lfs_files_spec.rb @@ -66,10 +66,30 @@ RSpec.describe 'Projects > Files > User browses LFS files' do expect(page).to have_content('History') expect(page).to have_content('Permalink') expect(page).to have_content('Replace') + expect(page).to have_link('Download') + expect(page).not_to have_content('Annotate') expect(page).not_to have_content('Blame') - expect(page).not_to have_content('Edit') - expect(page).to have_link('Download') + + expect(page).not_to have_selector(:link_or_button, text: /^Edit$/) + expect(page).to have_selector(:link_or_button, 'Edit in Web IDE') + end + end + + context 'when feature flag :consolidated_edit_button is off' do + before do + stub_feature_flags(consolidated_edit_button: false) + + click_link('files') + click_link('lfs') + click_link('lfs_object.iso') + end + + it 'does not show single file edit link' do + page.within('.content') do + expect(page).to have_selector(:link_or_button, 'Web IDE') + expect(page).not_to have_selector(:link_or_button, 'Edit') + end end end end diff --git a/spec/features/projects/files/user_creates_files_spec.rb b/spec/features/projects/files/user_creates_files_spec.rb index 39bc139656b..fd83547d064 100644 --- a/spec/features/projects/files/user_creates_files_spec.rb +++ b/spec/features/projects/files/user_creates_files_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe 'Projects > Files > User creates files', :js do + include BlobSpecHelpers + 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." @@ -103,6 +105,8 @@ RSpec.describe 'Projects > Files > User creates files', :js do end it 'creates and commit a new file with new lines at the end of file' do + set_default_button('edit') + find('#editor') execute_script('monaco.editor.getModels()[0].setValue("Sample\n\n\n")') fill_in(:file_name, with: 'not_a_file.md') @@ -113,7 +117,7 @@ RSpec.describe 'Projects > Files > User creates files', :js do expect(current_path).to eq(new_file_path) - find('.js-edit-blob').click + click_link('Edit') find('#editor') expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq("Sample\n\n\n") diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb index d3e075001c8..c18ff9ddbbc 100644 --- a/spec/features/projects/files/user_edits_files_spec.rb +++ b/spec/features/projects/files/user_edits_files_spec.rb @@ -4,6 +4,8 @@ require 'spec_helper' RSpec.describe 'Projects > Files > User edits files', :js do include ProjectForksHelper + include BlobSpecHelpers + 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) } @@ -14,6 +16,10 @@ RSpec.describe 'Projects > Files > User edits files', :js do sign_in(user) end + after do + unset_default_button + end + shared_examples 'unavailable for an archived project' do it 'does not show the edit link for an archived project', :js do project.update!(archived: true) @@ -39,14 +45,15 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'inserts a content of a file' do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') - expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq('*.rbca') + expect(editor_value).to eq('*.rbca') end it 'does not show the edit link if a file is binary' do @@ -60,12 +67,13 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'commits an edited file' do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') fill_in(:commit_message, with: 'New commit message', visible: true) click_button('Commit changes') @@ -77,13 +85,14 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'commits an edited file to a new branch' do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') fill_in(:commit_message, with: 'New commit message', visible: true) fill_in(:branch_name, with: 'new_branch_name', visible: true) click_button('Commit changes') @@ -96,12 +105,13 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'shows the diff of an edited file' do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') click_link('Preview changes') expect(page).to have_css('.line_holder.new') @@ -118,8 +128,8 @@ RSpec.describe 'Projects > Files > User edits files', :js do end def expect_fork_prompt - expect(page).to have_link('Fork') - expect(page).to have_button('Cancel') + expect(page).to have_selector(:link_or_button, 'Fork') + expect(page).to have_selector(:link_or_button, 'Cancel') expect(page).to have_content( "You're not allowed to edit files in this project directly. "\ "Please fork this project, make your changes there, and submit a merge request." @@ -134,30 +144,32 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do + set_default_button('edit') click_link('.gitignore') - click_button('Edit') + click_link_or_button('Edit') expect_fork_prompt - click_link('Fork') + click_link_or_button('Fork project') expect_fork_status find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') - expect(evaluate_script('monaco.editor.getModels()[0].getValue()')).to eq('*.rbca') + expect(editor_value).to eq('*.rbca') end it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do + set_default_button('webide') click_link('.gitignore') - click_button('Web IDE') + click_link_or_button('Web IDE') expect_fork_prompt - click_link('Fork') + click_link_or_button('Fork project') expect_fork_status @@ -166,17 +178,17 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') expect_fork_prompt - - click_link('Fork') + click_link_or_button('Fork project') find('.file-editor', match: :first) find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') fill_in(:commit_message, with: 'New commit message', visible: true) click_button('Commit changes') @@ -198,14 +210,14 @@ RSpec.describe 'Projects > Files > User edits files', :js do end it 'links to the forked project for editing', :sidekiq_might_not_need_inline do + set_default_button('edit') click_link('.gitignore') - find('.js-edit-blob').click + click_link_or_button('Edit') - expect(page).not_to have_link('Fork') - expect(page).not_to have_button('Cancel') + expect(page).not_to have_link('Fork project') find('#editor') - execute_script("monaco.editor.getModels()[0].setValue('*.rbca')") + set_editor_value('*.rbca') fill_in(:commit_message, with: 'Another commit', visible: true) click_button('Commit changes') @@ -224,5 +236,116 @@ RSpec.describe 'Projects > Files > User edits files', :js do let(:project) { project2 } end end + + context 'when feature flag :consolidated_edit_button is off' do + before do + stub_feature_flags(consolidated_edit_button: false) + end + + context 'when an user does not have write access', :js do + before do + project2.add_reporter(user) + visit(project2_tree_path_root_ref) + wait_for_requests + end + + it 'inserts a content of a file in a forked project', :sidekiq_might_not_need_inline do + set_default_button('edit') + click_link('.gitignore') + click_link_or_button('Edit') + + expect_fork_prompt + + click_link_or_button('Fork') + + expect_fork_status + + find('.file-editor', match: :first) + + find('#editor') + set_editor_value('*.rbca') + + expect(editor_value).to eq('*.rbca') + end + + it 'opens the Web IDE in a forked project', :sidekiq_might_not_need_inline do + set_default_button('webide') + click_link('.gitignore') + click_link_or_button('Web IDE') + + expect_fork_prompt + + click_link_or_button('Fork') + + expect_fork_status + + expect(page).to have_css('.ide-sidebar-project-title', text: "#{project2.name} #{user.namespace.full_path}/#{project2.path}") + expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore') + end + + it 'commits an edited file in a forked project', :sidekiq_might_not_need_inline do + set_default_button('edit') + click_link('.gitignore') + click_link_or_button('Edit') + + expect_fork_prompt + + click_link_or_button('Fork') + + expect_fork_status + + find('.file-editor', match: :first) + + find('#editor') + set_editor_value('*.rbca') + fill_in(:commit_message, with: 'New commit message', visible: true) + click_button('Commit changes') + + fork = user.fork_of(project2.reload) + + expect(current_path).to eq(project_new_merge_request_path(fork)) + + wait_for_requests + + expect(page).to have_content('New commit message') + end + + context 'when the user already had a fork of the project', :js do + let!(:forked_project) { fork_project(project2, user, namespace: user.namespace, repository: true) } + + before do + visit(project2_tree_path_root_ref) + wait_for_requests + end + + it 'links to the forked project for editing', :sidekiq_might_not_need_inline do + set_default_button('edit') + click_link('.gitignore') + click_link_or_button('Edit') + + expect(page).not_to have_link('Fork') + + find('#editor') + set_editor_value('*.rbca') + fill_in(:commit_message, with: 'Another commit', visible: true) + click_button('Commit changes') + + fork = user.fork_of(project2) + + expect(current_path).to eq(project_new_merge_request_path(fork)) + + wait_for_requests + + expect(page).to have_content('Another commit') + expect(page).to have_content("From #{forked_project.full_path}") + expect(page).to have_content("into #{project2.full_path}") + end + + it_behaves_like 'unavailable for an archived project' do + let(:project) { project2 } + end + end + end + end end end diff --git a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb index 8d5e99d7e2b..78fb470d4ea 100644 --- a/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb +++ b/spec/features/projects/issues/design_management/user_links_to_designs_in_issue_spec.rb @@ -90,34 +90,5 @@ RSpec.describe 'viewing issues with design references' do expect(page).not_to have_link(design_ref_b) end end - - context 'design management is enabled, but the filter is disabled globally' do - before do - enable_design_management - stub_feature_flags( - Banzai::Filter::DesignReferenceFilter::FEATURE_FLAG => false - ) - end - - it 'processes design tab links successfully, and design references as issue references', :aggregate_failures do - visit_page_with_design_references - - expect(page).to have_text('The designs I mentioned') - expect(page).to have_link(design_tab_ref) - expect(page).to have_link(issue_ref) - expect(page).not_to have_link(design_ref_a) - expect(page).not_to have_link(design_ref_b) - end - end - - context 'design management is enabled, and the filter is enabled for the current project' do - before do - stub_feature_flags( - Banzai::Filter::DesignReferenceFilter::FEATURE_FLAG => public_project - ) - end - - it_behaves_like 'successful use of design link references' - end end end diff --git a/spec/features/projects/issues/viewing_relocated_issues_spec.rb b/spec/features/projects/issues/viewing_relocated_issues_spec.rb new file mode 100644 index 00000000000..10d5ad1747c --- /dev/null +++ b/spec/features/projects/issues/viewing_relocated_issues_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'issues canonical link' do + include Spec::Support::Helpers::Features::CanonicalLinkHelpers + + let_it_be(:original_project) { create(:project, :public) } + let_it_be(:original_issue) { create(:issue, project: original_project) } + let_it_be(:canonical_issue) { create(:issue) } + let_it_be(:canonical_url) { issue_url(canonical_issue, Gitlab::Application.routes.default_url_options) } + + it "doesn't show the canonical URL" do + visit(issue_path(original_issue)) + + expect(page).not_to have_any_canonical_links + end + + context 'when the issue was moved' do + it 'shows the canonical URL' do + original_issue.moved_to = canonical_issue + original_issue.save! + + visit(issue_path(original_issue)) + + expect(page).to have_canonical_link(canonical_url) + end + end + + context 'when the issue was duplicated' do + it 'shows the canonical URL' do + original_issue.duplicated_to = canonical_issue + original_issue.save! + + visit(issue_path(original_issue)) + + expect(page).to have_canonical_link(canonical_url) + end + end +end diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index b935b99642b..9b199157d79 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -43,7 +43,7 @@ RSpec.describe 'User browses a job', :js do wait_for_all_requests within('.builds-container') do expect(page).to have_selector( - ".build-job > a[data-original-title='test - failed - (unknown failure)']") + ".build-job > a[title='test - failed - (unknown failure)']") end end end @@ -55,7 +55,7 @@ RSpec.describe 'User browses a job', :js do wait_for_all_requests within('.builds-container') do expect(page).to have_selector( - ".build-job > a[data-original-title='test - failed - (unknown failure) (retried)']") + ".build-job > a[title='test - failed - (unknown failure) (retried)']") end end end diff --git a/spec/features/projects/members/groups_with_access_list_spec.rb b/spec/features/projects/members/groups_with_access_list_spec.rb index 2ee6bc103e9..d59f8eb4b1d 100644 --- a/spec/features/projects/members/groups_with_access_list_spec.rb +++ b/spec/features/projects/members/groups_with_access_list_spec.rb @@ -3,20 +3,23 @@ require 'spec_helper' RSpec.describe 'Projects > Members > Groups with access list', :js do - let(:user) { create(:user) } - let(:group) { create(:group, :public) } - let(:project) { create(:project, :public) } + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group, :public) } + let_it_be(:project) { create(:project, :public) } + + let(:additional_link_attrs) { {} } + let!(:group_link) { create(:project_group_link, project: project, group: group, **additional_link_attrs) } before do - project.add_maintainer(user) - @group_link = create(:project_group_link, project: project, group: group) + travel_to Time.now.utc.beginning_of_day + project.add_maintainer(user) sign_in(user) visit project_project_members_path(project) end it 'updates group access level' do - click_button @group_link.human_access + click_button group_link.human_access page.within '.dropdown-menu' do click_link 'Guest' @@ -30,20 +33,38 @@ RSpec.describe 'Projects > Members > Groups with access list', :js do end it 'updates expiry date' do - tomorrow = Date.today + 3 + expires_at_field = "member_expires_at_#{group.id}" + fill_in expires_at_field, with: 3.days.from_now.to_date - fill_in "member_expires_at_#{group.id}", with: tomorrow.strftime("%F") - find('body').click + find_field(expires_at_field).native.send_keys :enter wait_for_requests page.within(find('li.group_member')) do - expect(page).to have_content('Expires in') + expect(page).to have_content('Expires in 3 days') + end + end + + context 'when link has expiry date set' do + let(:additional_link_attrs) { { expires_at: 3.days.from_now.to_date } } + + it 'clears expiry date' do + page.within(find('li.group_member')) do + expect(page).to have_content('Expires in 3 days') + + page.within(find('.js-edit-member-form')) do + find('.js-clear-input').click + end + + wait_for_requests + + expect(page).not_to have_content('Expires in') + end end end it 'deletes group link' do page.within(first('.group_member')) do - accept_confirm { find('.btn-remove').click } + accept_confirm { find('.btn-danger').click } end wait_for_requests diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index b32ccb0ccef..36ff461aac2 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -102,7 +102,7 @@ RSpec.describe 'Project members list' do visit_members_page expect(page).not_to have_selector("#edit_project_member_#{project_member.id}") - expect(page).not_to have_selector("#project_member_#{project_member.id} .btn-remove") + expect(page).to have_no_selector("#project_member_#{project_member.id} .btn-danger") end end diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 979bbd57aa3..d69c3f2652c 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -6,43 +6,64 @@ RSpec.describe 'Projects > Members > Maintainer adds member with expiration date include Select2Helper include ActiveSupport::Testing::TimeHelpers - let(:maintainer) { create(:user) } - let(:project) { create(:project) } - let!(:new_member) { create(:user) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:project) { create(:project) } + let(:new_member) { create(:user) } before do + travel_to Time.now.utc.beginning_of_day + project.add_maintainer(maintainer) sign_in(maintainer) end it 'expiration date is displayed in the members list' do - travel_to Time.zone.parse('2016-08-06 08:00') do - date = 4.days.from_now - visit project_project_members_path(project) - - page.within '.invite-users-form' do - select2(new_member.id, from: '#user_ids', multiple: true) - fill_in 'expires_at', with: date.to_s(:medium) + "\n" - click_on 'Invite' - end - - page.within "#project_member_#{new_member.project_members.first.id}" do - expect(page).to have_content('Expires in 4 days') - end + visit project_project_members_path(project) + + page.within '.invite-users-form' do + select2(new_member.id, from: '#user_ids', multiple: true) + + fill_in 'expires_at', with: 3.days.from_now.to_date + find_field('expires_at').native.send_keys :enter + + click_on 'Invite' + end + + page.within "#project_member_#{project_member_id}" do + expect(page).to have_content('Expires in 3 days') + end + end + + it 'changes expiration date' do + project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_date) + visit project_project_members_path(project) + + page.within "#project_member_#{project_member_id}" do + fill_in 'Expiration date', with: 3.days.from_now.to_date + find_field('Expiration date').native.send_keys :enter + + wait_for_requests + + expect(page).to have_content('Expires in 3 days') end end - it 'change expiration date' do - travel_to Time.zone.parse('2016-08-06 08:00') do - date = 3.days.from_now - project.team.add_users([new_member.id], :developer, expires_at: Date.today.to_s(:medium)) - visit project_project_members_path(project) - - page.within "#project_member_#{new_member.project_members.first.id}" do - find('.js-access-expiration-date').set date.to_s(:medium) + "\n" - wait_for_requests - expect(page).to have_content('Expires in 3 days') - end + it 'clears expiration date' do + project.team.add_users([new_member.id], :developer, expires_at: 3.days.from_now.to_date) + visit project_project_members_path(project) + + page.within "#project_member_#{project_member_id}" do + expect(page).to have_content('Expires in 3 days') + + find('.js-clear-input').click + + wait_for_requests + + expect(page).not_to have_content('Expires in') end end + + def project_member_id + project.members.find_by(user_id: new_member).id + end end diff --git a/spec/features/projects/navbar_spec.rb b/spec/features/projects/navbar_spec.rb index 07f65fe62df..4ff3827b240 100644 --- a/spec/features/projects/navbar_spec.rb +++ b/spec/features/projects/navbar_spec.rb @@ -12,20 +12,10 @@ RSpec.describe 'Project navbar' do let_it_be(:project) { create(:project, :repository) } before do - stub_feature_flags(project_iterations: false) - insert_package_nav(_('Operations')) project.add_maintainer(user) sign_in(user) - - if Gitlab.ee? - insert_after_sub_nav_item( - _('Kubernetes'), - within: _('Operations'), - new_sub_nav_item_name: _('Feature Flags') - ) - end end it_behaves_like 'verified navigation bar' do diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 243579ee2f7..c3eea0195a6 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -336,7 +336,7 @@ RSpec.shared_examples 'pages settings editing' do expect(page).not_to have_field(:project_pages_https_only) expect(page).not_to have_content('Force HTTPS (requires valid certificates)') - expect(page).not_to have_button('Save') + expect(page).to have_button('Save') end end end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index f59dc5dd074..51826d867cd 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -172,10 +172,17 @@ RSpec.describe 'Pipeline', :js do end end - it_behaves_like 'showing user status' do - let(:user_with_status) { pipeline.user } + describe 'pipelines details view' do + let!(:status) { create(:user_status, user: pipeline.user, emoji: 'smirk', message: 'Authoring this object') } - subject { visit project_pipeline_path(project, pipeline) } + it 'pipeline header shows the user status and emoji' do + visit project_pipeline_path(project, pipeline) + + within '[data-testid="ci-header-content"]' do + expect(page).to have_selector("[data-testid='#{status.message}']") + expect(page).to have_selector("[data-name='#{status.emoji}']") + end + end end describe 'pipeline graph' do @@ -400,7 +407,7 @@ RSpec.describe 'Pipeline', :js do context 'when retrying' do before do - find('[data-testid="retryButton"]').click + find('[data-testid="retryPipeline"]').click end it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do @@ -902,7 +909,7 @@ RSpec.describe 'Pipeline', :js do context 'when retrying' do before do - find('[data-testid="retryButton"]').click + find('[data-testid="retryPipeline"]').click end it 'does not show a "Retry" button', :sidekiq_might_not_need_inline do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index a9c196bb84b..3e78dfc3bc7 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -118,7 +118,7 @@ RSpec.describe 'Pipelines', :js do context 'when canceling' do before do find('.js-pipelines-cancel-button').click - find('.js-modal-primary-action').click + click_button 'Stop pipeline' wait_for_requests end @@ -407,7 +407,7 @@ RSpec.describe 'Pipelines', :js do context 'when canceling' do before do find('.js-pipelines-cancel-button').click - find('.js-modal-primary-action').click + click_button 'Stop pipeline' end it 'indicates that pipeline was canceled', :sidekiq_might_not_need_inline do diff --git a/spec/features/projects/releases/user_creates_release_spec.rb b/spec/features/projects/releases/user_creates_release_spec.rb index 5d05a7e4c91..0a5f7cc7edd 100644 --- a/spec/features/projects/releases/user_creates_release_spec.rb +++ b/spec/features/projects/releases/user_creates_release_spec.rb @@ -11,14 +11,11 @@ RSpec.describe 'User creates release', :js do let_it_be(:user) { create(:user) } let(:new_page_url) { new_project_release_path(project) } - let(:show_feature_flag) { true } before do - stub_feature_flags(release_show_page: show_feature_flag) - project.add_developer(user) - gitlab_sign_in(user) + sign_in(user) visit new_page_url @@ -75,14 +72,6 @@ RSpec.describe 'User creates release', :js do expect(page).to have_current_path(project_release_path(project, release)) end - - context 'when the release_show_page feature flag is disabled' do - let(:show_feature_flag) { false } - - it 'redirects to the main "Releases" page' do - expect(page).to have_current_path(project_releases_path(project)) - end - end end context 'when the "Cancel" button is clicked' do @@ -108,6 +97,24 @@ RSpec.describe 'User creates release', :js do end end + context 'when the release notes "Preview" tab is clicked' do + before do + find_field('Release notes').click + + fill_release_notes('**some** _markdown_ [content](https://example.com)') + + click_on 'Preview' + + wait_for_all_requests + end + + it 'renders a preview of the release notes markdown' do + within('[data-testid="release-notes"]') do + expect(page).to have_text('some markdown content') + end + end + end + def fill_out_form_and_submit fill_tag_name(tag_name) 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 4ed1be6db6b..9115a135aeb 100644 --- a/spec/features/projects/releases/user_views_edit_release_spec.rb +++ b/spec/features/projects/releases/user_views_edit_release_spec.rb @@ -6,14 +6,11 @@ RSpec.describe 'User edits Release', :js do let_it_be(:project) { create(:project, :repository) } let_it_be(:release) { create(:release, project: project, name: 'The first release' ) } let_it_be(:user) { create(:user) } - let(:show_feature_flag) { true } before do - stub_feature_flags(release_show_page: show_feature_flag) - project.add_developer(user) - gitlab_sign_in(user) + sign_in(user) visit edit_project_release_path(project, release) @@ -42,7 +39,7 @@ RSpec.describe 'User edits Release', :js do it 'renders the edit Release form' do expect(page).to have_content('Releases are based on Git tags. We recommend tags that use semantic versioning, for example v1.0, v2.0-pre.') - expect(find_field('Tag name', { disabled: true }).value).to eq(release.tag) + expect(find_field('Tag name', disabled: true).value).to eq(release.tag) expect(find_field('Release title').value).to eq(release.name) expect(find_field('Release notes').value).to eq(release.description) @@ -71,42 +68,24 @@ RSpec.describe 'User edits Release', :js do expect(release.description).to eq('Updated Release notes') end - context 'when the release_show_page feature flag is disabled' do - let(:show_feature_flag) { false } - - it 'redirects to the main Releases page when "Cancel" is clicked' do - fill_out_form_and_click 'Cancel' - - expect(page).to have_current_path(project_releases_path(project)) - end + it 'redirects to the previous page when "Cancel" is clicked when the url includes a back_url query parameter' do + back_path = project_releases_path(project, params: { page: 2 }) + visit edit_project_release_path(project, release, params: { back_url: back_path }) - it 'redirects to the main Releases page when "Save changes" is clicked' do - fill_out_form_and_click 'Save changes' + fill_out_form_and_click 'Cancel' - expect(page).to have_current_path(project_releases_path(project)) - end + expect(page).to have_current_path(back_path) end - context 'when the release_show_page feature flag is enabled' do - it 'redirects to the previous page when "Cancel" is clicked when the url includes a back_url query parameter' do - back_path = project_releases_path(project, params: { page: 2 }) - visit edit_project_release_path(project, release, params: { back_url: back_path }) - - fill_out_form_and_click 'Cancel' - - expect(page).to have_current_path(back_path) - end - - it 'redirects to the main Releases page when "Cancel" is clicked when the url does not include a back_url query parameter' do - fill_out_form_and_click 'Cancel' + it 'redirects to the main Releases page when "Cancel" is clicked when the url does not include a back_url query parameter' do + fill_out_form_and_click 'Cancel' - expect(page).to have_current_path(project_releases_path(project)) - end + expect(page).to have_current_path(project_releases_path(project)) + end - it 'redirects to the dedicated Release page when "Save changes" is clicked' do - fill_out_form_and_click 'Save changes' + it 'redirects to the dedicated Release page when "Save changes" is clicked' do + fill_out_form_and_click 'Save changes' - expect(page).to have_current_path(project_release_path(project, release)) - end + expect(page).to have_current_path(project_release_path(project, release)) end end diff --git a/spec/features/projects/releases/user_views_release_spec.rb b/spec/features/projects/releases/user_views_release_spec.rb index c82588746a8..186122536ce 100644 --- a/spec/features/projects/releases/user_views_release_spec.rb +++ b/spec/features/projects/releases/user_views_release_spec.rb @@ -4,34 +4,57 @@ require 'spec_helper' RSpec.describe 'User views Release', :js do let(:project) { create(:project, :repository) } - let(:release) { create(:release, project: project, name: 'The first release' ) } let(:user) { create(:user) } + let(:graphql_feature_flag) { true } + + let(:release) do + create(:release, + project: project, + name: 'The first release', + description: '**Lorem** _ipsum_ dolor sit [amet](https://example.com)') + end before do + stub_feature_flags(graphql_individual_release_page: graphql_feature_flag) + project.add_developer(user) - gitlab_sign_in(user) + sign_in(user) visit project_release_path(project, release) end - it 'renders the breadcrumbs' do - within('.breadcrumbs') do - expect(page).to have_content("#{project.creator.name} #{project.name} Releases #{release.name}") + it_behaves_like 'page meta description', 'Lorem ipsum dolor sit amet' - 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)) + shared_examples 'release page' do + it 'renders the breadcrumbs' do + within('.breadcrumbs') do + expect(page).to have_content("#{project.creator.name} #{project.name} Releases #{release.name}") + + 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)) + end end - end - it 'renders the release details' do - within('.release-block') do - expect(page).to have_content(release.name) - expect(page).to have_content(release.tag) - expect(page).to have_content(release.commit.short_id) - expect(page).to have_content(release.description) + it 'renders the release details' do + within('.release-block') do + expect(page).to have_content(release.name) + expect(page).to have_content(release.tag) + expect(page).to have_content(release.commit.short_id) + expect(page).to have_content('Lorem ipsum dolor sit amet') + end end end + + describe 'when the graphql_individual_release_page feature flag is enabled' do + it_behaves_like 'release page' + end + + describe 'when the graphql_individual_release_page feature flag is disabled' do + let(:graphql_feature_flag) { false } + + it_behaves_like 'release page' + end end diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb index 993d3371904..323c57570c3 100644 --- a/spec/features/projects/releases/user_views_releases_spec.rb +++ b/spec/features/projects/releases/user_views_releases_spec.rb @@ -16,7 +16,7 @@ RSpec.describe 'User views releases', :js do shared_examples 'releases page' do context('when the user is a maintainer') do before do - gitlab_sign_in(maintainer) + sign_in(maintainer) end it 'sees the release' do @@ -27,11 +27,23 @@ RSpec.describe 'User views releases', :js do expect(page).not_to have_content('Upcoming Release') end - shared_examples 'asset link tests' do - context 'when there is a link as an asset' do - let!(:release_link) { create(:release_link, release: release, url: url ) } + context 'when there is a link as an asset' do + let!(:release_link) { create(:release_link, release: release, url: url ) } + let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } + let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath } + + it 'sees the link' do + visit project_releases_path(project) + + page.within('.js-assets-list') do + expect(page).to have_link release_link.name, href: direct_asset_link + expect(page).not_to have_css('[data-testid="external-link-indicator"]') + end + end + + context 'when there is a link redirect' do + let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath } it 'sees the link' do visit project_releases_path(project) @@ -41,51 +53,21 @@ RSpec.describe 'User views releases', :js do expect(page).not_to have_css('[data-testid="external-link-indicator"]') end end + end - context 'when there is a link redirect' do - let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) } - let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } - - it 'sees the link' do - visit project_releases_path(project) - - page.within('.js-assets-list') do - expect(page).to have_link release_link.name, href: direct_asset_link - expect(page).not_to have_css('[data-testid="external-link-indicator"]') - end - end - end - - context 'when url points to external resource' do - let(:url) { 'http://google.com/download' } + context 'when url points to external resource' do + let(:url) { 'http://google.com/download' } - it 'sees that the link is external resource' do - visit project_releases_path(project) + it 'sees that the link is external resource' do + visit project_releases_path(project) - page.within('.js-assets-list') do - expect(page).to have_css('[data-testid="external-link-indicator"]') - end + page.within('.js-assets-list') do + expect(page).to have_css('[data-testid="external-link-indicator"]') end end end end - context 'when the release_asset_link_type feature flag is enabled' do - before do - stub_feature_flags(release_asset_link_type: true) - end - - it_behaves_like 'asset link tests' - end - - context 'when the release_asset_link_type feature flag is disabled' do - before do - stub_feature_flags(release_asset_link_type: false) - end - - it_behaves_like 'asset link tests' - end - context 'with an upcoming release' do let(:tomorrow) { Time.zone.now + 1.day } let!(:release) { create(:release, project: project, released_at: tomorrow ) } @@ -110,7 +92,7 @@ RSpec.describe 'User views releases', :js do context('when the user is a guest') do before do - gitlab_sign_in(guest) + sign_in(guest) end it 'renders release info except for Git-related data' do diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index 0358acc8dcc..ffc0ecc4966 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -64,7 +64,7 @@ RSpec.describe "Projects > Settings > Pipelines settings" do it 'updates forward_deployment_enabled' do visit project_settings_ci_cd_path(project) - checkbox = find_field('project_forward_deployment_enabled') + checkbox = find_field('project_ci_cd_settings_attributes_forward_deployment_enabled') expect(checkbox).to be_checked checkbox.set(false) @@ -79,7 +79,7 @@ RSpec.describe "Projects > Settings > Pipelines settings" do expect(page).to have_button('Save changes', disabled: false) end - checkbox = find_field('project_forward_deployment_enabled') + checkbox = find_field('project_ci_cd_settings_attributes_forward_deployment_enabled') expect(checkbox).not_to be_checked end diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index 8e2f97fd6a0..4e1b53ffc87 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -3,27 +3,35 @@ require 'spec_helper' RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration policy', :js do - let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace, container_registry_enabled: container_registry_enabled) } + using RSpec::Parameterized::TableSyntax + + let_it_be(:user) { create(:user) } + let_it_be(:project, reload: true) { create(:project, namespace: user.namespace) } + let(:container_registry_enabled) { true } + let(:container_registry_enabled_on_project) { true } + + subject { visit project_settings_ci_cd_path(project) } before do + project.update!(container_registry_enabled: container_registry_enabled_on_project) + sign_in(user) - stub_container_registry_config(enabled: true) + stub_container_registry_config(enabled: container_registry_enabled) stub_feature_flags(new_variables_ui: false) end context 'as owner' do - before do - visit project_settings_ci_cd_path(project) - end - it 'shows available section' do + subject + settings_block = find('#js-registry-policies') expect(settings_block).to have_text 'Cleanup policy for tags' end it 'saves cleanup policy submit the form' do + subject + within '#js-registry-policies' do within '.card-body' do select('7 days until tags are automatically removed', from: 'Expiration interval:') @@ -40,6 +48,8 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p end it 'does not save cleanup policy submit form with invalid regex' do + subject + within '#js-registry-policies' do within '.card-body' do fill_in('Tags with names matching this regex pattern will expire:', with: '*-production') @@ -53,25 +63,53 @@ RSpec.describe 'Project > Settings > CI/CD > Container registry tag expiration p end end - context 'when registry is disabled' do - before do - stub_container_registry_config(enabled: false) - visit project_settings_ci_cd_path(project) + context 'with a project without expiration policy' do + where(:application_setting, :feature_flag, :result) do + true | true | :available_section + true | false | :available_section + false | true | :available_section + false | false | :disabled_message end - it 'does not exists' do - expect(page).not_to have_selector('#js-registry-policies') + with_them do + before do + project.container_expiration_policy.destroy! + stub_feature_flags(container_expiration_policies_historic_entry: false) + stub_application_setting(container_expiration_policies_enable_historic_entries: application_setting) + stub_feature_flags(container_expiration_policies_historic_entry: project) if feature_flag + end + + it 'displays the expected result' do + subject + + within '#js-registry-policies' do + case result + when :available_section + expect(find('.card-header')).to have_content('Tag expiration policy') + when :disabled_message + expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') + end + end + end end end - context 'when container registry is disabled on project' do + context 'when registry is disabled' do let(:container_registry_enabled) { false } - before do - visit project_settings_ci_cd_path(project) + it 'does not exists' do + subject + + expect(page).not_to have_selector('#js-registry-policies') end + end + + context 'when container registry is disabled on project' do + let(:container_registry_enabled_on_project) { false } it 'does not exists' do + subject + expect(page).not_to have_selector('#js-registry-policies') end end diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb index 9d9a75c22be..d444ea27d35 100644 --- a/spec/features/projects/show/user_manages_notifications_spec.rb +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -18,7 +18,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do click_notifications_button click_link 'On mention' - wait_for_requests + page.within('.notification-dropdown') do + expect(page).not_to have_css('.gl-spinner') + end click_notifications_button expect(find('.update-notification.is-active')).to have_content('On mention') @@ -30,7 +32,9 @@ RSpec.describe 'Projects > Show > User manages notifications', :js do click_notifications_button click_link 'Disabled' - wait_for_requests + page.within('.notification-dropdown') do + expect(page).not_to have_css('.gl-spinner') + end expect(page).to have_css('.notifications-icon[data-testid="notifications-off-icon"]') end diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb index 81736fefae9..189aa45ff75 100644 --- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb +++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb @@ -46,21 +46,21 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do visit project_path(project) end - it '"New file" button linked to new file page' do + it '"New file" button linked to IDE new file page' do page.within('.project-buttons') do - expect(page).to have_link('New file', href: project_new_blob_path(project, project.default_branch || 'master')) + expect(page).to have_link('New file', href: presenter.ide_edit_path(project, project.default_branch || 'master')) end end - it '"Add README" button linked to new file populated for a README' do + it '"Add README" button linked to IDE new file populated for a README' do page.within('.project-buttons') do - expect(page).to have_link('Add README', href: presenter.add_readme_path) + expect(page).to have_link('Add README', href: presenter.add_readme_ide_path) end end - it '"Add license" button linked to new file populated for a license' do + it '"Add license" button linked to IDE new file populated for a license' do page.within('.project-buttons') do - expect(page).to have_link('Add LICENSE', href: presenter.add_license_path) + expect(page).to have_link('Add LICENSE', href: presenter.add_license_ide_path) end end @@ -74,9 +74,9 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do visit project_path(project) end - it '"New file" button linked to new file page' do + it '"New file" button linked to IDE new file page' do page.within('.project-buttons') do - expect(page).to have_link('New file', href: project_new_blob_path(project, 'example_branch')) + expect(page).to have_link('New file', href: presenter.ide_edit_path(project, 'example_branch')) end end end @@ -144,7 +144,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do expect(project.repository.readme).not_to be_nil page.within('.project-buttons') do - expect(page).not_to have_link('Add README', href: presenter.add_readme_path) + expect(page).not_to have_link('Add README', href: presenter.add_readme_ide_path) expect(page).to have_link('README', href: presenter.readme_path) end end @@ -164,7 +164,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do end context 'when the project does not have a README' do - it 'shows the "Add README" button' do + it 'shows the single file editor "Add README" button' do allow(project.repository).to receive(:readme).and_return(nil) visit project_path(project) @@ -226,7 +226,7 @@ RSpec.describe 'Projects > Show > User sees setup shortcut buttons' do expect(project.repository.gitlab_ci_yml).to be_nil page.within('.project-buttons') do - expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_ide_path) + expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path) end end diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 503246bbdcf..28fe0a0b7e1 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -17,115 +17,81 @@ RSpec.describe 'Projects > Snippets > Create Snippet', :js do let(:file_content) { 'Hello World!' } let(:md_description) { 'My Snippet **Description**' } let(:description) { 'My Snippet Description' } - let(:snippet_title_field) { 'project_snippet_title' } - shared_examples 'snippet creation' do - def fill_form - snippet_fill_in_form(title: title, content: file_content, description: md_description) - end - - it 'shows collapsible description input' do - collapsed = description_field + def fill_form + snippet_fill_in_form(title: title, content: file_content, description: md_description) + end - expect(page).not_to have_field(snippet_description_field) - expect(collapsed).to be_visible + before do + sign_in(user) - collapsed.click + visit new_project_snippet_path(project) + end - expect(page).to have_field(snippet_description_field) - expect(collapsed).not_to be_visible - end + it 'shows collapsible description input' do + collapsed = snippet_description_field_collapsed - it 'creates a new snippet' do - fill_form - click_button('Create snippet') - wait_for_requests + expect(page).not_to have_field(snippet_description_locator) + expect(collapsed).to be_visible - expect(page).to have_content(title) - expect(page).to have_content(file_content) - page.within(snippet_description_view_selector) do - expect(page).to have_content(description) - expect(page).to have_selector('strong') - end - end + collapsed.click - it 'uploads a file when dragging into textarea' do - fill_form - dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') - - expect(snippet_description_value).to have_content('banana_sample') + expect(page).to have_field(snippet_description_locator) + expect(collapsed).not_to be_visible + end - click_button('Create snippet') - wait_for_requests + it 'creates a new snippet' do + fill_form + click_button('Create snippet') + wait_for_requests - link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z}) + expect(page).to have_content(title) + expect(page).to have_content(file_content) + page.within('.snippet-header .snippet-description') do + expect(page).to have_content(description) + expect(page).to have_selector('strong') end + end - context 'when the git operation fails' do - let(:error) { 'Error creating the snippet' } - - before do - allow_next_instance_of(Snippets::CreateService) do |instance| - allow(instance).to receive(:create_commit).and_raise(StandardError, error) - end + it 'uploads a file when dragging into textarea' do + fill_form + dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') - fill_form + expect(snippet_description_value).to have_content('banana_sample') - click_button('Create snippet') - wait_for_requests - end + click_button('Create snippet') + wait_for_requests - it 'renders the new page and displays the error' do - expect(page).to have_content(error) - expect(page).to have_content('New Snippet') - end - end + link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] + expect(link).to match(%r{/#{Regexp.escape(project.full_path)}/uploads/\h{32}/banana_sample\.gif\z}) end - context 'Vue application' do - let(:snippet_description_field) { 'snippet-description' } - let(:snippet_description_view_selector) { '.snippet-header .snippet-description' } + context 'when the git operation fails' do + let(:error) { 'Error creating the snippet' } before do - sign_in(user) - - visit new_project_snippet_path(project) - end - - it_behaves_like 'snippet creation' - - it 'does not allow submitting the form without title and content' do - fill_in snippet_title_field, with: title + allow_next_instance_of(Snippets::CreateService) do |instance| + allow(instance).to receive(:create_commit).and_raise(StandardError, error) + end - expect(page).not_to have_button('Create snippet') + fill_form - snippet_fill_in_form(title: title, content: file_content) - expect(page).to have_button('Create snippet') + click_button('Create snippet') + wait_for_requests end - end - - context 'non-Vue application' do - let(:snippet_description_field) { 'project_snippet_description' } - let(:snippet_description_view_selector) { '.snippet-header .description' } - - before do - stub_feature_flags(snippets_vue: false) - stub_feature_flags(snippets_edit_vue: false) - - sign_in(user) - visit new_project_snippet_path(project) + it 'renders the new page and displays the error' do + expect(page).to have_content(error) + expect(page).to have_content('New Snippet') end + end - it_behaves_like 'snippet creation' + it 'does not allow submitting the form without title and content' do + snippet_fill_in_title(title) - it 'displays validation errors' do - fill_in snippet_title_field, with: title - click_button('Create snippet') - wait_for_requests + expect(page).not_to have_button('Create snippet') - expect(page).to have_selector('#error_explanation') - end + snippet_fill_in_form(title: title, content: file_content) + expect(page).to have_button('Create snippet') end end diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb index 8fded3cde80..5937ff75457 100644 --- a/spec/features/projects/snippets/show_spec.rb +++ b/spec/features/projects/snippets/show_spec.rb @@ -13,8 +13,6 @@ RSpec.describe 'Projects > Snippets > Project snippet', :js do let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) } before do - stub_feature_flags(snippets_vue: false) - sign_in(user) end @@ -28,12 +26,8 @@ RSpec.describe 'Projects > Snippets > Project snippet', :js do end end - it_behaves_like 'showing user status' do - let(:file_path) { 'files/ruby/popen.rb' } - let(:user_with_status) { snippet.author } - - subject { visit project_snippet_path(project, snippet) } - end + # it_behaves_like 'showing user status' do + # This will be handled in https://gitlab.com/gitlab-org/gitlab/-/issues/262394 it_behaves_like 'does not show New Snippet button' do let(:file_path) { 'files/ruby/popen.rb' } diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb index 2784fec3dc1..b37d40c0eed 100644 --- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb +++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb @@ -8,7 +8,6 @@ RSpec.describe 'Projects > Snippets > User comments on a snippet', :js do let_it_be(:snippet) { create(:project_snippet, :repository, project: project, author: user) } before do - stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/projects/snippets/user_deletes_snippet_spec.rb b/spec/features/projects/snippets/user_deletes_snippet_spec.rb index 44fe9834484..6d526e60512 100644 --- a/spec/features/projects/snippets/user_deletes_snippet_spec.rb +++ b/spec/features/projects/snippets/user_deletes_snippet_spec.rb @@ -2,13 +2,12 @@ require 'spec_helper' -RSpec.describe 'Projects > Snippets > User deletes a snippet' do +RSpec.describe 'Projects > Snippets > User deletes a snippet', :js do let(:project) { create(:project) } - let!(:snippet) { create(:project_snippet, project: project, author: user) } + let!(:snippet) { create(:project_snippet, :repository, project: project, author: user) } let(:user) { create(:user) } before do - stub_feature_flags(snippets_vue: false) project.add_maintainer(user) sign_in(user) @@ -16,7 +15,11 @@ RSpec.describe 'Projects > Snippets > User deletes a snippet' do end it 'deletes a snippet' do - first(:link, 'Delete').click + expect(page).to have_content(snippet.title) + + click_button('Delete') + click_button('Delete snippet') + wait_for_requests expect(page).not_to have_content(snippet.title) end diff --git a/spec/features/projects/snippets/user_updates_snippet_spec.rb b/spec/features/projects/snippets/user_updates_snippet_spec.rb index 193eaa9576a..aa498163f52 100644 --- a/spec/features/projects/snippets/user_updates_snippet_spec.rb +++ b/spec/features/projects/snippets/user_updates_snippet_spec.rb @@ -9,9 +9,7 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do let_it_be(:project) { create(:project, namespace: user.namespace) } let_it_be(:snippet, reload: true) { create(:project_snippet, :repository, project: project, author: user) } - let(:snippet_title_field) { 'project_snippet_title' } - - def bootstrap_snippet + before do project.add_maintainer(user) sign_in(user) @@ -20,64 +18,36 @@ RSpec.describe 'Projects > Snippets > User updates a snippet', :js do wait_for_all_requests end - shared_examples 'snippet update' do - it 'displays the snippet blob path and content' do - blob = snippet.blobs.first - - aggregate_failures do - expect(snippet_get_first_blob_path).to eq blob.path - expect(snippet_get_first_blob_value).to have_content(blob.data.strip) - end - end - - it 'updates a snippet' do - fill_in('project_snippet_title', with: 'Snippet new title') - click_button('Save') + it 'displays the snippet blob path and content' do + blob = snippet.blobs.first - expect(page).to have_content('Snippet new title') - end - - context 'when the git operation fails' do - before do - allow_next_instance_of(Snippets::UpdateService) do |instance| - allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message') - end - - fill_in(snippet_title_field, with: 'Snippet new title') - fill_in(snippet_blob_path_field, match: :first, with: 'new_file_name') - - click_button('Save') - end - - it 'renders edit page and displays the error' do - expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message') - expect(page).to have_content('Edit Snippet') - end + aggregate_failures do + expect(snippet_get_first_blob_path).to eq blob.path + expect(snippet_get_first_blob_value).to have_content(blob.data.strip) end end - context 'Vue application' do - before do - bootstrap_snippet - end + it 'updates a snippet' do + fill_in('snippet-title', with: 'Snippet new title') + click_button('Save') - it_behaves_like 'snippet update' do - let(:snippet_blob_path_field) { 'snippet_file_name' } - let(:snippet_blob_content_selector) { '.file-content' } - end + expect(page).to have_content('Snippet new title') end - context 'non-Vue application' do + context 'when the git operation fails' do before do - stub_feature_flags(snippets_vue: false) - stub_feature_flags(snippets_edit_vue: false) + allow_next_instance_of(Snippets::UpdateService) do |instance| + allow(instance).to receive(:create_commit).and_raise(StandardError, 'Error Message') + end - bootstrap_snippet + snippet_fill_in_form(title: 'Snippet new title', file_name: 'new_file_name') + + click_button('Save') end - it_behaves_like 'snippet update' do - let(:snippet_blob_path_field) { 'project_snippet_file_name' } - let(:snippet_blob_content_selector) { '.file-content' } + it 'renders edit page and displays the error' do + expect(page.find('.flash-container')).to have_content('Error updating the snippet - Error Message') + expect(page).to have_content('Edit Snippet') end end end diff --git a/spec/features/projects/tracings_spec.rb b/spec/features/projects/tracings_spec.rb new file mode 100644 index 00000000000..c4a4f1382ed --- /dev/null +++ b/spec/features/projects/tracings_spec.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Tracings Content Security Policy' do + let_it_be(:project) { create(:project) } + let_it_be(:user) { create(:user) } + + subject { response_headers['Content-Security-Policy'] } + + before_all do + project.add_maintainer(user) + end + + before do + sign_in(user) + end + + context 'when there is no global config' do + before do + expect_next_instance_of(Projects::TracingsController) do |controller| + expect(controller).to receive(:current_content_security_policy) + .and_return(ActionDispatch::ContentSecurityPolicy.new) + end + end + + it 'does not add CSP directives' do + visit project_tracing_path(project) + + is_expected.to be_blank + end + end + + context 'when a global CSP config exists' do + before do + csp = ActionDispatch::ContentSecurityPolicy.new do |p| + p.frame_src 'https://global-policy.com' + end + + expect_next_instance_of(Projects::TracingsController) do |controller| + expect(controller).to receive(:current_content_security_policy).and_return(csp) + end + end + + context 'when external_url is set' do + let!(:project_tracing_setting) { create(:project_tracing_setting, project: project) } + + it 'overwrites frame-src' do + visit project_tracing_path(project) + + is_expected.to eq("frame-src https://example.com") + end + end + + context 'when external_url is not set' do + it 'uses global policy' do + visit project_tracing_path(project) + + is_expected.to eq("frame-src https://global-policy.com") + end + end + end +end diff --git a/spec/features/projects/tree/tree_show_spec.rb b/spec/features/projects/tree/tree_show_spec.rb index bd2af66710a..ca9e0a23888 100644 --- a/spec/features/projects/tree/tree_show_spec.rb +++ b/spec/features/projects/tree/tree_show_spec.rb @@ -69,7 +69,7 @@ RSpec.describe 'Projects tree', :js do # Check last commit expect(find('.commit-content').text).to include(message) - expect(find('.commit-sha-group').text).to eq(short_newrev) + expect(find('.js-commit-sha-group').text).to eq(short_newrev) end end diff --git a/spec/features/projects/user_sees_sidebar_spec.rb b/spec/features/projects/user_sees_sidebar_spec.rb index 50d7b353c46..616c5065c07 100644 --- a/spec/features/projects/user_sees_sidebar_spec.rb +++ b/spec/features/projects/user_sees_sidebar_spec.rb @@ -128,6 +128,59 @@ RSpec.describe 'Projects > User sees sidebar' do end end + context 'as anonymous' do + let(:project) { create(:project, :public) } + let!(:issue) { create(:issue, :opened, project: project, author: user) } + + describe 'project landing page' do + before do + project.project_feature.update!( + builds_access_level: ProjectFeature::DISABLED, + merge_requests_access_level: ProjectFeature::DISABLED, + repository_access_level: ProjectFeature::DISABLED, + issues_access_level: ProjectFeature::DISABLED, + wiki_access_level: ProjectFeature::DISABLED + ) + end + + it 'does not show the project file list landing page, but the activity' do + visit project_path(project) + + expect(page).not_to have_selector '.project-stats' + expect(page).not_to have_selector '.project-last-commit' + expect(page).not_to have_selector '.project-show-files' + expect(page).to have_selector '.project-show-activity' + end + + it 'shows the wiki when enabled' do + project.project_feature.update!(wiki_access_level: ProjectFeature::ENABLED) + + visit project_path(project) + + expect(page).to have_selector '.project-show-wiki' + end + + it 'shows the issues when enabled' do + project.project_feature.update!(issues_access_level: ProjectFeature::ENABLED) + + visit project_path(project) + + expect(page).to have_selector '.issues-list' + end + + it 'shows the wiki when wiki and issues are enabled' do + project.project_feature.update!( + issues_access_level: ProjectFeature::ENABLED, + wiki_access_level: ProjectFeature::ENABLED + ) + + visit project_path(project) + + expect(page).to have_selector '.project-show-wiki' + end + end + end + context 'as guest' do let(:guest) { create(:user) } let!(:issue) { create(:issue, :opened, project: project, author: guest) } @@ -145,11 +198,11 @@ RSpec.describe 'Projects > User sees sidebar' do expect(page).to have_content 'Project' expect(page).to have_content 'Issues' expect(page).to have_content 'Wiki' + expect(page).to have_content 'Operations' expect(page).not_to have_content 'Repository' expect(page).not_to have_content 'CI / CD' expect(page).not_to have_content 'Merge Requests' - expect(page).not_to have_content 'Operations' end end @@ -194,13 +247,13 @@ RSpec.describe 'Projects > User sees sidebar' do expect(page).not_to have_selector '.project-stats' expect(page).not_to have_selector '.project-last-commit' expect(page).not_to have_selector '.project-show-files' - expect(page).to have_selector '.project-show-customize_workflow' + expect(page).to have_selector '.project-show-activity' end - it 'shows the customize workflow when issues and wiki are disabled' do + it 'shows the project activity when issues and wiki are disabled' do visit project_path(project) - expect(page).to have_selector '.project-show-customize_workflow' + expect(page).to have_selector '.project-show-activity' end it 'shows the wiki when enabled' do diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb deleted file mode 100644 index 8f2fb9e827c..00000000000 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Projects > Wiki > User previews markdown changes', :js do - let_it_be(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: '[some link](other-page)') } - let(:wiki_content) do - <<-HEREDOC -Some text so key event for [ does not trigger an incorrect replacement. -[regular link](regular) -[relative link 1](../relative) -[relative link 2](./relative) -[relative link 3](./e/f/relative) -[spaced link](title with spaces) - HEREDOC - end - - before do - project.add_maintainer(user) - - sign_in(user) - end - - context "while creating a new wiki page" do - context "when there are no spaces or hyphens in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a/b/c/d', content: wiki_content) - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - - context "when there are spaces in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a page/b page/c page/d page', content: wiki_content) - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - - context "when there are hyphens in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a-page/b-page/c-page/d-page', content: wiki_content) - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - end - - context "while editing a wiki page" do - context "when there are no spaces or hyphens in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a/b/c/d') - click_link 'Edit' - - fill_in :wiki_content, with: wiki_content - click_on "Preview" - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a/b/c/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - - context "when there are spaces in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a page/b page/c page/d page') - click_link 'Edit' - - fill_in :wiki_content, with: wiki_content - click_on "Preview" - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - - context "when there are hyphens in the page name" do - it "rewrites relative links as expected" do - create_wiki_page('a-page/b-page/c-page/d-page') - click_link 'Edit' - - fill_in :wiki_content, with: wiki_content - click_on "Preview" - - expect(page).to have_content("regular link") - - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") - expect(page.html).to include("<a href=\"/#{project.full_path}/-/wikis/title%20with%20spaces\">spaced link</a>") - end - end - - context 'when rendering the preview' do - it 'renders content with CommonMark' do - create_wiki_page('a-page/b-page/c-page/common-mark') - click_link 'Edit' - - fill_in :wiki_content, with: "1. one\n - sublist\n" - click_on "Preview" - - # the above generates two separate lists (not embedded) in CommonMark - expect(page).to have_content("sublist") - expect(page).not_to have_xpath("//ol//li//ul") - end - end - end - - it "does not linkify double brackets inside code blocks as expected" do - wiki_content = <<-HEREDOC - `[[do_not_linkify]]` - ``` - [[also_do_not_linkify]] - ``` - HEREDOC - - create_wiki_page('linkify_test', wiki_content) - - expect(page).to have_content("do_not_linkify") - - expect(page.html).to include('[[do_not_linkify]]') - expect(page.html).to include('[[also_do_not_linkify]]') - end - - private - - def create_wiki_page(path, content = 'content') - visit project_wiki_path(project, wiki_page) - - click_link 'New page' - - fill_in :wiki_title, with: path - fill_in :wiki_content, with: content - - click_button 'Create page' - end -end diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb deleted file mode 100644 index 170e7afb51f..00000000000 --- a/spec/features/projects/wiki/shortcuts_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'Wiki shortcuts', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'home', content: 'Home page') } - - before do - sign_in(user) - visit project_wiki_path(project, wiki_page) - end - - it 'Visit edit wiki page using "e" keyboard shortcut' do - find('body').native.send_key('e') - - expect(find('.wiki-page-title')).to have_content('Edit Page') - end -end diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb deleted file mode 100644 index eba1b63765a..00000000000 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ /dev/null @@ -1,360 +0,0 @@ -# frozen_string_literal: true - -require "spec_helper" - -RSpec.describe "User creates wiki page" do - include WikiHelpers - - let(:user) { create(:user) } - let(:wiki) { ProjectWiki.new(project, user) } - let(:project) { create(:project) } - - before do - project.add_maintainer(user) - - sign_in(user) - end - - context "when wiki is empty" do - before do |example| - visit(project_wikis_path(project)) - - wait_for_svg_to_be_loaded(example) - - click_link "Create your first page" - end - - context "in a user namespace" do - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - - it "shows validation error message" do - page.within(".wiki-form") do - fill_in(:wiki_content, with: "") - - click_on("Create page") - end - - expect(page).to have_content("The form contains the following error:").and have_content("Content can't be blank") - - page.within(".wiki-form") do - fill_in(:wiki_content, with: "[link test](test)") - - click_on("Create page") - end - - expect(page).to have_content("Home").and have_content("link test") - - click_link("link test") - - expect(page).to have_content("Create New Page") - end - - it "shows non-escaped link in the pages list" do - fill_in(:wiki_title, with: "one/two/three-test") - - page.within(".wiki-form") do - fill_in(:wiki_content, with: "wiki content") - - click_on("Create page") - end - - expect(current_path).to include("one/two/three-test") - expect(page).to have_xpath("//a[@href='/#{project.full_path}/-/wikis/one/two/three-test']") - end - - it "has `Create home` as a commit message", :js do - wait_for_requests - - expect(page).to have_field("wiki[message]", with: "Create home") - end - - it "creates a page from the home page" do - fill_in(:wiki_content, with: "[test](test)\n[GitLab API doc](api)\n[Rake tasks](raketasks)\n# Wiki header\n") - fill_in(:wiki_message, with: "Adding links to wiki") - - page.within(".wiki-form") do - click_button("Create page") - end - - expect(current_path).to eq(project_wiki_path(project, "home")) - expect(page).to have_content("test GitLab API doc Rake tasks Wiki header") - .and have_content("Home") - .and have_content("Last edited by #{user.name}") - .and have_header_with_correct_id_and_link(1, "Wiki header", "wiki-header") - - click_link("test") - - expect(current_path).to eq(project_wiki_path(project, "test")) - - page.within(:css, ".nav-text") do - expect(page).to have_content("Create New Page") - end - - click_link("Home") - - expect(current_path).to eq(project_wiki_path(project, "home")) - - click_link("GitLab API") - - expect(current_path).to eq(project_wiki_path(project, "api")) - - page.within(:css, ".nav-text") do - expect(page).to have_content("Create") - end - - click_link("Home") - - expect(current_path).to eq(project_wiki_path(project, "home")) - - click_link("Rake tasks") - - expect(current_path).to eq(project_wiki_path(project, "raketasks")) - - page.within(:css, ".nav-text") do - expect(page).to have_content("Create") - end - end - - it "creates ASCII wiki with LaTeX blocks", :js do - stub_application_setting(plantuml_url: "http://localhost", plantuml_enabled: true) - - ascii_content = <<~MD - :stem: latexmath - - [stem] - ++++ - \\sqrt{4} = 2 - ++++ - - another part - - [latexmath] - ++++ - \\beta_x \\gamma - ++++ - - stem:[2+2] is 4 - MD - - find("#wiki_format option[value=asciidoc]").select_option - - fill_in(:wiki_content, with: ascii_content) - - page.within(".wiki-form") do - click_button("Create page") - end - - page.within ".md" do - expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4") - end - end - - it 'creates a wiki page with Org markup', :aggregate_failures do - org_content = <<~ORG - * Heading - ** Subheading - [[home][Link to Home]] - ORG - - page.within('.wiki-form') do - find('#wiki_format option[value=org]').select_option - fill_in(:wiki_content, with: org_content) - click_button('Create page') - end - - expect(page).to have_selector('h1', text: 'Heading') - expect(page).to have_selector('h2', text: 'Subheading') - expect(page).to have_link('Link to Home', href: "/#{project.full_path}/-/wikis/home") - end - - it_behaves_like 'wiki file attachments' - end - - context "in a group namespace", :js do - let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) } - - it "has `Create home` as a commit message" do - wait_for_requests - - expect(page).to have_field("wiki[message]", with: "Create home") - end - - it "creates a page from the home page" do - page.within(".wiki-form") do - fill_in(:wiki_content, with: "My awesome wiki!") - - click_button("Create page") - end - - expect(page).to have_content("Home") - .and have_content("Last edited by #{user.name}") - .and have_content("My awesome wiki!") - end - end - end - - context "when wiki is not empty", :js do - before do - create(:wiki_page, wiki: wiki, title: 'home', content: 'Home page') - - visit(project_wikis_path(project)) - end - - context "in a user namespace" do - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - - context "via the `new wiki page` page" do - it "creates a page with a single word" do - click_link("New page") - - page.within(".wiki-form") do - fill_in(:wiki_title, with: "foo") - fill_in(:wiki_content, with: "My awesome wiki!") - end - - # Commit message field should have correct value. - expect(page).to have_field("wiki[message]", with: "Create foo") - - click_button("Create page") - - expect(page).to have_content("foo") - .and have_content("Last edited by #{user.name}") - .and have_content("My awesome wiki!") - end - - it "creates a page with spaces in the name" do - click_link("New page") - - page.within(".wiki-form") do - fill_in(:wiki_title, with: "Spaces in the name") - fill_in(:wiki_content, with: "My awesome wiki!") - end - - # Commit message field should have correct value. - expect(page).to have_field("wiki[message]", with: "Create Spaces in the name") - - click_button("Create page") - - expect(page).to have_content("Spaces in the name") - .and have_content("Last edited by #{user.name}") - .and have_content("My awesome wiki!") - end - - it "creates a page with hyphens in the name" do - click_link("New page") - - page.within(".wiki-form") do - fill_in(:wiki_title, with: "hyphens-in-the-name") - fill_in(:wiki_content, with: "My awesome wiki!") - end - - # Commit message field should have correct value. - expect(page).to have_field("wiki[message]", with: "Create hyphens in the name") - - page.within(".wiki-form") do - fill_in(:wiki_content, with: "My awesome wiki!") - - click_button("Create page") - end - - expect(page).to have_content("hyphens in the name") - .and have_content("Last edited by #{user.name}") - .and have_content("My awesome wiki!") - end - end - - it "shows the emoji autocompletion dropdown" do - click_link("New page") - - page.within(".wiki-form") do - find("#wiki_content").native.send_keys("") - - fill_in(:wiki_content, with: ":") - end - - expect(page).to have_selector(".atwho-view") - end - end - - context "in a group namespace" do - let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) } - - context "via the `new wiki page` page" do - it "creates a page" do - click_link("New page") - - page.within(".wiki-form") do - fill_in(:wiki_title, with: "foo") - fill_in(:wiki_content, with: "My awesome wiki!") - end - - # Commit message field should have correct value. - expect(page).to have_field("wiki[message]", with: "Create foo") - - click_button("Create page") - - expect(page).to have_content("foo") - .and have_content("Last edited by #{user.name}") - .and have_content("My awesome wiki!") - end - end - end - end - - describe 'sidebar feature' do - context 'when there are some existing pages' do - before do - create(:wiki_page, wiki: wiki, title: 'home', content: 'home') - create(:wiki_page, wiki: wiki, title: 'another', content: 'another') - end - - it 'renders a default sidebar when there is no customized sidebar' do - visit(project_wikis_path(project)) - - expect(page).to have_content('another') - expect(page).not_to have_link('View All Pages') - end - - context 'when there is a customized sidebar' do - before do - create(:wiki_page, wiki: wiki, title: '_sidebar', content: 'My customized sidebar') - end - - it 'renders my customized sidebar instead of the default one' do - visit(project_wikis_path(project)) - - expect(page).to have_content('My customized sidebar') - expect(page).not_to have_content('Another') - end - end - end - - context 'when there are 15 existing pages' do - before do - (1..5).each { |i| create(:wiki_page, wiki: wiki, title: "my page #{i}") } - (6..10).each { |i| create(:wiki_page, wiki: wiki, title: "parent/my page #{i}") } - (11..15).each { |i| create(:wiki_page, wiki: wiki, title: "grandparent/parent/my page #{i}") } - end - - it 'shows all pages in the sidebar' do - visit(project_wikis_path(project)) - - (1..15).each { |i| expect(page).to have_content("my page #{i}") } - expect(page).not_to have_link('View All Pages') - end - - context 'when there are more than 15 existing pages' do - before do - create(:wiki_page, wiki: wiki, title: 'my page 16') - end - - it 'shows the first 15 pages in the sidebar' do - visit(project_wikis_path(project)) - - expect(page).to have_text('my page', count: 15) - expect(page).to have_link('View All Pages') - end - end - end - end -end diff --git a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb b/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb deleted file mode 100644 index a5d865d581b..00000000000 --- a/spec/features/projects/wiki/user_deletes_wiki_page_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User deletes wiki page', :js do - let(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:wiki_page) { create(:wiki_page, wiki: project.wiki) } - - before do - sign_in(user) - visit(project_wiki_path(project, wiki_page)) - end - - it 'deletes a page' do - click_on('Edit') - click_on('Delete') - find('.modal-footer .btn-danger').click - - expect(page).to have_content('Page was successfully deleted') - end -end diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb deleted file mode 100644 index fdab63a56b8..00000000000 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ /dev/null @@ -1,263 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User updates wiki page' do - include WikiHelpers - - let(:user) { create(:user) } - - before do - project.add_maintainer(user) - sign_in(user) - end - - context 'when wiki is empty' do - before do |example| - visit(project_wikis_path(project)) - - wait_for_svg_to_be_loaded(example) - - click_link "Create your first page" - end - - context 'in a user namespace' do - let(:project) { create(:project, :wiki_repo) } - - it 'redirects back to the home edit page' do - page.within(:css, '.wiki-form .form-actions') do - click_on('Cancel') - end - - expect(current_path).to eq wiki_path(project.wiki) - end - - it 'updates a page that has a path', :js do - fill_in(:wiki_title, with: 'one/two/three-test') - - page.within '.wiki-form' do - fill_in(:wiki_content, with: 'wiki content') - click_on('Create page') - end - - expect(current_path).to include('one/two/three-test') - expect(find('.wiki-pages')).to have_content('three') - - first(:link, text: 'three').click - - expect(find('.nav-text')).to have_content('three') - - click_on('Edit') - - expect(current_path).to include('one/two/three-test') - expect(page).to have_content('Edit Page') - - fill_in('Content', with: 'Updated Wiki Content') - click_on('Save changes') - - expect(page).to have_content('Updated Wiki Content') - end - - it_behaves_like 'wiki file attachments' - end - end - - context 'when wiki is not empty' do - let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) } - let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: 'home', content: 'Home page') } - - before do - visit(project_wikis_path(project)) - - click_link('Edit') - end - - context 'in a user namespace' do - let(:project) { create(:project, :wiki_repo) } - - it 'updates a page', :js do - # Commit message field should have correct value. - expect(page).to have_field('wiki[message]', with: 'Update home') - - fill_in(:wiki_content, with: 'My awesome wiki!') - click_button('Save changes') - - expect(page).to have_content('Home') - expect(page).to have_content("Last edited by #{user.name}") - expect(page).to have_content('My awesome wiki!') - end - - it 'updates the commit message as the title is changed', :js do - fill_in(:wiki_title, with: '& < > \ \ { } &') - - expect(page).to have_field('wiki[message]', with: 'Update & < > \ \ { } &') - end - - it 'correctly escapes the commit message entities', :js do - fill_in(:wiki_title, with: 'Wiki title') - - expect(page).to have_field('wiki[message]', with: 'Update Wiki title') - end - - it 'shows a validation error message' do - fill_in(:wiki_content, with: '') - click_button('Save changes') - - expect(page).to have_selector('.wiki-form') - expect(page).to have_content('Edit Page') - expect(page).to have_content('The form contains the following error:') - expect(page).to have_content("Content can't be blank") - expect(find('textarea#wiki_content').value).to eq('') - end - - it 'shows the emoji autocompletion dropdown', :js do - find('#wiki_content').native.send_keys('') - fill_in(:wiki_content, with: ':') - - expect(page).to have_selector('.atwho-view') - end - - it 'shows the error message' do - wiki_page.update(content: 'Update') - - click_button('Save changes') - - expect(page).to have_content('Someone edited the page the same time you did.') - end - - it 'updates a page' do - fill_in('Content', with: 'Updated Wiki Content') - click_on('Save changes') - - expect(page).to have_content('Updated Wiki Content') - end - - it 'cancels editing of a page' do - page.within(:css, '.wiki-form .form-actions') do - click_on('Cancel') - end - - expect(current_path).to eq(project_wiki_path(project, wiki_page)) - end - - it_behaves_like 'wiki file attachments' - end - - context 'in a group namespace' do - let(:project) { create(:project, :wiki_repo, namespace: create(:group, :public)) } - - it 'updates a page', :js do - # Commit message field should have correct value. - expect(page).to have_field('wiki[message]', with: 'Update home') - - fill_in(:wiki_content, with: 'My awesome wiki!') - - click_button('Save changes') - - expect(page).to have_content('Home') - expect(page).to have_content("Last edited by #{user.name}") - expect(page).to have_content('My awesome wiki!') - end - - it_behaves_like 'wiki file attachments' - end - end - - context 'when the page is in a subdir' do - let!(:project) { create(:project, :wiki_repo) } - let(:project_wiki) { create(:project_wiki, project: project, user: project.creator) } - let(:page_name) { 'page_name' } - let(:page_dir) { "foo/bar/#{page_name}" } - let!(:wiki_page) { create(:wiki_page, wiki: project_wiki, title: page_dir, content: 'Home page') } - - before do - visit(project_wiki_edit_path(project, wiki_page)) - end - - it 'moves the page to the root folder' do - fill_in(:wiki_title, with: "/#{page_name}") - - click_button('Save changes') - - expect(current_path).to eq(project_wiki_path(project, page_name)) - end - - it 'moves the page to other dir' do - new_page_dir = "foo1/bar1/#{page_name}" - - fill_in(:wiki_title, with: new_page_dir) - - click_button('Save changes') - - expect(current_path).to eq(project_wiki_path(project, new_page_dir)) - end - - it 'remains in the same place if title has not changed' do - original_path = project_wiki_path(project, wiki_page) - - fill_in(:wiki_title, with: page_name) - - click_button('Save changes') - - expect(current_path).to eq(original_path) - end - - it 'can be moved to a different dir with a different name' do - new_page_dir = "foo1/bar1/new_page_name" - - fill_in(:wiki_title, with: new_page_dir) - - click_button('Save changes') - - expect(current_path).to eq(project_wiki_path(project, new_page_dir)) - end - - it 'can be renamed and moved to the root folder' do - new_name = 'new_page_name' - - fill_in(:wiki_title, with: "/#{new_name}") - - click_button('Save changes') - - expect(current_path).to eq(project_wiki_path(project, new_name)) - end - - it 'squishes the title before creating the page' do - new_page_dir = " foo1 / bar1 / #{page_name} " - - fill_in(:wiki_title, with: new_page_dir) - - click_button('Save changes') - - expect(current_path).to eq(project_wiki_path(project, "foo1/bar1/#{page_name}")) - end - - it_behaves_like 'wiki file attachments' - end - - context 'when an existing page exceeds the content size limit' do - let_it_be(:project) { create(:project, :wiki_repo) } - let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, content: "one\ntwo\nthree") } - - before do - stub_application_setting(wiki_page_max_content_bytes: 10) - - visit wiki_page_path(wiki_page.wiki, wiki_page, action: :edit) - end - - it 'allows changing the title if the content does not change' do - fill_in 'Title', with: 'new title' - click_on 'Save changes' - - expect(page).to have_content('Wiki was successfully updated.') - end - - it 'shows a validation error when trying to change the content' do - fill_in 'Content', with: 'new content' - click_on 'Save changes' - - expect(page).to have_content('The form contains the following error:') - expect(page).to have_content('Content is too long (11 Bytes). The maximum size is 10 Bytes.') - end - end -end diff --git a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb index 0af40a2d760..1f460f39267 100644 --- a/spec/features/projects/wiki/user_views_wiki_empty_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_empty_spec.rb @@ -2,108 +2,86 @@ require 'spec_helper' -RSpec.describe 'User views empty wiki' do - let(:user) { create(:user) } - let(:confluence_link) { 'Enable the Confluence Wiki integration' } - let(:element) { page.find('.row.empty-state') } - - shared_examples 'empty wiki and accessible issues' do - it 'show "issue tracker" message' do - visit(project_wikis_path(project)) - - expect(element).to have_content('This project has no wiki pages') - expect(element).to have_content('You must be a project member') - expect(element).to have_content('improve the wiki for this project') - expect(element).to have_link("issue tracker", href: project_issues_path(project)) - expect(element).to have_link("Suggest wiki improvement", href: new_project_issue_path(project)) - expect(element).to have_no_link(confluence_link) - end - end - - shared_examples 'empty wiki and non-accessible issues' do - it 'does not show "issue tracker" message' do - visit(project_wikis_path(project)) +RSpec.describe 'Project > User views empty wiki' do + let_it_be(:user) { create(:user) } - expect(element).to have_content('This project has no wiki pages') - expect(element).to have_content('You must be a project member') - expect(element).to have_no_link('Suggest wiki improvement') - expect(element).to have_no_link(confluence_link) - end - end + let(:wiki) { create(:project_wiki, project: project) } - context 'when user is logged out and issue tracker is public' do - let(:project) { create(:project, :public, :wiki_repo) } + it_behaves_like 'User views empty wiki' do + context 'when project is public' do + let(:project) { create(:project, :public) } - it_behaves_like 'empty wiki and accessible issues' - end + it_behaves_like 'empty wiki message', issuable: true - context 'when user is logged in and not a member' do - let(:project) { create(:project, :public, :wiki_repo) } + context 'when issue tracker is private' do + let(:project) { create(:project, :public, :issues_private) } - before do - sign_in(user) - end + it_behaves_like 'empty wiki message', issuable: false + end - it_behaves_like 'empty wiki and accessible issues' - end + context 'when issue tracker is disabled' do + let(:project) { create(:project, :public, :issues_disabled) } - context 'when issue tracker is private' do - let(:project) { create(:project, :public, :wiki_repo, :issues_private) } + it_behaves_like 'empty wiki message', issuable: false + end - it_behaves_like 'empty wiki and non-accessible issues' - end + context 'and user is logged in' do + before do + sign_in(user) + end - context 'when issue tracker is disabled' do - let(:project) { create(:project, :public, :wiki_repo, :issues_disabled) } + context 'and user is not a member' do + it_behaves_like 'empty wiki message', issuable: true + end - it_behaves_like 'empty wiki and non-accessible issues' - end + context 'and user is a member' do + before do + project.add_developer(user) + end - context 'when user is logged in and a member' do - let(:project) { create(:project, :public) } - - before do - sign_in(user) - project.add_developer(user) + it_behaves_like 'empty wiki message', writable: true, issuable: true + end + end end - it 'shows "create first page" message' do - visit(project_wikis_path(project)) - - expect(element).to have_content('your project', count: 2) + context 'when project is private' do + let(:project) { create(:project, :private) } - element.click_link 'Create your first page' + it_behaves_like 'wiki is not found' - expect(page).to have_button('Create page') - end + context 'and user is logged in' do + before do + sign_in(user) + end - it 'does not show the "enable confluence" button' do - visit(project_wikis_path(project)) + context 'and user is not a member' do + it_behaves_like 'wiki is not found' + end - expect(element).to have_no_link(confluence_link) - end - end + context 'and user is a member' do + before do + project.add_developer(user) + end - context 'when user is logged in and an admin' do - let(:project) { create(:project, :public, :wiki_repo) } + it_behaves_like 'empty wiki message', writable: true, issuable: true + end - before do - sign_in(user) - project.add_maintainer(user) - end - - it 'shows the "enable confluence" button' do - visit(project_wikis_path(project)) - - expect(element).to have_link(confluence_link) - end + context 'and user is a maintainer' do + before do + project.add_maintainer(user) + end - it 'does not show "enable confluence" button if confluence is already enabled' do - create(:confluence_service, project: project) + it_behaves_like 'empty wiki message', writable: true, issuable: true, confluence: true - visit(project_wikis_path(project)) + context 'and Confluence is already enabled' do + before do + create(:confluence_service, project: project) + end - expect(element).to have_no_link(confluence_link) + it_behaves_like 'empty wiki message', writable: true, issuable: true, confluence: false + end + end + end end end end diff --git a/spec/features/projects/wiki/user_views_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_page_spec.rb deleted file mode 100644 index e93689af0aa..00000000000 --- a/spec/features/projects/wiki/user_views_wiki_page_spec.rb +++ /dev/null @@ -1,276 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User views a wiki page' do - include WikiHelpers - - let(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - let(:path) { 'image.png' } - let(:wiki) { project.wiki } - let(:wiki_page) do - create(:wiki_page, - wiki: wiki, - title: 'home', content: "Look at this [image](#{path})\n\n ![alt text](#{path})") - end - - before do - project.add_maintainer(user) - sign_in(user) - end - - context 'when wiki is empty', :js do - before do - visit project_wikis_path(project) - - wait_for_svg_to_be_loaded - - click_link "Create your first page" - - fill_in(:wiki_title, with: 'one/two/three-test') - - page.within('.wiki-form') do - fill_in(:wiki_content, with: 'wiki content') - click_on('Create page') - end - - expect(page).to have_content('Wiki was successfully updated.') - end - - it 'shows the history of a page that has a path' do - expect(current_path).to include('one/two/three-test') - - first(:link, text: 'three').click - click_on('Page history') - - expect(current_path).to include('one/two/three-test') - - page.within(:css, '.nav-text') do - expect(page).to have_content('History') - end - end - - it 'shows an old version of a page' do - expect(current_path).to include('one/two/three-test') - expect(find('.wiki-pages')).to have_content('three') - - first(:link, text: 'three').click - - expect(find('.nav-text')).to have_content('three') - - click_on('Edit') - - expect(current_path).to include('one/two/three-test') - expect(page).to have_content('Edit Page') - - fill_in('Content', with: 'Updated Wiki Content') - click_on('Save changes') - - expect(page).to have_content('Wiki was successfully updated.') - - click_on('Page history') - - within('.nav-text') do - expect(page).to have_content('History') - end - - within('.wiki-history') do - expect(page).to have_css('a[href*="?version_id"]', count: 4) - end - end - end - - context 'when a page does not have history' do - before do - visit(project_wiki_path(project, wiki_page)) - end - - it 'shows all the pages' do - expect(page).to have_content(user.name) - expect(find('.wiki-pages')).to have_content(wiki_page.title.capitalize) - end - - context 'shows a file stored in a page' do - let(:path) { upload_file_to_wiki(project, user, 'dk.png') } - - it do - expect(page).to have_xpath("//img[@data-src='#{wiki.wiki_base_path}/#{path}']") - expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}") - - click_on('image') - - expect(current_path).to match("wikis/#{path}") - expect(page).not_to have_xpath('/html') # Page should render the image which means there is no html involved - end - end - - it 'shows the creation page if file does not exist' do - expect(page).to have_link('image', href: "#{wiki.wiki_base_path}/#{path}") - - click_on('image') - - expect(current_path).to match("wikis/#{path}") - expect(page).to have_content('Create New Page') - end - end - - context 'when a page has history' do - before do - wiki_page.update(message: 'updated home', content: 'updated [some link](other-page)') # rubocop:disable Rails/SaveBang - end - - it 'shows the page history' do - visit(project_wiki_path(project, wiki_page)) - - expect(page).to have_selector('a.btn', text: 'Edit') - - click_on('Page history') - - expect(page).to have_content(user.name) - expect(page).to have_content("#{user.username} created page: home") - expect(page).to have_content('updated home') - end - - it 'does not show the "Edit" button' do - visit(project_wiki_path(project, wiki_page, version_id: wiki_page.versions.last.id)) - - expect(page).not_to have_selector('a.btn', text: 'Edit') - end - - context 'show the diff' do - def expect_diff_links(commit) - diff_path = wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff) - - expect(page).to have_link('Hide whitespace changes', href: "#{diff_path}&w=1") - expect(page).to have_link('Inline', href: "#{diff_path}&view=inline") - expect(page).to have_link('Side-by-side', href: "#{diff_path}&view=parallel") - expect(page).to have_link("View page @ #{commit.short_id}", href: wiki_page_path(wiki, wiki_page, version_id: commit)) - expect(page).to have_css('.diff-file[data-blob-diff-path="%s"]' % diff_path) - end - - it 'links to the correct diffs' do - visit project_wiki_history_path(project, wiki_page) - - commit1 = wiki.commit('HEAD^') - commit2 = wiki.commit - - expect(page).to have_link('created page: home', href: wiki_page_path(wiki, wiki_page, version_id: commit1, action: :diff)) - expect(page).to have_link('updated home', href: wiki_page_path(wiki, wiki_page, version_id: commit2, action: :diff)) - end - - it 'between the current and the previous version of a page' do - commit = wiki.commit - visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff) - - expect(page).to have_content('by John Doe') - expect(page).to have_content('updated home') - expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions') - expect(page).to have_content('some link') - - expect_diff_links(commit) - end - - it 'between two old versions of a page' do - wiki_page.update(message: 'latest home change', content: 'updated [another link](other-page)') # rubocop:disable Rails/SaveBang: - commit = wiki.commit('HEAD^') - visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff) - - expect(page).to have_content('by John Doe') - expect(page).to have_content('updated home') - expect(page).to have_content('Showing 1 changed file with 1 addition and 3 deletions') - expect(page).to have_content('some link') - expect(page).not_to have_content('latest home change') - expect(page).not_to have_content('another link') - - expect_diff_links(commit) - end - - it 'for the oldest version of a page' do - commit = wiki.commit('HEAD^') - visit wiki_page_path(wiki, wiki_page, version_id: commit, action: :diff) - - expect(page).to have_content('by John Doe') - expect(page).to have_content('created page: home') - expect(page).to have_content('Showing 1 changed file with 4 additions and 0 deletions') - expect(page).to have_content('Look at this') - - expect_diff_links(commit) - end - end - end - - context 'when a page has special characters in its title' do - let(:title) { '<foo> !@#$%^&*()[]{}=_+\'"\\|<>? <bar>' } - - before do - wiki_page.update(title: title ) # rubocop:disable Rails/SaveBang - end - - it 'preserves the special characters' do - visit(project_wiki_path(project, wiki_page)) - - expect(page).to have_css('.wiki-page-title', text: title) - expect(page).to have_css('.wiki-pages li', text: title) - end - end - - context 'when a page has XSS in its title or content' do - let(:title) { '<script>alert("title")<script>' } - - before do - wiki_page.update(title: title, content: 'foo <script>alert("content")</script> bar') # rubocop:disable Rails/SaveBang - end - - it 'safely displays the page' do - visit(project_wiki_path(project, wiki_page)) - - expect(page).to have_css('.wiki-page-title', text: title) - expect(page).to have_content('foo bar') - end - end - - context 'when a page has XSS in its message' do - before do - wiki_page.update(message: '<script>alert(true)<script>', content: 'XSS update') # rubocop:disable Rails/SaveBang - end - - it 'safely displays the message' do - visit(project_wiki_history_path(project, wiki_page)) - - expect(page).to have_content('<script>alert(true)<script>') - end - end - - context 'when page has invalid content encoding' do - let(:content) { (+'whatever').force_encoding('ISO-8859-1') } - - before do - allow(Gitlab::EncodingHelper).to receive(:encode!).and_return(content) - - visit(project_wiki_path(project, wiki_page)) - end - - it 'does not show "Edit" button' do - expect(page).not_to have_selector('a.btn', text: 'Edit') - end - - it 'shows error' do - page.within(:css, '.flash-notice') do - expect(page).to have_content('The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository.') - end - end - end - - it 'opens a default wiki page', :js do - visit project_path(project) - - find('.shortcuts-wiki').click - - wait_for_svg_to_be_loaded - - click_link "Create your first page" - - expect(page).to have_content('Create New Page') - end -end diff --git a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb b/spec/features/projects/wiki/user_views_wiki_pages_spec.rb deleted file mode 100644 index 4f29ae0cc8a..00000000000 --- a/spec/features/projects/wiki/user_views_wiki_pages_spec.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User views wiki pages' do - include WikiHelpers - - let(:user) { create(:user) } - let(:project) { create(:project, :wiki_repo, namespace: user.namespace) } - - let!(:wiki_page1) do - create(:wiki_page, wiki: project.wiki, title: '3 home', content: '3') - end - - let!(:wiki_page2) do - create(:wiki_page, wiki: project.wiki, title: '1 home', content: '1') - end - - let!(:wiki_page3) do - create(:wiki_page, wiki: project.wiki, title: '2 home', content: '2') - end - - let(:pages) do - page.find('.wiki-pages-list').all('li').map { |li| li.find('a') } - end - - before do - project.add_maintainer(user) - sign_in(user) - visit(project_wikis_pages_path(project)) - end - - context 'ordered by title' do - let(:pages_ordered_by_title) { [wiki_page2, wiki_page3, wiki_page1] } - - context 'asc' do - it 'pages are displayed in direct order' do - pages.each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_title[index].title) - end - end - end - - context 'desc' do - before do - page.within('.wiki-sort-dropdown') do - page.find('.rspec-reverse-sort').click - end - end - - it 'pages are displayed in reversed order' do - pages.reverse_each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_title[index].title) - end - end - end - end - - context 'ordered by created_at' do - let(:pages_ordered_by_created_at) { [wiki_page1, wiki_page2, wiki_page3] } - - before do - page.within('.wiki-sort-dropdown') do - click_button('Title') - click_link('Created date') - end - end - - context 'asc' do - it 'pages are displayed in direct order' do - pages.each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) - end - end - end - - context 'desc' do - before do - page.within('.wiki-sort-dropdown') do - page.find('.rspec-reverse-sort').click - end - end - - it 'pages are displayed in reversed order' do - pages.reverse_each.with_index do |page_title, index| - expect(page_title.text).to eq(pages_ordered_by_created_at[index].title) - end - end - end - end -end diff --git a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb b/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb deleted file mode 100644 index 5c45e34595f..00000000000 --- a/spec/features/projects/wiki/users_views_asciidoc_page_with_includes_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User views AsciiDoc page with includes', :js do - let_it_be(:user) { create(:user) } - let_it_be(:wiki_content_selector) { '[data-qa-selector=wiki_page_content]' } - let(:project) { create(:project, :public, :wiki_repo) } - let!(:included_wiki_page) { create_wiki_page('included_page', content: 'Content from the included page')} - let!(:wiki_page) { create_wiki_page('home', content: "Content from the main page.\ninclude::included_page.asciidoc[]") } - - def create_wiki_page(title, content:) - attrs = { - title: title, - content: content, - format: :asciidoc - } - - create(:wiki_page, wiki: project.wiki, **attrs) - end - - before do - sign_in(user) - end - - context 'when the file being included exists' do - it 'includes the file contents' do - visit(project_wiki_path(project, wiki_page)) - - page.within(:css, wiki_content_selector) do - expect(page).to have_content('Content from the main page. Content from the included page') - end - end - - context 'when there are multiple versions of the wiki pages' do - before do - included_wiki_page.update(message: 'updated included file', content: 'Updated content from the included page') - wiki_page.update(message: 'updated wiki page', content: "Updated content from the main page.\ninclude::included_page.asciidoc[]") - end - - let(:latest_version_id) { wiki_page.versions.first.id } - let(:oldest_version_id) { wiki_page.versions.last.id } - - context 'viewing the latest version' do - it 'includes the latest content' do - visit(project_wiki_path(project, wiki_page, version_id: latest_version_id)) - - page.within(:css, wiki_content_selector) do - expect(page).to have_content('Updated content from the main page. Updated content from the included page') - end - end - end - - context 'viewing the original version' do - it 'includes the content from the original version' do - visit(project_wiki_path(project, wiki_page, version_id: oldest_version_id)) - - page.within(:css, wiki_content_selector) do - expect(page).to have_content('Content from the main page. Content from the included page') - end - end - end - end - end - - context 'when the file being included does not exist' do - before do - included_wiki_page.delete - end - - it 'outputs an error' do - visit(project_wiki_path(project, wiki_page)) - - page.within(:css, wiki_content_selector) do - expect(page).to have_content('Content from the main page. [ERROR: include::included_page.asciidoc[] - unresolved directive]') - end - end - end -end diff --git a/spec/features/projects/wikis_spec.rb b/spec/features/projects/wikis_spec.rb new file mode 100644 index 00000000000..1c66ad81145 --- /dev/null +++ b/spec/features/projects/wikis_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe 'Project wikis' do + let_it_be(:user) { create(:user) } + + let(:wiki) { create(:project_wiki, user: user, project: project) } + let(:project) { create(:project, namespace: user.namespace, creator: user) } + + it_behaves_like 'User creates wiki page' + it_behaves_like 'User deletes wiki page' + it_behaves_like 'User previews wiki changes' + it_behaves_like 'User updates wiki page' + it_behaves_like 'User uses wiki shortcuts' + it_behaves_like 'User views AsciiDoc page with includes' + it_behaves_like 'User views a wiki page' + it_behaves_like 'User views wiki pages' + it_behaves_like 'User views wiki sidebar' +end |