diff options
Diffstat (limited to 'spec/features')
21 files changed, 885 insertions, 339 deletions
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index a01c129defd..7eeed7da998 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -19,7 +19,7 @@ describe "Admin Runners" do end it 'has all necessary texts' do - expect(page).to have_text "How to setup" + expect(page).to have_text "Setup a shared Runner manually" expect(page).to have_text "Runners with last contact more than a minute ago: 1" end @@ -54,7 +54,7 @@ describe "Admin Runners" do end it 'has all necessary texts including no runner message' do - expect(page).to have_text "How to setup" + expect(page).to have_text "Setup a shared Runner manually" expect(page).to have_text "Runners with last contact more than a minute ago: 0" expect(page).to have_text 'No runners found' end diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb deleted file mode 100644 index 9aef68b7156..00000000000 --- a/spec/features/auto_deploy_spec.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'spec_helper' - -describe 'Auto deploy' do - let(:user) { create(:user) } - let(:project) { create(:project, :repository) } - - shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do - context 'when no deployment service is active' do - before do - trun_off - end - - it 'does not show a button to set up auto deploy' do - visit project_path(project) - expect(page).to have_no_content('Set up auto deploy') - end - end - - context 'when a deployment service is active' do - before do - trun_on - visit project_path(project) - end - - it 'shows a button to set up auto deploy' do - expect(page).to have_link('Set up auto deploy') - end - - it 'includes OpenShift as an available template', :js do - click_link 'Set up auto deploy' - click_button 'Apply a GitLab CI Yaml template' - - within '.gitlab-ci-yml-selector' do - expect(page).to have_content('OpenShift') - end - end - - it 'creates a merge request using "auto-deploy" branch', :js do - click_link 'Set up auto deploy' - click_button 'Apply a GitLab CI Yaml template' - within '.gitlab-ci-yml-selector' do - click_on 'OpenShift' - end - wait_for_requests - click_button 'Commit changes' - - expect(page).to have_content('New Merge Request From auto-deploy into master') - end - end - end - - context 'when user configured kubernetes from Integration > Kubernetes' do - before do - create :kubernetes_service, project: project - project.add_master(user) - sign_in user - end - - let(:trun_on) { project.deployment_platform.update!(active: true) } - let(:trun_off) { project.deployment_platform.update!(active: false) } - - it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes' - end - - context 'when user configured kubernetes from CI/CD > Clusters' do - before do - create(:cluster, :provided_by_gcp, projects: [project]) - project.add_master(user) - sign_in user - end - - let(:trun_on) { project.deployment_platform.cluster.update!(enabled: true) } - let(:trun_off) { project.deployment_platform.cluster.update!(enabled: false) } - - it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes' - end -end diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index f355cec3ba9..41b9ada988a 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -39,8 +39,8 @@ describe 'Recent searches', :js do items = all('.filtered-search-history-dropdown-item', visible: false, count: 2) - expect(items[0].text).to eq('label:~qux garply') - expect(items[1].text).to eq('label:~foo bar') + expect(items[0].text).to eq('label: ~qux garply') + expect(items[1].text).to eq('label: ~foo bar') end it 'saved recent searches are restored last on the list' do diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index b02d2d4261c..cc12a1005ba 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -66,15 +66,16 @@ feature 'Milestone' do end end - feature 'Open a milestone' do + feature 'Open a milestone', :js do scenario 'shows total issue time spent correctly when no time has been logged' do milestone = create(:milestone, project: project, title: 8.7) visit project_milestone_path(project, milestone) - page.within('.block.time_spent') do - expect(page).to have_content 'No time spent' - expect(page).to have_content 'None' + wait_for_requests + + page.within('.time-tracking-no-tracking-pane') do + expect(page).to have_content 'No estimate or time spent' end end @@ -89,8 +90,10 @@ feature 'Milestone' do visit project_milestone_path(project, milestone) - page.within('.block.time_spent') do - expect(page).to have_content '3h' + wait_for_requests + + page.within('.time-tracking-spend-only-pane') do + expect(page).to have_content 'Spent: 3h' end end end 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 8ac9821b879..7f1d1934103 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 @@ -11,7 +11,7 @@ feature 'project owner sees a link to create a license file in empty project', : scenario 'project master creates a license file from a template' do visit project_path(project) - click_on 'LICENSE' + click_on 'Add License' expect(page).to have_content('New file') expect(current_path).to eq( diff --git a/spec/features/projects/members/share_with_group_spec.rb b/spec/features/projects/members/share_with_group_spec.rb index 4cf48098401..134c8b8bc39 100644 --- a/spec/features/projects/members/share_with_group_spec.rb +++ b/spec/features/projects/members/share_with_group_spec.rb @@ -149,6 +149,11 @@ feature 'Project > Members > Share with Group', :js do create(:group).add_owner(master) visit project_settings_members_path(project) + + click_link 'Share with group' + + find('.ajax-groups-select.select2-container') + execute_script 'GROUP_SELECT_PER_PAGE = 1;' open_select2 '#link_group_id' end diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb new file mode 100644 index 00000000000..9f9a7787093 --- /dev/null +++ b/spec/features/projects/network_graph_spec.rb @@ -0,0 +1,108 @@ +require 'spec_helper' + +describe 'Project Network Graph', :js do + let(:user) { create :user } + let(:project) { create :project, :repository, namespace: user.namespace } + + before do + sign_in(user) + + # Stub Graph max_size to speed up test (10 commits vs. 650) + allow(Network::Graph).to receive(:max_count).and_return(10) + end + + context 'when branch is master' do + def switch_ref_to(ref_name) + first('.js-project-refs-dropdown').click + + page.within '.project-refs-form' do + click_link ref_name + end + end + + def click_show_only_selected_branch_checkbox + find('#filter_ref').click + end + + before do + visit project_network_path(project, 'master') + end + + it 'renders project network' do + expect(page).to have_selector ".network-graph" + expect(page).to have_selector '.dropdown-menu-toggle', text: "master" + page.within '.network-graph' do + expect(page).to have_content 'master' + end + end + + it 'switches ref to branch' do + switch_ref_to('feature') + + expect(page).to have_selector '.dropdown-menu-toggle', text: 'feature' + page.within '.network-graph' do + expect(page).to have_content 'feature' + end + end + + it 'switches ref to tag' do + switch_ref_to('v1.0.0') + + expect(page).to have_selector '.dropdown-menu-toggle', text: 'v1.0.0' + page.within '.network-graph' do + expect(page).to have_content 'v1.0.0' + end + end + + it 'renders by commit sha of "v1.0.0"' do + page.within ".network-form" do + fill_in 'extended_sha1', with: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' + find('button').click + end + + expect(page).to have_selector ".network-graph" + expect(page).to have_selector '.dropdown-menu-toggle', text: "master" + page.within '.network-graph' do + expect(page).to have_content 'v1.0.0' + end + end + + it 'filters select tag' do + switch_ref_to('v1.0.0') + + expect(page).to have_css 'title', text: 'Graph · v1.0.0', visible: false + page.within '.network-graph' do + expect(page).to have_content 'Change some files' + end + + click_show_only_selected_branch_checkbox + + page.within '.network-graph' do + expect(page).not_to have_content 'Change some files' + end + + click_show_only_selected_branch_checkbox + + page.within '.network-graph' do + expect(page).to have_content 'Change some files' + end + end + + it 'renders error message when sha commit not exists' do + page.within ".network-form" do + fill_in 'extended_sha1', with: ';' + find('button').click + end + + expect(page).to have_selector '.flash-alert', text: "Git revision ';' does not exist." + end + end + + it 'renders project network with test branch' do + visit project_network_path(project, "'test'") + + page.within '.network-graph' do + expect(page).to have_content "'test'" + end + end +end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index 6f097ad16c7..b5104747d00 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -140,7 +140,7 @@ feature 'New project' do find('#import-project-tab').click end - context 'from git repository url' do + context 'from git repository url, "Repo by URL"' do before do first('.import_git').click end @@ -157,6 +157,18 @@ feature 'New project' do expect(git_import_instructions).to be_visible expect(git_import_instructions).to have_content 'Git repository URL' end + + it 'keeps "Import project" tab open after form validation error' do + collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace) + + fill_in 'project_import_url', with: collision_project.http_url_to_repo + fill_in 'project_path', with: collision_project.path + + click_on 'Create project' + + expect(page).to have_css('#import-project-pane.active') + expect(page).not_to have_css('.toggle-import-form.hide') + end end context 'from GitHub' do diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 2e334caa98f..a96f2c186a4 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -17,6 +17,7 @@ feature 'Pages' do scenario 'does not see anything to destroy' do visit project_pages_path(project) + expect(page).to have_content('Configure pages') expect(page).not_to have_link('Remove pages') expect(page).not_to have_text('Only the project owner can remove pages') end @@ -32,14 +33,161 @@ feature 'Pages' do allow_any_instance_of(Project).to receive(:pages_deployed?) { true } end - scenario 'sees "Remove pages" link' do + scenario 'renders Access pages' do visit project_pages_path(project) - expect(page).to have_link('Remove pages') + expect(page).to have_content('Access pages') + end + + context 'when support for external domains is disabled' do + before do + allow(Gitlab.config.pages).to receive(:external_http).and_return(nil) + allow(Gitlab.config.pages).to receive(:external_https).and_return(nil) + end + + it 'renders message that support is disabled' do + visit project_pages_path(project) + + expect(page).to have_content('Support for domains and certificates is disabled') + end + end + + context 'when pages are exposed on external HTTP address' do + shared_examples 'adds new domain' do + it 'adds new domain' do + visit new_project_pages_domain_path(project) + + fill_in 'Domain', with: 'my.test.domain.com' + click_button 'Create New Domain' + + expect(page).to have_content('my.test.domain.com') + end + end + + before do + allow(Gitlab.config.pages).to receive(:external_http).and_return(['1.1.1.1:80']) + allow(Gitlab.config.pages).to receive(:external_https).and_return(nil) + end + + it 'allows to add new domain' do + visit project_pages_path(project) + + expect(page).to have_content('New Domain') + end + + it_behaves_like 'adds new domain' + + context 'when project in group namespace' do + it_behaves_like 'adds new domain' do + let(:group) { create :group } + let(:project) { create :project, namespace: group } + end + end + + context 'when pages domain is added' do + before do + project.pages_domains.create!(domain: 'my.test.domain.com') + + visit new_project_pages_domain_path(project) + end + + it 'renders certificates is disabled' do + expect(page).to have_content('Support for custom certificates is disabled') + end + + it 'does not adds new domain and renders error message' do + fill_in 'Domain', with: 'my.test.domain.com' + click_button 'Create New Domain' + + expect(page).to have_content('Domain has already been taken') + end + end + end + + context 'when pages are exposed on external HTTPS address' do + let(:certificate_pem) do + <<~PEM + -----BEGIN CERTIFICATE----- + MIICGzCCAYSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAbMRkwFwYDVQQDExB0ZXN0 + LWNlcnRpZmljYXRlMB4XDTE2MDIxMjE0MzIwMFoXDTIwMDQxMjE0MzIwMFowGzEZ + MBcGA1UEAxMQdGVzdC1jZXJ0aWZpY2F0ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw + gYkCgYEApL4J9L0ZxFJ1hI1LPIflAlAGvm6ZEvoT4qKU5Xf2JgU7/2geNR1qlNFa + SvCc08Knupp5yTgmvyK/Xi09U0N82vvp4Zvr/diSc4A/RA6Mta6egLySNT438kdT + nY2tR5feoTLwQpX0t4IMlwGQGT5h6Of2fKmDxzuwuyffcIHqLdsCAwEAAaNvMG0w + DAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUxl9WSxBprB0z0ibJs3rXEk0+95AwCwYD + VR0PBAQDAgXgMBEGCWCGSAGG+EIBAQQEAwIGQDAeBglghkgBhvhCAQ0EERYPeGNh + IGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAGC4T8SlFHK0yPSa+idGLQFQ + joZp2JHYvNlTPkRJ/J4TcXxBTJmArcQgTIuNoBtC+0A/SwdK4MfTCUY4vNWNdese + 5A4K65Nb7Oh1AdQieTBHNXXCdyFsva9/ScfQGEl7p55a52jOPs0StPd7g64uvjlg + YHi2yesCrOvVXt+lgPTd + -----END CERTIFICATE----- + PEM + end + + let(:certificate_key) do + <<~KEY + -----BEGIN PRIVATE KEY----- + MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKS+CfS9GcRSdYSN + SzyH5QJQBr5umRL6E+KilOV39iYFO/9oHjUdapTRWkrwnNPCp7qaeck4Jr8iv14t + PVNDfNr76eGb6/3YknOAP0QOjLWunoC8kjU+N/JHU52NrUeX3qEy8EKV9LeCDJcB + kBk+Yejn9nypg8c7sLsn33CB6i3bAgMBAAECgYA2D26w80T7WZvazYr86BNMePpd + j2mIAqx32KZHzt/lhh40J/SRtX9+Kl0Y7nBoRR5Ja9u/HkAIxNxLiUjwg9r6cpg/ + uITEF5nMt7lAk391BuI+7VOZZGbJDsq2ulPd6lO+C8Kq/PI/e4kXcIjeH6KwQsuR + 5vrXfBZ3sQfflaiN4QJBANBt8JY2LIGQF8o89qwUpRL5vbnKQ4IzZ5+TOl4RLR7O + AQpJ81tGuINghO7aunctb6rrcKJrxmEH1whzComybrMCQQDKV49nOBudRBAIgG4K + EnLzsRKISUHMZSJiYTYnablof8cKw1JaQduw7zgrUlLwnroSaAGX88+Jw1f5n2Lh + Vlg5AkBDdUGnrDLtYBCDEQYZHblrkc7ZAeCllDOWjxUV+uMqlCv8A4Ey6omvY57C + m6I8DkWVAQx8VPtozhvHjUw80rZHAkB55HWHAM3h13axKG0htCt7klhPsZHpx6MH + EPjGlXIT+aW2XiPmK3ZlCDcWIenE+lmtbOpI159Wpk8BGXs/s/xBAkEAlAY3ymgx + 63BDJEwvOb2IaP8lDDxNsXx9XJNVvQbv5n15vNsLHbjslHfAhAbxnLQ1fLhUPqSi + nNp/xedE1YxutQ== + -----END PRIVATE KEY----- + KEY + end + + before do + allow(Gitlab.config.pages).to receive(:external_http).and_return(['1.1.1.1:80']) + allow(Gitlab.config.pages).to receive(:external_https).and_return(['1.1.1.1:443']) + end + + it 'adds new domain with certificate' do + visit new_project_pages_domain_path(project) + + fill_in 'Domain', with: 'my.test.domain.com' + fill_in 'Certificate (PEM)', with: certificate_pem + fill_in 'Key (PEM)', with: certificate_key + click_button 'Create New Domain' + + expect(page).to have_content('my.test.domain.com') + end end end it_behaves_like 'no pages deployed' + + describe 'project settings page' do + it 'renders "Pages" tab' do + visit edit_project_path(project) + + page.within '.nav-sidebar' do + expect(page).to have_link('Pages') + end + end + + context 'when pages are disabled' do + before do + allow(Gitlab.config.pages).to receive(:enabled).and_return(false) + end + + it 'does not render "Pages" tab' do + visit edit_project_path(project) + + page.within '.nav-sidebar' do + expect(page).not_to have_link('Pages') + end + end + end + end end context 'when the user is not the owner' do @@ -57,4 +205,54 @@ feature 'Pages' do it_behaves_like 'no pages deployed' end + + describe 'Remove page' do + context 'when user is the owner' do + let(:project) { create :project, :repository } + + before do + project.namespace.update(owner: user) + end + + context 'when pages are deployed' do + let(:pipeline) do + commit_sha = project.commit('HEAD').sha + + project.pipelines.create( + ref: 'HEAD', + sha: commit_sha, + source: :push, + protected: false + ) + end + + let(:ci_build) do + build( + :ci_build, + project: project, + pipeline: pipeline, + ref: 'HEAD', + legacy_artifacts_file: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip')), + legacy_artifacts_metadata: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip.meta')) + ) + end + + before do + result = Projects::UpdatePagesService.new(project, ci_build).execute + expect(result[:status]).to eq(:success) + expect(project).to be_pages_deployed + end + + it 'removes the pages' do + visit project_pages_path(project) + + expect(page).to have_link('Remove pages') + + click_link 'Remove pages' + + expect(project.pages_deployed?).to be_falsey + end + end + end + end end diff --git a/spec/features/projects/show_project_spec.rb b/spec/features/projects/show_project_spec.rb index 0b94c9eae5d..0a014e9f080 100644 --- a/spec/features/projects/show_project_spec.rb +++ b/spec/features/projects/show_project_spec.rb @@ -17,4 +17,321 @@ describe 'Project show page', :feature do expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{project.delete_error}") end end + + describe 'stat button existence' do + # For "New file", "Add License" functionality, + # see spec/features/projects/files/project_owner_creates_license_file_spec.rb + # see spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb + + let(:user) { create(:user) } + + describe 'empty project' do + let(:project) { create(:project, :public, :empty_repo) } + let(:presenter) { project.present(current_user: user) } + + describe 'as a normal user' do + before do + sign_in(user) + + visit project_path(project) + end + + it 'no Auto DevOps button if can not manage pipelines' do + page.within('.project-stats') do + expect(page).not_to have_link('Enable Auto DevOps') + expect(page).not_to have_link('Auto DevOps enabled') + end + end + + it '"Auto DevOps enabled" button not linked' do + project.create_auto_devops!(enabled: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_text('Auto DevOps enabled') + end + end + end + + describe 'as a master' do + before do + project.add_master(user) + sign_in(user) + + visit project_path(project) + end + + it '"New file" button linked to new file page' do + page.within('.project-stats') do + expect(page).to have_link('New file', href: project_new_blob_path(project, project.default_branch || 'master')) + end + end + + it '"Add Readme" button linked to new file populated for a readme' do + page.within('.project-stats') do + expect(page).to have_link('Add Readme', href: presenter.add_readme_path) + end + end + + it '"Add License" button linked to new file populated for a license' do + page.within('.project-stats') do + expect(page).to have_link('Add License', href: presenter.add_license_path) + end + end + + describe 'Auto DevOps button' do + it '"Enable Auto DevOps" button linked to settings page' do + page.within('.project-stats') do + expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) + end + end + + it '"Auto DevOps enabled" anchor linked to settings page' do + project.create_auto_devops!(enabled: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) + end + end + end + + describe 'Kubernetes cluster button' do + it '"Add Kubernetes cluster" button linked to clusters page' do + page.within('.project-stats') do + expect(page).to have_link('Add Kubernetes cluster', href: new_project_cluster_path(project)) + end + end + + it '"Kubernetes cluster" anchor linked to cluster page' do + cluster = create(:cluster, :provided_by_gcp, projects: [project]) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_link('Kubernetes configured', href: project_cluster_path(project, cluster)) + end + end + end + end + end + + describe 'populated project' do + let(:project) { create(:project, :public, :repository) } + let(:presenter) { project.present(current_user: user) } + + describe 'as a normal user' do + before do + sign_in(user) + + visit project_path(project) + end + + it 'no Auto DevOps button if can not manage pipelines' do + page.within('.project-stats') do + expect(page).not_to have_link('Enable Auto DevOps') + expect(page).not_to have_link('Auto DevOps enabled') + end + end + + it '"Auto DevOps enabled" button not linked' do + project.create_auto_devops!(enabled: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_text('Auto DevOps enabled') + end + end + + it 'no Kubernetes cluster button if can not manage clusters' do + page.within('.project-stats') do + expect(page).not_to have_link('Add Kubernetes cluster') + expect(page).not_to have_link('Kubernetes configured') + end + end + end + + describe 'as a master' do + before do + allow_any_instance_of(AutoDevopsHelper).to receive(:show_auto_devops_callout?).and_return(false) + project.add_master(user) + sign_in(user) + + visit project_path(project) + end + + it 'no "Add Changelog" button if the project already has a changelog' do + expect(project.repository.changelog).not_to be_nil + + page.within('.project-stats') do + expect(page).not_to have_link('Add Changelog') + end + end + + it 'no "Add License" button if the project already has a license' do + expect(project.repository.license_blob).not_to be_nil + + page.within('.project-stats') do + expect(page).not_to have_link('Add License') + end + end + + it 'no "Add Contribution guide" button if the project already has a contribution guide' do + expect(project.repository.contribution_guide).not_to be_nil + + page.within('.project-stats') do + expect(page).not_to have_link('Add Contribution guide') + end + end + + describe 'GitLab CI configuration button' do + it '"Set up CI/CD" button linked to new file populated for a .gitlab-ci.yml' do + expect(project.repository.gitlab_ci_yml).to be_nil + + page.within('.project-stats') do + expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path) + end + end + + it 'no "Set up CI/CD" button if the project already has a .gitlab-ci.yml' do + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add .gitlab-ci.yml", + file_path: '.gitlab-ci.yml', + file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + ).execute + + expect(project.repository.gitlab_ci_yml).not_to be_nil + + visit project_path(project) + + page.within('.project-stats') do + expect(page).not_to have_link('Set up CI/CD') + end + end + + it 'no "Set up CI/CD" button if the project has Auto DevOps enabled' do + project.create_auto_devops!(enabled: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).not_to have_link('Set up CI/CD') + end + end + end + + describe 'Auto DevOps button' do + it '"Enable Auto DevOps" button linked to settings page' do + page.within('.project-stats') do + expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) + end + end + + it '"Enable Auto DevOps" button linked to settings page' do + project.create_auto_devops!(enabled: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'js-general-pipeline-settings')) + end + end + + it 'no Auto DevOps button if Auto DevOps callout is shown' do + allow_any_instance_of(AutoDevopsHelper).to receive(:show_auto_devops_callout?).and_return(true) + + visit project_path(project) + + expect(page).to have_selector('.js-autodevops-banner') + + page.within('.project-stats') do + expect(page).not_to have_link('Enable Auto DevOps') + expect(page).not_to have_link('Auto DevOps enabled') + end + end + + it 'no "Enable Auto DevOps" button when .gitlab-ci.yml already exists' do + Files::CreateService.new( + project, + project.creator, + start_branch: 'master', + branch_name: 'master', + commit_message: "Add .gitlab-ci.yml", + file_path: '.gitlab-ci.yml', + file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + ).execute + + expect(project.repository.gitlab_ci_yml).not_to be_nil + + visit project_path(project) + + page.within('.project-stats') do + expect(page).not_to have_link('Enable Auto DevOps') + expect(page).not_to have_link('Auto DevOps enabled') + end + end + end + + describe 'Kubernetes cluster button' do + it '"Add Kubernetes cluster" button linked to clusters page' do + page.within('.project-stats') do + expect(page).to have_link('Add Kubernetes cluster', href: new_project_cluster_path(project)) + end + end + + it '"Kubernetes cluster" button linked to cluster page' do + cluster = create(:cluster, :provided_by_gcp, projects: [project]) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_link('Kubernetes configured', href: project_cluster_path(project, cluster)) + end + end + end + + describe '"Set up Koding" button' do + it 'no "Set up Koding" button if Koding disabled' do + stub_application_setting(koding_enabled?: false) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).not_to have_link('Set up Koding') + end + end + + it 'no "Set up Koding" button if the project already has a .koding.yml' do + stub_application_setting(koding_enabled?: true) + allow(Gitlab::CurrentSettings.current_application_settings).to receive(:koding_url).and_return('http://koding.example.com') + expect(project.repository.changelog).not_to be_nil + allow_any_instance_of(Repository).to receive(:koding_yml).and_return(project.repository.changelog) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).not_to have_link('Set up Koding') + end + end + + it '"Set up Koding" button linked to new file populated for a .koding.yml' do + stub_application_setting(koding_enabled?: true) + + visit project_path(project) + + page.within('.project-stats') do + expect(page).to have_link('Set up Koding', href: presenter.add_koding_stack_path) + end + end + end + end + end + end end diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index b66a7dea598..645d12da09f 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -25,6 +25,24 @@ feature 'Project' do end end + describe 'shows tip about push to create git command' do + let(:user) { create(:user) } + + before do + sign_in user + visit new_project_path + end + + it 'shows the command in a popover', :js do + page.within '.profile-settings-sidebar' do + click_link 'Show command' + end + + expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip') + expect(page).to have_content 'Private projects can be created in your personal namespace with:' + end + end + describe 'description' do let(:project) { create(:project, :repository) } let(:path) { project_path(project) } diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index aec9de6c7ca..df65c2d2f83 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -7,6 +7,20 @@ feature 'Runners' do sign_in(user) end + context 'when user opens runners page' do + given(:project) { create(:project) } + + background do + project.add_master(user) + end + + scenario 'user can see a button to install runners on kubernetes clusters' do + visit runners_path(project) + + expect(page).to have_link('Install Runner on Kubernetes', href: project_clusters_path(project)) + end + end + context 'when a project has enabled shared_runners' do given(:project) { create(:project) } diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb deleted file mode 100644 index 917fad74ef1..00000000000 --- a/spec/features/signup_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'spec_helper' - -feature 'Signup' do - describe 'signup with no errors' do - context "when sending confirmation email" do - before do - stub_application_setting(send_user_confirmation_email: true) - end - - it 'creates the user account and sends a confirmation email' do - user = build(:user) - - visit root_path - - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: user.email - fill_in 'new_user_email_confirmation', with: user.email - fill_in 'new_user_password', with: user.password - click_button "Register" - - expect(current_path).to eq users_almost_there_path - expect(page).to have_content("Please check your email to confirm your account") - end - end - - context "when sigining up with different cased emails" do - it "creates the user successfully" do - user = build(:user) - - visit root_path - - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: user.email - fill_in 'new_user_email_confirmation', with: user.email.capitalize - fill_in 'new_user_password', with: user.password - click_button "Register" - - expect(current_path).to eq dashboard_projects_path - expect(page).to have_content("Welcome! You have signed up successfully.") - end - end - - context "when not sending confirmation email" do - before do - stub_application_setting(send_user_confirmation_email: false) - end - - it 'creates the user account and goes to dashboard' do - user = build(:user) - - visit root_path - - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: user.email - fill_in 'new_user_email_confirmation', with: user.email - fill_in 'new_user_password', with: user.password - click_button "Register" - - expect(current_path).to eq dashboard_projects_path - expect(page).to have_content("Welcome! You have signed up successfully.") - end - end - end - - describe 'signup with errors' do - it "displays the errors" do - existing_user = create(:user) - user = build(:user) - - visit root_path - - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: existing_user.email - fill_in 'new_user_password', with: user.password - click_button "Register" - - expect(current_path).to eq user_registration_path - expect(page).to have_content("errors prohibited this user from being saved") - expect(page).to have_content("Email has already been taken") - expect(page).to have_content("Email confirmation doesn't match") - end - - it 'does not redisplay the password' do - existing_user = create(:user) - user = build(:user) - - visit root_path - - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: existing_user.email - fill_in 'new_user_password', with: user.password - click_button "Register" - - expect(current_path).to eq user_registration_path - expect(page.body).not_to match(/#{user.password}/) - end - end -end diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb index 4662367d843..b625e7065cc 100644 --- a/spec/features/tags/master_views_tags_spec.rb +++ b/spec/features/tags/master_views_tags_spec.rb @@ -13,7 +13,7 @@ feature 'Master views tags' do before do visit project_path(project) - click_on 'README' + click_on 'Add Readme' fill_in :commit_message, with: 'Add a README file', visible: true click_button 'Commit changes' visit project_tags_path(project) diff --git a/spec/features/login_spec.rb b/spec/features/users/login_spec.rb index 6dfabcc7225..6ef235cf870 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -1,6 +1,26 @@ require 'spec_helper' feature 'Login' do + scenario 'Successful user signin invalidates password reset token' do + user = create(:user) + + expect(user.reset_password_token).to be_nil + + visit new_user_password_path + fill_in 'user_email', with: user.email + click_button 'Reset password' + + user.reload + expect(user.reset_password_token).not_to be_nil + + find('a[href="#login-pane"]').click + gitlab_sign_in(user) + expect(current_path).to eq root_path + + user.reload + expect(user.reset_password_token).to be_nil + end + describe 'initial login after setup' do it 'allows the initial admin to create a password' do # This behavior is dependent on there only being one user diff --git a/spec/features/logout_spec.rb b/spec/features/users/logout_spec.rb index 635729efa53..635729efa53 100644 --- a/spec/features/logout_spec.rb +++ b/spec/features/users/logout_spec.rb diff --git a/spec/features/users/projects_spec.rb b/spec/features/users/projects_spec.rb deleted file mode 100644 index f079771cee1..00000000000 --- a/spec/features/users/projects_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'spec_helper' - -describe 'Projects tab on a user profile', :js do - let(:user) { create(:user) } - let!(:project) { create(:project, namespace: user.namespace) } - let!(:project2) { create(:project, namespace: user.namespace) } - - before do - allow(Project).to receive(:default_per_page).and_return(1) - - sign_in(user) - - visit user_path(user) - - page.within('.user-profile-nav') do - click_link('Personal projects') - end - - wait_for_requests - end - - it 'paginates results' do - expect(page).to have_content(project2.name) - - click_link('Next') - - expect(page).to have_content(project.name) - end -end diff --git a/spec/features/users/show_spec.rb b/spec/features/users/show_spec.rb new file mode 100644 index 00000000000..b5bbb2c0ea5 --- /dev/null +++ b/spec/features/users/show_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe 'User page' do + let(:user) { create(:user) } + + it 'shows all the tabs' do + visit(user_path(user)) + + page.within '.nav-links' do + expect(page).to have_link('Activity') + expect(page).to have_link('Groups') + expect(page).to have_link('Contributed projects') + expect(page).to have_link('Personal projects') + expect(page).to have_link('Snippets') + end + end +end diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb new file mode 100644 index 00000000000..5d539f0ccbe --- /dev/null +++ b/spec/features/users/signup_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' + +describe 'Signup' do + let(:new_user) { build_stubbed(:user) } + + describe 'username validation', :js do + before do + visit root_path + click_link 'Register' + end + + it 'does not show an error border if the username is available' do + fill_in 'new_user_username', with: 'new-user' + wait_for_requests + + expect(find('.username')).not_to have_css '.gl-field-error-outline' + end + + it 'does not show an error border if the username contains dots (.)' do + fill_in 'new_user_username', with: 'new.user.username' + wait_for_requests + + expect(find('.username')).not_to have_css '.gl-field-error-outline' + end + + it 'shows an error border if the username already exists' do + existing_user = create(:user) + + fill_in 'new_user_username', with: existing_user.username + wait_for_requests + + expect(find('.username')).to have_css '.gl-field-error-outline' + end + + it 'shows an error border if the username contains special characters' do + fill_in 'new_user_username', with: 'new$user!username' + wait_for_requests + + expect(find('.username')).to have_css '.gl-field-error-outline' + end + end + + context 'with no errors' do + context "when sending confirmation email" do + before do + stub_application_setting(send_user_confirmation_email: true) + end + + it 'creates the user account and sends a confirmation email' do + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email + fill_in 'new_user_email_confirmation', with: new_user.email + fill_in 'new_user_password', with: new_user.password + + expect { click_button 'Register' }.to change { User.count }.by(1) + + expect(current_path).to eq users_almost_there_path + expect(page).to have_content("Please check your email to confirm your account") + end + end + + context "when sigining up with different cased emails" do + it "creates the user successfully" do + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email + fill_in 'new_user_email_confirmation', with: new_user.email.capitalize + fill_in 'new_user_password', with: new_user.password + click_button "Register" + + expect(current_path).to eq dashboard_projects_path + expect(page).to have_content("Welcome! You have signed up successfully.") + end + end + + context "when not sending confirmation email" do + before do + stub_application_setting(send_user_confirmation_email: false) + end + + it 'creates the user account and goes to dashboard' do + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email + fill_in 'new_user_email_confirmation', with: new_user.email + fill_in 'new_user_password', with: new_user.password + click_button "Register" + + expect(current_path).to eq dashboard_projects_path + expect(page).to have_content("Welcome! You have signed up successfully.") + end + end + end + + context 'with errors' do + it "displays the errors" do + existing_user = create(:user) + + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: existing_user.email + fill_in 'new_user_password', with: new_user.password + click_button "Register" + + expect(current_path).to eq user_registration_path + expect(page).to have_content("errors prohibited this user from being saved") + expect(page).to have_content("Email has already been taken") + expect(page).to have_content("Email confirmation doesn't match") + end + + it 'does not redisplay the password' do + existing_user = create(:user) + + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: existing_user.email + fill_in 'new_user_password', with: new_user.password + click_button "Register" + + expect(current_path).to eq user_registration_path + expect(page.body).not_to match(/#{new_user.password}/) + end + end +end diff --git a/spec/features/user_page_spec.rb b/spec/features/users/user_browses_projects_on_user_page_spec.rb index 19c587e53c8..a70637c8370 100644 --- a/spec/features/user_page_spec.rb +++ b/spec/features/users/user_browses_projects_on_user_page_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'User page', :js do +describe 'Users > User browses projects on user page', :js do let!(:user) { create :user } let!(:private_project) do create :project, :private, name: 'private', namespace: user.namespace do |project| @@ -26,6 +26,28 @@ describe 'User page', :js do end end + it 'paginates projects', :js do + project = create(:project, namespace: user.namespace) + project2 = create(:project, namespace: user.namespace) + allow(Project).to receive(:default_per_page).and_return(1) + + sign_in(user) + + visit user_path(user) + + page.within('.user-profile-nav') do + click_link('Personal projects') + end + + wait_for_requests + + expect(page).to have_content(project2.name) + + click_link('Next') + + expect(page).to have_content(project.name) + end + context 'when not signed in' do it 'renders user public project' do visit user_path(user) diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb deleted file mode 100644 index a9973cdf214..00000000000 --- a/spec/features/users_spec.rb +++ /dev/null @@ -1,114 +0,0 @@ -require 'spec_helper' - -feature 'Users', :js do - let(:user) { create(:user, username: 'user1', name: 'User 1', email: 'user1@gitlab.com') } - - scenario 'GET /users/sign_in creates a new user account' do - visit new_user_session_path - click_link 'Register' - fill_in 'new_user_name', with: 'Name Surname' - fill_in 'new_user_username', with: 'Great' - fill_in 'new_user_email', with: 'name@mail.com' - fill_in 'new_user_email_confirmation', with: 'name@mail.com' - fill_in 'new_user_password', with: 'password1234' - expect { click_button 'Register' }.to change { User.count }.by(1) - end - - scenario 'Successful user signin invalidates password reset token' do - expect(user.reset_password_token).to be_nil - - visit new_user_password_path - fill_in 'user_email', with: user.email - click_button 'Reset password' - - user.reload - expect(user.reset_password_token).not_to be_nil - - find('a[href="#login-pane"]').click - gitlab_sign_in(user) - expect(current_path).to eq root_path - - user.reload - expect(user.reset_password_token).to be_nil - end - - scenario 'Should show one error if email is already taken' do - visit new_user_session_path - click_link 'Register' - fill_in 'new_user_name', with: 'Another user name' - fill_in 'new_user_username', with: 'anotheruser' - fill_in 'new_user_email', with: user.email - fill_in 'new_user_email_confirmation', with: user.email - fill_in 'new_user_password', with: '12341234' - expect { click_button 'Register' }.to change { User.count }.by(0) - expect(page).to have_text('Email has already been taken') - expect(number_of_errors_on_page(page)).to be(1), 'errors on page:\n #{errors_on_page page}' - end - - describe 'redirect alias routes' do - before do - expect(user).to be_persisted - end - - scenario '/u/user1 redirects to user page' do - visit '/u/user1' - - expect(current_path).to eq user_path(user) - expect(page).to have_text(user.name) - end - - scenario '/u/user1/groups redirects to user groups page' do - visit '/u/user1/groups' - - expect(current_path).to eq user_groups_path(user) - end - - scenario '/u/user1/projects redirects to user projects page' do - visit '/u/user1/projects' - - expect(current_path).to eq user_projects_path(user) - end - end - - feature 'username validation' do - let(:loading_icon) { '.fa.fa-spinner' } - let(:username_input) { 'new_user_username' } - - before do - visit new_user_session_path - click_link 'Register' - end - - scenario 'doesn\'t show an error border if the username is available' do - fill_in username_input, with: 'new-user' - wait_for_requests - expect(find('.username')).not_to have_css '.gl-field-error-outline' - end - - scenario 'does not show an error border if the username contains dots (.)' do - fill_in username_input, with: 'new.user.username' - wait_for_requests - expect(find('.username')).not_to have_css '.gl-field-error-outline' - end - - scenario 'shows an error border if the username already exists' do - fill_in username_input, with: user.username - wait_for_requests - expect(find('.username')).to have_css '.gl-field-error-outline' - end - - scenario 'shows an error border if the username contains special characters' do - fill_in username_input, with: 'new$user!username' - wait_for_requests - expect(find('.username')).to have_css '.gl-field-error-outline' - end - end - - def errors_on_page(page) - page.find('#error_explanation').find('ul').all('li').map { |item| item.text }.join("\n") - end - - def number_of_errors_on_page(page) - page.find('#error_explanation').find('ul').all('li').count - end -end |