summaryrefslogtreecommitdiff
path: root/spec/features
diff options
context:
space:
mode:
Diffstat (limited to 'spec/features')
-rw-r--r--spec/features/admin/admin_builds_spec.rb26
-rw-r--r--spec/features/admin/admin_runners_spec.rb6
-rw-r--r--spec/features/admin/admin_users_spec.rb20
-rw-r--r--spec/features/atom/dashboard_issues_spec.rb51
-rw-r--r--spec/features/builds_spec.rb208
-rw-r--r--spec/features/commits_spec.rb66
-rw-r--r--spec/features/container_registry_spec.rb44
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb46
-rw-r--r--spec/features/groups/members/owner_manages_access_requests_spec.rb48
-rw-r--r--spec/features/groups/members/user_requests_access_spec.rb48
-rw-r--r--spec/features/issues/award_emoji_spec.rb2
-rw-r--r--spec/features/issues/award_spec.rb49
-rw-r--r--spec/features/issues/bulk_assigment_labels_spec.rb213
-rw-r--r--spec/features/issues/filter_by_labels_spec.rb50
-rw-r--r--spec/features/issues/filter_issues_spec.rb163
-rw-r--r--spec/features/issues/move_spec.rb16
-rw-r--r--spec/features/issues/note_polling_spec.rb5
-rw-r--r--spec/features/issues/todo_spec.rb33
-rw-r--r--spec/features/issues/update_issues_spec.rb23
-rw-r--r--spec/features/issues_spec.rb109
-rw-r--r--spec/features/login_spec.rb36
-rw-r--r--spec/features/markdown_spec.rb21
-rw-r--r--spec/features/merge_requests/award_spec.rb49
-rw-r--r--spec/features/merge_requests/created_from_fork_spec.rb58
-rw-r--r--spec/features/merge_requests/merge_when_build_succeeds_spec.rb8
-rw-r--r--spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb105
-rw-r--r--spec/features/merge_requests/user_lists_merge_requests_spec.rb9
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb33
-rw-r--r--spec/features/participants_autocomplete_spec.rb6
-rw-r--r--spec/features/pipelines_spec.rb189
-rw-r--r--spec/features/profiles/preferences_spec.rb8
-rw-r--r--spec/features/projects/badges/list_spec.rb5
-rw-r--r--spec/features/projects/commit/builds_spec.rb6
-rw-r--r--spec/features/projects/commits/cherry_pick_spec.rb1
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb30
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb8
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb4
-rw-r--r--spec/features/projects/labels/issues_sorted_by_priority_spec.rb87
-rw-r--r--spec/features/projects/labels/update_prioritization_spec.rb115
-rw-r--r--spec/features/projects/members/master_manages_access_requests_spec.rb47
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb54
-rw-r--r--spec/features/projects/shortcuts_spec.rb (renamed from spec/features/project/shortcuts_spec.rb)4
-rw-r--r--spec/features/runners_spec.rb37
-rw-r--r--spec/features/security/project/public_access_spec.rb4
-rw-r--r--spec/features/tags/master_updates_tag_spec.rb2
-rw-r--r--spec/features/task_lists_spec.rb5
-rw-r--r--spec/features/todos/target_state_spec.rb65
-rw-r--r--spec/features/todos/todos_spec.rb36
-rw-r--r--spec/features/u2f_spec.rb239
-rw-r--r--spec/features/variables_spec.rb61
50 files changed, 2322 insertions, 236 deletions
diff --git a/spec/features/admin/admin_builds_spec.rb b/spec/features/admin/admin_builds_spec.rb
index 7bbe20fec43..a6198389f04 100644
--- a/spec/features/admin/admin_builds_spec.rb
+++ b/spec/features/admin/admin_builds_spec.rb
@@ -6,15 +6,15 @@ describe 'Admin Builds' do
end
describe 'GET /admin/builds' do
- let(:commit) { create(:ci_commit) }
+ let(:pipeline) { create(:ci_pipeline) }
context 'All tab' do
context 'when have builds' do
it 'shows all builds' do
- create(:ci_build, commit: commit, status: :pending)
- create(:ci_build, commit: commit, status: :running)
- create(:ci_build, commit: commit, status: :success)
- create(:ci_build, commit: commit, status: :failed)
+ create(:ci_build, pipeline: pipeline, status: :pending)
+ create(:ci_build, pipeline: pipeline, status: :running)
+ create(:ci_build, pipeline: pipeline, status: :success)
+ create(:ci_build, pipeline: pipeline, status: :failed)
visit admin_builds_path
@@ -39,9 +39,9 @@ describe 'Admin Builds' do
context 'Running tab' do
context 'when have running builds' do
it 'shows running builds' do
- build1 = create(:ci_build, commit: commit, status: :pending)
- build2 = create(:ci_build, commit: commit, status: :success)
- build3 = create(:ci_build, commit: commit, status: :failed)
+ build1 = create(:ci_build, pipeline: pipeline, status: :pending)
+ build2 = create(:ci_build, pipeline: pipeline, status: :success)
+ build3 = create(:ci_build, pipeline: pipeline, status: :failed)
visit admin_builds_path(scope: :running)
@@ -55,7 +55,7 @@ describe 'Admin Builds' do
context 'when have no builds running' do
it 'shows a message' do
- create(:ci_build, commit: commit, status: :success)
+ create(:ci_build, pipeline: pipeline, status: :success)
visit admin_builds_path(scope: :running)
@@ -69,9 +69,9 @@ describe 'Admin Builds' do
context 'Finished tab' do
context 'when have finished builds' do
it 'shows finished builds' do
- build1 = create(:ci_build, commit: commit, status: :pending)
- build2 = create(:ci_build, commit: commit, status: :running)
- build3 = create(:ci_build, commit: commit, status: :success)
+ build1 = create(:ci_build, pipeline: pipeline, status: :pending)
+ build2 = create(:ci_build, pipeline: pipeline, status: :running)
+ build3 = create(:ci_build, pipeline: pipeline, status: :success)
visit admin_builds_path(scope: :finished)
@@ -85,7 +85,7 @@ describe 'Admin Builds' do
context 'when have no builds finished' do
it 'shows a message' do
- create(:ci_build, commit: commit, status: :running)
+ create(:ci_build, pipeline: pipeline, status: :running)
visit admin_builds_path(scope: :finished)
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 26d03944b8a..9499cd4e025 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -8,8 +8,8 @@ describe "Admin Runners" do
describe "Runners page" do
before do
runner = FactoryGirl.create(:ci_runner)
- commit = FactoryGirl.create(:ci_commit)
- FactoryGirl.create(:ci_build, commit: commit, runner_id: runner.id)
+ pipeline = FactoryGirl.create(:ci_pipeline)
+ FactoryGirl.create(:ci_build, pipeline: pipeline, runner_id: runner.id)
visit admin_runners_path
end
@@ -79,7 +79,7 @@ describe "Admin Runners" do
end
it 'changes registration token' do
- expect(page_token).to_not eq token
+ expect(page_token).not_to eq token
end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 6dee0cd8d47..1cb709c1de3 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -19,7 +19,7 @@ describe "Admin::Users", feature: true do
describe 'Two-factor Authentication filters' do
it 'counts users who have enabled 2FA' do
- create(:user, two_factor_enabled: true)
+ create(:user, :two_factor)
visit admin_users_path
@@ -29,7 +29,7 @@ describe "Admin::Users", feature: true do
end
it 'filters by users who have enabled 2FA' do
- user = create(:user, two_factor_enabled: true)
+ user = create(:user, :two_factor)
visit admin_users_path
click_link '2FA Enabled'
@@ -38,7 +38,7 @@ describe "Admin::Users", feature: true do
end
it 'counts users who have not enabled 2FA' do
- create(:user, two_factor_enabled: false)
+ create(:user)
visit admin_users_path
@@ -48,7 +48,7 @@ describe "Admin::Users", feature: true do
end
it 'filters by users who have not enabled 2FA' do
- user = create(:user, two_factor_enabled: false)
+ user = create(:user)
visit admin_users_path
click_link '2FA Disabled'
@@ -144,22 +144,22 @@ describe "Admin::Users", feature: true do
before { click_link 'Impersonate' }
it 'logs in as the user when impersonate is clicked' do
- page.within '.sidebar-user .username' do
- expect(page).to have_content(another_user.username)
+ page.within '.sidebar-wrapper' do
+ expect(page.find('.sidebar-user')['data-user']).to eql(another_user.username)
end
end
it 'sees impersonation log out icon' do
icon = first('.fa.fa-user-secret')
- expect(icon).to_not eql nil
+ expect(icon).not_to eql nil
end
it 'can log out of impersonated user back to original user' do
find(:css, 'li.impersonation a').click
- page.within '.sidebar-user .username' do
- expect(page).to have_content(@user.username)
+ page.within '.sidebar-wrapper' do
+ expect(page.find('.sidebar-user')['data-user']).to eql(@user.username)
end
end
@@ -173,7 +173,7 @@ describe "Admin::Users", feature: true do
describe 'Two-factor Authentication status' do
it 'shows when enabled' do
- @user.update_attribute(:two_factor_enabled, true)
+ @user.update_attribute(:otp_required_for_login, true)
visit admin_user_path(@user)
diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb
index b710cb3c72f..4dd9548cfc5 100644
--- a/spec/features/atom/dashboard_issues_spec.rb
+++ b/spec/features/atom/dashboard_issues_spec.rb
@@ -5,8 +5,6 @@ describe "Dashboard Issues Feed", feature: true do
let!(:user) { create(:user) }
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
- let!(:issue1) { create(:issue, author: user, assignee: user, project: project1) }
- let!(:issue2) { create(:issue, author: user, assignee: user, project: project2) }
before do
project1.team << [user, :master]
@@ -14,16 +12,51 @@ describe "Dashboard Issues Feed", feature: true do
end
describe "atom feed" do
- it "should render atom feed via private token" do
+ it "renders atom feed via private token" do
visit issues_dashboard_path(:atom, private_token: user.private_token)
- expect(response_headers['Content-Type']).
- to have_content('application/atom+xml')
+ expect(response_headers['Content-Type']).to have_content('application/atom+xml')
expect(body).to have_selector('title', text: "#{user.name} issues")
- expect(body).to have_selector('author email', text: issue1.author_email)
- expect(body).to have_selector('entry summary', text: issue1.title)
- expect(body).to have_selector('author email', text: issue2.author_email)
- expect(body).to have_selector('entry summary', text: issue2.title)
+ end
+
+ context "issue with basic fields" do
+ let!(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'test desc') }
+
+ it "renders issue fields" do
+ visit issues_dashboard_path(:atom, private_token: user.private_token)
+
+ entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue2.title}')]")
+
+ expect(entry).to be_present
+ expect(entry).to have_selector('author email', text: issue2.author_email)
+ expect(entry).to have_selector('assignee email', text: issue2.author_email)
+ expect(entry).not_to have_selector('labels')
+ expect(entry).not_to have_selector('milestone')
+ expect(entry).to have_selector('description', text: issue2.description)
+ end
+ end
+
+ context "issue with label and milestone" do
+ let!(:milestone1) { create(:milestone, project: project1, title: 'v1') }
+ let!(:label1) { create(:label, project: project1, title: 'label1') }
+ let!(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone1) }
+
+ before do
+ issue1.labels << label1
+ end
+
+ it "renders issue label and milestone info" do
+ visit issues_dashboard_path(:atom, private_token: user.private_token)
+
+ entry = find(:xpath, "//feed/entry[contains(summary/text(),'#{issue1.title}')]")
+
+ expect(entry).to be_present
+ expect(entry).to have_selector('author email', text: issue1.author_email)
+ expect(entry).to have_selector('assignee email', text: issue1.author_email)
+ expect(entry).to have_selector('labels label', text: label1.title)
+ expect(entry).to have_selector('milestone', text: milestone1.title)
+ expect(entry).not_to have_selector('description')
+ end
end
end
end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index f83a78308e3..16832c297ac 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -5,8 +5,9 @@ describe "Builds" do
before do
login_as(:user)
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
+ @commit = FactoryGirl.create :ci_pipeline
+ @build = FactoryGirl.create :ci_build, pipeline: @commit
+ @build2 = FactoryGirl.create :ci_build
@project = @commit.project
@project.team << [@user, :developer]
end
@@ -43,11 +44,10 @@ describe "Builds" do
end
it { expect(page).to have_selector('.nav-links li.active', text: 'All') }
- it { expect(page).to have_selector('.row-content-block', text: 'All builds from this project') }
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
- it { expect(page).to_not have_link 'Cancel running' }
+ it { expect(page).not_to have_link 'Cancel running' }
end
end
@@ -63,17 +63,28 @@ describe "Builds" do
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
- it { expect(page).to_not have_link 'Cancel running' }
+ it { expect(page).not_to have_link 'Cancel running' }
end
describe "GET /:project/builds/:id" do
- before do
- visit namespace_project_build_path(@project.namespace, @project, @build)
+ context "Build from project" do
+ before do
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ end
+
+ it { expect(page.status_code).to eq(200) }
+ it { expect(page).to have_content @commit.sha[0..7] }
+ it { expect(page).to have_content @commit.git_commit_message }
+ it { expect(page).to have_content @commit.git_author_name }
end
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
+ context "Build from other project" do
+ before do
+ visit namespace_project_build_path(@project.namespace, @project, @build2)
+ end
+
+ it { expect(page.status_code).to eq(404) }
+ end
context "Download artifacts" do
before do
@@ -82,8 +93,42 @@ describe "Builds" do
end
it 'has button to download artifacts' do
- page.within('.artifacts') do
- expect(page).to have_content 'Download'
+ expect(page).to have_content 'Download'
+ end
+ end
+
+ context 'Artifacts expire date' do
+ before do
+ @build.update_attributes(artifacts_file: artifacts_file, artifacts_expire_at: expire_at)
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ end
+
+ context 'no expire date defined' do
+ let(:expire_at) { nil }
+
+ it 'does not have the Keep button' do
+ expect(page).not_to have_content 'Keep'
+ end
+ end
+
+ context 'when expire date is defined' do
+ let(:expire_at) { Time.now + 7.days }
+
+ it 'keeps artifacts when Keep button is clicked' do
+ expect(page).to have_content 'The artifacts will be removed'
+ click_link 'Keep'
+
+ expect(page).not_to have_link 'Keep'
+ expect(page).not_to have_content 'The artifacts will be removed'
+ end
+ end
+
+ context 'when artifacts expired' do
+ let(:expire_at) { Time.now - 7.days }
+
+ it 'does not have the Keep button' do
+ expect(page).to have_content 'The artifacts were removed'
+ expect(page).not_to have_link 'Keep'
end
end
end
@@ -96,59 +141,144 @@ describe "Builds" do
end
it do
- page.within('.build-controls') do
- expect(page).to have_link 'Raw'
- end
+ expect(page).to have_link 'Raw'
end
end
end
describe "POST /:project/builds/:id/cancel" do
- before do
- @build.run!
- visit namespace_project_build_path(@project.namespace, @project, @build)
- click_link "Cancel"
+ context "Build from project" do
+ before do
+ @build.run!
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ click_link "Cancel"
+ end
+
+ it { expect(page.status_code).to eq(200) }
+ it { expect(page).to have_content 'canceled' }
+ it { expect(page).to have_content 'Retry' }
end
- it { expect(page).to have_content 'canceled' }
- it { expect(page).to have_content 'Retry' }
+ context "Build from other project" do
+ before do
+ @build.run!
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ page.driver.post(cancel_namespace_project_build_path(@project.namespace, @project, @build2))
+ end
+
+ it { expect(page.status_code).to eq(404) }
+ end
end
describe "POST /:project/builds/:id/retry" do
- before do
- @build.run!
- visit namespace_project_build_path(@project.namespace, @project, @build)
- click_link "Cancel"
- click_link 'Retry'
+ context "Build from project" do
+ before do
+ @build.run!
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ click_link 'Cancel'
+ click_link 'Retry'
+ end
+
+ it { expect(page.status_code).to eq(200) }
+ it { expect(page).to have_content 'pending' }
+ it { expect(page).to have_content 'Cancel' }
end
- it { expect(page).to have_content 'pending' }
- it { expect(page).to have_content 'Cancel' }
+ context "Build from other project" do
+ before do
+ @build.run!
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ click_link 'Cancel'
+ page.driver.post(retry_namespace_project_build_path(@project.namespace, @project, @build2))
+ end
+
+ it { expect(page.status_code).to eq(404) }
+ end
end
describe "GET /:project/builds/:id/download" do
before do
@build.update_attributes(artifacts_file: artifacts_file)
visit namespace_project_build_path(@project.namespace, @project, @build)
- page.within('.artifacts') { click_link 'Download' }
+ click_link 'Download'
end
- it { expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type) }
+ context "Build from other project" do
+ before do
+ @build2.update_attributes(artifacts_file: artifacts_file)
+ visit download_namespace_project_build_artifacts_path(@project.namespace, @project, @build2)
+ end
+
+ it { expect(page.status_code).to eq(404) }
+ end
end
describe "GET /:project/builds/:id/raw" do
- before do
- Capybara.current_session.driver.header('X-Sendfile-Type', 'X-Sendfile')
- @build.run!
- @build.trace = 'BUILD TRACE'
- visit namespace_project_build_path(@project.namespace, @project, @build)
+ context "Build from project" do
+ before do
+ Capybara.current_session.driver.header('X-Sendfile-Type', 'X-Sendfile')
+ @build.run!
+ @build.trace = 'BUILD TRACE'
+ visit namespace_project_build_path(@project.namespace, @project, @build)
+ page.within('.js-build-sidebar') { click_link 'Raw' }
+ end
+
+ it 'sends the right headers' do
+ expect(page.status_code).to eq(200)
+ expect(page.response_headers['Content-Type']).to eq('text/plain; charset=utf-8')
+ expect(page.response_headers['X-Sendfile']).to eq(@build.path_to_trace)
+ end
+ end
+
+ context "Build from other project" do
+ before do
+ Capybara.current_session.driver.header('X-Sendfile-Type', 'X-Sendfile')
+ @build2.run!
+ @build2.trace = 'BUILD TRACE'
+ visit raw_namespace_project_build_path(@project.namespace, @project, @build2)
+ puts page.status_code
+ puts current_url
+ end
+
+ it 'sends the right headers' do
+ expect(page.status_code).to eq(404)
+ end
+ end
+ end
+
+ describe "GET /:project/builds/:id/trace.json" do
+ context "Build from project" do
+ before do
+ visit trace_namespace_project_build_path(@project.namespace, @project, @build, format: :json)
+ end
+
+ it { expect(page.status_code).to eq(200) }
+ end
+
+ context "Build from other project" do
+ before do
+ visit trace_namespace_project_build_path(@project.namespace, @project, @build2, format: :json)
+ end
+
+ it { expect(page.status_code).to eq(404) }
+ end
+ end
+
+ describe "GET /:project/builds/:id/status" do
+ context "Build from project" do
+ before do
+ visit status_namespace_project_build_path(@project.namespace, @project, @build)
+ end
+
+ it { expect(page.status_code).to eq(200) }
end
- it 'sends the right headers' do
- page.within('.build-controls') { click_link 'Raw' }
+ context "Build from other project" do
+ before do
+ visit status_namespace_project_build_path(@project.namespace, @project, @build2)
+ end
- expect(page.response_headers['Content-Type']).to eq('text/plain; charset=utf-8')
- expect(page.response_headers['X-Sendfile']).to eq(@build.path_to_trace)
+ it { expect(page.status_code).to eq(404) }
end
end
end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index dacaa96d760..45e1a157a1f 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -8,15 +8,15 @@ describe 'Commits' do
describe 'CI' do
before do
login_as :user
- stub_ci_commit_to_return_yaml_file
+ stub_ci_pipeline_to_return_yaml_file
end
- let!(:commit) do
- FactoryGirl.create :ci_commit, project: project, sha: project.commit.sha
+ let!(:pipeline) do
+ FactoryGirl.create :ci_pipeline, project: project, sha: project.commit.sha
end
context 'commit status is Generic Commit Status' do
- let!(:status) { FactoryGirl.create :generic_commit_status, commit: commit }
+ let!(:status) { FactoryGirl.create :generic_commit_status, pipeline: pipeline }
before do
project.team << [@user, :reporter]
@@ -24,10 +24,10 @@ describe 'Commits' do
describe 'Commit builds' do
before do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
end
- it { expect(page).to have_content commit.sha[0..7] }
+ it { expect(page).to have_content pipeline.sha[0..7] }
it 'contains generic commit status build' do
page.within('.table-holder') do
@@ -39,7 +39,7 @@ describe 'Commits' do
end
context 'commit status is Ci Build' do
- let!(:build) { FactoryGirl.create :ci_build, commit: commit }
+ let!(:build) { FactoryGirl.create :ci_build, pipeline: pipeline }
let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
context 'when logged as developer' do
@@ -53,7 +53,7 @@ describe 'Commits' do
end
it 'should show build status' do
- page.within("//li[@id='commit-#{commit.short_sha}']") do
+ page.within("//li[@id='commit-#{pipeline.short_sha}']") do
expect(page).to have_css(".ci-status-link")
end
end
@@ -61,12 +61,12 @@ describe 'Commits' do
describe 'Commit builds' do
before do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
end
- it { expect(page).to have_content commit.sha[0..7] }
- it { expect(page).to have_content commit.git_commit_message }
- it { expect(page).to have_content commit.git_author_name }
+ it { expect(page).to have_content pipeline.sha[0..7] }
+ it { expect(page).to have_content pipeline.git_commit_message }
+ it { expect(page).to have_content pipeline.git_author_name }
end
context 'Download artifacts' do
@@ -75,7 +75,7 @@ describe 'Commits' do
end
it do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
click_on 'Download artifacts'
expect(page.response_headers['Content-Type']).to eq(artifacts_file.content_type)
end
@@ -83,7 +83,7 @@ describe 'Commits' do
describe 'Cancel all builds' do
it 'cancels commit' do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
click_on 'Cancel running'
expect(page).to have_content 'canceled'
end
@@ -91,7 +91,7 @@ describe 'Commits' do
describe 'Cancel build' do
it 'cancels build' do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
click_on 'Cancel'
expect(page).to have_content 'canceled'
end
@@ -100,13 +100,13 @@ describe 'Commits' do
describe '.gitlab-ci.yml not found warning' do
context 'ci builds enabled' do
it "does not show warning" do
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
expect(page).not_to have_content '.gitlab-ci.yml not found in this commit'
end
it 'shows warning' do
- stub_ci_commit_yaml_file(nil)
- visit ci_status_path(commit)
+ stub_ci_pipeline_yaml_file(nil)
+ visit ci_status_path(pipeline)
expect(page).to have_content '.gitlab-ci.yml not found in this commit'
end
end
@@ -114,8 +114,8 @@ describe 'Commits' do
context 'ci builds disabled' do
before do
stub_ci_builds_disabled
- stub_ci_commit_yaml_file(nil)
- visit ci_status_path(commit)
+ stub_ci_pipeline_yaml_file(nil)
+ visit ci_status_path(pipeline)
end
it 'does not show warning' do
@@ -129,16 +129,16 @@ describe 'Commits' do
before do
project.team << [@user, :reporter]
build.update_attributes(artifacts_file: artifacts_file)
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
end
it do
- expect(page).to have_content commit.sha[0..7]
- expect(page).to have_content commit.git_commit_message
- expect(page).to have_content commit.git_author_name
+ expect(page).to have_content pipeline.sha[0..7]
+ expect(page).to have_content pipeline.git_commit_message
+ expect(page).to have_content pipeline.git_author_name
expect(page).to have_link('Download artifacts')
- expect(page).to_not have_link('Cancel running')
- expect(page).to_not have_link('Retry failed')
+ expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Retry failed')
end
end
@@ -148,16 +148,16 @@ describe 'Commits' do
visibility_level: Gitlab::VisibilityLevel::INTERNAL,
public_builds: false)
build.update_attributes(artifacts_file: artifacts_file)
- visit ci_status_path(commit)
+ visit ci_status_path(pipeline)
end
it do
- expect(page).to have_content commit.sha[0..7]
- expect(page).to have_content commit.git_commit_message
- expect(page).to have_content commit.git_author_name
- expect(page).to_not have_link('Download artifacts')
- expect(page).to_not have_link('Cancel running')
- expect(page).to_not have_link('Retry failed')
+ expect(page).to have_content pipeline.sha[0..7]
+ expect(page).to have_content pipeline.git_commit_message
+ expect(page).to have_content pipeline.git_author_name
+ expect(page).not_to have_link('Download artifacts')
+ expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Retry failed')
end
end
end
diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb
new file mode 100644
index 00000000000..53b4f027117
--- /dev/null
+++ b/spec/features/container_registry_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe "Container Registry" do
+ let(:project) { create(:empty_project) }
+ let(:repository) { project.container_registry_repository }
+ let(:tag_name) { 'latest' }
+ let(:tags) { [tag_name] }
+
+ before do
+ login_as(:user)
+ project.team << [@user, :developer]
+ stub_container_registry_tags(*tags)
+ stub_container_registry_config(enabled: true)
+ allow(Auth::ContainerRegistryAuthenticationService).to receive(:full_access_token).and_return('token')
+ end
+
+ describe 'GET /:project/container_registry' do
+ before do
+ visit namespace_project_container_registry_index_path(project.namespace, project)
+ end
+
+ context 'when no tags' do
+ let(:tags) { [] }
+
+ it { expect(page).to have_content('No images in Container Registry for this project') }
+ end
+
+ context 'when there are tags' do
+ it { expect(page).to have_content(tag_name)}
+ end
+ end
+
+ describe 'DELETE /:project/container_registry/tag' do
+ before do
+ visit namespace_project_container_registry_index_path(project.namespace, project)
+ end
+
+ it do
+ expect_any_instance_of(::ContainerRegistry::Tag).to receive(:delete).and_return(true)
+
+ click_on 'Remove'
+ end
+ end
+end
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
new file mode 100644
index 00000000000..365cb445df1
--- /dev/null
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -0,0 +1,46 @@
+require 'spec_helper'
+
+feature 'Tooltips on .timeago dates', feature: true, js: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+ let(:created_date) { Date.yesterday.to_time }
+ let(:expected_format) { created_date.strftime('%b %-d, %Y %l:%M%P UTC') }
+
+ context 'on the activity tab' do
+ before do
+ project.team << [user, :master]
+
+ Event.create( project: project, author_id: user.id, action: Event::JOINED,
+ updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+
+ context 'on the snippets tab' do
+ before do
+ project.team << [user, :master]
+ create(:snippet, author: user, updated_at: created_date, created_at: created_date)
+
+ login_as user
+ visit user_snippets_path(user)
+ wait_for_ajax()
+
+ page.find('.js-timeago').hover
+ end
+
+ it 'has the datetime formated correctly' do
+ expect(page).to have_selector('.local-timeago', text: expected_format)
+ end
+ end
+end
diff --git a/spec/features/groups/members/owner_manages_access_requests_spec.rb b/spec/features/groups/members/owner_manages_access_requests_spec.rb
new file mode 100644
index 00000000000..22525ce530b
--- /dev/null
+++ b/spec/features/groups/members/owner_manages_access_requests_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+feature 'Groups > Members > Owner manages access requests', feature: true do
+ let(:user) { create(:user) }
+ let(:owner) { create(:user) }
+ let(:group) { create(:group, :public) }
+
+ background do
+ group.request_access(user)
+ group.add_owner(owner)
+ login_as(owner)
+ end
+
+ scenario 'owner can see access requests' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+ end
+
+ scenario 'master can grant access' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+
+ perform_enqueued_jobs { click_on 'Grant access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{group.name} group was granted"
+ end
+
+ scenario 'master can deny access' do
+ visit group_group_members_path(group)
+
+ expect_visible_access_request(group, user)
+
+ perform_enqueued_jobs { click_on 'Deny access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{group.name} group was denied"
+ end
+
+
+ def expect_visible_access_request(group, user)
+ expect(group.members.request.exists?(user_id: user)).to be_truthy
+ expect(page).to have_content "#{group.name} access requests (1)"
+ expect(page).to have_content user.name
+ end
+end
diff --git a/spec/features/groups/members/user_requests_access_spec.rb b/spec/features/groups/members/user_requests_access_spec.rb
new file mode 100644
index 00000000000..a878a96b6ee
--- /dev/null
+++ b/spec/features/groups/members/user_requests_access_spec.rb
@@ -0,0 +1,48 @@
+require 'spec_helper'
+
+feature 'Groups > Members > User requests access', feature: true do
+ let(:user) { create(:user) }
+ let(:owner) { create(:user) }
+ let(:group) { create(:group, :public) }
+
+ background do
+ group.add_owner(owner)
+ login_as(user)
+ visit group_path(group)
+ end
+
+ scenario 'user can request access to a group' do
+ perform_enqueued_jobs { click_link 'Request Access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [owner.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Request to join the #{group.name} group"
+
+ expect(group.members.request.exists?(user_id: user)).to be_truthy
+ expect(page).to have_content 'Your request for access has been queued for review.'
+
+ expect(page).to have_content 'Withdraw Access Request'
+ end
+
+ scenario 'user is not listed in the group members page' do
+ click_link 'Request Access'
+
+ expect(group.members.request.exists?(user_id: user)).to be_truthy
+
+ click_link 'Members'
+
+ page.within('.content') do
+ expect(page).not_to have_content(user.name)
+ end
+ end
+
+ scenario 'user can withdraw its request for access' do
+ click_link 'Request Access'
+
+ expect(group.members.request.exists?(user_id: user)).to be_truthy
+
+ click_link 'Withdraw Access Request'
+
+ expect(group.members.request.exists?(user_id: user)).to be_falsey
+ expect(page).to have_content 'Your access request to the group has been withdrawn.'
+ end
+end
diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb
index 41af789aae2..07a854ea014 100644
--- a/spec/features/issues/award_emoji_spec.rb
+++ b/spec/features/issues/award_emoji_spec.rb
@@ -28,7 +28,6 @@ describe 'Awards Emoji', feature: true do
end
context 'click the thumbsup emoji' do
-
it 'should increment the thumbsup emoji', js: true do
find('[data-emoji="thumbsup"]').click
sleep 2
@@ -41,7 +40,6 @@ describe 'Awards Emoji', feature: true do
end
context 'click the thumbsdown emoji' do
-
it 'should increment the thumbsdown emoji', js: true do
find('[data-emoji="thumbsdown"]').click
sleep 2
diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb
new file mode 100644
index 00000000000..63efecf8780
--- /dev/null
+++ b/spec/features/issues/award_spec.rb
@@ -0,0 +1,49 @@
+require 'rails_helper'
+
+feature 'Issue awards', js: true, feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:issue) { create(:issue, project: project) }
+
+ describe 'logged in' do
+ before do
+ login_as(user)
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should add award to issue' do
+ first('.js-emoji-btn').click
+ expect(page).to have_selector('.js-emoji-btn.active')
+ expect(first('.js-emoji-btn')).to have_content '1'
+
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(first('.js-emoji-btn')).to have_content '1'
+ end
+
+ it 'should remove award from issue' do
+ first('.js-emoji-btn').click
+ find('.js-emoji-btn.active').click
+ expect(first('.js-emoji-btn')).to have_content '0'
+
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ expect(first('.js-emoji-btn')).to have_content '0'
+ end
+
+ it 'should only have one menu on the page' do
+ first('.js-add-award').click
+ expect(page).to have_selector('.emoji-menu')
+
+ expect(page).to have_selector('.emoji-menu', count: 1)
+ end
+ end
+
+ describe 'logged out' do
+ before do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should not see award menu button' do
+ expect(page).not_to have_selector('.js-award-holder')
+ end
+ end
+end
diff --git a/spec/features/issues/bulk_assigment_labels_spec.rb b/spec/features/issues/bulk_assigment_labels_spec.rb
new file mode 100644
index 00000000000..0fbc2062e39
--- /dev/null
+++ b/spec/features/issues/bulk_assigment_labels_spec.rb
@@ -0,0 +1,213 @@
+require 'rails_helper'
+
+feature 'Issues > Labels bulk assignment', feature: true do
+ include WaitForAjax
+
+ let(:user) { create(:user) }
+ let!(:project) { create(:project) }
+ let!(:issue1) { create(:issue, project: project, title: "Issue 1") }
+ let!(:issue2) { create(:issue, project: project, title: "Issue 2") }
+ let!(:bug) { create(:label, project: project, title: 'bug') }
+ let!(:feature) { create(:label, project: project, title: 'feature') }
+
+ context 'as a allowed user', js: true do
+ before do
+ project.team << [user, :master]
+
+ login_as user
+ end
+
+ context 'can bulk assign' do
+ before do
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ context 'a label' do
+ context 'to all issues' do
+ before do
+ check 'check_all_issues'
+ open_labels_dropdown ['bug']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).to have_content 'bug'
+ end
+ end
+
+ context 'to a issue' do
+ before do
+ check "selected_issue_#{issue1.id}"
+ open_labels_dropdown ['bug']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'bug'
+ end
+ end
+ end
+
+ context 'multiple labels' do
+ context 'to all issues' do
+ before do
+ check 'check_all_issues'
+ open_labels_dropdown ['bug', 'feature']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue1.id}")).to have_content 'feature'
+ expect(find("#issue_#{issue2.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).to have_content 'feature'
+ end
+ end
+
+ context 'to a issue' do
+ before do
+ check "selected_issue_#{issue1.id}"
+ open_labels_dropdown ['bug', 'feature']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue1.id}")).to have_content 'feature'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'feature'
+ end
+ end
+ end
+ end
+
+ context 'can assign a label to all issues when label is present' do
+ before do
+ issue2.labels << bug
+ issue2.labels << feature
+ visit namespace_project_issues_path(project.namespace, project)
+
+ check 'check_all_issues'
+ open_labels_dropdown ['bug']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).to have_content 'bug'
+ end
+ end
+
+ context 'can bulk un-assign' do
+ context 'all labels to all issues' do
+ before do
+ issue1.labels << bug
+ issue1.labels << feature
+ issue2.labels << bug
+ issue2.labels << feature
+
+ visit namespace_project_issues_path(project.namespace, project)
+
+ check 'check_all_issues'
+ unmark_labels_in_dropdown ['bug', 'feature']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue1.id}")).not_to have_content 'feature'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'feature'
+ end
+ end
+
+ context 'a label to a issue' do
+ before do
+ issue1.labels << bug
+ issue2.labels << feature
+
+ visit namespace_project_issues_path(project.namespace, project)
+
+ check_issue issue1
+ unmark_labels_in_dropdown ['bug']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).to have_content 'feature'
+ end
+ end
+
+ context 'a label and keep the others label' do
+ before do
+ issue1.labels << bug
+ issue1.labels << feature
+ issue2.labels << bug
+ issue2.labels << feature
+
+ visit namespace_project_issues_path(project.namespace, project)
+
+ check_issue issue1
+ check_issue issue2
+ unmark_labels_in_dropdown ['bug']
+ update_issues
+ end
+
+ it do
+ expect(find("#issue_#{issue1.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue1.id}")).to have_content 'feature'
+ expect(find("#issue_#{issue2.id}")).not_to have_content 'bug'
+ expect(find("#issue_#{issue2.id}")).to have_content 'feature'
+ end
+ end
+ end
+ end
+
+ context 'as a guest' do
+ before do
+ login_as user
+
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ context 'cannot bulk assign labels' do
+ it do
+ expect(page).not_to have_css '.check_all_issues'
+ expect(page).not_to have_css '.issue-check'
+ end
+ end
+ end
+
+ def open_labels_dropdown(items = [], unmark = false)
+ page.within('.issues_bulk_update') do
+ click_button 'Label'
+ wait_for_ajax
+ items.map do |item|
+ click_link item
+ end
+ if unmark
+ items.map do |item|
+ click_link item
+ end
+ end
+ end
+ end
+
+ def unmark_labels_in_dropdown(items = [])
+ open_labels_dropdown(items, true)
+ end
+
+ def check_issue(issue)
+ page.within('.issues-list') do
+ check "selected_issue_#{issue.id}"
+ end
+ end
+
+ def update_issues
+ click_button 'Update issues'
+ wait_for_ajax
+ end
+end
diff --git a/spec/features/issues/filter_by_labels_spec.rb b/spec/features/issues/filter_by_labels_spec.rb
index 7f654684143..5ea02b8d39c 100644
--- a/spec/features/issues/filter_by_labels_spec.rb
+++ b/spec/features/issues/filter_by_labels_spec.rb
@@ -54,6 +54,12 @@ feature 'Issue filtering by Labels', feature: true do
expect(find('.filtered-labels')).not_to have_content "feature"
expect(find('.filtered-labels')).not_to have_content "enhancement"
end
+
+ it 'should remove label "bug"' do
+ find('.js-label-filter-remove').click
+ wait_for_ajax
+ expect(find('.filtered-labels', visible: false)).to have_no_content "bug"
+ end
end
context 'filter by label feature', js: true do
@@ -135,6 +141,12 @@ feature 'Issue filtering by Labels', feature: true do
it 'should not show label "bug" in filtered-labels' do
expect(find('.filtered-labels')).not_to have_content "bug"
end
+
+ it 'should remove label "enhancement"' do
+ find('.js-label-filter-remove', match: :first).click
+ wait_for_ajax
+ expect(find('.filtered-labels')).to have_no_content "enhancement"
+ end
end
context 'filter by label enhancement and bug in issues list', js: true do
@@ -164,4 +176,42 @@ feature 'Issue filtering by Labels', feature: true do
expect(find('.filtered-labels')).not_to have_content "feature"
end
end
+
+ context 'remove filtered labels', js: true do
+ before do
+ page.within '.labels-filter' do
+ click_button 'Label'
+ wait_for_ajax
+ click_link 'bug'
+ find('.dropdown-menu-close').click
+ end
+
+ page.within '.filtered-labels' do
+ expect(page).to have_content 'bug'
+ end
+ end
+
+ it 'should allow user to remove filtered labels' do
+ first('.js-label-filter-remove').click
+ wait_for_ajax
+
+ expect(find('.filtered-labels', visible: false)).not_to have_content 'bug'
+ expect(find('.labels-filter')).not_to have_content 'bug'
+ end
+ end
+
+ context 'dropdown filtering', js: true do
+ it 'should filter by label name' do
+ page.within '.labels-filter' do
+ click_button 'Label'
+ wait_for_ajax
+ fill_in 'label-name', with: 'bug'
+
+ page.within '.dropdown-content' do
+ expect(page).not_to have_content 'enhancement'
+ expect(page).to have_content 'bug'
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 192e3619375..4bcb105b17d 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -1,6 +1,7 @@
require 'rails_helper'
describe 'Filter issues', feature: true do
+ include WaitForAjax
let!(:project) { create(:project) }
let!(:user) { create(:user)}
@@ -21,7 +22,7 @@ describe 'Filter issues', feature: true do
find('.dropdown-menu-user-link', text: user.username).click
- sleep 2
+ wait_for_ajax
end
context 'assignee', js: true do
@@ -53,7 +54,7 @@ describe 'Filter issues', feature: true do
find('.milestone-filter .dropdown-content a', text: milestone.title).click
- sleep 2
+ wait_for_ajax
end
context 'milestone', js: true do
@@ -80,23 +81,21 @@ describe 'Filter issues', feature: true do
before do
visit namespace_project_issues_path(project.namespace, project)
find('.js-label-select').click
+ wait_for_ajax
end
it 'should filter by any label' do
find('.dropdown-menu-labels a', text: 'Any Label').click
page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
- sleep 2
+ wait_for_ajax
- page.within '.labels-filter' do
- expect(page).to have_content 'Any Label'
- end
- expect(find('.js-label-select .dropdown-toggle-text')).to have_content('Any Label')
+ expect(find('.labels-filter')).to have_content 'Label'
end
it 'should filter by no label' do
find('.dropdown-menu-labels a', text: 'No Label').click
page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
- sleep 2
+ wait_for_ajax
page.within '.labels-filter' do
expect(page).to have_content 'No Label'
@@ -122,14 +121,14 @@ describe 'Filter issues', feature: true do
find('.dropdown-menu-user-link', text: user.username).click
- sleep 2
+ wait_for_ajax
find('.js-label-select').click
find('.dropdown-menu-labels .dropdown-content a', text: label.title).click
page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
- sleep 2
+ wait_for_ajax
end
context 'assignee and label', js: true do
@@ -154,4 +153,148 @@ describe 'Filter issues', feature: true do
end
end
end
+
+ describe 'filter issues by text' do
+ before do
+ create(:issue, title: "Bug", project: project)
+
+ bug_label = create(:label, project: project, title: 'bug')
+ milestone = create(:milestone, title: "8", project: project)
+
+ issue = create(:issue,
+ title: "Bug 2",
+ project: project,
+ milestone: milestone,
+ author: user,
+ assignee: user)
+ issue.labels << bug_label
+
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ context 'only text', js: true do
+ it 'should filter issues by searched text' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+ end
+
+ it 'should not show any issues' do
+ fill_in 'issue_search', with: 'testing'
+
+ page.within '.issues-list' do
+ expect(page).not_to have_selector('.issue')
+ end
+ end
+ end
+
+ context 'text and dropdown options', js: true do
+ it 'should filter by text and label' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Label'
+ page.within '.labels-filter' do
+ click_link 'bug'
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and milestone' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Milestone'
+ page.within '.milestone-filter' do
+ click_link '8'
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and assignee' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Assignee'
+ page.within '.dropdown-menu-assignee' do
+ click_link user.name
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and author' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Author'
+ page.within '.dropdown-menu-author' do
+ click_link user.name
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+ end
+ end
+
+ describe 'filter issues and sort', js: true do
+ before do
+ bug_label = create(:label, project: project, title: 'bug')
+ bug_one = create(:issue, title: "Frontend", project: project)
+ bug_two = create(:issue, title: "Bug 2", project: project)
+
+ bug_one.labels << bug_label
+ bug_two.labels << bug_label
+
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ it 'should be able to filter and sort issues' do
+ click_button 'Label'
+ wait_for_ajax
+ page.within '.labels-filter' do
+ click_link 'bug'
+ end
+ find('.dropdown-menu-close-icon').click
+ wait_for_ajax
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Last created'
+ page.within '.dropdown-menu-sort' do
+ click_link 'Oldest created'
+ end
+ wait_for_ajax
+
+ page.within '.issues-list' do
+ expect(first('.issue')).to have_content('Frontend')
+ end
+ end
+ end
end
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index 84c8e20ebaa..c7019c5aea1 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -19,7 +19,7 @@ feature 'issue move to another project' do
end
scenario 'moving issue to another project not allowed' do
- expect(page).to have_no_select('move_to_project_id')
+ expect(page).to have_no_selector('#move_to_project_id')
end
end
@@ -37,7 +37,7 @@ feature 'issue move to another project' do
end
scenario 'moving issue to another project' do
- select(new_project.name_with_namespace, from: 'move_to_project_id')
+ first('#move_to_project_id', visible: false).set(new_project.id)
click_button('Save changes')
expect(current_url).to include project_path(new_project)
@@ -47,14 +47,18 @@ feature 'issue move to another project' do
expect(page).to have_content(issue.title)
end
- context 'projects user does not have permission to move issue to exist' do
+ context 'user does not have permission to move the issue to a project', js: true do
let!(:private_project) { create(:project, :private) }
let(:another_project) { create(:project) }
background { another_project.team << [user, :guest] }
scenario 'browsing projects in projects select' do
- options = [ '', 'No project', new_project.name_with_namespace ]
- expect(page).to have_select('move_to_project_id', options: options)
+ click_link 'Select project'
+
+ page.within '.select2-results' do
+ expect(page).to have_content 'No project'
+ expect(page).to have_content new_project.name_with_namespace
+ end
end
end
@@ -65,7 +69,7 @@ feature 'issue move to another project' do
end
scenario 'user wants to move issue that has already been moved' do
- expect(page).to have_no_select('move_to_project_id')
+ expect(page).to have_no_selector('#move_to_project_id')
end
end
end
diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb
index e4efdbe2421..f5cfe2d666e 100644
--- a/spec/features/issues/note_polling_spec.rb
+++ b/spec/features/issues/note_polling_spec.rb
@@ -9,8 +9,11 @@ feature 'Issue notes polling' do
end
scenario 'Another user adds a comment to an issue', js: true do
- note = create(:note_on_issue, noteable: issue, note: 'Looks good!')
+ note = create(:note, noteable: issue, project: project,
+ note: 'Looks good!')
+
page.execute_script('notes.refresh();')
+
expect(page).to have_selector("#note_#{note.id}", text: 'Looks good!')
end
end
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
new file mode 100644
index 00000000000..b69cce3e7d7
--- /dev/null
+++ b/spec/features/issues/todo_spec.rb
@@ -0,0 +1,33 @@
+require 'rails_helper'
+
+feature 'Manually create a todo item from issue', feature: true, js: true do
+ let!(:project) { create(:project) }
+ let!(:issue) { create(:issue, project: project) }
+ let!(:user) { create(:user)}
+
+ before do
+ project.team << [user, :master]
+ login_as(user)
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should create todo when clicking button' do
+ page.within '.issuable-sidebar' do
+ click_button 'Add Todo'
+ expect(page).to have_content 'Mark Done'
+ end
+
+ page.within '.header-content .todos-pending-count' do
+ expect(page).to have_content '1'
+ end
+ end
+
+ it 'should mark a todo as done' do
+ page.within '.issuable-sidebar' do
+ click_button 'Add Todo'
+ click_button 'Mark Done'
+ end
+
+ expect(page).to have_selector('.todos-pending-count', visible: false)
+ end
+end
diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb
index b03dd0f666d..ddbd69b2891 100644
--- a/spec/features/issues/update_issues_spec.rb
+++ b/spec/features/issues/update_issues_spec.rb
@@ -1,6 +1,8 @@
require 'rails_helper'
feature 'Multiple issue updating from issues#index', feature: true do
+ include WaitForAjax
+
let!(:project) { create(:project) }
let!(:issue) { create(:issue, project: project) }
let!(:user) { create(:user)}
@@ -24,9 +26,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
it 'should be set to open' do
create_closed
- visit namespace_project_issues_path(project.namespace, project)
-
- find('.issues-state-filters a', text: 'Closed').click
+ visit namespace_project_issues_path(project.namespace, project, state: 'closed')
find('#check_all_issues').click
find('.js-issue-status').click
@@ -42,7 +42,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
visit namespace_project_issues_path(project.namespace, project)
find('#check_all_issues').click
- find('.js-update-assignee').click
+ click_update_assignee_button
find('.dropdown-menu-user-link', text: user.username).click
click_update_issues_button
@@ -57,14 +57,11 @@ feature 'Multiple issue updating from issues#index', feature: true do
visit namespace_project_issues_path(project.namespace, project)
find('#check_all_issues').click
- find('.js-update-assignee').click
+ click_update_assignee_button
click_link 'Unassigned'
click_update_issues_button
-
- within first('.issue .controls') do
- expect(page).to have_no_selector('.author_link')
- end
+ expect(find('.issue:first-child .controls')).not_to have_css('.author_link')
end
end
@@ -95,7 +92,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
find('.dropdown-menu-milestone a', text: "No Milestone").click
click_update_issues_button
- expect(first('.issue')).to_not have_content milestone.title
+ expect(find('.issue:first-child')).not_to have_content milestone.title
end
end
@@ -111,7 +108,13 @@ feature 'Multiple issue updating from issues#index', feature: true do
create(:issue, project: project, milestone: milestone)
end
+ def click_update_assignee_button
+ find('.js-update-assignee').click
+ wait_for_ajax
+ end
+
def click_update_issues_button
find('.update_selected_issues').click
+ wait_for_ajax
end
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index d5755c293c5..f6fb6a72d22 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -64,10 +64,70 @@ describe 'Issues', feature: true do
end
end
+ describe 'due date', js: true do
+ context 'on new form' do
+ before do
+ visit new_namespace_project_issue_path(project.namespace, project)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
+
+ page.within '.ui-datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date').value).to eq date.to_s
+
+ click_button 'Submit issue'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+
+ context 'on edit form' do
+ let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) }
+
+ before do
+ visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ expect(find('#issuable-due-date').value).to eq date.to_s
+
+ date = date.tomorrow
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
+
+ page.within '.ui-datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date').value).to eq date.to_s
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+ end
+
describe 'Issue info' do
it 'excludes award_emoji from comment count' do
issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
- create(:upvote_note, noteable: issue)
+ create(:award_emoji, awardable: issue)
visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)
@@ -307,13 +367,9 @@ describe 'Issues', feature: true do
page.within('.assignee') do
expect(page).to have_content "#{@user.name}"
- end
- find('.block.assignee .edit-link').click
- sleep 2 # wait for ajax stuff to complete
- first('.dropdown-menu-user-link').click
- sleep 2
- page.within('.assignee') do
+ click_link 'Edit'
+ click_link 'Unassigned'
expect(page).to have_content 'No assignee'
end
@@ -331,7 +387,7 @@ describe 'Issues', feature: true do
page.within '.assignee' do
click_link 'Edit'
end
-
+
page.within '.dropdown-menu-user' do
click_link @user.name
end
@@ -431,6 +487,43 @@ describe 'Issues', feature: true do
end
end
+ describe 'due date' do
+ context 'update due on issue#show', js: true do
+ let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
+
+ before do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should add due date to issue' do
+ page.within '.due_date' do
+ click_link 'Edit'
+
+ page.within '.ui-datepicker-calendar' do
+ first('.ui-state-default').click
+ end
+
+ expect(page).to have_no_content 'None'
+ end
+ end
+
+ it 'should remove due date from issue' do
+ page.within '.due_date' do
+ click_link 'Edit'
+
+ page.within '.ui-datepicker-calendar' do
+ first('.ui-state-default').click
+ end
+
+ expect(page).to have_no_content 'None'
+
+ click_link 'remove due date'
+ expect(page).to have_content 'None'
+ end
+ end
+ end
+ end
+
def first_issue
page.all('ul.issues-list > li').first.text
end
diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb
index 8c38dd5b122..72b5ff231f7 100644
--- a/spec/features/login_spec.rb
+++ b/spec/features/login_spec.rb
@@ -32,12 +32,12 @@ feature 'Login', feature: true do
let(:user) { create(:user, :two_factor) }
before do
- login_with(user)
- expect(page).to have_content('Two-factor Authentication')
+ login_with(user, remember: true)
+ expect(page).to have_content('Two-Factor Authentication')
end
def enter_code(code)
- fill_in 'Two-factor Authentication code', with: code
+ fill_in 'Two-Factor Authentication code', with: code
click_button 'Verify code'
end
@@ -52,6 +52,12 @@ feature 'Login', feature: true do
expect(current_path).to eq root_path
end
+ it 'persists remember_me value via hidden field' do
+ field = first('input#user_remember_me', visible: false)
+
+ expect(field.value).to eq '1'
+ end
+
it 'blocks login with invalid code' do
enter_code('foo')
expect(page).to have_content('Invalid two-factor code')
@@ -121,7 +127,7 @@ feature 'Login', feature: true do
user = create(:user, password: 'not-the-default')
login_with(user)
- expect(page).to have_content('Invalid login or password.')
+ expect(page).to have_content('Invalid Login or password.')
end
end
@@ -137,12 +143,12 @@ feature 'Login', feature: true do
context 'within the grace period' do
it 'redirects to two-factor configuration page' do
- expect(current_path).to eq new_profile_two_factor_auth_path
- expect(page).to have_content('You must enable Two-factor Authentication for your account before')
+ expect(current_path).to eq profile_two_factor_auth_path
+ expect(page).to have_content('You must enable Two-Factor Authentication for your account before')
end
- it 'disallows skipping two-factor configuration' do
- expect(current_path).to eq new_profile_two_factor_auth_path
+ it 'allows skipping two-factor configuration', js: true do
+ expect(current_path).to eq profile_two_factor_auth_path
click_link 'Configure it later'
expect(current_path).to eq root_path
@@ -153,26 +159,26 @@ feature 'Login', feature: true do
let(:user) { create(:user, otp_grace_period_started_at: 9999.hours.ago) }
it 'redirects to two-factor configuration page' do
- expect(current_path).to eq new_profile_two_factor_auth_path
- expect(page).to have_content('You must enable Two-factor Authentication for your account.')
+ expect(current_path).to eq profile_two_factor_auth_path
+ expect(page).to have_content('You must enable Two-Factor Authentication for your account.')
end
- it 'disallows skipping two-factor configuration' do
- expect(current_path).to eq new_profile_two_factor_auth_path
+ it 'disallows skipping two-factor configuration', js: true do
+ expect(current_path).to eq profile_two_factor_auth_path
expect(page).not_to have_link('Configure it later')
end
end
end
- context 'without grace pariod defined' do
+ context 'without grace period defined' do
before(:each) do
stub_application_setting(two_factor_grace_period: 0)
login_with(user)
end
it 'redirects to two-factor configuration page' do
- expect(current_path).to eq new_profile_two_factor_auth_path
- expect(page).to have_content('You must enable Two-factor Authentication for your account.')
+ expect(current_path).to eq profile_two_factor_auth_path
+ expect(page).to have_content('You must enable Two-Factor Authentication for your account.')
end
end
end
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 0148c87084a..09ccc77c101 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -165,22 +165,32 @@ describe 'GitLab Markdown', feature: true do
describe 'ExternalLinkFilter' do
it 'adds nofollow to external link' do
link = doc.at_css('a:contains("Google")')
+
expect(link.attr('rel')).to include('nofollow')
end
it 'adds noreferrer to external link' do
link = doc.at_css('a:contains("Google")')
+
expect(link.attr('rel')).to include('noreferrer')
end
+ it 'adds _blank to target attribute for external links' do
+ link = doc.at_css('a:contains("Google")')
+
+ expect(link.attr('target')).to match('_blank')
+ end
+
it 'ignores internal link' do
link = doc.at_css('a:contains("GitLab Root")')
+
expect(link.attr('rel')).not_to match 'nofollow'
+ expect(link.attr('target')).not_to match '_blank'
end
end
end
- before(:all) do
+ before do
@feat = MarkdownFeature.new
# `markdown` helper expects a `@project` variable
@@ -188,7 +198,7 @@ describe 'GitLab Markdown', feature: true do
end
context 'default pipeline' do
- before(:all) do
+ before do
@html = markdown(@feat.raw_markdown)
end
@@ -231,13 +241,14 @@ describe 'GitLab Markdown', feature: true do
context 'wiki pipeline' do
before do
@project_wiki = @feat.project_wiki
+ @project_wiki_page = @feat.project_wiki_page
file = Gollum::File.new(@project_wiki.wiki)
expect(file).to receive(:path).and_return('images/example.jpg')
expect(@project_wiki).to receive(:find_file).with('images/example.jpg').and_return(file)
allow(@project_wiki).to receive(:wiki_base_path) { '/namespace1/gitlabhq/wikis' }
- @html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki })
+ @html = markdown(@feat.raw_markdown, { pipeline: :wiki, project_wiki: @project_wiki, page_slug: @project_wiki_page.slug })
end
it_behaves_like 'all pipelines'
@@ -278,6 +289,10 @@ describe 'GitLab Markdown', feature: true do
it 'includes GollumTagsFilter' do
expect(doc).to parse_gollum_tags
end
+
+ it 'includes InlineDiffFilter' do
+ expect(doc).to parse_inline_diffs
+ end
end
# Fake a `current_user` helper
diff --git a/spec/features/merge_requests/award_spec.rb b/spec/features/merge_requests/award_spec.rb
new file mode 100644
index 00000000000..007f67d6080
--- /dev/null
+++ b/spec/features/merge_requests/award_spec.rb
@@ -0,0 +1,49 @@
+require 'rails_helper'
+
+feature 'Merge request awards', js: true, feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ describe 'logged in' do
+ before do
+ login_as(user)
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ it 'should add award to merge request' do
+ first('.js-emoji-btn').click
+ expect(page).to have_selector('.js-emoji-btn.active')
+ expect(first('.js-emoji-btn')).to have_content '1'
+
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ expect(first('.js-emoji-btn')).to have_content '1'
+ end
+
+ it 'should remove award from merge request' do
+ first('.js-emoji-btn').click
+ find('.js-emoji-btn.active').click
+ expect(first('.js-emoji-btn')).to have_content '0'
+
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ expect(first('.js-emoji-btn')).to have_content '0'
+ end
+
+ it 'should only have one menu on the page' do
+ first('.js-add-award').click
+ expect(page).to have_selector('.emoji-menu')
+
+ expect(page).to have_selector('.emoji-menu', count: 1)
+ end
+ end
+
+ describe 'logged out' do
+ before do
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ it 'should not see award menu button' do
+ expect(page).not_to have_selector('.js-award-holder')
+ end
+ end
+end
diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb
new file mode 100644
index 00000000000..b4d2201c729
--- /dev/null
+++ b/spec/features/merge_requests/created_from_fork_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+feature 'Merge request created from fork' do
+ given(:user) { create(:user) }
+ given(:project) { create(:project, :public) }
+ given(:fork_project) { create(:project, :public) }
+
+ given!(:merge_request) do
+ create(:forked_project_link, forked_to_project: fork_project,
+ forked_from_project: project)
+
+ create(:merge_request_with_diffs, source_project: fork_project,
+ target_project: project,
+ description: 'Test merge request')
+ end
+
+ background do
+ fork_project.team << [user, :master]
+ login_as user
+ end
+
+ scenario 'user can access merge request' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_content 'Test merge request'
+ end
+
+ context 'pipeline present in source project' do
+ include WaitForAjax
+
+ given(:pipeline) do
+ create(:ci_pipeline_with_two_job, project: fork_project,
+ sha: merge_request.last_commit.id,
+ ref: merge_request.source_branch)
+ end
+
+ background { pipeline.create_builds(user) }
+
+ scenario 'user visits a pipelines page', js: true do
+ visit_merge_request(merge_request)
+ page.within('.merge-request-tabs') { click_link 'Builds' }
+ wait_for_ajax
+
+ page.within('table.builds') do
+ expect(page).to have_content 'rspec'
+ expect(page).to have_content 'spinach'
+ end
+
+ expect(find_link('Cancel running')[:href])
+ .to include fork_project.path_with_namespace
+ end
+ end
+
+ def visit_merge_request(mr)
+ visit namespace_project_merge_request_path(project.namespace,
+ project, mr)
+ end
+end
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
index 7aa7eb965e9..c5e6412d7bf 100644
--- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
@@ -12,8 +12,8 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
end
context "Active build for Merge Request" do
- let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
- let!(:ci_build) { create(:ci_build, commit: ci_commit) }
+ let!(:pipeline) { create(:ci_pipeline, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_build) { create(:ci_build, pipeline: pipeline) }
before do
login_as user
@@ -47,8 +47,8 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
merge_user: user, title: "MepMep", merge_when_build_succeeds: true)
end
- let!(:ci_commit) { create(:ci_commit, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
- let!(:ci_build) { create(:ci_build, commit: ci_commit) }
+ let!(:pipeline) { create(:ci_pipeline, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+ let!(:ci_build) { create(:ci_build, pipeline: pipeline) }
before do
login_as user
diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb
new file mode 100644
index 00000000000..65e9185ec24
--- /dev/null
+++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds.rb
@@ -0,0 +1,105 @@
+require 'spec_helper'
+
+feature 'Only allow merge requests to be merged if the build succeeds', feature: true do
+ let(:project) { create(:project, :public) }
+ let(:merge_request) { create(:merge_request_with_diffs, source_project: project) }
+
+ before do
+ login_as merge_request.author
+
+ project.team << [merge_request.author, :master]
+ end
+
+ context 'project does not have CI enabled' do
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+
+ context 'when project has CI enabled' do
+ let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: merge_request.last_commit.id, ref: merge_request.source_branch) }
+
+ context 'when merge requests can only be merged if the build succeeds' do
+ before do
+ project.update_attribute(:only_allow_merge_if_build_succeeds, true)
+ end
+
+ context 'when CI is running' do
+ before { pipeline.update_column(:status, :running) }
+
+ it 'does not allow to merge immediately' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Merge When Build Succeeds'
+ expect(page).not_to have_button 'Select Merge Moment'
+ end
+ end
+
+ context 'when CI failed' do
+ before { pipeline.update_column(:status, :failed) }
+
+ it 'does not allow MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).not_to have_button 'Accept Merge Request'
+ expect(page).to have_content('Please retry the build or push a new commit to fix the failure.')
+ end
+ end
+
+ context 'when CI succeeded' do
+ before { pipeline.update_column(:status, :success) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+ end
+
+ context 'when merge requests can be merged when the build failed' do
+ before do
+ project.update_attribute(:only_allow_merge_if_build_succeeds, false)
+ end
+
+ context 'when CI is running' do
+ before { pipeline.update_column(:status, :running) }
+
+ it 'allows MR to be merged immediately', js: true do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Merge When Build Succeeds'
+
+ click_button 'Select Merge Moment'
+ expect(page).to have_content 'Merge Immediately'
+ end
+ end
+
+ context 'when CI failed' do
+ before { pipeline.update_column(:status, :failed) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+
+ context 'when CI succeeded' do
+ before { pipeline.update_column(:status, :success) }
+
+ it 'allows MR to be merged' do
+ visit_merge_request(merge_request)
+
+ expect(page).to have_button 'Accept Merge Request'
+ end
+ end
+ end
+ end
+
+ def visit_merge_request(merge_request)
+ visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
+ end
+end
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
index 2c7e1c748ad..1c130057c56 100644
--- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb
+++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb
@@ -131,6 +131,15 @@ describe 'Projects > Merge requests > User lists merge requests', feature: true
expect(first_merge_request).to include('fix')
expect(count_merge_requests).to eq(1)
end
+
+ it 'sorts by recently due milestone' do
+ visit namespace_project_merge_requests_path(project.namespace, project,
+ label_name: [label.name, label2.name],
+ assignee_id: user.id,
+ sort: sort_value_milestone_soon)
+
+ expect(first_merge_request).to include('fix')
+ end
end
end
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 9e9fec01943..737efcef45d 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -4,25 +4,15 @@ describe 'Comments', feature: true do
include RepoHelpers
include WaitForAjax
- describe 'On merge requests page', feature: true do
- it 'excludes award_emoji from comment count' do
- merge_request = create(:merge_request)
- project = merge_request.source_project
- create(:upvote_note, noteable: merge_request, project: project)
-
- login_as :admin
- visit namespace_project_merge_requests_path(project.namespace, project)
-
- expect(merge_request.mr_and_commit_notes.count).to eq 1
- expect(page.all('.merge-request-no-comments').first.text).to eq "0"
+ describe 'On a merge request', js: true, feature: true do
+ let!(:project) { create(:project) }
+ let!(:merge_request) do
+ create(:merge_request, source_project: project, target_project: project)
end
- end
- describe 'On a merge request', js: true, feature: true do
- let!(:merge_request) { create(:merge_request) }
- let!(:project) { merge_request.source_project }
let!(:note) do
- create(:note_on_merge_request, :with_attachment, project: project)
+ create(:note_on_merge_request, :with_attachment, noteable: merge_request,
+ project: project)
end
before do
@@ -143,17 +133,6 @@ describe 'Comments', feature: true do
end
end
end
-
- describe 'comment info' do
- it 'excludes award_emoji from comment count' do
- create(:upvote_note, noteable: merge_request, project: project)
-
- visit namespace_project_merge_request_path(project.namespace, project, merge_request)
-
- expect(merge_request.mr_and_commit_notes.count).to eq 2
- expect(find('.notes-tab span.badge').text).to eq "1"
- end
- end
end
describe 'On a merge request diff', js: true, feature: true do
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index 1adab7e9c6c..c7c00a3266a 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -32,7 +32,8 @@ feature 'Member autocomplete', feature: true do
context 'adding a new note on a Issue', js: true do
before do
issue = create(:issue, author: author, project: project)
- create(:note, note: 'Ultralight Beam', noteable: issue, author: participant)
+ create(:note, note: 'Ultralight Beam', noteable: issue,
+ project: project, author: participant)
visit_issue(project, issue)
end
@@ -47,7 +48,8 @@ feature 'Member autocomplete', feature: true do
context 'adding a new note on a Merge Request ', js: true do
before do
merge = create(:merge_request, source_project: project, target_project: project, author: author)
- create(:note, note: 'Ultralight Beam', noteable: merge, author: participant)
+ create(:note, note: 'Ultralight Beam', noteable: merge,
+ project: project, author: participant)
visit_merge_request(project, merge)
end
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
new file mode 100644
index 00000000000..98703ef3ac4
--- /dev/null
+++ b/spec/features/pipelines_spec.rb
@@ -0,0 +1,189 @@
+require 'spec_helper'
+
+describe "Pipelines" do
+ include GitlabRoutingHelper
+
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ login_as(user)
+ project.team << [user, :developer]
+ end
+
+ describe 'GET /:project/pipelines' do
+ let!(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', status: 'running') }
+
+ [:all, :running, :branches].each do |scope|
+ context "displaying #{scope}" do
+ let(:project) { create(:project) }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project, scope: scope) }
+
+ it { expect(page).to have_content(pipeline.short_sha) }
+ end
+ end
+
+ context 'anonymous access' do
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_http_status(:success) }
+ end
+
+ context 'cancelable pipeline' do
+ let!(:running) { create(:ci_build, :running, pipeline: pipeline, stage: 'test', commands: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_link('Cancel') }
+ it { expect(page).to have_selector('.ci-running') }
+
+ context 'when canceling' do
+ before { click_link('Cancel') }
+
+ it { expect(page).not_to have_link('Cancel') }
+ it { expect(page).to have_selector('.ci-canceled') }
+ end
+ end
+
+ context 'retryable pipelines' do
+ let!(:failed) { create(:ci_build, :failed, pipeline: pipeline, stage: 'test', commands: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_link('Retry') }
+ it { expect(page).to have_selector('.ci-failed') }
+
+ context 'when retrying' do
+ before { click_link('Retry') }
+
+ it { expect(page).not_to have_link('Retry') }
+ it { expect(page).to have_selector('.ci-pending') }
+ end
+ end
+
+ context 'for generic statuses' do
+ context 'when running' do
+ let!(:running) { create(:generic_commit_status, status: 'running', pipeline: pipeline, stage: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it 'not be cancelable' do
+ expect(page).not_to have_link('Cancel')
+ end
+
+ it 'pipeline is running' do
+ expect(page).to have_selector('.ci-running')
+ end
+ end
+
+ context 'when failed' do
+ let!(:running) { create(:generic_commit_status, status: 'failed', pipeline: pipeline, stage: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it 'not be retryable' do
+ expect(page).not_to have_link('Retry')
+ end
+
+ it 'pipeline is failed' do
+ expect(page).to have_selector('.ci-failed')
+ end
+ end
+ end
+
+ context 'downloadable pipelines' do
+ context 'with artifacts' do
+ let!(:with_artifacts) { create(:ci_build, :artifacts, :success, pipeline: pipeline, name: 'rspec tests', stage: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_selector('.build-artifacts') }
+ it { expect(page).to have_link(with_artifacts.name) }
+ end
+
+ context 'without artifacts' do
+ let!(:without_artifacts) { create(:ci_build, :success, pipeline: pipeline, name: 'rspec', stage: 'test') }
+
+ it { expect(page).not_to have_selector('.build-artifacts') }
+ end
+ end
+ end
+
+ describe 'GET /:project/pipelines/:id' do
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
+
+ before do
+ @success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
+ @failed = create(:ci_build, :failed, pipeline: pipeline, stage: 'test', name: 'test', commands: 'test')
+ @running = create(:ci_build, :running, pipeline: pipeline, stage: 'deploy', name: 'deploy')
+ @external = create(:generic_commit_status, status: 'success', pipeline: pipeline, name: 'jenkins', stage: 'external')
+ end
+
+ before { visit namespace_project_pipeline_path(project.namespace, project, pipeline) }
+
+ it 'showing a list of builds' do
+ expect(page).to have_content('Tests')
+ expect(page).to have_content(@success.id)
+ expect(page).to have_content('Deploy')
+ expect(page).to have_content(@failed.id)
+ expect(page).to have_content(@running.id)
+ expect(page).to have_content(@external.id)
+ expect(page).to have_content('Retry failed')
+ expect(page).to have_content('Cancel running')
+ end
+
+ context 'retrying builds' do
+ it { expect(page).not_to have_content('retried') }
+
+ context 'when retrying' do
+ before { click_on 'Retry failed' }
+
+ it { expect(page).not_to have_content('Retry failed') }
+ it { expect(page).to have_content('retried') }
+ end
+ end
+
+ context 'canceling builds' do
+ it { expect(page).not_to have_selector('.ci-canceled') }
+
+ context 'when canceling' do
+ before { click_on 'Cancel running' }
+
+ it { expect(page).not_to have_content('Cancel running') }
+ it { expect(page).to have_selector('.ci-canceled') }
+ end
+ end
+ end
+
+ describe 'POST /:project/pipelines' do
+ let(:project) { create(:project) }
+
+ before { visit new_namespace_project_pipeline_path(project.namespace, project) }
+
+ context 'for valid commit' do
+ before { fill_in('Create for', with: 'master') }
+
+ context 'with gitlab-ci.yml' do
+ before { stub_ci_pipeline_to_return_yaml_file }
+
+ it { expect{ click_on 'Create pipeline' }.to change{ Ci::Pipeline.count }.by(1) }
+ end
+
+ context 'without gitlab-ci.yml' do
+ before { click_on 'Create pipeline' }
+
+ it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
+ end
+ end
+
+ context 'for invalid commit' do
+ before do
+ fill_in('Create for', with: 'invalid reference')
+ click_on 'Create pipeline'
+ end
+
+ it { expect(page).to have_content('Reference not found') }
+ end
+ end
+end
diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb
index 8f645438cff..787bf42d048 100644
--- a/spec/features/profiles/preferences_spec.rb
+++ b/spec/features/profiles/preferences_spec.rb
@@ -54,7 +54,7 @@ describe 'Profile > Preferences', feature: true do
end
end
- describe 'User changes their default dashboard' do
+ describe 'User changes their default dashboard', js: true do
it 'creates a flash message' do
select 'Starred Projects', from: 'user_dashboard'
click_button 'Save'
@@ -66,8 +66,10 @@ describe 'Profile > Preferences', feature: true do
select 'Starred Projects', from: 'user_dashboard'
click_button 'Save'
- click_link 'Dashboard'
- expect(page.current_path).to eq starred_dashboard_projects_path
+ allowing_for_delay do
+ find('#logo').click
+ expect(page.current_path).to eq starred_dashboard_projects_path
+ end
click_link 'Your Projects'
expect(page.current_path).to eq dashboard_projects_path
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index 13c9b95b316..51be81d634c 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -8,12 +8,10 @@ feature 'list of badges' do
project = create(:project)
project.team << [user, :master]
login_as(user)
- visit edit_namespace_project_path(project.namespace, project)
+ visit namespace_project_badges_path(project.namespace, project)
end
scenario 'user displays list of badges' do
- click_link 'Badges'
-
expect(page).to have_content 'build status'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
@@ -26,7 +24,6 @@ feature 'list of badges' do
end
scenario 'user changes current ref on badges list page', js: true do
- click_link 'Badges'
select2('improve/awesome', from: '#ref')
expect(page).to have_content 'badges/improve/awesome/build.svg'
diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb
index 40ba0bdc115..15c381c0f5a 100644
--- a/spec/features/projects/commit/builds_spec.rb
+++ b/spec/features/projects/commit/builds_spec.rb
@@ -11,9 +11,9 @@ feature 'project commit builds' do
context 'when no builds triggered yet' do
background do
- create(:ci_commit, project: project,
- sha: project.commit.sha,
- ref: 'master')
+ create(:ci_pipeline, project: project,
+ sha: project.commit.sha,
+ ref: 'master')
end
scenario 'user views commit builds page' do
diff --git a/spec/features/projects/commits/cherry_pick_spec.rb b/spec/features/projects/commits/cherry_pick_spec.rb
index 0559b02f321..f88c0616b52 100644
--- a/spec/features/projects/commits/cherry_pick_spec.rb
+++ b/spec/features/projects/commits/cherry_pick_spec.rb
@@ -16,6 +16,7 @@ describe 'Cherry-pick Commits' do
it do
visit namespace_project_commit_path(project.namespace, project, master_pickable_commit.id)
find("a[href='#modal-cherry-pick-commit']").click
+ expect(page).not_to have_content('v1.0.0') # Only branches, not tags
page.within('#modal-cherry-pick-commit') do
uncheck 'create_merge_request'
click_button 'Cherry-pick'
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
new file mode 100644
index 00000000000..073a83b6896
--- /dev/null
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+feature 'User wants to add a .gitignore file', feature: true do
+ include WaitForAjax
+
+ before do
+ user = create(:user)
+ project = create(:project)
+ project.team << [user, :master]
+ login_as user
+ visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitignore')
+ end
+
+ scenario 'user can see .gitignore dropdown' do
+ expect(page).to have_css('.gitignore-selector')
+ end
+
+ scenario 'user can pick a .gitignore file from the dropdown', js: true do
+ find('.js-gitignore-selector').click
+ wait_for_ajax
+ within '.gitignore-selector' do
+ find('.dropdown-input-field').set('rails')
+ find('.dropdown-content li', text: 'Rails').click
+ end
+ wait_for_ajax
+
+ expect(page).to have_content('/.bundle')
+ expect(page).to have_content('# Gemfile.lock, .ruby-version, .ruby-gemset')
+ end
+end
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index 3d6ffbc4c6b..ecc818eb1e1 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -25,7 +25,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -33,7 +33,7 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
scenario 'project master creates a license file from the "Add license" link' do
@@ -48,7 +48,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -56,6 +56,6 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
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 3268e240200..34eda29c285 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
@@ -24,7 +24,7 @@ feature 'project owner sees a link to create a license file in empty project', f
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
# Remove pre-receive hook so we can push without auth
@@ -34,6 +34,6 @@ feature 'project owner sees a link to create a license file in empty project', f
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
new file mode 100644
index 00000000000..461f1737928
--- /dev/null
+++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb
@@ -0,0 +1,87 @@
+require 'spec_helper'
+
+feature 'Issue prioritization', feature: true do
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+
+ # Labels
+ let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) }
+ let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) }
+ let(:label_3) { create(:label, title: 'label_3', project: project, priority: 3) }
+ let(:label_4) { create(:label, title: 'label_4', project: project, priority: 4) }
+ let(:label_5) { create(:label, title: 'label_5', project: project) } # no priority
+
+ # According to https://gitlab.com/gitlab-org/gitlab-ce/issues/14189#note_4360653
+ context 'when issues have one label' do
+ scenario 'Are sorted properly' do
+
+ # Issues
+ issue_1 = create(:issue, title: 'issue_1', project: project)
+ issue_2 = create(:issue, title: 'issue_2', project: project)
+ issue_3 = create(:issue, title: 'issue_3', project: project)
+ issue_4 = create(:issue, title: 'issue_4', project: project)
+ issue_5 = create(:issue, title: 'issue_5', project: project)
+
+ # Assign labels to issues disorderly
+ issue_4.labels << label_1
+ issue_3.labels << label_2
+ issue_5.labels << label_3
+ issue_2.labels << label_4
+ issue_1.labels << label_5
+
+ login_as user
+ visit namespace_project_issues_path(project.namespace, project, sort: 'priority')
+
+ # Ensure we are indicating that issues are sorted by priority
+ expect(page).to have_selector('.dropdown-toggle', text: 'Priority')
+
+ page.within('.issues-holder') do
+ issue_titles = all('.issues-list .issue-title-text').map(&:text)
+
+ expect(issue_titles).to eq(['issue_4', 'issue_3', 'issue_5', 'issue_2', 'issue_1'])
+ end
+ end
+ end
+
+ context 'when issues have multiple labels' do
+ scenario 'Are sorted properly' do
+
+ # Issues
+ issue_1 = create(:issue, title: 'issue_1', project: project)
+ issue_2 = create(:issue, title: 'issue_2', project: project)
+ issue_3 = create(:issue, title: 'issue_3', project: project)
+ issue_4 = create(:issue, title: 'issue_4', project: project)
+ issue_5 = create(:issue, title: 'issue_5', project: project)
+ issue_6 = create(:issue, title: 'issue_6', project: project)
+ issue_7 = create(:issue, title: 'issue_7', project: project)
+ issue_8 = create(:issue, title: 'issue_8', project: project)
+
+ # Assign labels to issues disorderly
+ issue_5.labels << label_1 # 1
+ issue_5.labels << label_2
+ issue_8.labels << label_1 # 2
+ issue_1.labels << label_2 # 3
+ issue_1.labels << label_3
+ issue_3.labels << label_2 # 4
+ issue_3.labels << label_4
+ issue_7.labels << label_2 # 5
+ issue_2.labels << label_3 # 6
+ issue_4.labels << label_4 # 7
+ issue_6.labels << label_5 # 8 - No priority
+
+ login_as user
+ visit namespace_project_issues_path(project.namespace, project, sort: 'priority')
+
+ expect(page).to have_selector('.dropdown-toggle', text: 'Priority')
+
+ page.within('.issues-holder') do
+ issue_titles = all('.issues-list .issue-title-text').map(&:text)
+
+ expect(issue_titles[0..1]).to contain_exactly('issue_5', 'issue_8')
+ expect(issue_titles[2..4]).to contain_exactly('issue_1', 'issue_3', 'issue_7')
+ expect(issue_titles[5..-1]).to eq(['issue_2', 'issue_4', 'issue_6'])
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb
new file mode 100644
index 00000000000..8550d279d09
--- /dev/null
+++ b/spec/features/projects/labels/update_prioritization_spec.rb
@@ -0,0 +1,115 @@
+require 'spec_helper'
+
+feature 'Prioritize labels', feature: true do
+ include WaitForAjax
+
+ context 'when project belongs to user' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, name: 'test', namespace: user.namespace) }
+
+ scenario 'user can prioritize a label', js: true do
+ bug = create(:label, title: 'bug')
+ wontfix = create(:label, title: 'wontfix')
+
+ project.labels << bug
+ project.labels << wontfix
+
+ login_as user
+ visit namespace_project_labels_path(project.namespace, project)
+
+ expect(page).to have_content('No prioritized labels yet')
+
+ page.within('.other-labels') do
+ first('.js-toggle-priority').click
+ wait_for_ajax
+ expect(page).not_to have_content('bug')
+ end
+
+ page.within('.prioritized-labels') do
+ expect(page).not_to have_content('No prioritized labels yet')
+ expect(page).to have_content('bug')
+ end
+ end
+
+ scenario 'user can unprioritize a label', js: true do
+ bug = create(:label, title: 'bug', priority: 1)
+ wontfix = create(:label, title: 'wontfix')
+
+ project.labels << bug
+ project.labels << wontfix
+
+ login_as user
+ visit namespace_project_labels_path(project.namespace, project)
+
+ expect(page).to have_content('bug')
+
+ page.within('.prioritized-labels') do
+ first('.js-toggle-priority').click
+ wait_for_ajax
+ expect(page).not_to have_content('bug')
+ end
+
+ page.within('.other-labels') do
+ expect(page).to have_content('bug')
+ expect(page).to have_content('wontfix')
+ end
+ end
+
+ scenario 'user can sort prioritized labels and persist across reloads', js: true do
+ bug = create(:label, title: 'bug', priority: 1)
+ wontfix = create(:label, title: 'wontfix', priority: 2)
+
+ project.labels << bug
+ project.labels << wontfix
+
+ login_as user
+ visit namespace_project_labels_path(project.namespace, project)
+
+ expect(page).to have_content 'bug'
+ expect(page).to have_content 'wontfix'
+
+ # Sort labels
+ find("#label_#{bug.id}").drag_to find("#label_#{wontfix.id}")
+
+ page.within('.prioritized-labels') do
+ expect(first('li')).to have_content('wontfix')
+ expect(page.all('li').last).to have_content('bug')
+ end
+
+ visit current_url
+
+ page.within('.prioritized-labels') do
+ expect(first('li')).to have_content('wontfix')
+ expect(page.all('li').last).to have_content('bug')
+ end
+ end
+ end
+
+ context 'as a guest' do
+ it 'can not prioritize labels' do
+ user = create(:user)
+ guest = create(:user)
+ project = create(:project, name: 'test', namespace: user.namespace)
+
+ create(:label, title: 'bug')
+
+ login_as guest
+ visit namespace_project_labels_path(project.namespace, project)
+
+ expect(page).not_to have_css('.prioritized-labels')
+ end
+ end
+
+ context 'as a non signed in user' do
+ it 'can not prioritize labels' do
+ user = create(:user)
+ project = create(:project, name: 'test', namespace: user.namespace)
+
+ create(:label, title: 'bug')
+
+ visit namespace_project_labels_path(project.namespace, project)
+
+ expect(page).not_to have_css('.prioritized-labels')
+ end
+ end
+end
diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb
new file mode 100644
index 00000000000..5fe4caa12f0
--- /dev/null
+++ b/spec/features/projects/members/master_manages_access_requests_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+feature 'Projects > Members > Master manages access requests', feature: true do
+ let(:user) { create(:user) }
+ let(:master) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ background do
+ project.request_access(user)
+ project.team << [master, :master]
+ login_as(master)
+ end
+
+ scenario 'master can see access requests' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+ end
+
+ scenario 'master can grant access' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+
+ perform_enqueued_jobs { click_on 'Grant access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.name_with_namespace} project was granted"
+ end
+
+ scenario 'master can deny access' do
+ visit namespace_project_project_members_path(project.namespace, project)
+
+ expect_visible_access_request(project, user)
+
+ perform_enqueued_jobs { click_on 'Deny access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [user.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to match "Access to the #{project.name_with_namespace} project was denied"
+ end
+
+ def expect_visible_access_request(project, user)
+ expect(project.members.request.exists?(user_id: user)).to be_truthy
+ expect(page).to have_content "#{project.name} access requests (1)"
+ expect(page).to have_content user.name
+ end
+end
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
new file mode 100644
index 00000000000..fd92a3a2f0c
--- /dev/null
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+feature 'Projects > Members > User requests access', feature: true do
+ let(:user) { create(:user) }
+ let(:master) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ background do
+ project.team << [master, :master]
+ login_as(user)
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ scenario 'user can request access to a project' do
+ perform_enqueued_jobs { click_link 'Request Access' }
+
+ expect(ActionMailer::Base.deliveries.last.to).to eq [master.notification_email]
+ expect(ActionMailer::Base.deliveries.last.subject).to eq "Request to join the #{project.name_with_namespace} project"
+
+ expect(project.members.request.exists?(user_id: user)).to be_truthy
+ expect(page).to have_content 'Your request for access has been queued for review.'
+
+ expect(page).to have_content 'Withdraw Access Request'
+ end
+
+ scenario 'user is not listed in the project members page' do
+ click_link 'Request Access'
+
+ expect(project.members.request.exists?(user_id: user)).to be_truthy
+
+ open_project_settings_menu
+ click_link 'Members'
+
+ visit namespace_project_project_members_path(project.namespace, project)
+ page.within('.content') do
+ expect(page).not_to have_content(user.name)
+ end
+ end
+
+ scenario 'user can withdraw its request for access' do
+ click_link 'Request Access'
+
+ expect(project.members.request.exists?(user_id: user)).to be_truthy
+
+ click_link 'Withdraw Access Request'
+
+ expect(project.members.request.exists?(user_id: user)).to be_falsey
+ expect(page).to have_content 'Your access request to the project has been withdrawn.'
+ end
+
+ def open_project_settings_menu
+ find('#project-settings-button').click
+ end
+end
diff --git a/spec/features/project/shortcuts_spec.rb b/spec/features/projects/shortcuts_spec.rb
index 2595c4181e5..54aa9c66a08 100644
--- a/spec/features/project/shortcuts_spec.rb
+++ b/spec/features/projects/shortcuts_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
feature 'Project shortcuts', feature: true do
- let(:project) { create(:project) }
+ let(:project) { create(:project, name: 'Victorialand') }
let(:user) { create(:user) }
describe 'On a project', js: true do
@@ -14,7 +14,7 @@ feature 'Project shortcuts', feature: true do
describe 'pressing "i"' do
it 'redirects to new issue page' do
find('body').native.send_key('i')
- expect(page).to have_content('New Issue')
+ expect(page).to have_content('Victorialand')
end
end
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 8edeb8d18af..a5ed3595b0a 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -29,8 +29,8 @@ describe "Runners" do
end
before do
- expect(page).to_not have_content(@specific_runner3.display_name)
- expect(page).to_not have_content(@specific_runner3.display_name)
+ expect(page).not_to have_content(@specific_runner3.display_name)
+ expect(page).not_to have_content(@specific_runner3.display_name)
end
it "places runners in right places" do
@@ -110,4 +110,37 @@ describe "Runners" do
expect(page).to have_content(@specific_runner.platform)
end
end
+
+ feature 'configuring runners ability to picking untagged jobs' do
+ given(:project) { create(:empty_project) }
+ given(:runner) { create(:ci_runner) }
+
+ background do
+ project.team << [user, :master]
+ project.runners << runner
+ end
+
+ scenario 'user checks default configuration' do
+ visit namespace_project_runner_path(project.namespace, project, runner)
+
+ expect(page).to have_content 'Can run untagged jobs Yes'
+ end
+
+ context 'when runner has tags' do
+ before { runner.update_attribute(:tag_list, ['tag']) }
+
+ scenario 'user wants to prevent runner from running untagged job' do
+ visit runners_path(project)
+ page.within('.activated-specific-runners') do
+ first('small > a').click
+ end
+
+ uncheck 'runner_run_untagged'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Can run untagged jobs No'
+ expect(runner.reload.run_untagged?).to eq false
+ end
+ end
+ end
end
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 4def4f99bc0..c5f741709ad 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -142,8 +142,8 @@ describe "Public Project Access", feature: true do
end
describe "GET /:project_path/builds/:id" do
- let(:commit) { create(:ci_commit, project: project) }
- let(:build) { create(:ci_build, commit: commit) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
subject { namespace_project_build_path(project.namespace, project, build.id) }
context "when allowed for public" do
diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb
index c926e9841f3..6b5b3122f72 100644
--- a/spec/features/tags/master_updates_tag_spec.rb
+++ b/spec/features/tags/master_updates_tag_spec.rb
@@ -12,7 +12,7 @@ feature 'Master updates tag', feature: true do
context 'from the tags list page' do
scenario 'updates the release notes' do
- page.within(first('.controls')) do
+ page.within(first('.content-list .controls')) do
click_link 'Edit release notes'
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index b7368cca29d..6ed279ef9be 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -75,7 +75,10 @@ feature 'Task Lists', feature: true do
describe 'for Notes' do
let!(:issue) { create(:issue, author: user, project: project) }
- let!(:note) { create(:note, note: markdown, noteable: issue, author: user) }
+ let!(:note) do
+ create(:note, note: markdown, noteable: issue,
+ project: project, author: user)
+ end
it 'renders for note body' do
visit_issue(project, issue)
diff --git a/spec/features/todos/target_state_spec.rb b/spec/features/todos/target_state_spec.rb
new file mode 100644
index 00000000000..32fa88a2b21
--- /dev/null
+++ b/spec/features/todos/target_state_spec.rb
@@ -0,0 +1,65 @@
+require 'rails_helper'
+
+feature 'Todo target states', feature: true do
+ let(:user) { create(:user) }
+ let(:author) { create(:user) }
+ let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
+
+ before do
+ login_as user
+ end
+
+ scenario 'on a closed issue todo has closed label' do
+ issue_closed = create(:issue, state: 'closed')
+ create_todo issue_closed
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Closed')
+ end
+ end
+
+ scenario 'on an open issue todo does not have an open label' do
+ issue_open = create(:issue)
+ create_todo issue_open
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).not_to have_content('Open')
+ end
+ end
+
+ scenario 'on a merged merge request todo has merged label' do
+ mr_merged = create(:merge_request, :simple, author: user, state: 'merged')
+ create_todo mr_merged
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Merged')
+ end
+ end
+
+ scenario 'on a closed merge request todo has closed label' do
+ mr_closed = create(:merge_request, :simple, author: user, state: 'closed')
+ create_todo mr_closed
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Closed')
+ end
+ end
+
+ scenario 'on an open merge request todo does not have an open label' do
+ mr_open = create(:merge_request, :simple, author: user)
+ create_todo mr_open
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).not_to have_content('Open')
+ end
+ end
+
+ def create_todo(target)
+ create(:todo, :mentioned, user: user, project: project, target: target, author: author)
+ end
+end
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index 3354f529295..8e1833a069e 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'Dashboard Todos', feature: true do
let(:user) { create(:user) }
let(:author) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
let(:issue) { create(:issue) }
describe 'GET /dashboard/todos' do
@@ -43,6 +43,27 @@ describe 'Dashboard Todos', feature: true do
end
end
+ context 'User has Todos with labels spanning multiple projects' do
+ before do
+ label1 = create(:label, project: project)
+ note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project)
+ create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id)
+
+ project2 = create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ label2 = create(:label, project: project2)
+ issue2 = create(:issue, project: project2)
+ note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2)
+ create(:todo, :mentioned, project: project2, target: issue2, user: user, note_id: note2.id)
+
+ login_as(user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows page with two Todos' do
+ expect(page).to have_selector('.todos-list .todo', count: 2)
+ end
+ end
+
context 'User has multiple pages of Todos' do
before do
allow(Todo).to receive(:default_per_page).and_return(1)
@@ -77,5 +98,18 @@ describe 'Dashboard Todos', feature: true do
end
end
end
+
+ context 'User has a Todo in a project pending deletion' do
+ before do
+ deleted_project = create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC, pending_delete: true)
+ create(:todo, :mentioned, user: user, project: deleted_project, target: issue, author: author)
+ login_as(user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows "All done" message' do
+ expect(page).to have_content "You're all done!"
+ end
+ end
end
end
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
new file mode 100644
index 00000000000..366a90228b1
--- /dev/null
+++ b/spec/features/u2f_spec.rb
@@ -0,0 +1,239 @@
+require 'spec_helper'
+
+feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: true, js: true do
+ def register_u2f_device(u2f_device = nil)
+ u2f_device ||= FakeU2fDevice.new(page)
+ u2f_device.respond_to_u2f_registration
+ click_on 'Setup New U2F Device'
+ expect(page).to have_content('Your device was successfully set up')
+ click_on 'Register U2F Device'
+ u2f_device
+ end
+
+ describe "registration" do
+ let(:user) { create(:user) }
+ before { login_as(user) }
+
+ describe 'when 2FA via OTP is disabled' do
+ it 'allows registering a new device' do
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+
+ register_u2f_device
+
+ expect(page.body).to match('Your U2F device was registered')
+ end
+
+ it 'allows registering more than one device' do
+ visit profile_account_path
+
+ # First device
+ click_on 'Enable Two-Factor Authentication'
+ register_u2f_device
+ expect(page.body).to match('Your U2F device was registered')
+
+ # Second device
+ click_on 'Manage Two-Factor Authentication'
+ register_u2f_device
+ expect(page.body).to match('Your U2F device was registered')
+ click_on 'Manage Two-Factor Authentication'
+
+ expect(page.body).to match('You have 2 U2F devices registered')
+ end
+ end
+
+ describe 'when 2FA via OTP is enabled' do
+ before { user.update_attributes(otp_required_for_login: true) }
+
+ it 'allows registering a new device' do
+ visit profile_account_path
+ click_on 'Manage Two-Factor Authentication'
+ expect(page.body).to match("You've already enabled two-factor authentication using mobile")
+
+ register_u2f_device
+
+ expect(page.body).to match('Your U2F device was registered')
+ end
+
+ it 'allows registering more than one device' do
+ visit profile_account_path
+
+ # First device
+ click_on 'Manage Two-Factor Authentication'
+ register_u2f_device
+ expect(page.body).to match('Your U2F device was registered')
+
+ # Second device
+ click_on 'Manage Two-Factor Authentication'
+ register_u2f_device
+ expect(page.body).to match('Your U2F device was registered')
+
+ click_on 'Manage Two-Factor Authentication'
+ expect(page.body).to match('You have 2 U2F devices registered')
+ end
+ end
+
+ it 'allows the same device to be registered for multiple users' do
+ # First user
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ u2f_device = register_u2f_device
+ expect(page.body).to match('Your U2F device was registered')
+ logout
+
+ # Second user
+ login_as(:user)
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ register_u2f_device(u2f_device)
+ expect(page.body).to match('Your U2F device was registered')
+
+ expect(U2fRegistration.count).to eq(2)
+ end
+
+ context "when there are form errors" do
+ it "doesn't register the device if there are errors" do
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+
+ # Have the "u2f device" respond with bad data
+ page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
+ click_on 'Setup New U2F Device'
+ expect(page).to have_content('Your device was successfully set up')
+ click_on 'Register U2F Device'
+
+ expect(U2fRegistration.count).to eq(0)
+ expect(page.body).to match("The form contains the following error")
+ expect(page.body).to match("did not send a valid JSON response")
+ end
+
+ it "allows retrying registration" do
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+
+ # Failed registration
+ page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
+ click_on 'Setup New U2F Device'
+ expect(page).to have_content('Your device was successfully set up')
+ click_on 'Register U2F Device'
+ expect(page.body).to match("The form contains the following error")
+
+ # Successful registration
+ register_u2f_device
+
+ expect(page.body).to match('Your U2F device was registered')
+ expect(U2fRegistration.count).to eq(1)
+ end
+ end
+ end
+
+ describe "authentication" do
+ let(:user) { create(:user) }
+
+ before do
+ # Register and logout
+ login_as(user)
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ @u2f_device = register_u2f_device
+ logout
+ end
+
+ describe "when 2FA via OTP is disabled" do
+ it "allows logging in with the U2F device" do
+ login_with(user)
+
+ @u2f_device.respond_to_u2f_authentication
+ click_on "Login Via U2F Device"
+ expect(page.body).to match('We heard back from your U2F device')
+ click_on "Authenticate via U2F Device"
+
+ expect(page.body).to match('Signed in successfully')
+ end
+ end
+
+ describe "when 2FA via OTP is enabled" do
+ it "allows logging in with the U2F device" do
+ user.update_attributes(otp_required_for_login: true)
+ login_with(user)
+
+ @u2f_device.respond_to_u2f_authentication
+ click_on "Login Via U2F Device"
+ expect(page.body).to match('We heard back from your U2F device')
+ click_on "Authenticate via U2F Device"
+
+ expect(page.body).to match('Signed in successfully')
+ end
+ end
+
+ describe "when a given U2F device has already been registered by another user" do
+ describe "but not the current user" do
+ it "does not allow logging in with that particular device" do
+ # Register current user with the different U2F device
+ current_user = login_as(:user)
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ register_u2f_device
+ logout
+
+ # Try authenticating user with the old U2F device
+ login_as(current_user)
+ @u2f_device.respond_to_u2f_authentication
+ click_on "Login Via U2F Device"
+ expect(page.body).to match('We heard back from your U2F device')
+ click_on "Authenticate via U2F Device"
+
+ expect(page.body).to match('Authentication via U2F device failed')
+ end
+ end
+
+ describe "and also the current user" do
+ it "allows logging in with that particular device" do
+ # Register current user with the same U2F device
+ current_user = login_as(:user)
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ register_u2f_device(@u2f_device)
+ logout
+
+ # Try authenticating user with the same U2F device
+ login_as(current_user)
+ @u2f_device.respond_to_u2f_authentication
+ click_on "Login Via U2F Device"
+ expect(page.body).to match('We heard back from your U2F device')
+ click_on "Authenticate via U2F Device"
+
+ expect(page.body).to match('Signed in successfully')
+ end
+ end
+ end
+
+ describe "when a given U2F device has not been registered" do
+ it "does not allow logging in with that particular device" do
+ unregistered_device = FakeU2fDevice.new(page)
+ login_as(user)
+ unregistered_device.respond_to_u2f_authentication
+ click_on "Login Via U2F Device"
+ expect(page.body).to match('We heard back from your U2F device')
+ click_on "Authenticate via U2F Device"
+
+ expect(page.body).to match('Authentication via U2F device failed')
+ end
+ end
+ end
+
+ describe "when two-factor authentication is disabled" do
+ let(:user) { create(:user) }
+
+ before do
+ login_as(user)
+ visit profile_account_path
+ click_on 'Enable Two-Factor Authentication'
+ register_u2f_device
+ end
+
+ it "deletes u2f registrations" do
+ expect { click_on "Disable" }.to change { U2fRegistration.count }.from(1).to(0)
+ end
+ end
+end
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index afea1840cd7..a2b8f7b6931 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -1,24 +1,53 @@
require 'spec_helper'
-describe "Variables" do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- describe "specific runners" do
- before do
- @project = FactoryGirl.create :empty_project
- @project.team << [user, :master]
+describe 'Project variables', js: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:variable) { create(:ci_variable, key: 'test') }
+
+ before do
+ login_as(user)
+ project.team << [user, :master]
+ project.variables << variable
+
+ visit namespace_project_variables_path(project.namespace, project)
+ end
+
+ it 'should show list of variables' do
+ page.within('.variables-table') do
+ expect(page).to have_content(variable.key)
+ end
+ end
+
+ it 'should add new variable' do
+ fill_in('variable_key', with: 'key')
+ fill_in('variable_value', with: 'key value')
+ click_button('Add new variable')
+
+ page.within('.variables-table') do
+ expect(page).to have_content('key')
+ end
+ end
+
+ it 'should delete variable' do
+ page.within('.variables-table') do
+ find('.btn-variable-delete').click
+ end
+
+ expect(page).not_to have_selector('variables-table')
+ end
+
+ it 'should edit variable' do
+ page.within('.variables-table') do
+ find('.btn-variable-edit').click
end
- it "creates variable", js: true do
- visit namespace_project_variables_path(@project.namespace, @project)
- click_on "Add a variable"
- fill_in "Key", with: "SECRET_KEY"
- fill_in "Value", with: "SECRET_VALUE"
- click_on "Save changes"
+ fill_in('variable_key', with: 'key')
+ fill_in('variable_value', with: 'key value')
+ click_button('Save variable')
- expect(page).to have_content("Variables were successfully updated.")
- expect(@project.variables.count).to eq(1)
+ page.within('.variables-table') do
+ expect(page).to have_content('key')
end
end
end