diff options
Diffstat (limited to 'spec')
30 files changed, 567 insertions, 113 deletions
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index b4f066d8600..2a7523c6512 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -14,49 +14,49 @@ describe Projects::ProjectMembersController do end describe 'POST create' do - context 'when users are added' do - let(:project_user) { create(:user) } + let(:project_user) { create(:user) } - before { sign_in(user) } + before { sign_in(user) } - context 'when user does not have enough rights' do - before { project.team << [user, :developer] } + context 'when user does not have enough rights' do + before { project.team << [user, :developer] } - it 'returns 404' do - post :create, namespace_id: project.namespace, - project_id: project, - user_ids: project_user.id, - access_level: Gitlab::Access::GUEST + it 'returns 404' do + post :create, namespace_id: project.namespace, + project_id: project, + user_ids: project_user.id, + access_level: Gitlab::Access::GUEST - expect(response).to have_http_status(404) - expect(project.users).not_to include project_user - end + expect(response).to have_http_status(404) + expect(project.users).not_to include project_user end + end - context 'when user has enough rights' do - before { project.team << [user, :master] } + context 'when user has enough rights' do + before { project.team << [user, :master] } - it 'adds user to members' do - post :create, namespace_id: project.namespace, - project_id: project, - user_ids: project_user.id, - access_level: Gitlab::Access::GUEST - - expect(response).to set_flash.to 'Users were successfully added.' - expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) - expect(project.users).to include project_user - end + it 'adds user to members' do + expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(true) - it 'adds no user to members' do - post :create, namespace_id: project.namespace, - project_id: project, - user_ids: '', - access_level: Gitlab::Access::GUEST + post :create, namespace_id: project.namespace, + project_id: project, + user_ids: project_user.id, + access_level: Gitlab::Access::GUEST - expect(response).to set_flash.to 'No users or groups specified.' - expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) - expect(project.users).not_to include project_user - end + expect(response).to set_flash.to 'Users were successfully added.' + expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) + end + + it 'adds no user to members' do + expect_any_instance_of(Members::CreateService).to receive(:execute).and_return(false) + + post :create, namespace_id: project.namespace, + project_id: project, + user_ids: '', + access_level: Gitlab::Access::GUEST + + expect(response).to set_flash.to 'No users or groups specified.' + expect(response).to redirect_to(namespace_project_project_members_path(project.namespace, project)) end end end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 3234fabe288..a92075fec8f 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -53,7 +53,7 @@ describe 'Issue Boards', feature: true, js: true do context 'with lists' do let(:milestone) { create(:milestone, project: project) } - let(:planning) { create(:label, project: project, name: 'Planning') } + let(:planning) { create(:label, project: project, name: 'Planning', description: 'Test') } let(:development) { create(:label, project: project, name: 'Development') } let(:testing) { create(:label, project: project, name: 'Testing') } let(:bug) { create(:label, project: project, name: 'Bug') } @@ -91,6 +91,12 @@ describe 'Issue Boards', feature: true, js: true do expect(page).to have_selector('.board', count: 4) end + it 'shows description tooltip on list title' do + page.within('.board:nth-child(2)') do + expect(find('.board-title span.has-tooltip')[:title]).to eq('Test') + end + end + it 'shows issues in lists' do wait_for_board_cards(2, 2) wait_for_board_cards(3, 2) diff --git a/spec/features/issues/filter_by_milestone_spec.rb b/spec/features/issues/filter_by_milestone_spec.rb index 88e1549a22b..9dfa5d1de19 100644 --- a/spec/features/issues/filter_by_milestone_spec.rb +++ b/spec/features/issues/filter_by_milestone_spec.rb @@ -11,6 +11,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::None.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'No Milestone') expect(page).to have_css('.issue', count: 1) end @@ -22,6 +23,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 0) end @@ -33,6 +35,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 1) end @@ -44,6 +47,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(Milestone::Upcoming.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: 'Upcoming') expect(page).to have_css('.issue', count: 0) end end @@ -55,6 +59,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(milestone.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: milestone.title) expect(page).to have_css('.issue', count: 1) end @@ -70,6 +75,7 @@ feature 'Issue filtering by Milestone', feature: true do visit_issues(project) filter_by_milestone(milestone.title) + expect(page).to have_css('.milestone-filter .dropdown-toggle-text', text: milestone.title) expect(page).to have_css('.issue', count: 1) end end diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index b963d1305b5..c68e1ea4af9 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -59,4 +59,12 @@ feature 'Create New Merge Request', feature: true, js: true do expect(page).to have_css('a.btn.active', text: 'Side-by-side') end end + + it 'does not allow non-existing branches' do + visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_branch: 'non-exist-target', source_branch: 'non-exist-source' }) + + expect(page).to have_content('The form contains the following errors') + expect(page).to have_content('Source branch "non-exist-source" does not exist') + expect(page).to have_content('Target branch "non-exist-target" does not exist') + end end diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb index d1685f95503..63a23a14f20 100644 --- a/spec/features/projects/builds_spec.rb +++ b/spec/features/projects/builds_spec.rb @@ -216,7 +216,9 @@ describe "Builds" do @build.run! visit namespace_project_build_path(@project.namespace, @project, @build) click_link 'Cancel' - click_link 'Retry' + page.within('.build-header') do + click_link 'Retry build' + end end it 'shows the right status and buttons' do diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index d25cf7fb353..e796ee570b7 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -164,5 +164,23 @@ describe 'Edit Project Settings', feature: true do expect(page).to have_content "Customize your workflow!" end + + it "hides project activity tabs" do + select "Disabled", from: "project_project_feature_attributes_repository_access_level" + select "Disabled", from: "project_project_feature_attributes_issues_access_level" + select "Disabled", from: "project_project_feature_attributes_wiki_access_level" + + click_button "Save changes" + wait_for_ajax + + visit activity_namespace_project_path(project.namespace, project) + + page.within(".event-filter") do + expect(page).to have_selector("a", count: 2) + expect(page).not_to have_content("Push events") + expect(page).not_to have_content("Merge events") + expect(page).not_to have_content("Comments") + end + end end end diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb new file mode 100644 index 00000000000..b4f5f6b3fc5 --- /dev/null +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'Projects > Wiki > User views wiki in project page', feature: true do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + + before do + project.team << [user, :master] + login_as(user) + end + + context 'when repository is disabled for project' do + before do + project.project_feature.update!( + repository_access_level: ProjectFeature::DISABLED, + merge_requests_access_level: ProjectFeature::DISABLED, + builds_access_level: ProjectFeature::DISABLED + ) + end + + context 'when wiki homepage contains a link' do + before do + WikiPages::CreateService.new( + project, + user, + title: 'home', + content: '[some link](other-page)' + ).execute + end + + it 'displays the correct URL for the link' do + visit namespace_project_path(project.namespace, project) + expect(page).to have_link( + 'some link', + href: namespace_project_wiki_path( + project.namespace, + project, + 'other-page' + ) + ) + end + end + end +end diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index 230543cd175..3ae83ac082d 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -13,7 +13,7 @@ describe 'Dashboard Todos', feature: true do visit dashboard_todos_path end it 'shows "All done" message' do - expect(page).to have_content "You're all done!" + expect(page).to have_content "Todos let you see what you should do next." end end @@ -44,7 +44,7 @@ describe 'Dashboard Todos', feature: true do end it 'shows "All done" message' do - expect(page).to have_content("You're all done!") + expect(page).to have_content("Good job! Looks like you don't have any todos left.") end end @@ -64,7 +64,7 @@ describe 'Dashboard Todos', feature: true do end it 'shows "All done" message' do - expect(page).to have_content("You're all done!") + expect(page).to have_content("Good job! Looks like you don't have any todos left.") end end end @@ -152,7 +152,7 @@ describe 'Dashboard Todos', feature: true do within('.todos-pending-count') { expect(page).to have_content '0' } expect(page).to have_content 'To do 0' expect(page).to have_content 'Done 0' - expect(page).to have_content "You're all done!" + expect(page).to have_content "Good job! Looks like you don't have any todos left." end end end diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index bdce2465fbf..9cb8243ee2c 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -28,7 +28,7 @@ // setTimeout(Teaspoon.execute, 1000) // Matching files // By default Teaspoon will look for files that match -// _spec.{js,js.coffee,.coffee}. Add a filename_spec.js file in your spec path +// _spec.{js,js.es6}. Add a filename_spec.js file in your spec path // and it'll be included in the default suite automatically. If you want to // customize suites, check out the configuration in teaspoon_env.rb // Manifest diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb index 2f9343fadaf..fbf7a461fa5 100644 --- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb @@ -8,6 +8,8 @@ describe Banzai::Filter::ExternalIssueReferenceFilter, lib: true do end shared_examples_for "external issue tracker" do + it_behaves_like 'a reference containing an element node' + it 'requires project context' do expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) end diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index a2025672ad9..8f0b2db3e8e 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -22,6 +22,8 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end context 'internal reference' do + it_behaves_like 'a reference containing an element node' + let(:reference) { issue.to_reference } it 'ignores valid references when using non-default tracker' do @@ -83,6 +85,20 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do expect(link.attr('data-issue')).to eq issue.id.to_s end + it 'includes a data-original attribute' do + doc = reference_filter("See #{reference}") + link = doc.css('a').first + + expect(link).to have_attribute('data-original') + expect(link.attr('data-original')).to eq reference + end + + it 'does not escape the data-original attribute' do + inner_html = 'element <code>node</code> inside' + doc = reference_filter(%{<a href="#{reference}">#{inner_html}</a>}) + expect(doc.children.first.attr('data-original')).to eq inner_html + end + it 'supports an :only_path context' do doc = reference_filter("Issue #{reference}", only_path: true) link = doc.css('a').first.attr('href') @@ -101,6 +117,8 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end context 'cross-project reference' do + it_behaves_like 'a reference containing an element node' + let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:empty_project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } @@ -141,6 +159,8 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end context 'cross-project URL reference' do + it_behaves_like 'a reference containing an element node' + let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:empty_project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } @@ -160,39 +180,45 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do end context 'cross-project reference in link href' do + it_behaves_like 'a reference containing an element node' + let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:empty_project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { %Q{<a href="#{issue.to_reference(project)}">Reference</a>} } + let(:reference) { issue.to_reference(project) } + let(:reference_link) { %{<a href="#{reference}">Reference</a>} } it 'links to a valid reference' do - doc = reference_filter("See #{reference}") + doc = reference_filter("See #{reference_link}") expect(doc.css('a').first.attr('href')). to eq helper.url_for_issue(issue.iid, project2) end it 'links with adjacent text' do - doc = reference_filter("Fixed (#{reference}.)") + doc = reference_filter("Fixed (#{reference_link}.)") expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/) end end context 'cross-project URL in link href' do + it_behaves_like 'a reference containing an element node' + let(:namespace) { create(:namespace, name: 'cross-reference') } let(:project2) { create(:empty_project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { %Q{<a href="#{helper.url_for_issue(issue.iid, project2) + "#note_123"}">Reference</a>} } + let(:reference) { "#{helper.url_for_issue(issue.iid, project2) + "#note_123"}" } + let(:reference_link) { %{<a href="#{reference}">Reference</a>} } it 'links to a valid reference' do - doc = reference_filter("See #{reference}") + doc = reference_filter("See #{reference_link}") expect(doc.css('a').first.attr('href')). to eq helper.url_for_issue(issue.iid, project2) + "#note_123" end it 'links with adjacent text' do - doc = reference_filter("Fixed (#{reference}.)") + doc = reference_filter("Fixed (#{reference_link}.)") expect(doc.to_html).to match(/\(<a.+>Reference<\/a>\.\)/) end end diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 729e77fd43f..5bfeb82e738 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -24,6 +24,8 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do end context 'mentioning @all' do + it_behaves_like 'a reference containing an element node' + let(:reference) { User.reference_prefix + 'all' } before do @@ -60,6 +62,8 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do end context 'mentioning a user' do + it_behaves_like 'a reference containing an element node' + it 'links to a User' do doc = reference_filter("Hey #{reference}") expect(doc.css('a').first.attr('href')).to eq urls.user_url(user) @@ -89,6 +93,8 @@ describe Banzai::Filter::UserReferenceFilter, lib: true do end context 'mentioning a group' do + it_behaves_like 'a reference containing an element node' + let(:group) { create(:group) } let(:reference) { group.to_reference } diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb new file mode 100644 index 00000000000..2501b638774 --- /dev/null +++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +describe Banzai::Pipeline::FullPipeline do + describe 'References' do + let(:project) { create(:empty_project, :public) } + let(:issue) { create(:issue, project: project) } + + it 'handles markdown inside a reference' do + markdown = "[some `code` inside](#{issue.to_reference})" + result = described_class.call(markdown, project: project) + link_content = result[:output].css('a').inner_html + expect(link_content).to eq('some <code>code</code> inside') + end + + it 'sanitizes reference HTML' do + link_label = '<script>bad things</script>' + markdown = "[#{link_label}](#{issue.to_reference})" + result = described_class.to_html(markdown, project: project) + expect(result).not_to include(link_label) + end + + it 'escapes the data-original attribute on a reference' do + markdown = %Q{[">bad things](#{issue.to_reference})} + result = described_class.to_html(markdown, project: project) + expect(result).to include(%{data-original='\">bad things'}) + end + end +end diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb index 254657a881d..6d2c141e18b 100644 --- a/spec/lib/banzai/redactor_spec.rb +++ b/spec/lib/banzai/redactor_spec.rb @@ -6,39 +6,60 @@ describe Banzai::Redactor do let(:redactor) { described_class.new(project, user) } describe '#redact' do - it 'redacts an Array of documents' do - doc1 = Nokogiri::HTML. - fragment('<a class="gfm" data-reference-type="issue">foo</a>') - - doc2 = Nokogiri::HTML. - fragment('<a class="gfm" data-reference-type="issue">bar</a>') - - expect(redactor).to receive(:nodes_visible_to_user).and_return([]) - - redacted_data = redactor.redact([doc1, doc2]) - - expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) - expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0]) - expect(doc1.to_html).to eq('foo') - expect(doc2.to_html).to eq('bar') + context 'when reference not visible to user' do + before do + expect(redactor).to receive(:nodes_visible_to_user).and_return([]) + end + + it 'redacts an array of documents' do + doc1 = Nokogiri::HTML. + fragment('<a class="gfm" data-reference-type="issue">foo</a>') + + doc2 = Nokogiri::HTML. + fragment('<a class="gfm" data-reference-type="issue">bar</a>') + + redacted_data = redactor.redact([doc1, doc2]) + + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([0, 0]) + expect(doc1.to_html).to eq('foo') + expect(doc2.to_html).to eq('bar') + end + + it 'replaces redacted reference with inner HTML' do + doc = Nokogiri::HTML.fragment("<a class='gfm' data-reference-type='issue'>foo</a>") + redactor.redact([doc]) + expect(doc.to_html).to eq('foo') + end + + context 'when data-original attribute provided' do + let(:original_content) { '<code>foo</code>' } + it 'replaces redacted reference with original content' do + doc = Nokogiri::HTML.fragment("<a class='gfm' data-reference-type='issue' data-original='#{original_content}'>bar</a>") + redactor.redact([doc]) + expect(doc.to_html).to eq(original_content) + end + end end - it 'does not redact an Array of documents' do - doc1_html = '<a class="gfm" data-reference-type="issue">foo</a>' - doc1 = Nokogiri::HTML.fragment(doc1_html) + context 'when reference visible to user' do + it 'does not redact an array of documents' do + doc1_html = '<a class="gfm" data-reference-type="issue">foo</a>' + doc1 = Nokogiri::HTML.fragment(doc1_html) - doc2_html = '<a class="gfm" data-reference-type="issue">bar</a>' - doc2 = Nokogiri::HTML.fragment(doc2_html) + doc2_html = '<a class="gfm" data-reference-type="issue">bar</a>' + doc2 = Nokogiri::HTML.fragment(doc2_html) - nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] } - expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten) + nodes = redactor.document_nodes([doc1, doc2]).map { |x| x[:nodes] } + expect(redactor).to receive(:nodes_visible_to_user).and_return(nodes.flatten) - redacted_data = redactor.redact([doc1, doc2]) + redacted_data = redactor.redact([doc1, doc2]) - expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) - expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1]) - expect(doc1.to_html).to eq(doc1_html) - expect(doc2.to_html).to eq(doc2_html) + expect(redacted_data.map { |data| data[:document] }).to eq([doc1, doc2]) + expect(redacted_data.map { |data| data[:visible_reference_count] }).to eq([1, 1]) + expect(doc1.to_html).to eq(doc1_html) + expect(doc2.to_html).to eq(doc2_html) + end end end diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index a5aa387f4f7..62aa212f1f6 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -122,6 +122,14 @@ describe Gitlab::GitAccess, lib: true do describe 'build authentication_abilities permissions' do let(:authentication_abilities) { build_authentication_abilities } + describe 'owner' do + let(:project) { create(:project, namespace: user.namespace) } + + context 'pull code' do + it { expect(subject).to be_allowed } + end + end + describe 'reporter user' do before { project.team << [user, :reporter] } diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb new file mode 100644 index 00000000000..d5d87310874 --- /dev/null +++ b/spec/lib/gitlab/utils_spec.rb @@ -0,0 +1,35 @@ +describe Gitlab::Utils, lib: true do + def to_boolean(value) + described_class.to_boolean(value) + end + + describe '.to_boolean' do + it 'accepts booleans' do + expect(to_boolean(true)).to be(true) + expect(to_boolean(false)).to be(false) + end + + it 'converts a valid string to a boolean' do + expect(to_boolean(true)).to be(true) + expect(to_boolean('true')).to be(true) + expect(to_boolean('YeS')).to be(true) + expect(to_boolean('t')).to be(true) + expect(to_boolean('1')).to be(true) + expect(to_boolean('ON')).to be(true) + + expect(to_boolean('FaLse')).to be(false) + expect(to_boolean('F')).to be(false) + expect(to_boolean('NO')).to be(false) + expect(to_boolean('n')).to be(false) + expect(to_boolean('0')).to be(false) + expect(to_boolean('oFF')).to be(false) + end + + it 'converts an invalid string to nil' do + expect(to_boolean('fals')).to be_nil + expect(to_boolean('yeah')).to be_nil + expect(to_boolean('')).to be_nil + expect(to_boolean(nil)).to be_nil + end + end +end diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 5363aea4d22..9041690023f 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -22,4 +22,18 @@ describe ProjectFeaturesCompatibility do expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::DISABLED) end end + + it "converts fields from true to ProjectFeature::ENABLED" do + features.each do |feature| + project.update_attribute("#{feature}_enabled".to_sym, true) + expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::ENABLED) + end + end + + it "converts fields from false to ProjectFeature::DISABLED" do + features.each do |feature| + project.update_attribute("#{feature}_enabled".to_sym, false) + expect(project.project_feature.public_send("#{feature}_access_level")).to eq(ProjectFeature::DISABLED) + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f4dda1ee558..aef277357cf 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -67,11 +67,11 @@ describe Project, models: true do it { is_expected.to have_many(:notification_settings).dependent(:destroy) } it { is_expected.to have_many(:forks).through(:forked_project_links) } - context 'after create' do - it "creates project feature" do + context 'after initialized' do + it "has a project_feature" do project = FactoryGirl.build(:project) - expect { project.save }.to change{ project.project_feature.present? }.from(false).to(true) + expect(project.project_feature.present?).to be_present end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 10c39b90212..d1ed774a914 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -599,6 +599,80 @@ describe User, models: true do end end + describe '.search_with_secondary_emails' do + def search_with_secondary_emails(query) + described_class.search_with_secondary_emails(query) + end + + let!(:user) { create(:user) } + let!(:email) { create(:email) } + + it 'returns users with a matching name' do + expect(search_with_secondary_emails(user.name)).to eq([user]) + end + + it 'returns users with a partially matching name' do + expect(search_with_secondary_emails(user.name[0..2])).to eq([user]) + end + + it 'returns users with a matching name regardless of the casing' do + expect(search_with_secondary_emails(user.name.upcase)).to eq([user]) + end + + it 'returns users with a matching email' do + expect(search_with_secondary_emails(user.email)).to eq([user]) + end + + it 'returns users with a partially matching email' do + expect(search_with_secondary_emails(user.email[0..2])).to eq([user]) + end + + it 'returns users with a matching email regardless of the casing' do + expect(search_with_secondary_emails(user.email.upcase)).to eq([user]) + end + + it 'returns users with a matching username' do + expect(search_with_secondary_emails(user.username)).to eq([user]) + end + + it 'returns users with a partially matching username' do + expect(search_with_secondary_emails(user.username[0..2])).to eq([user]) + end + + it 'returns users with a matching username regardless of the casing' do + expect(search_with_secondary_emails(user.username.upcase)).to eq([user]) + end + + it 'returns users with a matching whole secondary email' do + expect(search_with_secondary_emails(email.email)).to eq([email.user]) + end + + it 'returns users with a matching part of secondary email' do + expect(search_with_secondary_emails(email.email[1..4])).to eq([email.user]) + end + + it 'return users with a matching part of secondary email regardless of case' do + expect(search_with_secondary_emails(email.email[1..4].upcase)).to eq([email.user]) + expect(search_with_secondary_emails(email.email[1..4].downcase)).to eq([email.user]) + expect(search_with_secondary_emails(email.email[1..4].capitalize)).to eq([email.user]) + end + + it 'returns multiple users with matching secondary emails' do + email1 = create(:email, email: '1_testemail@example.com') + email2 = create(:email, email: '2_testemail@example.com') + email3 = create(:email, email: 'other@email.com') + email3.user.update_attributes!(email: 'another@mail.com') + + expect( + search_with_secondary_emails('testemail@example.com').map(&:id) + ).to include(email1.user.id, email2.user.id) + + expect( + search_with_secondary_emails('testemail@example.com').map(&:id) + ).not_to include(email3.user.id) + end + end + describe 'by_username_or_id' do let(:user1) { create(:user, username: 'foo') } diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 658e3c13a73..96249a7d8c3 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -6,6 +6,7 @@ describe ProjectPolicy, models: true do let(:dev) { create(:user) } let(:master) { create(:user) } let(:owner) { create(:user) } + let(:admin) { create(:admin) } let(:project) { create(:empty_project, :public, namespace: owner.namespace) } let(:guest_permissions) do @@ -155,6 +156,19 @@ describe ProjectPolicy, models: true do it do is_expected.to include(*guest_permissions) is_expected.to include(*reporter_permissions) + is_expected.to include(*team_member_reporter_permissions) + is_expected.to include(*developer_permissions) + is_expected.to include(*master_permissions) + is_expected.to include(*owner_permissions) + end + end + + context 'admin' do + let(:current_user) { admin } + + it do + is_expected.to include(*guest_permissions) + is_expected.to include(*reporter_permissions) is_expected.not_to include(*team_member_reporter_permissions) is_expected.to include(*developer_permissions) is_expected.to include(*master_permissions) diff --git a/spec/rake_helper.rb b/spec/rake_helper.rb new file mode 100644 index 00000000000..9b5b4bf9fea --- /dev/null +++ b/spec/rake_helper.rb @@ -0,0 +1,19 @@ +require 'spec_helper' +require 'rake' + +RSpec.configure do |config| + config.include RakeHelpers + + # Redirect stdout so specs don't have so much noise + config.before(:all) do + $stdout = StringIO.new + + Rake.application.rake_require 'tasks/gitlab/task_helpers' + Rake::Task.define_task :environment + end + + # Reset stdout + config.after(:all) do + $stdout = STDOUT + end +end diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/api_helpers_spec.rb index f7fe4c10873..01bb9e955e0 100644 --- a/spec/requests/api/api_helpers_spec.rb +++ b/spec/requests/api/api_helpers_spec.rb @@ -265,36 +265,6 @@ describe API::Helpers, api: true do end end - describe '.to_boolean' do - it 'accepts booleans' do - expect(to_boolean(true)).to be(true) - expect(to_boolean(false)).to be(false) - end - - it 'converts a valid string to a boolean' do - expect(to_boolean(true)).to be(true) - expect(to_boolean('true')).to be(true) - expect(to_boolean('YeS')).to be(true) - expect(to_boolean('t')).to be(true) - expect(to_boolean('1')).to be(true) - expect(to_boolean('ON')).to be(true) - - expect(to_boolean('FaLse')).to be(false) - expect(to_boolean('F')).to be(false) - expect(to_boolean('NO')).to be(false) - expect(to_boolean('n')).to be(false) - expect(to_boolean('0')).to be(false) - expect(to_boolean('oFF')).to be(false) - end - - it 'converts an invalid string to nil' do - expect(to_boolean('fals')).to be_nil - expect(to_boolean('yeah')).to be_nil - expect(to_boolean('')).to be_nil - expect(to_boolean(nil)).to be_nil - end - end - describe '.handle_api_exception' do before do allow_any_instance_of(self.class).to receive(:sentry_enabled?).and_return(true) diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index dbdf83a0dff..9bfc84c7425 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -284,7 +284,17 @@ describe 'Git LFS API and storage' do let(:authorization) { authorize_ci_project } shared_examples 'can download LFS only from own projects' do - context 'for own project' do + context 'for owned project' do + let(:project) { create(:empty_project, namespace: user.namespace) } + + let(:update_permissions) do + project.lfs_objects << lfs_object + end + + it_behaves_like 'responds with a file' + end + + context 'for member of project' do let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:update_permissions) do diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index c64df4979b0..bb26513103d 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -245,6 +245,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do it_behaves_like 'a pullable' end + + context 'when you are owner' do + let(:project) { create(:empty_project, namespace: current_user.namespace) } + + it_behaves_like 'a pullable' + end end context 'for private' do @@ -266,6 +272,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do it_behaves_like 'a pullable' end + + context 'when you are owner' do + let(:project) { create(:empty_project, namespace: current_user.namespace) } + + it_behaves_like 'a pullable' + end end end end @@ -276,13 +288,21 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do end context 'disallow for all' do - let(:project) { create(:empty_project, :public) } + context 'when you are member' do + let(:project) { create(:empty_project, :public) } - before do - project.team << [current_user, :developer] + before do + project.team << [current_user, :developer] + end + + it_behaves_like 'an inaccessible' end - it_behaves_like 'an inaccessible' + context 'when you are owner' do + let(:project) { create(:empty_project, :public, namespace: current_user.namespace) } + + it_behaves_like 'an inaccessible' + end end end end diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb new file mode 100644 index 00000000000..0670ac2faa2 --- /dev/null +++ b/spec/services/members/create_service_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Members::CreateService, services: true do + let(:project) { create(:empty_project) } + let(:user) { create(:user) } + let(:project_user) { create(:user) } + + before { project.team << [user, :master] } + + it 'adds user to members' do + params = { user_ids: project_user.id.to_s, access_level: Gitlab::Access::GUEST } + result = described_class.new(project, user, params).execute + + expect(result).to be_truthy + expect(project.users).to include project_user + end + + it 'adds no user to members' do + params = { user_ids: '', access_level: Gitlab::Access::GUEST } + result = described_class.new(project, user, params).execute + + expect(result).to be_falsey + expect(project.users).not_to include project_user + end +end diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 3a3f07ddcb9..3f5df049ea2 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -25,6 +25,8 @@ describe MergeRequests::BuildService, services: true do before do allow(CompareService).to receive_message_chain(:new, :execute).and_return(compare) + allow(project).to receive(:commit).and_return(commit_1) + allow(project).to receive(:commit).and_return(commit_2) end describe 'execute' do @@ -193,5 +195,52 @@ describe MergeRequests::BuildService, services: true do end end end + + context 'source branch does not exist' do + before do + allow(project).to receive(:commit).with(source_branch).and_return(nil) + allow(project).to receive(:commit).with(target_branch).and_return(commit_1) + end + + it 'forbids the merge request from being created' do + expect(merge_request.can_be_created).to eq(false) + end + + it 'adds an error message to the merge request' do + expect(merge_request.errors).to contain_exactly('Source branch "feature-branch" does not exist') + end + end + + context 'target branch does not exist' do + before do + allow(project).to receive(:commit).with(source_branch).and_return(commit_1) + allow(project).to receive(:commit).with(target_branch).and_return(nil) + end + + it 'forbids the merge request from being created' do + expect(merge_request.can_be_created).to eq(false) + end + + it 'adds an error message to the merge request' do + expect(merge_request.errors).to contain_exactly('Target branch "master" does not exist') + end + end + + context 'both source and target branches do not exist' do + before do + allow(project).to receive(:commit).and_return(nil) + end + + it 'forbids the merge request from being created' do + expect(merge_request.can_be_created).to eq(false) + end + + it 'adds both error messages to the merge request' do + expect(merge_request.errors).to contain_exactly( + 'Source branch "feature-branch" does not exist', + 'Target branch "master" does not exist' + ) + end + end end end diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 3ea1273abc3..876bfaf085c 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -69,7 +69,7 @@ describe Projects::CreateService, services: true do context 'wiki_enabled false does not create wiki repository directory' do before do - @opts.merge!( { project_feature_attributes: { wiki_access_level: ProjectFeature::DISABLED } }) + @opts.merge!(wiki_enabled: false) @project = create_project(@user, @opts) @path = ProjectWiki.new(@project, @user).send(:path_to_repo) end diff --git a/spec/support/banzai/reference_filter_shared_examples.rb b/spec/support/banzai/reference_filter_shared_examples.rb new file mode 100644 index 00000000000..eb5da662ab5 --- /dev/null +++ b/spec/support/banzai/reference_filter_shared_examples.rb @@ -0,0 +1,13 @@ +# Specs for reference links containing HTML. +# +# Requires a reference: +# let(:reference) { '#42' } +shared_examples 'a reference containing an element node' do + let(:inner_html) { 'element <code>node</code> inside' } + let(:reference_with_element) { %{<a href="#{reference}">#{inner_html}</a>} } + + it 'does not escape inner html' do + doc = reference_filter(reference_with_element) + expect(doc.children.first.inner_html).to eq(inner_html) + end +end diff --git a/spec/support/rake_helpers.rb b/spec/support/rake_helpers.rb new file mode 100644 index 00000000000..52d80c69835 --- /dev/null +++ b/spec/support/rake_helpers.rb @@ -0,0 +1,10 @@ +module RakeHelpers + def run_rake_task(task_name) + Rake::Task[task_name].reenable + Rake.application.invoke_task task_name + end + + def stub_warn_user_is_not_gitlab + allow_any_instance_of(Object).to receive(:warn_user_is_not_gitlab) + end +end diff --git a/spec/tasks/gitlab/shell_rake_spec.rb b/spec/tasks/gitlab/shell_rake_spec.rb new file mode 100644 index 00000000000..226d34fe2c9 --- /dev/null +++ b/spec/tasks/gitlab/shell_rake_spec.rb @@ -0,0 +1,26 @@ +require 'rake_helper' + +describe 'gitlab:shell rake tasks' do + before do + Rake.application.rake_require 'tasks/gitlab/shell' + + stub_warn_user_is_not_gitlab + end + + describe 'install task' do + it 'invokes create_hooks task' do + expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke) + + run_rake_task('gitlab:shell:install') + end + end + + describe 'create_hooks task' do + it 'calls gitlab-shell bin/create_hooks' do + expect_any_instance_of(Object).to receive(:system) + .with("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks", *repository_storage_paths_args) + + run_rake_task('gitlab:shell:create_hooks') + end + end +end |