diff options
Diffstat (limited to 'spec/features/projects/show')
12 files changed, 879 insertions, 0 deletions
diff --git a/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb new file mode 100644 index 00000000000..8803b5222be --- /dev/null +++ b/spec/features/projects/show/developer_views_empty_project_instructions_spec.rb @@ -0,0 +1,63 @@ +require 'rails_helper' + +feature 'Projects > Show > Developer views empty project instructions' do + let(:project) { create(:project, :empty_repo) } + let(:developer) { create(:user) } + + background do + project.add_developer(developer) + + sign_in(developer) + end + + context 'without an SSH key' do + scenario 'defaults to HTTP' do + visit_project + + expect_instructions_for('http') + end + + scenario 'switches to SSH', :js do + visit_project + + select_protocol('SSH') + + expect_instructions_for('ssh') + end + end + + context 'with an SSH key' do + background do + create(:personal_key, user: developer) + end + + scenario 'defaults to SSH' do + visit_project + + expect_instructions_for('ssh') + end + + scenario 'switches to HTTP', :js do + visit_project + + select_protocol('HTTP') + + expect_instructions_for('http') + end + end + + def visit_project + visit project_path(project) + end + + def select_protocol(protocol) + find('#clone-dropdown').click + find(".#{protocol.downcase}-selector").click + end + + def expect_instructions_for(protocol) + msg = :"#{protocol.downcase}_url_to_repo" + + expect(page).to have_content("git clone #{project.send(msg)}") + end +end diff --git a/spec/features/projects/show/download_buttons_spec.rb b/spec/features/projects/show/download_buttons_spec.rb new file mode 100644 index 00000000000..254affd4a94 --- /dev/null +++ b/spec/features/projects/show/download_buttons_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +feature 'Projects > Show > Download buttons' do + given(:user) { create(:user) } + given(:role) { :developer } + given(:status) { 'success' } + given(:project) { create(:project, :repository) } + + given(:pipeline) do + create(:ci_pipeline, + project: project, + sha: project.commit.sha, + ref: project.default_branch, + status: status) + end + + given!(:build) do + create(:ci_build, :success, :artifacts, + pipeline: pipeline, + status: pipeline.status, + name: 'build') + end + + background do + sign_in(user) + project.add_role(user, role) + end + + describe 'when checking project main page' do + context 'with artifacts' do + before do + visit project_path(project) + end + + scenario 'shows download artifacts button' do + href = latest_succeeded_project_artifacts_path(project, "#{project.default_branch}/download", job: 'build') + + expect(page).to have_link "Download '#{build.name}'", href: href + end + + scenario 'download links have download attribute' do + expect(page).to have_selector('a', text: 'Download') + page.all('a', text: 'Download').each do |link| + expect(link[:download]).to eq '' + end + end + end + end +end diff --git a/spec/features/projects/show/no_password_spec.rb b/spec/features/projects/show/no_password_spec.rb new file mode 100644 index 00000000000..b3b3212556c --- /dev/null +++ b/spec/features/projects/show/no_password_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +feature 'No Password Alert' do + let(:project) { create(:project, :repository, namespace: user.namespace) } + + context 'with internal auth enabled' do + before do + sign_in(user) + visit project_path(project) + end + + context 'when user has a password' do + let(:user) { create(:user) } + + it 'shows no alert' do + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + end + end + + context 'when user has password automatically set' do + let(:user) { create(:user, password_automatically_set: true) } + + it 'shows a password alert' do + expect(page).to have_content "You won't be able to pull or push project code via HTTP until you set a password on your account" + end + end + end + + context 'with internal auth disabled' do + let(:user) { create(:omniauth_user, extern_uid: 'my-uid', provider: 'saml') } + + before do + stub_application_setting(password_authentication_enabled_for_git?: false) + stub_omniauth_saml_config(enabled: true, auto_link_saml_user: true, allow_single_sign_on: ['saml'], providers: [mock_saml_config]) + end + + context 'when user has no personal access tokens' do + it 'has a personal access token alert' do + gitlab_sign_in_via('saml', user, 'my-uid') + visit project_path(project) + + expect(page).to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + end + end + + context 'when user has a personal access token' do + it 'shows no alert' do + create(:personal_access_token, user: user) + gitlab_sign_in_via('saml', user, 'my-uid') + visit project_path(project) + + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you create a personal access token on your account" + end + end + end + + context 'when user is ldap user' do + let(:user) { create(:omniauth_user, password_automatically_set: true) } + + before do + sign_in(user) + visit project_path(project) + end + + it 'shows no alert' do + expect(page).not_to have_content "You won't be able to pull or push project code via HTTP until you" + end + end +end diff --git a/spec/features/projects/show/redirects_spec.rb b/spec/features/projects/show/redirects_spec.rb new file mode 100644 index 00000000000..8d41c547d77 --- /dev/null +++ b/spec/features/projects/show/redirects_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe 'Projects > Show > Redirects' do + let(:user) { create :user } + let(:public_project) { create :project, :public } + let(:private_project) { create :project, :private } + + before do + allow(Gitlab.config.gitlab).to receive(:host).and_return('www.example.com') + end + + it 'shows public project page' do + visit project_path(public_project) + + page.within '.breadcrumbs .breadcrumb-item-text' do + expect(page).to have_content(public_project.name) + end + end + + it 'redirects to sign in page when project is private' do + visit project_path(private_project) + + expect(current_path).to eq(new_user_session_path) + end + + it 'redirects to sign in page when project does not exist' do + visit project_path(build(:project, :public)) + + expect(current_path).to eq(new_user_session_path) + end + + it 'redirects to public project page after signing in' do + visit project_path(public_project) + + first(:link, 'Sign in').click + + fill_in 'user_login', with: user.email + fill_in 'user_password', with: user.password + click_button 'Sign in' + + expect(status_code).to eq(200) + expect(current_path).to eq("/#{public_project.full_path}") + end + + it 'redirects to private project page after sign in' do + visit project_path(private_project) + + owner = private_project.owner + fill_in 'user_login', with: owner.email + fill_in 'user_password', with: owner.password + click_button 'Sign in' + + expect(status_code).to eq(200) + expect(current_path).to eq("/#{private_project.full_path}") + end + + context 'when signed in' do + before do + sign_in(user) + end + + it 'returns 404 status when project does not exist' do + visit project_path(build(:project, :public)) + + expect(status_code).to eq(404) + end + + it 'returns 404 when project is private' do + visit project_path(private_project) + + expect(status_code).to eq(404) + end + end +end diff --git a/spec/features/projects/show/rss_spec.rb b/spec/features/projects/show/rss_spec.rb new file mode 100644 index 00000000000..d02eaf34533 --- /dev/null +++ b/spec/features/projects/show/rss_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +feature 'Projects > Show > RSS' do + let(:user) { create(:user) } + let(:project) { create(:project, :repository, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let(:path) { project_path(project) } + + context 'when signed in' do + before do + project.add_developer(user) + sign_in(user) + visit path + end + + it_behaves_like "an autodiscoverable RSS feed with current_user's RSS token" + end + + context 'when signed out' do + before do + visit path + end + + it_behaves_like "an autodiscoverable RSS feed without an RSS token" + end +end diff --git a/spec/features/projects/show/user_interacts_with_stars_spec.rb b/spec/features/projects/show/user_interacts_with_stars_spec.rb new file mode 100644 index 00000000000..ba28c0e1b8a --- /dev/null +++ b/spec/features/projects/show/user_interacts_with_stars_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe 'Projects > Show > User interacts with project stars' do + let(:project) { create(:project, :public, :repository) } + + context 'when user is signed in', :js do + let(:user) { create(:user) } + + before do + sign_in(user) + visit(project_path(project)) + end + + it 'toggles the star' do + find('.star-btn').click + + expect(page).to have_css('.star-count', text: 1) + + find('.star-btn').click + + expect(page).to have_css('.star-count', text: 0) + end + end + + context 'when user is not signed in' do + before do + visit(project_path(project)) + end + + it 'does not allow to star a project' do + expect(page).not_to have_content('.toggle-star') + + find('.star-btn').click + + expect(current_path).to eq(new_user_session_path) + end + end +end diff --git a/spec/features/projects/show/user_manages_notifications_spec.rb b/spec/features/projects/show/user_manages_notifications_spec.rb new file mode 100644 index 00000000000..31b105229be --- /dev/null +++ b/spec/features/projects/show/user_manages_notifications_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'Projects > Show > User manages notifications', :js do + let(:project) { create(:project, :public, :repository) } + + before do + sign_in(project.owner) + visit project_path(project) + end + + it 'changes the notification setting' do + first('.notifications-btn').click + click_link 'On mention' + + page.within '#notifications-button' do + expect(page).to have_content 'On mention' + end + end +end diff --git a/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb new file mode 100644 index 00000000000..aa23bef6fd8 --- /dev/null +++ b/spec/features/projects/show/user_sees_deletion_failure_message_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe 'Projects > Show > User sees a deletion failure message' do + let(:project) { create(:project, :empty_repo, pending_delete: true) } + + before do + sign_in(project.owner) + end + + it 'shows error message if deletion for project fails' do + project.update_attributes(delete_error: "Something went wrong", pending_delete: false) + + visit project_path(project) + + expect(page).to have_selector('.project-deletion-failed-message') + expect(page).to have_content("This project was scheduled for deletion, but failed with the following message: #{project.delete_error}") + end +end diff --git a/spec/features/projects/show/user_sees_git_instructions_spec.rb b/spec/features/projects/show/user_sees_git_instructions_spec.rb new file mode 100644 index 00000000000..9a82fee1b5d --- /dev/null +++ b/spec/features/projects/show/user_sees_git_instructions_spec.rb @@ -0,0 +1,172 @@ +require 'spec_helper' + +describe 'Projects > Show > User sees Git instructions' do + set(:user) { create(:user) } + + shared_examples_for 'redirects to the sign in page' do + it 'redirects to the sign in page' do + expect(current_path).to eq(new_user_session_path) + end + end + + shared_examples_for 'shows details of empty project with no repo' do + it 'shows Git command line instructions' do + click_link 'Create empty repository' + + page.within '.empty_wrapper' do + expect(page).to have_content('Command line instructions') + end + end + end + + shared_examples_for 'shows details of empty project' do + let(:user_has_ssh_key) { false } + + it 'shows details' do + expect(page).not_to have_content('Git global setup') + + page.all(:css, '.git-empty .clone').each do |element| + expect(element.text).to include(project.http_url_to_repo) + end + + expect(page).to have_field('project_clone', with: project.http_url_to_repo) unless user_has_ssh_key + end + end + + shared_examples_for 'shows details of non empty project' do + let(:user_has_ssh_key) { false } + + it 'shows details' do + page.within('.breadcrumbs .breadcrumb-item-text') do + expect(page).to have_content(project.title) + end + + expect(page).to have_field('project_clone', with: project.http_url_to_repo) unless user_has_ssh_key + end + end + + context 'when project is public' do + context 'when project has no repo' do + set(:project) { create(:project, :public) } + + before do + sign_in(project.owner) + visit project_path(project) + end + + include_examples 'shows details of empty project with no repo' + end + + context 'when project is empty' do + set(:project) { create(:project_empty_repo, :public) } + + context 'when not signed in' do + before do + visit(project_path(project)) + end + + include_examples 'shows details of empty project' + end + + context 'when signed in' do + before do + sign_in(user) + end + + context 'when user does not have ssh keys' do + before do + visit(project_path(project)) + end + + include_examples 'shows details of empty project' + end + + context 'when user has ssh keys' do + before do + create(:personal_key, user: user) + + visit(project_path(project)) + end + + include_examples 'shows details of empty project' do + let(:user_has_ssh_key) { true } + end + end + end + end + + context 'when project is not empty' do + set(:project) { create(:project, :public, :repository) } + + before do + visit(project_path(project)) + end + + context 'when not signed in' do + before do + allow(Gitlab.config.gitlab).to receive(:host).and_return('www.example.com') + end + + include_examples 'shows details of non empty project' + end + + context 'when signed in' do + before do + sign_in(user) + end + + context 'when user does not have ssh keys' do + before do + visit(project_path(project)) + end + + include_examples 'shows details of non empty project' + end + + context 'when user has ssh keys' do + before do + create(:personal_key, user: user) + + visit(project_path(project)) + end + + include_examples 'shows details of non empty project' do + let(:user_has_ssh_key) { true } + end + end + end + end + end + + context 'when project is internal' do + set(:project) { create(:project, :internal, :repository) } + + context 'when not signed in' do + before do + visit(project_path(project)) + end + + include_examples 'redirects to the sign in page' + end + + context 'when signed in' do + before do + sign_in(user) + + visit(project_path(project)) + end + + include_examples 'shows details of non empty project' + end + end + + context 'when project is private' do + set(:project) { create(:project, :private) } + + before do + visit(project_path(project)) + end + + include_examples 'redirects to the sign in page' + end +end diff --git a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb new file mode 100644 index 00000000000..e277bfb8011 --- /dev/null +++ b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe 'Projects > Show > User sees last commit CI status' do + set(:project) { create(:project, :repository, :public) } + + it 'shows the project README', :js do + project.enable_ci + pipeline = create(:ci_pipeline, project: project, sha: project.commit.sha, ref: 'master') + pipeline.skip + + visit project_path(project) + + page.within '.blob-commit-info' do + expect(page).to have_content(project.commit.sha[0..6]) + expect(page).to have_link('Commit: skipped') + end + end +end diff --git a/spec/features/projects/show/user_sees_readme_spec.rb b/spec/features/projects/show/user_sees_readme_spec.rb new file mode 100644 index 00000000000..d80606c1c23 --- /dev/null +++ b/spec/features/projects/show/user_sees_readme_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'Projects > Show > User sees README' do + set(:user) { create(:user) } + + set(:project) { create(:project, :repository, :public) } + + it 'shows the project README', :js do + visit project_path(project) + wait_for_requests + + page.within('.readme-holder') do + expect(page).to have_content 'testme' + end + end +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 new file mode 100644 index 00000000000..a906fa20233 --- /dev/null +++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb @@ -0,0 +1,318 @@ +require 'spec_helper' + +describe 'Projects > Show > User sees setup shortcut buttons' 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 |