summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2017-12-20 09:47:43 +0000
committerFilipa Lacerda <filipa@gitlab.com>2017-12-20 09:47:43 +0000
commit800ab47a53ea1dfaabdb67501360a14322268315 (patch)
treef6bb2327510806a066cc3776120a2d92b23cc205 /spec
parent572de0c1c2788d8d434a967f6ef0cb144f7f668f (diff)
parentfebb0b9a8014f5b480ff7baab1d189fce49210a5 (diff)
downloadgitlab-ce-800ab47a53ea1dfaabdb67501360a14322268315.tar.gz
Merge branch 'master' into 22643-manual-job-page
* master: (50 commits) Prevent some specs from mangling the gitlab-shell checkout Line up search dropdown with other nav dropdowns Fix onion-skin re-entering state Remove related links in MR widget when empty state Show inline edit button for issues Fix tags in the Activity tab not being clickable Fix shortcut links on help page Don't link LFS-objects multiple times. [CE->EE] Fix spec/lib/gitlab/git/gitlab_projects_spec.rb Tidy up the documentation of Gitlab HA/Gitlab Application Make sure two except won't overwrite each other Update axios.md Remove transitionend event from GL dropdown Preserve gem path so that we use the same gems Load commit in batches for pipelines#index BlobViewer::PackageJson - if private link to homepage Do not generate links for private NPM modules in blob view Fix missing WHERE clause in 20171106135924_issues_milestone_id_foreign_key migration Inverse the has_multiple_clusters? helper usage Remove block styling from search dropdown ...
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb2
-rw-r--r--spec/controllers/projects/pipeline_schedules_controller_spec.rb67
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb13
-rw-r--r--spec/features/help_pages_spec.rb18
-rw-r--r--spec/features/issues/issue_detail_spec.rb2
-rw-r--r--spec/features/issues_spec.rb1006
-rw-r--r--spec/features/merge_requests/image_diff_notes_spec.rb (renamed from spec/features/merge_requests/image_diff_notes.rb)42
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb8
-rw-r--r--spec/features/projects/issuable_templates_spec.rb8
-rw-r--r--spec/features/tags/master_views_tags_spec.rb5
-rw-r--r--spec/helpers/notes_helper_spec.rb14
-rw-r--r--spec/javascripts/merge_request_notes_spec.js4
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js19
-rw-r--r--spec/javascripts/notes_spec.js4
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js28
-rw-r--r--spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js13
-rw-r--r--spec/lib/gitlab/action_rate_limiter_spec.rb29
-rw-r--r--spec/lib/gitlab/git/gitlab_projects_spec.rb6
-rw-r--r--spec/models/blob_viewer/package_json_spec.rb47
-rw-r--r--spec/models/commit_spec.rb39
-rw-r--r--spec/models/repository_spec.rb57
-rw-r--r--spec/policies/ci/pipeline_schedule_policy_spec.rb92
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb6
-rw-r--r--spec/services/issuable/destroy_service_spec.rb16
-rw-r--r--spec/services/notes/destroy_service_spec.rb16
-rw-r--r--spec/services/projects/unlink_fork_service_spec.rb20
-rw-r--r--spec/services/todo_service_spec.rb23
-rw-r--r--spec/views/events/event/_push.html.haml_spec.rb55
-rw-r--r--spec/workers/run_pipeline_schedule_worker_spec.rb39
30 files changed, 1137 insertions, 563 deletions
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index c5d08cb0b9d..a2ef937609b 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -874,7 +874,7 @@ describe Projects::IssuesController do
end
it 'delegates the update of the todos count cache to TodoService' do
- expect_any_instance_of(TodoService).to receive(:destroy_issuable).with(issue, owner).once
+ expect_any_instance_of(TodoService).to receive(:destroy_target).with(issue).once
delete :destroy, namespace_id: project.namespace, project_id: project, id: issue.iid
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index d03ecefe47f..58116e6e0fe 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -468,7 +468,7 @@ describe Projects::MergeRequestsController do
end
it 'delegates the update of the todos count cache to TodoService' do
- expect_any_instance_of(TodoService).to receive(:destroy_issuable).with(merge_request, owner).once
+ expect_any_instance_of(TodoService).to receive(:destroy_target).with(merge_request).once
delete :destroy, namespace_id: project.namespace, project_id: project, id: merge_request.iid
end
diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index 4e52e261920..966ffdf6996 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -3,10 +3,12 @@ require 'spec_helper'
describe Projects::PipelineSchedulesController do
include AccessMatchersForController
- set(:project) { create(:project, :public) }
- let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) }
+ set(:project) { create(:project, :public, :repository) }
+ set(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) }
describe 'GET #index' do
+ render_views
+
let(:scope) { nil }
let!(:inactive_pipeline_schedule) do
create(:ci_pipeline_schedule, :inactive, project: project)
@@ -96,7 +98,7 @@ describe Projects::PipelineSchedulesController do
end
end
- context 'when variables_attributes has two variables and duplicted' do
+ context 'when variables_attributes has two variables and duplicated' do
let(:schedule) do
basic_param.merge({
variables_attributes: [{ key: 'AAA', value: 'AAA123' }, { key: 'AAA', value: 'BBB123' }]
@@ -364,6 +366,65 @@ describe Projects::PipelineSchedulesController do
end
end
+ describe 'POST #play', :clean_gitlab_redis_cache do
+ set(:user) { create(:user) }
+ let(:ref) { 'master' }
+
+ before do
+ project.add_developer(user)
+
+ sign_in(user)
+ end
+
+ context 'when an anonymous user makes the request' do
+ before do
+ sign_out(user)
+ end
+
+ it 'does not allow pipeline to be executed' do
+ expect(RunPipelineScheduleWorker).not_to receive(:perform_async)
+
+ post :play, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'when a developer makes the request' do
+ it 'executes a new pipeline' do
+ expect(RunPipelineScheduleWorker).to receive(:perform_async).with(pipeline_schedule.id, user.id).and_return('job-123')
+
+ post :play, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+
+ expect(flash[:notice]).to start_with 'Successfully scheduled a pipeline to run'
+ expect(response).to have_gitlab_http_status(302)
+ end
+
+ it 'prevents users from scheduling the same pipeline repeatedly' do
+ 2.times do
+ post :play, namespace_id: project.namespace.to_param, project_id: project, id: pipeline_schedule.id
+ end
+
+ expect(flash.to_a.size).to eq(2)
+ expect(flash[:alert]).to eq 'You cannot play this scheduled pipeline at the moment. Please wait a minute.'
+ expect(response).to have_gitlab_http_status(302)
+ end
+ end
+
+ context 'when a developer attempts to schedule a protected ref' do
+ it 'does not allow pipeline to be executed' do
+ create(:protected_branch, project: project, name: ref)
+ protected_schedule = create(:ci_pipeline_schedule, project: project, ref: ref)
+
+ expect(RunPipelineScheduleWorker).not_to receive(:perform_async)
+
+ post :play, namespace_id: project.namespace.to_param, project_id: project, id: protected_schedule.id
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+
describe 'DELETE #destroy' do
set(:user) { create(:user) }
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index 1604a2da485..35ac999cc65 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -17,13 +17,10 @@ describe Projects::PipelinesController do
describe 'GET index.json' do
before do
- branch_head = project.commit
- parent = branch_head.parent
-
- create(:ci_empty_pipeline, status: 'pending', project: project, sha: branch_head.id)
- create(:ci_empty_pipeline, status: 'running', project: project, sha: branch_head.id)
- create(:ci_empty_pipeline, status: 'created', project: project, sha: parent.id)
- create(:ci_empty_pipeline, status: 'success', project: project, sha: parent.id)
+ %w(pending running created success).each_with_index do |status, index|
+ sha = project.commit("HEAD~#{index}")
+ create(:ci_empty_pipeline, status: status, project: project, sha: sha)
+ end
end
subject do
@@ -46,7 +43,7 @@ describe Projects::PipelinesController do
context 'when performing gitaly calls', :request_store do
it 'limits the Gitaly requests' do
- expect { subject }.to change { Gitlab::GitalyClient.get_request_count }.by(8)
+ expect { subject }.to change { Gitlab::GitalyClient.get_request_count }.by(3)
end
end
end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index ab896a310be..0d04ed612c2 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -32,6 +32,24 @@ describe 'Help Pages' do
it_behaves_like 'help page', prefix: '/gitlab'
end
+
+ context 'quick link shortcuts', :js do
+ before do
+ visit help_path
+ end
+
+ it 'focuses search bar' do
+ find('.js-trigger-search-bar').click
+
+ expect(page).to have_selector('#search:focus')
+ end
+
+ it 'opens shortcuts help dialog' do
+ find('.js-trigger-shortcut').click
+
+ expect(page).to have_selector('#modal-shortcuts')
+ end
+ end
end
context 'in a production environment with version check enabled', :js do
diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb
index 4224a8fe5d4..babb0285590 100644
--- a/spec/features/issues/issue_detail_spec.rb
+++ b/spec/features/issues/issue_detail_spec.rb
@@ -24,7 +24,7 @@ feature 'Issue Detail', :js do
visit project_issue_path(project, issue)
wait_for_requests
- click_link 'Edit'
+ page.find('.js-issuable-edit').click
fill_in 'issuable-title', with: 'issue title'
click_button 'Save'
wait_for_requests
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 852d9e368aa..d1ff057a0c6 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -8,729 +8,753 @@ describe 'Issues' do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
- before do
- sign_in(user)
- user2 = create(:user)
-
- project.team << [[user, user2], :developer]
- end
+ describe 'while user is signed out' do
+ describe 'empty state' do
+ it 'user sees empty state' do
+ visit project_issues_path(project)
- describe 'Edit issue' do
- let!(:issue) do
- create(:issue,
- author: user,
- assignees: [user],
- project: project)
+ expect(page).to have_content('Register / Sign In')
+ expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project.')
+ expect(page).to have_content('You can register or sign in to create issues for this project.')
+ end
end
+ end
+ describe 'while user is signed in' do
before do
- visit edit_project_issue_path(project, issue)
- find('.js-zen-enter').click
- end
-
- it 'opens new issue popup' do
- expect(page).to have_content("Issue ##{issue.iid}")
- end
- end
+ sign_in(user)
+ user2 = create(:user)
- describe 'Editing issue assignee' do
- let!(:issue) do
- create(:issue,
- author: user,
- assignees: [user],
- project: project)
+ project.team << [[user, user2], :developer]
end
- it 'allows user to select unassigned', :js do
- visit edit_project_issue_path(project, issue)
-
- expect(page).to have_content "Assignee #{user.name}"
+ describe 'empty state' do
+ it 'user sees empty state' do
+ visit project_issues_path(project)
- first('.js-user-search').click
- click_link 'Unassigned'
+ expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project')
+ expect(page).to have_content('Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.')
+ expect(page).to have_content('New issue')
+ end
+ end
- click_button 'Save changes'
+ describe 'Edit issue' do
+ let!(:issue) do
+ create(:issue,
+ author: user,
+ assignees: [user],
+ project: project)
+ end
- page.within('.assignee') do
- expect(page).to have_content 'No assignee - assign yourself'
+ before do
+ visit edit_project_issue_path(project, issue)
+ find('.js-zen-enter').click
end
- expect(issue.reload.assignees).to be_empty
+ it 'opens new issue popup' do
+ expect(page).to have_content("Issue ##{issue.iid}")
+ end
end
- end
- describe 'due date', :js do
- context 'on new form' do
- before do
- visit new_project_issue_path(project)
+ describe 'Editing issue assignee' do
+ let!(:issue) do
+ create(:issue,
+ author: user,
+ assignees: [user],
+ project: project)
end
- it 'saves 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
+ it 'allows user to select unassigned', :js do
+ visit edit_project_issue_path(project, issue)
- page.within '.pika-single' do
- click_button date.day
- end
+ expect(page).to have_content "Assignee #{user.name}"
- expect(find('#issuable-due-date').value).to eq date.to_s
+ first('.js-user-search').click
+ click_link 'Unassigned'
- click_button 'Submit issue'
+ click_button 'Save changes'
- page.within '.issuable-sidebar' do
- expect(page).to have_content date.to_s(:medium)
+ page.within('.assignee') do
+ expect(page).to have_content 'No assignee - assign yourself'
end
+
+ expect(issue.reload.assignees).to be_empty
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) }
+ describe 'due date', :js do
+ context 'on new form' do
+ before do
+ visit new_project_issue_path(project)
+ end
- before do
- visit edit_project_issue_path(project, issue)
- end
+ it 'saves with due date' do
+ date = Date.today.at_beginning_of_month
- it 'saves 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
- expect(find('#issuable-due-date').value).to eq date.to_s
+ page.within '.pika-single' do
+ click_button date.day
+ end
- date = date.tomorrow
+ expect(find('#issuable-due-date').value).to eq date.to_s
- fill_in 'issue_title', with: 'bug 345'
- fill_in 'issue_description', with: 'bug description'
- find('#issuable-due-date').click
+ click_button 'Submit issue'
- page.within '.pika-single' do
- click_button date.day
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
end
+ end
- expect(find('#issuable-due-date').value).to eq date.to_s
+ context 'on edit form' do
+ let(:issue) { create(:issue, author: user, project: project, due_date: Date.today.at_beginning_of_month.to_s) }
- click_button 'Save changes'
-
- page.within '.issuable-sidebar' do
- expect(page).to have_content date.to_s(:medium)
+ before do
+ visit edit_project_issue_path(project, issue)
end
- end
- it 'warns about version conflict' do
- issue.update(title: "New title")
+ it 'saves 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'
+ expect(find('#issuable-due-date').value).to eq date.to_s
- click_button 'Save changes'
+ date = date.tomorrow
- expect(page).to have_content 'Someone edited the issue the same time you did'
- end
- end
- end
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+ find('#issuable-due-date').click
+
+ page.within '.pika-single' do
+ click_button date.day
+ end
- describe 'Issue info' do
- it 'links to current issue in breadcrubs' do
- issue = create(:issue, project: project)
+ expect(find('#issuable-due-date').value).to eq date.to_s
- visit project_issue_path(project, issue)
+ click_button 'Save changes'
- expect(find('.breadcrumbs-sub-title a')[:href]).to end_with(issue_path(issue))
- end
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
- it 'excludes award_emoji from comment count' do
- issue = create(:issue, author: user, assignees: [user], project: project, title: 'foobar')
- create(:award_emoji, awardable: issue)
+ it 'warns about version conflict' do
+ issue.update(title: "New title")
- visit project_issues_path(project, assignee_id: user.id)
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
- expect(page).to have_content 'foobar'
- expect(page.all('.no-comments').first.text).to eq "0"
- end
- end
+ click_button 'Save changes'
- describe 'Filter issue' do
- before do
- %w(foobar barbaz gitlab).each do |title|
- create(:issue,
- author: user,
- assignees: [user],
- project: project,
- title: title)
+ expect(page).to have_content 'Someone edited the issue the same time you did'
+ end
end
-
- @issue = Issue.find_by(title: 'foobar')
- @issue.milestone = create(:milestone, project: project)
- @issue.assignees = []
- @issue.save
end
- let(:issue) { @issue }
+ describe 'Issue info' do
+ it 'links to current issue in breadcrubs' do
+ issue = create(:issue, project: project)
- it 'allows filtering by issues with no specified assignee' do
- visit project_issues_path(project, assignee_id: IssuableFinder::NONE)
+ visit project_issue_path(project, issue)
- expect(page).to have_content 'foobar'
- expect(page).not_to have_content 'barbaz'
- expect(page).not_to have_content 'gitlab'
- end
+ expect(find('.breadcrumbs-sub-title a')[:href]).to end_with(issue_path(issue))
+ end
- it 'allows filtering by a specified assignee' do
- visit project_issues_path(project, assignee_id: user.id)
+ it 'excludes award_emoji from comment count' do
+ issue = create(:issue, author: user, assignees: [user], project: project, title: 'foobar')
+ create(:award_emoji, awardable: issue)
- expect(page).not_to have_content 'foobar'
- expect(page).to have_content 'barbaz'
- expect(page).to have_content 'gitlab'
- end
- end
+ visit project_issues_path(project, assignee_id: user.id)
- describe 'filter issue' do
- titles = %w[foo bar baz]
- titles.each_with_index do |title, index|
- let!(title.to_sym) do
- create(:issue, title: title,
- project: project,
- created_at: Time.now - (index * 60))
+ expect(page).to have_content 'foobar'
+ expect(page.all('.no-comments').first.text).to eq "0"
end
end
- let(:newer_due_milestone) { create(:milestone, due_date: '2013-12-11') }
- let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
- it 'sorts by newest' do
- visit project_issues_path(project, sort: sort_value_created_date)
+ describe 'Filter issue' do
+ before do
+ %w(foobar barbaz gitlab).each do |title|
+ create(:issue,
+ author: user,
+ assignees: [user],
+ project: project,
+ title: title)
+ end
- expect(first_issue).to include('foo')
- expect(last_issue).to include('baz')
- end
+ @issue = Issue.find_by(title: 'foobar')
+ @issue.milestone = create(:milestone, project: project)
+ @issue.assignees = []
+ @issue.save
+ end
- it 'sorts by most recently updated' do
- baz.updated_at = Time.now + 100
- baz.save
- visit project_issues_path(project, sort: sort_value_recently_updated)
+ let(:issue) { @issue }
- expect(first_issue).to include('baz')
- end
+ it 'allows filtering by issues with no specified assignee' do
+ visit project_issues_path(project, assignee_id: IssuableFinder::NONE)
- describe 'sorting by due date' do
- before do
- foo.update(due_date: 1.day.from_now)
- bar.update(due_date: 6.days.from_now)
+ expect(page).to have_content 'foobar'
+ expect(page).not_to have_content 'barbaz'
+ expect(page).not_to have_content 'gitlab'
end
- it 'sorts by due date' do
- visit project_issues_path(project, sort: sort_value_due_date)
+ it 'allows filtering by a specified assignee' do
+ visit project_issues_path(project, assignee_id: user.id)
- expect(first_issue).to include('foo')
+ expect(page).not_to have_content 'foobar'
+ expect(page).to have_content 'barbaz'
+ expect(page).to have_content 'gitlab'
end
+ end
- it 'sorts by due date by excluding nil due dates' do
- bar.update(due_date: nil)
+ describe 'filter issue' do
+ titles = %w[foo bar baz]
+ titles.each_with_index do |title, index|
+ let!(title.to_sym) do
+ create(:issue, title: title,
+ project: project,
+ created_at: Time.now - (index * 60))
+ end
+ end
+ let(:newer_due_milestone) { create(:milestone, due_date: '2013-12-11') }
+ let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') }
- visit project_issues_path(project, sort: sort_value_due_date)
+ it 'sorts by newest' do
+ visit project_issues_path(project, sort: sort_value_created_date)
expect(first_issue).to include('foo')
+ expect(last_issue).to include('baz')
end
- context 'with a filter on labels' do
- let(:label) { create(:label, project: project) }
+ it 'sorts by most recently updated' do
+ baz.updated_at = Time.now + 100
+ baz.save
+ visit project_issues_path(project, sort: sort_value_recently_updated)
+ expect(first_issue).to include('baz')
+ end
+
+ describe 'sorting by due date' do
before do
- create(:label_link, label: label, target: foo)
+ foo.update(due_date: 1.day.from_now)
+ bar.update(due_date: 6.days.from_now)
+ end
+
+ it 'sorts by due date' do
+ visit project_issues_path(project, sort: sort_value_due_date)
+
+ expect(first_issue).to include('foo')
end
- it 'sorts by least recently due date by excluding nil due dates' do
+ it 'sorts by due date by excluding nil due dates' do
bar.update(due_date: nil)
- visit project_issues_path(project, label_names: [label.name], sort: sort_value_due_date_later)
+ visit project_issues_path(project, sort: sort_value_due_date)
expect(first_issue).to include('foo')
end
- end
- end
- describe 'filtering by due date' do
- before do
- foo.update(due_date: 1.day.from_now)
- bar.update(due_date: 6.days.from_now)
- end
+ context 'with a filter on labels' do
+ let(:label) { create(:label, project: project) }
+
+ before do
+ create(:label_link, label: label, target: foo)
+ end
+
+ it 'sorts by least recently due date by excluding nil due dates' do
+ bar.update(due_date: nil)
- it 'filters by none' do
- visit project_issues_path(project, due_date: Issue::NoDueDate.name)
+ visit project_issues_path(project, label_names: [label.name], sort: sort_value_due_date_later)
- page.within '.issues-holder' do
- expect(page).not_to have_content('foo')
- expect(page).not_to have_content('bar')
- expect(page).to have_content('baz')
+ expect(first_issue).to include('foo')
+ end
end
end
- it 'filters by any' do
- visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
+ describe 'filtering by due date' do
+ before do
+ foo.update(due_date: 1.day.from_now)
+ bar.update(due_date: 6.days.from_now)
+ end
+
+ it 'filters by none' do
+ visit project_issues_path(project, due_date: Issue::NoDueDate.name)
- page.within '.issues-holder' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).to have_content('baz')
+ page.within '.issues-holder' do
+ expect(page).not_to have_content('foo')
+ expect(page).not_to have_content('bar')
+ expect(page).to have_content('baz')
+ end
+ end
+
+ it 'filters by any' do
+ visit project_issues_path(project, due_date: Issue::AnyDueDate.name)
+
+ page.within '.issues-holder' do
+ expect(page).to have_content('foo')
+ expect(page).to have_content('bar')
+ expect(page).to have_content('baz')
+ end
end
- end
- it 'filters by due this week' do
- foo.update(due_date: Date.today.beginning_of_week + 2.days)
- bar.update(due_date: Date.today.end_of_week)
- baz.update(due_date: Date.today - 8.days)
+ it 'filters by due this week' do
+ foo.update(due_date: Date.today.beginning_of_week + 2.days)
+ bar.update(due_date: Date.today.end_of_week)
+ baz.update(due_date: Date.today - 8.days)
- visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
+ visit project_issues_path(project, due_date: Issue::DueThisWeek.name)
- page.within '.issues-holder' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).not_to have_content('baz')
+ page.within '.issues-holder' do
+ expect(page).to have_content('foo')
+ expect(page).to have_content('bar')
+ expect(page).not_to have_content('baz')
+ end
end
- end
- it 'filters by due this month' do
- foo.update(due_date: Date.today.beginning_of_month + 2.days)
- bar.update(due_date: Date.today.end_of_month)
- baz.update(due_date: Date.today - 50.days)
+ it 'filters by due this month' do
+ foo.update(due_date: Date.today.beginning_of_month + 2.days)
+ bar.update(due_date: Date.today.end_of_month)
+ baz.update(due_date: Date.today - 50.days)
- visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
+ visit project_issues_path(project, due_date: Issue::DueThisMonth.name)
- page.within '.issues-holder' do
- expect(page).to have_content('foo')
- expect(page).to have_content('bar')
- expect(page).not_to have_content('baz')
+ page.within '.issues-holder' do
+ expect(page).to have_content('foo')
+ expect(page).to have_content('bar')
+ expect(page).not_to have_content('baz')
+ end
end
- end
- it 'filters by overdue' do
- foo.update(due_date: Date.today + 2.days)
- bar.update(due_date: Date.today + 20.days)
- baz.update(due_date: Date.yesterday)
+ it 'filters by overdue' do
+ foo.update(due_date: Date.today + 2.days)
+ bar.update(due_date: Date.today + 20.days)
+ baz.update(due_date: Date.yesterday)
- visit project_issues_path(project, due_date: Issue::Overdue.name)
+ visit project_issues_path(project, due_date: Issue::Overdue.name)
- page.within '.issues-holder' do
- expect(page).not_to have_content('foo')
- expect(page).not_to have_content('bar')
- expect(page).to have_content('baz')
+ page.within '.issues-holder' do
+ expect(page).not_to have_content('foo')
+ expect(page).not_to have_content('bar')
+ expect(page).to have_content('baz')
+ end
end
end
- end
- describe 'sorting by milestone' do
- before do
- foo.milestone = newer_due_milestone
- foo.save
- bar.milestone = later_due_milestone
- bar.save
- end
+ describe 'sorting by milestone' do
+ before do
+ foo.milestone = newer_due_milestone
+ foo.save
+ bar.milestone = later_due_milestone
+ bar.save
+ end
- it 'sorts by milestone' do
- visit project_issues_path(project, sort: sort_value_milestone)
+ it 'sorts by milestone' do
+ visit project_issues_path(project, sort: sort_value_milestone)
- expect(first_issue).to include('foo')
- expect(last_issue).to include('baz')
+ expect(first_issue).to include('foo')
+ expect(last_issue).to include('baz')
+ end
end
- end
- describe 'combine filter and sort' do
- let(:user2) { create(:user) }
+ describe 'combine filter and sort' do
+ let(:user2) { create(:user) }
- before do
- foo.assignees << user2
- foo.save
- bar.assignees << user2
- bar.save
- end
+ before do
+ foo.assignees << user2
+ foo.save
+ bar.assignees << user2
+ bar.save
+ end
- it 'sorts with a filter applied' do
- visit project_issues_path(project, sort: sort_value_created_date, assignee_id: user2.id)
+ it 'sorts with a filter applied' do
+ visit project_issues_path(project, sort: sort_value_created_date, assignee_id: user2.id)
- expect(first_issue).to include('foo')
- expect(last_issue).to include('bar')
- expect(page).not_to have_content('baz')
+ expect(first_issue).to include('foo')
+ expect(last_issue).to include('bar')
+ expect(page).not_to have_content('baz')
+ end
end
end
- end
- describe 'when I want to reset my incoming email token' do
- let(:project1) { create(:project, namespace: user.namespace) }
- let!(:issue) { create(:issue, project: project1) }
+ describe 'when I want to reset my incoming email token' do
+ let(:project1) { create(:project, namespace: user.namespace) }
+ let!(:issue) { create(:issue, project: project1) }
- before do
- stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
- project1.team << [user, :master]
- visit namespace_project_issues_path(user.namespace, project1)
- end
+ before do
+ stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
+ project1.team << [user, :master]
+ visit namespace_project_issues_path(user.namespace, project1)
+ end
- it 'changes incoming email address token', :js do
- find('.issuable-email-modal-btn').click
- previous_token = find('input#issuable_email').value
- find('.incoming-email-token-reset').click
+ it 'changes incoming email address token', :js do
+ find('.issuable-email-modal-btn').click
+ previous_token = find('input#issuable_email').value
+ find('.incoming-email-token-reset').click
- wait_for_requests
+ wait_for_requests
- expect(page).to have_no_field('issuable_email', with: previous_token)
- new_token = project1.new_issuable_address(user.reload, 'issue')
- expect(page).to have_field(
- 'issuable_email',
- with: new_token
- )
+ expect(page).to have_no_field('issuable_email', with: previous_token)
+ new_token = project1.new_issuable_address(user.reload, 'issue')
+ expect(page).to have_field(
+ 'issuable_email',
+ with: new_token
+ )
+ end
end
- end
- describe 'update labels from issue#show', :js do
- let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
- let!(:label) { create(:label, project: project) }
+ describe 'update labels from issue#show', :js do
+ let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ let!(:label) { create(:label, project: project) }
- before do
- visit project_issue_path(project, issue)
- end
+ before do
+ visit project_issue_path(project, issue)
+ end
- it 'will not send ajax request when no data is changed' do
- page.within '.labels' do
- click_link 'Edit'
+ it 'will not send ajax request when no data is changed' do
+ page.within '.labels' do
+ click_link 'Edit'
- find('.dropdown-menu-close', match: :first).click
+ find('.dropdown-menu-close', match: :first).click
- expect(page).not_to have_selector('.block-loading')
+ expect(page).not_to have_selector('.block-loading')
+ end
end
end
- end
- describe 'update assignee from issue#show' do
- let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ describe 'update assignee from issue#show' do
+ let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
- context 'by authorized user' do
- it 'allows user to select unassigned', :js do
- visit project_issue_path(project, issue)
+ context 'by authorized user' do
+ it 'allows user to select unassigned', :js do
+ visit project_issue_path(project, issue)
- page.within('.assignee') do
- expect(page).to have_content "#{user.name}"
+ page.within('.assignee') do
+ expect(page).to have_content "#{user.name}"
- click_link 'Edit'
- click_link 'Unassigned'
- first('.title').click
- expect(page).to have_content 'No assignee'
- end
+ click_link 'Edit'
+ click_link 'Unassigned'
+ first('.title').click
+ expect(page).to have_content 'No assignee'
+ end
- # wait_for_requests does not work with vue-resource at the moment
- sleep 1
+ # wait_for_requests does not work with vue-resource at the moment
+ sleep 1
- expect(issue.reload.assignees).to be_empty
- end
+ expect(issue.reload.assignees).to be_empty
+ end
- it 'allows user to select an assignee', :js do
- issue2 = create(:issue, project: project, author: user)
- visit project_issue_path(project, issue2)
+ it 'allows user to select an assignee', :js do
+ issue2 = create(:issue, project: project, author: user)
+ visit project_issue_path(project, issue2)
- page.within('.assignee') do
- expect(page).to have_content "No assignee"
- end
+ page.within('.assignee') do
+ expect(page).to have_content "No assignee"
+ end
- page.within '.assignee' do
- click_link 'Edit'
- end
+ page.within '.assignee' do
+ click_link 'Edit'
+ end
- page.within '.dropdown-menu-user' do
- click_link user.name
- end
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
- page.within('.assignee') do
- expect(page).to have_content user.name
+ page.within('.assignee') do
+ expect(page).to have_content user.name
+ end
end
- end
- it 'allows user to unselect themselves', :js do
- issue2 = create(:issue, project: project, author: user)
- visit project_issue_path(project, issue2)
+ it 'allows user to unselect themselves', :js do
+ issue2 = create(:issue, project: project, author: user)
+ visit project_issue_path(project, issue2)
- page.within '.assignee' do
- click_link 'Edit'
- click_link user.name
+ page.within '.assignee' do
+ click_link 'Edit'
+ click_link user.name
- page.within '.value .author' do
- expect(page).to have_content user.name
- end
+ page.within '.value .author' do
+ expect(page).to have_content user.name
+ end
- click_link 'Edit'
- click_link user.name
+ click_link 'Edit'
+ click_link user.name
- page.within '.value .assign-yourself' do
- expect(page).to have_content "No assignee"
+ page.within '.value .assign-yourself' do
+ expect(page).to have_content "No assignee"
+ end
end
end
end
- end
- context 'by unauthorized user' do
- let(:guest) { create(:user) }
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- before do
- project.team << [[guest], :guest]
- end
+ before do
+ project.team << [[guest], :guest]
+ end
- it 'shows assignee text', :js do
- sign_out(:user)
- sign_in(guest)
+ it 'shows assignee text', :js do
+ sign_out(:user)
+ sign_in(guest)
- visit project_issue_path(project, issue)
- expect(page).to have_content issue.assignees.first.name
+ visit project_issue_path(project, issue)
+ expect(page).to have_content issue.assignees.first.name
+ end
end
end
- end
- describe 'update milestone from issue#show' do
- let!(:issue) { create(:issue, project: project, author: user) }
- let!(:milestone) { create(:milestone, project: project) }
+ describe 'update milestone from issue#show' do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:milestone) { create(:milestone, project: project) }
- context 'by authorized user' do
- it 'allows user to select unassigned', :js do
- visit project_issue_path(project, issue)
+ context 'by authorized user' do
+ it 'allows user to select unassigned', :js do
+ visit project_issue_path(project, issue)
- page.within('.milestone') do
- expect(page).to have_content "None"
- end
+ page.within('.milestone') do
+ expect(page).to have_content "None"
+ end
- find('.block.milestone .edit-link').click
- sleep 2 # wait for ajax stuff to complete
- first('.dropdown-content li').click
- sleep 2
- page.within('.milestone') do
- expect(page).to have_content 'None'
+ find('.block.milestone .edit-link').click
+ sleep 2 # wait for ajax stuff to complete
+ first('.dropdown-content li').click
+ sleep 2
+ page.within('.milestone') do
+ expect(page).to have_content 'None'
+ end
+
+ expect(issue.reload.milestone).to be_nil
end
- expect(issue.reload.milestone).to be_nil
- end
+ it 'allows user to de-select milestone', :js do
+ visit project_issue_path(project, issue)
- it 'allows user to de-select milestone', :js do
- visit project_issue_path(project, issue)
+ page.within('.milestone') do
+ click_link 'Edit'
+ click_link milestone.title
- page.within('.milestone') do
- click_link 'Edit'
- click_link milestone.title
-
- page.within '.value' do
- expect(page).to have_content milestone.title
- end
+ page.within '.value' do
+ expect(page).to have_content milestone.title
+ end
- click_link 'Edit'
- click_link milestone.title
+ click_link 'Edit'
+ click_link milestone.title
- page.within '.value' do
- expect(page).to have_content 'None'
+ page.within '.value' do
+ expect(page).to have_content 'None'
+ end
end
end
end
- end
- context 'by unauthorized user' do
- let(:guest) { create(:user) }
+ context 'by unauthorized user' do
+ let(:guest) { create(:user) }
- before do
- project.team << [guest, :guest]
- issue.milestone = milestone
- issue.save
- end
+ before do
+ project.team << [guest, :guest]
+ issue.milestone = milestone
+ issue.save
+ end
- it 'shows milestone text', :js do
- sign_out(:user)
- sign_in(guest)
+ it 'shows milestone text', :js do
+ sign_out(:user)
+ sign_in(guest)
- visit project_issue_path(project, issue)
- expect(page).to have_content milestone.title
+ visit project_issue_path(project, issue)
+ expect(page).to have_content milestone.title
+ end
end
end
- end
- describe 'new issue' do
- let!(:issue) { create(:issue, project: project) }
+ describe 'new issue' do
+ let!(:issue) { create(:issue, project: project) }
- context 'by unauthenticated user' do
- before do
- sign_out(:user)
- end
+ context 'by unauthenticated user' do
+ before do
+ sign_out(:user)
+ end
- it 'redirects to signin then back to new issue after signin' do
- visit project_issues_path(project)
+ it 'redirects to signin then back to new issue after signin' do
+ visit project_issues_path(project)
- page.within '.nav-controls' do
- click_link 'New issue'
- end
+ page.within '.nav-controls' do
+ click_link 'New issue'
+ end
- expect(current_path).to eq new_user_session_path
+ expect(current_path).to eq new_user_session_path
- gitlab_sign_in(create(:user))
+ gitlab_sign_in(create(:user))
- expect(current_path).to eq new_project_issue_path(project)
+ expect(current_path).to eq new_project_issue_path(project)
+ end
end
- end
- context 'dropzone upload file', :js do
- before do
- visit new_project_issue_path(project)
- end
+ context 'dropzone upload file', :js do
+ before do
+ visit new_project_issue_path(project)
+ end
- it 'uploads file when dragging into textarea' do
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ it 'uploads file when dragging into textarea' do
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- expect(page.find_field("issue_description").value).to have_content 'banana_sample'
- end
+ expect(page.find_field("issue_description").value).to have_content 'banana_sample'
+ end
- it "doesn't add double newline to end of a single attachment markdown" do
- dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
+ it "doesn't add double newline to end of a single attachment markdown" do
+ dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif')
- expect(page.find_field("issue_description").value).not_to match /\n\n$/
- end
+ expect(page.find_field("issue_description").value).not_to match /\n\n$/
+ end
- it "cancels a file upload correctly" do
- slow_requests do
- dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false)
+ it "cancels a file upload correctly" do
+ slow_requests do
+ dropzone_file([Rails.root.join('spec', 'fixtures', 'dk.png')], 0, false)
- click_button 'Cancel'
- end
+ click_button 'Cancel'
+ end
- expect(page).to have_button('Attach a file')
- expect(page).not_to have_button('Cancel')
- expect(page).not_to have_selector('.uploading-progress-container', visible: true)
+ expect(page).to have_button('Attach a file')
+ expect(page).not_to have_button('Cancel')
+ expect(page).not_to have_selector('.uploading-progress-container', visible: true)
+ end
end
- end
- context 'form filled by URL parameters' do
- let(:project) { create(:project, :public, :repository) }
+ context 'form filled by URL parameters' do
+ let(:project) { create(:project, :public, :repository) }
- before do
- project.repository.create_file(
- user,
- '.gitlab/issue_templates/bug.md',
- 'this is a test "bug" template',
- message: 'added issue template',
- branch_name: 'master')
-
- visit new_project_issue_path(project, issuable_template: 'bug')
- end
+ before do
+ project.repository.create_file(
+ user,
+ '.gitlab/issue_templates/bug.md',
+ 'this is a test "bug" template',
+ message: 'added issue template',
+ branch_name: 'master')
+
+ visit new_project_issue_path(project, issuable_template: 'bug')
+ end
- it 'fills in template' do
- expect(find('.js-issuable-selector .dropdown-toggle-text')).to have_content('bug')
+ it 'fills in template' do
+ expect(find('.js-issuable-selector .dropdown-toggle-text')).to have_content('bug')
+ end
end
end
- end
- describe 'new issue by email' do
- shared_examples 'show the email in the modal' do
- let(:issue) { create(:issue, project: project) }
+ describe 'new issue by email' do
+ shared_examples 'show the email in the modal' do
+ let(:issue) { create(:issue, project: project) }
- before do
- project.issues << issue
- stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
+ before do
+ project.issues << issue
+ stub_incoming_email_setting(enabled: true, address: "p+%{key}@gl.ab")
- visit project_issues_path(project)
- click_button('Email a new issue')
- end
+ visit project_issues_path(project)
+ click_button('Email a new issue')
+ end
- it 'click the button to show modal for the new email' do
- page.within '#issuable-email-modal' do
- email = project.new_issuable_address(user, 'issue')
+ it 'click the button to show modal for the new email' do
+ page.within '#issuable-email-modal' do
+ email = project.new_issuable_address(user, 'issue')
- expect(page).to have_selector("input[value='#{email}']")
+ expect(page).to have_selector("input[value='#{email}']")
+ end
end
end
- end
- context 'with existing issues' do
- let!(:issue) { create(:issue, project: project, author: user) }
+ context 'with existing issues' do
+ let!(:issue) { create(:issue, project: project, author: user) }
- it_behaves_like 'show the email in the modal'
- end
+ it_behaves_like 'show the email in the modal'
+ end
- context 'without existing issues' do
- it_behaves_like 'show the email in the modal'
+ context 'without existing issues' do
+ it_behaves_like 'show the email in the modal'
+ end
end
- end
- describe 'due date' do
- context 'update due on issue#show', :js do
- let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
+ describe 'due date' do
+ context 'update due on issue#show', :js do
+ let(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
- before do
- visit project_issue_path(project, issue)
- end
+ before do
+ visit project_issue_path(project, issue)
+ end
- it 'adds due date to issue' do
- date = Date.today.at_beginning_of_month + 2.days
+ it 'adds due date to issue' do
+ date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
+ page.within '.due_date' do
+ click_link 'Edit'
- page.within '.pika-single' do
- click_button date.day
- end
+ page.within '.pika-single' do
+ click_button date.day
+ end
- wait_for_requests
+ wait_for_requests
- expect(find('.value').text).to have_content date.strftime('%b %-d, %Y')
+ expect(find('.value').text).to have_content date.strftime('%b %-d, %Y')
+ end
end
- end
- it 'removes due date from issue' do
- date = Date.today.at_beginning_of_month + 2.days
+ it 'removes due date from issue' do
+ date = Date.today.at_beginning_of_month + 2.days
- page.within '.due_date' do
- click_link 'Edit'
+ page.within '.due_date' do
+ click_link 'Edit'
- page.within '.pika-single' do
- click_button date.day
- end
+ page.within '.pika-single' do
+ click_button date.day
+ end
- wait_for_requests
+ wait_for_requests
- expect(page).to have_no_content 'No due date'
+ expect(page).to have_no_content 'No due date'
- click_link 'remove due date'
- expect(page).to have_content 'No due date'
+ click_link 'remove due date'
+ expect(page).to have_content 'No due date'
+ end
end
end
end
- end
- describe 'title issue#show', :js do
- it 'updates the title', :js do
- issue = create(:issue, author: user, assignees: [user], project: project, title: 'new title')
+ describe 'title issue#show', :js do
+ it 'updates the title', :js do
+ issue = create(:issue, author: user, assignees: [user], project: project, title: 'new title')
- visit project_issue_path(project, issue)
+ visit project_issue_path(project, issue)
- expect(page).to have_text("new title")
+ expect(page).to have_text("new title")
- issue.update(title: "updated title")
+ issue.update(title: "updated title")
- wait_for_requests
- expect(page).to have_text("updated title")
+ wait_for_requests
+ expect(page).to have_text("updated title")
+ end
end
- end
- describe 'confidential issue#show', :js do
- it 'shows confidential sibebar information as confidential and can be turned off' do
- issue = create(:issue, :confidential, project: project)
+ describe 'confidential issue#show', :js do
+ it 'shows confidential sibebar information as confidential and can be turned off' do
+ issue = create(:issue, :confidential, project: project)
- visit project_issue_path(project, issue)
+ visit project_issue_path(project, issue)
- expect(page).to have_css('.issuable-note-warning')
- expect(find('.issuable-sidebar-item.confidentiality')).to have_css('.is-active')
- expect(find('.issuable-sidebar-item.confidentiality')).not_to have_css('.not-active')
+ expect(page).to have_css('.issuable-note-warning')
+ expect(find('.issuable-sidebar-item.confidentiality')).to have_css('.is-active')
+ expect(find('.issuable-sidebar-item.confidentiality')).not_to have_css('.not-active')
- find('.confidential-edit').click
- expect(page).to have_css('.sidebar-item-warning-message')
+ find('.confidential-edit').click
+ expect(page).to have_css('.sidebar-item-warning-message')
- within('.sidebar-item-warning-message') do
- find('.btn-close').click
- end
+ within('.sidebar-item-warning-message') do
+ find('.btn-close').click
+ end
- wait_for_requests
+ wait_for_requests
- visit project_issue_path(project, issue)
+ visit project_issue_path(project, issue)
- expect(page).not_to have_css('.is-active')
+ expect(page).not_to have_css('.is-active')
+ end
end
end
end
diff --git a/spec/features/merge_requests/image_diff_notes.rb b/spec/features/merge_requests/image_diff_notes_spec.rb
index 021c4e03428..ddc73437917 100644
--- a/spec/features/merge_requests/image_diff_notes.rb
+++ b/spec/features/merge_requests/image_diff_notes_spec.rb
@@ -10,8 +10,6 @@ feature 'image diff notes', :js do
project.team << [user, :master]
sign_in user
- page.driver.set_cookie('sidebar_collapsed', 'true')
-
# Stub helper to return any blob file as image from public app folder.
# This is necessary to run this specs since we don't display repo images in capybara.
allow_any_instance_of(DiffHelper).to receive(:diff_file_blob_raw_path).and_return('/apple-touch-icon.png')
@@ -141,13 +139,13 @@ feature 'image diff notes', :js do
end
it 'allows expanding/collapsing the discussion notes' do
- page.all('.js-diff-notes-toggle')[0].trigger('click')
- page.all('.js-diff-notes-toggle')[1].trigger('click')
+ page.all('.js-diff-notes-toggle')[0].click
+ page.all('.js-diff-notes-toggle')[1].click
expect(page).not_to have_content('image diff test comment')
- page.all('.js-diff-notes-toggle')[0].trigger('click')
- page.all('.js-diff-notes-toggle')[1].trigger('click')
+ page.all('.js-diff-notes-toggle')[0].click
+ page.all('.js-diff-notes-toggle')[1].click
expect(page).to have_content('image diff test comment')
end
@@ -196,13 +194,31 @@ feature 'image diff notes', :js do
expect(find('.onion-skin-frame')['style']).to match('width: 228px; height: 240px;')
end
+
+ it 'resets onion skin view mode opacity when toggling between view modes' do
+ find('.view-modes-menu .onion-skin').click
+
+ # Simulate dragging onion-skin slider
+ drag_and_drop_by(find('.dragger'), -30, 0)
+
+ expect(find('.onion-skin-frame .frame.added', visible: false)['style']).not_to match('opacity: 1;')
+
+ find('.view-modes-menu .swipe').click
+ find('.view-modes-menu .onion-skin').click
+
+ expect(find('.onion-skin-frame .frame.added', visible: false)['style']).to match('opacity: 1;')
+ end
end
-end
-def create_image_diff_note
- find('.js-add-image-diff-note-button', match: :first).click
- page.all('.js-add-image-diff-note-button')[0].trigger('click')
- find('.diff-content .note-textarea').native.send_keys('image diff test comment')
- click_button 'Comment'
- wait_for_requests
+ def drag_and_drop_by(element, right_by, down_by)
+ page.driver.browser.action.drag_and_drop_by(element.native, right_by, down_by).perform
+ end
+
+ def create_image_diff_note
+ find('.js-add-image-diff-note-button', match: :first).click
+ page.all('.js-add-image-diff-note-button')[0].click
+ find('.diff-content .note-textarea').native.send_keys('image diff test comment')
+ click_button 'Comment'
+ wait_for_requests
+ 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 6c616bf0456..8ac9821b879 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
@@ -2,15 +2,15 @@ require 'spec_helper'
feature 'project owner sees a link to create a license file in empty project', :js do
let(:project_master) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project_empty_repo) }
+
background do
- project.team << [project_master, :master]
+ project.add_master(project_master)
sign_in(project_master)
end
scenario 'project master creates a license file from a template' do
visit project_path(project)
- click_link 'Create empty bare repository'
click_on 'LICENSE'
expect(page).to have_content('New file')
@@ -26,8 +26,6 @@ feature 'project owner sees a link to create a license file in empty project', :
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
- FileUtils.rm_f(File.join(project.repository.path, 'hooks', 'pre-receive'))
click_button 'Commit changes'
expect(current_path).to eq(
diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb
index 0257cd157c9..4319fc2746c 100644
--- a/spec/features/projects/issuable_templates_spec.rb
+++ b/spec/features/projects/issuable_templates_spec.rb
@@ -32,9 +32,7 @@ feature 'issuable templates', :js do
message: 'added issue template',
branch_name: 'master')
visit project_issue_path project, issue
- page.within('.js-issuable-actions') do
- click_on 'Edit'
- end
+ page.find('.js-issuable-edit').click
fill_in :'issuable-title', with: 'test issue title'
end
@@ -77,9 +75,7 @@ feature 'issuable templates', :js do
message: 'added issue template',
branch_name: 'master')
visit project_issue_path project, issue
- page.within('.js-issuable-actions') do
- click_on 'Edit'
- end
+ page.find('.js-issuable-edit').click
fill_in :'issuable-title', with: 'test issue title'
fill_in :'issue-description', with: prior_description
end
diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb
index 9edc7ced163..4662367d843 100644
--- a/spec/features/tags/master_views_tags_spec.rb
+++ b/spec/features/tags/master_views_tags_spec.rb
@@ -4,18 +4,17 @@ feature 'Master views tags' do
let(:user) { create(:user) }
before do
- project.team << [user, :master]
+ project.add_master(user)
sign_in(user)
end
context 'when project has no tags' do
let(:project) { create(:project_empty_repo) }
+
before do
visit project_path(project)
click_on 'README'
fill_in :commit_message, with: 'Add a README file', visible: true
- # Remove pre-receive hook so we can push without auth
- FileUtils.rm_f(File.join(project.repository.path, 'hooks', 'pre-receive'))
click_button 'Commit changes'
visit project_tags_path(project)
end
diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb
index cd15e27b497..36a44f8567a 100644
--- a/spec/helpers/notes_helper_spec.rb
+++ b/spec/helpers/notes_helper_spec.rb
@@ -41,6 +41,7 @@ describe NotesHelper do
describe '#discussion_path' do
let(:project) { create(:project, :repository) }
+ let(:anchor) { discussion.line_code }
context 'for a merge request discusion' do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project, importing: true) }
@@ -151,6 +152,15 @@ describe NotesHelper do
expect(helper.discussion_path(discussion)).to be_nil
end
end
+
+ context 'for a contextual commit discussion' do
+ let(:commit) { merge_request.commits.last }
+ let(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project, commit_id: commit.id).to_discussion }
+
+ it 'returns the merge request diff discussion scoped in the commit' do
+ expect(helper.discussion_path(discussion)).to eq(diffs_project_merge_request_path(project, merge_request, commit_id: commit.id, anchor: anchor))
+ end
+ end
end
context 'for a commit discussion' do
@@ -160,7 +170,7 @@ describe NotesHelper do
let(:discussion) { create(:diff_note_on_commit, project: project).to_discussion }
it 'returns the commit path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: anchor))
end
end
@@ -168,7 +178,7 @@ describe NotesHelper do
let(:discussion) { create(:legacy_diff_note_on_commit, project: project).to_discussion }
it 'returns the commit path with the line code' do
- expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: discussion.line_code))
+ expect(helper.discussion_path(discussion)).to eq(project_commit_path(project, commit, anchor: anchor))
end
end
diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js
index 6054b75d0b8..e983e4de3fc 100644
--- a/spec/javascripts/merge_request_notes_spec.js
+++ b/spec/javascripts/merge_request_notes_spec.js
@@ -1,11 +1,9 @@
-/* global Notes */
-
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
import '~/render_gfm';
import '~/render_math';
-import '~/notes';
+import Notes from '~/notes';
const upArrowKeyCode = 38;
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 31426ceb110..050f0ea9ebd 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -1,5 +1,4 @@
/* eslint-disable no-var, comma-dangle, object-shorthand */
-/* global Notes */
import * as urlUtils from '~/lib/utils/url_utility';
import MergeRequestTabs from '~/merge_request_tabs';
@@ -7,7 +6,7 @@ import '~/commit/pipelines/pipelines_bundle';
import '~/breakpoints';
import '~/lib/utils/common_utils';
import Diff from '~/diff';
-import '~/notes';
+import Notes from '~/notes';
import 'vendor/jquery.scrollTo';
(function () {
@@ -279,8 +278,8 @@ import 'vendor/jquery.scrollTo';
loadFixtures('merge_requests/diff_comment.html.raw');
$('body').attr('data-page', 'projects:merge_requests:show');
window.gl.ImageFile = () => {};
- window.notes = new Notes('', []);
- spyOn(window.notes, 'toggleDiffNote').and.callThrough();
+ Notes.initialize('', []);
+ spyOn(Notes.instance, 'toggleDiffNote').and.callThrough();
});
afterEach(() => {
@@ -338,7 +337,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0);
- expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
+ expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
target: jasmine.any(Object),
lineType: 'old',
forceShow: true,
@@ -349,7 +348,7 @@ import 'vendor/jquery.scrollTo';
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
@@ -359,7 +358,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteLineNumId.length).toBeGreaterThan(0);
- expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
});
@@ -393,7 +392,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0);
- expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
+ expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
target: jasmine.any(Object),
lineType: 'new',
forceShow: true,
@@ -404,7 +403,7 @@ import 'vendor/jquery.scrollTo';
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
- expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
@@ -414,7 +413,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteLineNumId.length).toBeGreaterThan(0);
- expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
+ expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index e09b8dc7fc5..167f074fb9b 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -1,12 +1,10 @@
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
-/* global Notes */
-
import * as urlUtils from '~/lib/utils/url_utility';
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
import '~/render_gfm';
-import '~/notes';
+import Notes from '~/notes';
(function() {
window.gon || (window.gon = {});
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index 9e6d0aa472c..74b343c573e 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options';
import eventHub from '~/vue_merge_request_widget/event_hub';
import notify from '~/lib/utils/notify';
+import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
import mockData from './mock_data';
import mountComponent from '../helpers/vue_mount_component_helper';
@@ -344,4 +345,31 @@ describe('mrWidgetOptions', () => {
expect(comps['mr-widget-merge-when-pipeline-succeeds']).toBeDefined();
});
});
+
+ describe('rendering relatedLinks', () => {
+ beforeEach((done) => {
+ vm.mr.relatedLinks = {
+ assignToMe: null,
+ closing: `
+ <a class="close-related-link" href="#'>
+ Close
+ </a>
+ `,
+ mentioned: '',
+ };
+ Vue.nextTick(done);
+ });
+
+ it('renders if there are relatedLinks', () => {
+ expect(vm.$el.querySelector('.close-related-link')).toBeDefined();
+ });
+
+ it('does not render if state is nothingToMerge', (done) => {
+ vm.mr.state = stateKey.nothingToMerge;
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.close-related-link')).toBeNull();
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
index 8e5614b20f0..33d052aceb2 100644
--- a/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
+++ b/spec/javascripts/vue_mr_widget/stores/mr_widget_store_spec.js
@@ -1,4 +1,5 @@
import MergeRequestStore from '~/vue_merge_request_widget/stores/mr_widget_store';
+import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
import mockData from '../mock_data';
describe('MergeRequestStore', () => {
@@ -52,5 +53,17 @@ describe('MergeRequestStore', () => {
expect(store.isPipelineSkipped).toBe(false);
});
});
+
+ describe('isNothingToMergeState', () => {
+ it('returns true when nothingToMerge', () => {
+ store.state = stateKey.nothingToMerge;
+ expect(store.isNothingToMergeState).toEqual(true);
+ });
+
+ it('returns false when not nothingToMerge', () => {
+ store.state = 'state';
+ expect(store.isNothingToMergeState).toEqual(false);
+ });
+ });
});
});
diff --git a/spec/lib/gitlab/action_rate_limiter_spec.rb b/spec/lib/gitlab/action_rate_limiter_spec.rb
new file mode 100644
index 00000000000..542fc03e555
--- /dev/null
+++ b/spec/lib/gitlab/action_rate_limiter_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Gitlab::ActionRateLimiter do
+ let(:redis) { double('redis') }
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:key) { [user, project] }
+ let(:cache_key) { "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" }
+
+ subject { described_class.new(action: :test_action, expiry_time: 100) }
+
+ before do
+ allow(Gitlab::Redis::Cache).to receive(:with).and_yield(redis)
+ end
+
+ it 'increases the throttle count and sets the expire time' do
+ expect(redis).to receive(:incr).with(cache_key).and_return(1)
+ expect(redis).to receive(:expire).with(cache_key, 100)
+
+ expect(subject.throttled?(key, 1)).to be false
+ end
+
+ it 'returns true if the key is throttled' do
+ expect(redis).to receive(:incr).with(cache_key).and_return(2)
+ expect(redis).not_to receive(:expire)
+
+ expect(subject.throttled?(key, 1)).to be true
+ end
+end
diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb
index 18906955df6..24da9589458 100644
--- a/spec/lib/gitlab/git/gitlab_projects_spec.rb
+++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb
@@ -41,7 +41,8 @@ describe Gitlab::Git::GitlabProjects do
end
it "fails if the source path doesn't exist" do
- expect(logger).to receive(:error).with("mv-project failed: source path <#{tmp_repos_path}/bad-src.git> does not exist.")
+ expected_source_path = File.join(tmp_repos_path, 'bad-src.git')
+ expect(logger).to receive(:error).with("mv-project failed: source path <#{expected_source_path}> does not exist.")
result = build_gitlab_projects(tmp_repos_path, 'bad-src.git').mv_project('repo.git')
expect(result).to be_falsy
@@ -50,7 +51,8 @@ describe Gitlab::Git::GitlabProjects do
it 'fails if the destination path already exists' do
FileUtils.mkdir_p(File.join(tmp_repos_path, 'already-exists.git'))
- message = "mv-project failed: destination path <#{tmp_repos_path}/already-exists.git> already exists."
+ expected_distination_path = File.join(tmp_repos_path, 'already-exists.git')
+ message = "mv-project failed: destination path <#{expected_distination_path}> already exists."
expect(logger).to receive(:error).with(message)
expect(gl_projects.mv_project('already-exists.git')).to be_falsy
diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb
index 0f8330e91c1..5ed2f4400bc 100644
--- a/spec/models/blob_viewer/package_json_spec.rb
+++ b/spec/models/blob_viewer/package_json_spec.rb
@@ -22,4 +22,51 @@ describe BlobViewer::PackageJson do
expect(subject.package_name).to eq('module-name')
end
end
+
+ describe '#package_url' do
+ it 'returns the package URL' do
+ expect(subject).to receive(:prepare!)
+
+ expect(subject.package_url).to eq("https://www.npmjs.com/package/#{subject.package_name}")
+ end
+ end
+
+ describe '#package_type' do
+ it 'returns "package"' do
+ expect(subject).to receive(:prepare!)
+
+ expect(subject.package_type).to eq('package')
+ end
+ end
+
+ context 'when package.json has "private": true' do
+ let(:data) do
+ <<-SPEC.strip_heredoc
+ {
+ "name": "module-name",
+ "version": "10.3.1",
+ "private": true,
+ "homepage": "myawesomepackage.com"
+ }
+ SPEC
+ end
+ let(:blob) { fake_blob(path: 'package.json', data: data) }
+ subject { described_class.new(blob) }
+
+ describe '#package_url' do
+ it 'returns homepage if any' do
+ expect(subject).to receive(:prepare!)
+
+ expect(subject.package_url).to eq('myawesomepackage.com')
+ end
+ end
+
+ describe '#package_type' do
+ it 'returns "private package"' do
+ expect(subject).to receive(:prepare!)
+
+ expect(subject.package_type).to eq('private package')
+ end
+ end
+ end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index d18a5c9dfa6..cd955a5eb69 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -13,6 +13,45 @@ describe Commit do
it { is_expected.to include_module(StaticModel) }
end
+ describe '.lazy' do
+ set(:project) { create(:project, :repository) }
+
+ context 'when the commits are found' do
+ let(:oids) do
+ %w(
+ 498214de67004b1da3d820901307bed2a68a8ef6
+ c642fe9b8b9f28f9225d7ea953fe14e74748d53b
+ 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+ 048721d90c449b244b7b4c53a9186b04330174ec
+ 281d3a76f31c812dbf48abce82ccf6860adedd81
+ )
+ end
+
+ subject { oids.map { |oid| described_class.lazy(project, oid) } }
+
+ it 'batches requests for commits' do
+ expect(project.repository).to receive(:commits_by).once.and_call_original
+
+ subject.first.title
+ subject.last.title
+ end
+
+ it 'maintains ordering' do
+ subject.each_with_index do |commit, i|
+ expect(commit.id).to eq(oids[i])
+ end
+ end
+ end
+
+ context 'when not found' do
+ it 'returns nil as commit' do
+ commit = described_class.lazy(project, 'deadbeef').__sync
+
+ expect(commit).to be_nil
+ end
+ end
+ end
+
describe '#author' do
it 'looks up the author in a case-insensitive way' do
user = create(:user, email: commit.author_email.upcase)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 799d99c0369..1d7069feebd 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -239,6 +239,54 @@ describe Repository do
end
end
+ describe '#commits_by' do
+ set(:project) { create(:project, :repository) }
+
+ shared_examples 'batch commits fetching' do
+ let(:oids) { TestEnv::BRANCH_SHA.values }
+
+ subject { project.repository.commits_by(oids: oids) }
+
+ it 'finds each commit' do
+ expect(subject).not_to include(nil)
+ expect(subject.size).to eq(oids.size)
+ end
+
+ it 'returns only Commit instances' do
+ expect(subject).to all( be_a(Commit) )
+ end
+
+ context 'when some commits are not found ' do
+ let(:oids) do
+ ['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
+ end
+
+ it 'returns only found commits' do
+ expect(subject).not_to include(nil)
+ expect(subject.size).to eq(10)
+ end
+ end
+
+ context 'when no oids are passed' do
+ let(:oids) { [] }
+
+ it 'does not call #batch_by_oid' do
+ expect(Gitlab::Git::Commit).not_to receive(:batch_by_oid)
+
+ subject
+ end
+ end
+ end
+
+ context 'when Gitaly list_commits_by_oid is enabled' do
+ it_behaves_like 'batch commits fetching'
+ end
+
+ context 'when Gitaly list_commits_by_oid is enabled', :disable_gitaly do
+ it_behaves_like 'batch commits fetching'
+ end
+ end
+
describe '#find_commits_by_message' do
shared_examples 'finding commits by message' do
it 'returns commits with messages containing a given string' do
@@ -1163,6 +1211,15 @@ describe Repository do
end
end
+ describe '#tag_exists?' do
+ it 'uses tag_names' do
+ allow(repository).to receive(:tag_names).and_return(['foobar'])
+
+ expect(repository.tag_exists?('foobar')).to eq(true)
+ expect(repository.tag_exists?('master')).to eq(false)
+ end
+ end
+
describe '#branch_names', :use_clean_rails_memory_store_caching do
let(:fake_branch_names) { ['foobar'] }
diff --git a/spec/policies/ci/pipeline_schedule_policy_spec.rb b/spec/policies/ci/pipeline_schedule_policy_spec.rb
new file mode 100644
index 00000000000..1b0e9fac355
--- /dev/null
+++ b/spec/policies/ci/pipeline_schedule_policy_spec.rb
@@ -0,0 +1,92 @@
+require 'spec_helper'
+
+describe Ci::PipelineSchedulePolicy, :models do
+ set(:user) { create(:user) }
+ set(:project) { create(:project, :repository) }
+ set(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
+
+ let(:policy) do
+ described_class.new(user, pipeline_schedule)
+ end
+
+ describe 'rules' do
+ describe 'rules for protected ref' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when no one can push or merge to the branch' do
+ before do
+ create(:protected_branch, :no_one_can_push,
+ name: pipeline_schedule.ref, project: project)
+ end
+
+ it 'does not include ability to play pipeline schedule' do
+ expect(policy).to be_disallowed :play_pipeline_schedule
+ end
+ end
+
+ context 'when developers can push to the branch' do
+ before do
+ create(:protected_branch, :developers_can_merge,
+ name: pipeline_schedule.ref, project: project)
+ end
+
+ it 'includes ability to update pipeline' do
+ expect(policy).to be_allowed :play_pipeline_schedule
+ end
+ end
+
+ context 'when no one can create the tag' do
+ let(:tag) { 'v1.0.0' }
+
+ before do
+ pipeline_schedule.update(ref: tag)
+
+ create(:protected_tag, :no_one_can_create,
+ name: pipeline_schedule.ref, project: project)
+ end
+
+ it 'does not include ability to play pipeline schedule' do
+ expect(policy).to be_disallowed :play_pipeline_schedule
+ end
+ end
+
+ context 'when no one can create the tag but it is not a tag' do
+ before do
+ create(:protected_tag, :no_one_can_create,
+ name: pipeline_schedule.ref, project: project)
+ end
+
+ it 'includes ability to play pipeline schedule' do
+ expect(policy).to be_allowed :play_pipeline_schedule
+ end
+ end
+ end
+
+ describe 'rules for owner of schedule' do
+ before do
+ project.add_developer(user)
+ pipeline_schedule.update(owner: user)
+ end
+
+ it 'includes abilities to do do all operations on pipeline schedule' do
+ expect(policy).to be_allowed :play_pipeline_schedule
+ expect(policy).to be_allowed :update_pipeline_schedule
+ expect(policy).to be_allowed :admin_pipeline_schedule
+ end
+ end
+
+ describe 'rules for a master' do
+ before do
+ project.add_master(user)
+ end
+
+ it 'includes abilities to do do all operations on pipeline schedule' do
+ expect(policy).to be_allowed :play_pipeline_schedule
+ expect(policy).to be_allowed :update_pipeline_schedule
+ expect(policy).to be_allowed :admin_pipeline_schedule
+ end
+ end
+ end
+end
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 88d347322a6..c38795ad1a1 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'
describe PipelineSerializer do
+ set(:project) { create(:project, :repository) }
set(:user) { create(:user) }
let(:serializer) do
@@ -16,7 +17,7 @@ describe PipelineSerializer do
end
context 'when a single object is being serialized' do
- let(:resource) { create(:ci_empty_pipeline) }
+ let(:resource) { create(:ci_empty_pipeline, project: project) }
it 'serializers the pipeline object' do
expect(subject[:id]).to eq resource.id
@@ -24,7 +25,7 @@ describe PipelineSerializer do
end
context 'when multiple objects are being serialized' do
- let(:resource) { create_list(:ci_pipeline, 2) }
+ let(:resource) { create_list(:ci_pipeline, 2, project: project) }
it 'serializers the array of pipelines' do
expect(subject).not_to be_empty
@@ -100,7 +101,6 @@ describe PipelineSerializer do
context 'number of queries' do
let(:resource) { Ci::Pipeline.all }
- let(:project) { create(:project) }
before do
# Since RequestStore.active? is true we have to allow the
diff --git a/spec/services/issuable/destroy_service_spec.rb b/spec/services/issuable/destroy_service_spec.rb
index d74d98c6079..0a3647a814f 100644
--- a/spec/services/issuable/destroy_service_spec.rb
+++ b/spec/services/issuable/destroy_service_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Issuable::DestroyService do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
subject(:service) { described_class.new(project, user) }
@@ -19,6 +19,13 @@ describe Issuable::DestroyService do
service.execute(issue)
end
+
+ it 'updates the todo caches for users with todos on the issue' do
+ create(:todo, target: issue, user: user, author: user, project: project)
+
+ expect { service.execute(issue) }
+ .to change { user.todos_pending_count }.from(1).to(0)
+ end
end
context 'when issuable is a merge request' do
@@ -33,6 +40,13 @@ describe Issuable::DestroyService do
service.execute(merge_request)
end
+
+ it 'updates the todo caches for users with todos on the merge request' do
+ create(:todo, target: merge_request, user: user, author: user, project: project)
+
+ expect { service.execute(merge_request) }
+ .to change { user.todos_pending_count }.from(1).to(0)
+ end
end
end
end
diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb
index c9a99a43edb..64445be560e 100644
--- a/spec/services/notes/destroy_service_spec.rb
+++ b/spec/services/notes/destroy_service_spec.rb
@@ -1,15 +1,25 @@
require 'spec_helper'
describe Notes::DestroyService do
+ set(:project) { create(:project, :public) }
+ set(:issue) { create(:issue, project: project) }
+ let(:user) { issue.author }
+
describe '#execute' do
it 'deletes a note' do
- project = create(:project)
- issue = create(:issue, project: project)
note = create(:note, project: project, noteable: issue)
- described_class.new(project, note.author).execute(note)
+ described_class.new(project, user).execute(note)
expect(project.issues.find(issue.id).notes).not_to include(note)
end
+
+ it 'updates the todo counts for users with todos for the note' do
+ note = create(:note, project: project, noteable: issue)
+ create(:todo, note: note, target: issue, user: user, author: user, project: project)
+
+ expect { described_class.new(project, user).execute(note) }
+ .to change { user.todos_pending_count }.from(1).to(0)
+ end
end
end
diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb
index 2bba71fef4f..3ec6139bfa6 100644
--- a/spec/services/projects/unlink_fork_service_spec.rb
+++ b/spec/services/projects/unlink_fork_service_spec.rb
@@ -62,6 +62,26 @@ describe Projects::UnlinkForkService do
expect(source.forks_count).to be_zero
end
+ context 'when the source has LFS objects' do
+ let(:lfs_object) { create(:lfs_object) }
+
+ before do
+ lfs_object.projects << project
+ end
+
+ it 'links the fork to the lfs object before unlinking' do
+ subject.execute
+
+ expect(lfs_object.projects).to include(forked_project)
+ end
+
+ it 'does not fail if the lfs objects were already linked' do
+ lfs_object.projects << forked_project
+
+ expect { subject.execute }.not_to raise_error
+ end
+ end
+
context 'when the original project was deleted' do
it 'does not fail when the original project is deleted' do
source = forked_project.forked_from_project
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index dc2673abc73..88013acae0a 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -248,11 +248,26 @@ describe TodoService do
end
end
- describe '#destroy_issuable' do
- it 'refresh the todos count cache for the user' do
- expect(john_doe).to receive(:update_todos_count_cache).and_call_original
+ describe '#destroy_target' do
+ it 'refreshes the todos count cache for users with todos on the target' do
+ create(:todo, target: issue, user: john_doe, author: john_doe, project: issue.project)
- service.destroy_issuable(issue, john_doe)
+ expect_any_instance_of(User).to receive(:update_todos_count_cache).and_call_original
+
+ service.destroy_target(issue) { }
+ end
+
+ it 'does not refresh the todos count cache for users with only done todos on the target' do
+ create(:todo, :done, target: issue, user: john_doe, author: john_doe, project: issue.project)
+
+ expect_any_instance_of(User).not_to receive(:update_todos_count_cache)
+
+ service.destroy_target(issue) { }
+ end
+
+ it 'yields the target to the caller' do
+ expect { |b| service.destroy_target(issue, &b) }
+ .to yield_with_args(issue)
end
end
diff --git a/spec/views/events/event/_push.html.haml_spec.rb b/spec/views/events/event/_push.html.haml_spec.rb
new file mode 100644
index 00000000000..f5634de4916
--- /dev/null
+++ b/spec/views/events/event/_push.html.haml_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe 'events/event/_push.html.haml' do
+ let(:event) { build_stubbed(:push_event) }
+
+ context 'with a branch' do
+ let(:payload) { build_stubbed(:push_event_payload, event: event) }
+
+ before do
+ allow(event).to receive(:push_event_payload).and_return(payload)
+ end
+
+ it 'links to the branch' do
+ allow(event.project.repository).to receive(:branch_exists?).with(event.ref_name).and_return(true)
+ link = project_commits_path(event.project, event.ref_name)
+
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).to have_link(event.ref_name, href: link)
+ end
+
+ context 'that has been deleted' do
+ it 'does not link to the branch' do
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).not_to have_link(event.ref_name)
+ end
+ end
+ end
+
+ context 'with a tag' do
+ let(:payload) { build_stubbed(:push_event_payload, event: event, ref_type: :tag, ref: 'v0.1.0') }
+
+ before do
+ allow(event).to receive(:push_event_payload).and_return(payload)
+ end
+
+ it 'links to the tag' do
+ allow(event.project.repository).to receive(:tag_exists?).with(event.ref_name).and_return(true)
+ link = project_commits_path(event.project, event.ref_name)
+
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).to have_link(event.ref_name, href: link)
+ end
+
+ context 'that has been deleted' do
+ it 'does not link to the tag' do
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).not_to have_link(event.ref_name)
+ end
+ end
+ end
+end
diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb
new file mode 100644
index 00000000000..481a84837f9
--- /dev/null
+++ b/spec/workers/run_pipeline_schedule_worker_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe RunPipelineScheduleWorker do
+ describe '#perform' do
+ set(:project) { create(:project) }
+ set(:user) { create(:user) }
+ set(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) }
+ let(:worker) { described_class.new }
+
+ context 'when a project not found' do
+ it 'does not call the Service' do
+ expect(Ci::CreatePipelineService).not_to receive(:new)
+ expect(worker).not_to receive(:run_pipeline_schedule)
+
+ worker.perform(100000, user.id)
+ end
+ end
+
+ context 'when a user not found' do
+ it 'does not call the Service' do
+ expect(Ci::CreatePipelineService).not_to receive(:new)
+ expect(worker).not_to receive(:run_pipeline_schedule)
+
+ worker.perform(pipeline_schedule.id, 10000)
+ end
+ end
+
+ context 'when everything is ok' do
+ let(:create_pipeline_service) { instance_double(Ci::CreatePipelineService) }
+
+ it 'calls the Service' do
+ expect(Ci::CreatePipelineService).to receive(:new).with(project, user, ref: pipeline_schedule.ref).and_return(create_pipeline_service)
+ expect(create_pipeline_service).to receive(:execute).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule)
+
+ worker.perform(pipeline_schedule.id, user.id)
+ end
+ end
+ end
+end