diff options
author | Lin Jen-Shin <godfat@godfat.org> | 2017-02-02 11:54:35 +0800 |
---|---|---|
committer | Lin Jen-Shin <godfat@godfat.org> | 2017-02-02 11:54:35 +0800 |
commit | 54fca95160389fe7993df5d82635b83804833fee (patch) | |
tree | 8552f29a7bfbf24af39a5d6a3f8b110c1695f7de /spec | |
parent | eb242fc865c032f6408f3b68700da9b840b416dd (diff) | |
parent | 40a824357c700280f3d2f8e2cda2fabc65af7f69 (diff) | |
download | gitlab-ce-54fca95160389fe7993df5d82635b83804833fee.tar.gz |
Merge remote-tracking branch 'upstream/master' into fix-git-hooks-when-creating-filefix-git-hooks-when-creating-file
* upstream/master: (190 commits)
Remove unnecessary returns / unset variables from the CoffeeScript -> JS conversion.
update spec
Change the reply shortcut to focus the field even without a selection.
use destroy_all
Remove settings cog from within admin scroll tabs; keep links centered
add changelog
remove old project members from project
add spec replicating validation error
Fix small typo on new branch button spec
Improve styling of the new issue message
Don't capitalize environment name in show page
Abillity to promote project labels to group labels
Edited the column header for the environments list from created to updated and added created to environments detail page colum header titles
Update and pin the `jwt` gem to ~> 1.5.6
refactor merge request build service
Update index.md
Clarify that Auto Deploy requires a public project.
19164 Add settings dropdown to mobile screens
cop for gem fetched from a git source
Add CHANGELOG entry
...
Diffstat (limited to 'spec')
163 files changed, 2123 insertions, 686 deletions
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb new file mode 100644 index 00000000000..9dceeca168d --- /dev/null +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe Explore::ProjectsController do + describe 'GET #trending' do + context 'sorting by update date' do + let(:project1) { create(:empty_project, :public, updated_at: 3.days.ago) } + let(:project2) { create(:empty_project, :public, updated_at: 1.day.ago) } + + before do + create(:trending_project, project: project1) + create(:trending_project, project: project2) + end + + it 'sorts by last updated' do + get :trending, sort: 'updated_desc' + + expect(assigns(:projects)).to eq [project2, project1] + end + + it 'sorts by oldest updated' do + get :trending, sort: 'updated_asc' + + expect(assigns(:projects)).to eq [project1, project2] + end + end + end +end diff --git a/spec/controllers/projects/commit_controller_spec.rb b/spec/controllers/projects/commit_controller_spec.rb index a95cfc5c6be..ebd2d0e092b 100644 --- a/spec/controllers/projects/commit_controller_spec.rb +++ b/spec/controllers/projects/commit_controller_spec.rb @@ -4,7 +4,6 @@ describe Projects::CommitController do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:commit) { project.commit("master") } - let(:pipeline) { create(:ci_pipeline, project: project, commit: commit) } let(:master_pickable_sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' } let(:master_pickable_commit) { project.commit(master_pickable_sha) } @@ -322,11 +321,26 @@ describe Projects::CommitController do end context 'when the commit exists' do - context 'when the commit has one or more pipelines' do - it 'shows pipelines' do - get_pipelines(id: commit.id) + context 'when the commit has pipelines' do + before do + create(:ci_pipeline, project: project, sha: commit.id) + end + + context 'when rendering a HTML format' do + it 'shows pipelines' do + get_pipelines(id: commit.id) + + expect(response).to be_ok + end + end - expect(response).to be_ok + context 'when rendering a JSON format' do + it 'responds with serialized pipelines' do + get_pipelines(id: commit.id, format: :json) + + expect(response).to be_ok + expect(JSON.parse(response.body)).not_to be_empty + end end end end diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index ec6cea5c0f4..3e0326dd47d 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -112,4 +112,49 @@ describe Projects::LabelsController do post :toggle_subscription, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label.to_param end end + + describe 'POST #promote' do + let!(:promoted_label_name) { "Promoted Label" } + let!(:label_1) { create(:label, title: promoted_label_name, project: project) } + + context 'not group owner' do + it 'denies access' do + post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + + expect(response).to have_http_status(404) + end + end + + context 'group owner' do + before do + GroupMember.add_users_to_group(group, [user], :owner) + end + + it 'gives access' do + post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + + expect(response).to redirect_to(namespace_project_labels_path) + end + + it 'promotes the label' do + post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + + expect(Label.where(id: label_1.id)).to be_empty + expect(GroupLabel.find_by(title: promoted_label_name)).not_to be_nil + end + + context 'service raising InvalidRecord' do + before do + expect_any_instance_of(Labels::PromoteService).to receive(:execute) do |label| + raise ActiveRecord::RecordInvalid.new(label_1) + end + end + + it 'returns to label list' do + post :promote, namespace_id: project.namespace.to_param, project_id: project.to_param, id: label_1.to_param + expect(response).to redirect_to(namespace_project_labels_path) + end + end + end + end end diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 2ae635a1244..cae733f0cfb 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -13,13 +13,13 @@ describe Projects::MattermostsController do before do allow_any_instance_of(MattermostSlashCommandsService). to receive(:list_teams).and_return([]) + end + it 'accepts the request' do get(:new, namespace_id: project.namespace.to_param, project_id: project.to_param) - end - it 'accepts the request' do expect(response).to have_http_status(200) end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 7ea3ea4f376..e019541e74f 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Projects::MergeRequestsController do + include ApiHelpers + let(:project) { create(:project) } let(:user) { create(:user) } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } @@ -455,7 +457,7 @@ describe Projects::MergeRequestsController do it 'renders the diffs template to a string' do expect(response).to render_template('projects/merge_requests/show/_diffs') - expect(JSON.parse(response.body)).to have_key('html') + expect(json_response).to have_key('html') end end @@ -494,7 +496,7 @@ describe Projects::MergeRequestsController do it 'renders the diffs template to a string' do expect(response).to render_template('projects/merge_requests/show/_diffs') - expect(JSON.parse(response.body)).to have_key('html') + expect(json_response).to have_key('html') end end end @@ -662,18 +664,45 @@ describe Projects::MergeRequestsController do go format: 'json' expect(response).to render_template('projects/merge_requests/show/_commits') - expect(JSON.parse(response.body)).to have_key('html') + expect(json_response).to have_key('html') end end end describe 'GET pipelines' do - it_behaves_like "loads labels", :pipelines + before do + create(:ci_pipeline, project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + context 'when using HTML format' do + it_behaves_like "loads labels", :pipelines + end + + context 'when using JSON format' do + before do + get :pipelines, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + id: merge_request.iid, + format: :json + end + + it 'responds with a rendered HTML partial' do + expect(response) + .to render_template('projects/merge_requests/show/_pipelines') + expect(json_response).to have_key 'html' + end + + it 'responds with serialized pipelines' do + expect(json_response).to have_key 'pipelines' + expect(json_response['pipelines']).not_to be_empty + end + end end describe 'GET conflicts' do - let(:json_response) { JSON.parse(response.body) } - context 'when the conflicts cannot be resolved in the UI' do before do allow_any_instance_of(Gitlab::Conflict::Parser). @@ -770,8 +799,6 @@ describe Projects::MergeRequestsController do end describe 'GET conflict_for_path' do - let(:json_response) { JSON.parse(response.body) } - def conflict_for_path(path) get :conflict_for_path, namespace_id: merge_request_with_conflicts.project.namespace.to_param, @@ -826,7 +853,6 @@ describe Projects::MergeRequestsController do end context 'POST resolve_conflicts' do - let(:json_response) { JSON.parse(response.body) } let!(:original_head_sha) { merge_request_with_conflicts.diff_head_sha } def resolve_conflicts(files) @@ -1024,7 +1050,6 @@ describe Projects::MergeRequestsController do let!(:forked) { create(:project) } let!(:environment) { create(:environment, project: forked) } let!(:deployment) { create(:deployment, environment: environment, sha: forked.commit.id, ref: 'master') } - let(:json_response) { JSON.parse(response.body) } let(:admin) { create(:admin) } let(:merge_request) do diff --git a/spec/factories/trending_project.rb b/spec/factories/trending_project.rb new file mode 100644 index 00000000000..246176611dc --- /dev/null +++ b/spec/factories/trending_project.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + # TrendingProject + factory :trending_project, class: 'TrendingProject' do + project + end +end diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 188d33e8ef4..c28bb0dcdae 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -141,6 +141,36 @@ describe 'Issue Boards', feature: true, js: true do end end end + + it 'resets assignee dropdown' do + page.within(first('.board')) do + first('.card').click + end + + page.within('.assignee') do + click_link 'Edit' + + wait_for_ajax + + page.within('.dropdown-menu-user') do + click_link user.name + + wait_for_vue_resource + end + + expect(page).to have_content(user.name) + end + + page.within(first('.board')) do + find('.card:nth-child(2)').click + end + + page.within('.assignee') do + click_link 'Edit' + + expect(page).not_to have_selector('.is-active') + end + end end context 'milestone' do diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index 56f6cd2e095..511c95b758f 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -19,6 +19,10 @@ feature 'Environment', :feature do visit_environment(environment) end + scenario 'shows environment name' do + expect(page).to have_content(environment.name) + end + context 'without deployments' do scenario 'does show no deployments' do expect(page).to have_content('You don\'t have any deployments right now.') diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index 72b984cfab8..c033b693213 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -194,7 +194,7 @@ feature 'Environments page', :feature, :js do end scenario 'does create a new pipeline' do - expect(page).to have_content('Production') + expect(page).to have_content('production') end end diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index 8a155c3bfc5..93763f092fb 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -43,14 +43,6 @@ describe 'Dropdown assignee', js: true, feature: true do expect(page).to have_css(js_dropdown_assignee, visible: true) end - it 'shows assigned to me link' do - filtered_search.set('assignee:') - - page.within js_dropdown_assignee do - expect(page).to have_content('Assigned to me') - end - end - it 'closes when the search bar is unfocused' do find('body').click() @@ -129,14 +121,6 @@ describe 'Dropdown assignee', js: true, feature: true do filtered_search.set('assignee:') end - it 'filters by current user' do - page.within js_dropdown_assignee do - click_button 'Assigned to me' - end - - expect(filtered_search.value).to eq("assignee:#{user.to_reference} ") - end - it 'fills in the assignee username when the assignee has not been filtered' do click_assignee(user_jacob.name) @@ -185,4 +169,22 @@ describe 'Dropdown assignee', js: true, feature: true do expect(page).to have_css(js_dropdown_assignee, visible: true) end end + + describe 'caching requests' do + it 'caches requests after the first load' do + filtered_search.set('assignee') + send_keys_to_filtered_search(':') + initial_size = dropdown_assignee_size + + expect(initial_size).to be > 0 + + new_user = create(:user) + project.team << [new_user, :master] + find('.filtered-search-input-container .clear-search').click + filtered_search.set('assignee') + send_keys_to_filtered_search(':') + + expect(dropdown_assignee_size).to eq(initial_size) + end + end end diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index a5d5d9d4c5e..59e302f0e2d 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -157,4 +157,22 @@ describe 'Dropdown author', js: true, feature: true do expect(page).to have_css(js_dropdown_author, visible: true) end end + + describe 'caching requests' do + it 'caches requests after the first load' do + filtered_search.set('author') + send_keys_to_filtered_search(':') + initial_size = dropdown_author_size + + expect(initial_size).to be > 0 + + new_user = create(:user) + project.team << [new_user, :master] + find('.filtered-search-input-container .clear-search').click + filtered_search.set('author') + send_keys_to_filtered_search(':') + + expect(dropdown_author_size).to eq(initial_size) + end + end end diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index f09ad2dd86b..5079eb8dd00 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -249,4 +249,21 @@ describe 'Dropdown label', js: true, feature: true do expect(page).to have_css(js_dropdown_label, visible: true) end end + + describe 'caching requests' do + it 'caches requests after the first load' do + filtered_search.set('label') + send_keys_to_filtered_search(':') + initial_size = dropdown_label_size + + expect(initial_size).to be > 0 + + create(:label, project: project) + find('.filtered-search-input-container .clear-search').click + filtered_search.set('label') + send_keys_to_filtered_search(':') + + expect(dropdown_label_size).to eq(initial_size) + end + end end diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index 134e58ad586..0ce16715b86 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -219,4 +219,21 @@ describe 'Dropdown milestone', js: true, feature: true do expect(page).to have_css(js_dropdown_milestone, visible: true) end end + + describe 'caching requests' do + it 'caches requests after the first load' do + filtered_search.set('milestone') + send_keys_to_filtered_search(':') + initial_size = dropdown_milestone_size + + expect(initial_size).to be > 0 + + create(:milestone, project: project) + find('.filtered-search-input-container .clear-search').click + filtered_search.set('milestone') + send_keys_to_filtered_search(':') + + expect(dropdown_milestone_size).to eq(initial_size) + end + end end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index f48a0193545..3f70a6aa75f 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -773,7 +773,7 @@ describe 'Filter issues', js: true, feature: true do describe 'RSS feeds' do it 'updates atom feed link for project issues' do visit namespace_project_issues_path(project.namespace, project, milestone_title: milestone.title, assignee_id: user.id) - link = find('.nav-controls a', text: 'Subscribe') + link = find_link('Subscribe') params = CGI.parse(URI.parse(link[:href]).query) auto_discovery_link = find('link[type="application/atom+xml"]', visible: false) auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query) diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index bc068b5e7e0..1eb981942ea 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -2,6 +2,7 @@ require 'rails_helper' feature 'Issue Sidebar', feature: true do include WaitForAjax + include MobileHelpers let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } @@ -59,6 +60,23 @@ feature 'Issue Sidebar', feature: true do end end + context 'sidebar', js: true do + it 'changes size when the screen size is smaller' do + sidebar_selector = 'aside.right-sidebar.right-sidebar-collapsed' + # Resize the window + resize_screen_sm + # Make sure the sidebar is collapsed + expect(page).to have_css(sidebar_selector) + # Once is collapsed let's open the sidebard and reload + open_issue_sidebar + refresh + expect(page).to have_css(sidebar_selector) + # Restore the window size as it was including the sidebar + restore_window_size + open_issue_sidebar + end + end + context 'creating a new label', js: true do it 'shows option to crate a new label is present' do page.within('.block.labels') do @@ -109,4 +127,11 @@ feature 'Issue Sidebar', feature: true do def visit_issue(project, issue) visit namespace_project_issue_path(project.namespace, project, issue) end + + def open_issue_sidebar + page.within('aside.right-sidebar.right-sidebar-collapsed') do + find('.js-sidebar-toggle').click + sleep 1 + end + end end diff --git a/spec/features/issues/new_branch_button_spec.rb b/spec/features/issues/new_branch_button_spec.rb index a4d3053d10c..c0ab42c6822 100644 --- a/spec/features/issues/new_branch_button_spec.rb +++ b/spec/features/issues/new_branch_button_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Start new branch from an issue', feature: true do +feature 'Start new branch from an issue', feature: true, js: true do let!(:project) { create(:project) } let!(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} @@ -11,7 +11,7 @@ feature 'Start new branch from an issue', feature: true do login_as(user) end - it 'shows the new branch button', js: true do + it 'shows the new branch button' do visit namespace_project_issue_path(project.namespace, project, issue) expect(page).to have_css('#new-branch .available') @@ -34,16 +34,26 @@ feature 'Start new branch from an issue', feature: true do visit namespace_project_issue_path(project.namespace, project, issue) end - it "hides the new branch button", js: true do + it "hides the new branch button" do expect(page).to have_css('#new-branch .unavailable') expect(page).not_to have_css('#new-branch .available') expect(page).to have_content /1 Related Merge Request/ end end + + context 'when issue is confidential' do + it 'hides the new branch button' do + issue = create(:issue, :confidential, project: project) + + visit namespace_project_issue_path(project.namespace, project, issue) + + expect(page).not_to have_css('#new-branch') + end + end end - context "for visiters" do - it 'shows no buttons', js: true do + context 'for visitors' do + it 'shows no buttons' do visit namespace_project_issue_path(project.namespace, project, issue) expect(page).not_to have_css('#new-branch') diff --git a/spec/features/login_spec.rb b/spec/features/login_spec.rb index 76bcfbe523a..ab7d89306db 100644 --- a/spec/features/login_spec.rb +++ b/spec/features/login_spec.rb @@ -25,6 +25,11 @@ feature 'Login', feature: true do expect(current_path).to eq root_path end + + it 'does not show flash messages when login page' do + visit root_path + expect(page).not_to have_content('You need to sign in or sign up before continuing.') + end end describe 'with two-factor authentication' do diff --git a/spec/features/merge_requests/toggler_behavior_spec.rb b/spec/features/merge_requests/toggler_behavior_spec.rb new file mode 100644 index 00000000000..6958f6a2c9f --- /dev/null +++ b/spec/features/merge_requests/toggler_behavior_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +feature 'toggler_behavior', js: true, feature: true do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:merge_request) { create(:merge_request, source_project: project, author: user) } + let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } + let(:fragment_id) { "#note_#{note.id}" } + + before do + login_as :admin + project = merge_request.source_project + visit "#{namespace_project_merge_request_path(project.namespace, project, merge_request)}#{fragment_id}" + page.current_window.resize_to(1000, 300) + end + + describe 'scroll position' do + it 'should be scrolled down to fragment' do + page_height = page.current_window.size[1] + page_scroll_y = page.evaluate_script("window.scrollY") + fragment_position_top = page.evaluate_script("document.querySelector('#{fragment_id}').getBoundingClientRect().top") + + expect(find('.js-toggle-content').visible?).to eq true + expect(find(fragment_id).visible?).to eq true + expect(fragment_position_top).to be > page_scroll_y + expect(fragment_position_top).to be < (page_scroll_y + page_height) + end + end +end diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb index b13674b4db9..2582a540240 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -11,7 +11,7 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do it_behaves_like 'issuable record that supports slash commands in its description and notes', :merge_request do let(:issuable) { create(:merge_request, source_project: project) } - let(:new_url_opts) { { merge_request: { source_branch: 'feature' } } } + let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } } end describe 'merge-request-only commands' do diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb new file mode 100644 index 00000000000..7d1805f5001 --- /dev/null +++ b/spec/features/merge_requests/widget_spec.rb @@ -0,0 +1,34 @@ +require 'rails_helper' + +describe 'Merge request', :feature, :js do + include WaitForAjax + + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + project.team << [user, :master] + login_as(user) + + visit new_namespace_project_merge_request_path( + project.namespace, + project, + merge_request: { + source_project_id: project.id, + target_project_id: project.id, + source_branch: 'feature', + target_branch: 'master' + } + ) + end + + it 'shows widget status after creating new merge request' do + click_button 'Submit merge request' + + expect(find('.mr-state-widget')).to have_content('Checking ability to merge automatically') + + wait_for_ajax + + expect(page).to have_selector('.accept_merge_request') + end +end diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb index 52d08982c7a..16dddb2a86b 100644 --- a/spec/features/projects/import_export/export_file_spec.rb +++ b/spec/features/projects/import_export/export_file_spec.rb @@ -74,6 +74,9 @@ feature 'Import/Export - project export integration test', feature: true, js: tr Otherwise, please add the exception to +safe_list+ in CURRENT_SPEC using #{sensitive_word} as the key and the correspondent hash or model as the value. + Also, if the attribute is a generated unique token, please add it to RelationFactory::TOKEN_RESET_MODELS if it needs to be + reset (to prevent duplicate column problems while importing to the same instance). + IMPORT_EXPORT_CONFIG: #{Gitlab::ImportExport.config_file} CURRENT_SPEC: #{__FILE__} MSG diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz Binary files differindex 7655c2b351f..20cdfbae24f 100644 --- a/spec/features/projects/import_export/test_project_export.tar.gz +++ b/spec/features/projects/import_export/test_project_export.tar.gz diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index c9fa8315e79..97ce9cdfd87 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -20,7 +20,7 @@ feature 'Prioritize labels', feature: true do scenario 'user can prioritize a group label', js: true do visit namespace_project_labels_path(project.namespace, project) - expect(page).to have_content('No prioritized labels yet') + expect(page).to have_content('Star labels to start sorting by priority') page.within('.other-labels') do all('.js-toggle-priority')[1].click @@ -29,7 +29,7 @@ feature 'Prioritize labels', feature: true do end page.within('.prioritized-labels') do - expect(page).not_to have_content('No prioritized labels yet') + expect(page).not_to have_content('Star labels to start sorting by priority') expect(page).to have_content('feature') end end @@ -55,7 +55,7 @@ feature 'Prioritize labels', feature: true do scenario 'user can prioritize a project label', js: true do visit namespace_project_labels_path(project.namespace, project) - expect(page).to have_content('No prioritized labels yet') + expect(page).to have_content('Star labels to start sorting by priority') page.within('.other-labels') do first('.js-toggle-priority').click @@ -64,7 +64,7 @@ feature 'Prioritize labels', feature: true do end page.within('.prioritized-labels') do - expect(page).not_to have_content('No prioritized labels yet') + expect(page).not_to have_content('Star labels to start sorting by priority') expect(page).to have_content('bug') end end diff --git a/spec/features/projects/new_project_spec.rb b/spec/features/projects/new_project_spec.rb index abfc46601fb..b56e562b2b6 100644 --- a/spec/features/projects/new_project_spec.rb +++ b/spec/features/projects/new_project_spec.rb @@ -1,11 +1,13 @@ require "spec_helper" feature "New project", feature: true do - context "Visibility level selector" do - let(:user) { create(:admin) } + let(:user) { create(:admin) } - before { login_as(user) } + before do + login_as(user) + end + context "Visibility level selector" do Gitlab::VisibilityLevel.options.each do |key, level| it "sets selector to #{key}" do stub_application_setting(default_project_visibility: level) @@ -16,4 +18,16 @@ feature "New project", feature: true do end end end + + context 'Import project options' do + before do + visit new_project_path + end + + it 'does not autocomplete sensitive git repo URL' do + autocomplete = find('#project_import_url')['autocomplete'] + + expect(autocomplete).to eq('off') + end + end end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index e673ece37c3..917b545e98b 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -66,8 +66,8 @@ describe 'Pipeline', :feature, :js do context 'when pipeline has running builds' do it 'shows a running icon and a cancel action for the running build' do page.within('#ci-badge-deploy') do - expect(page).to have_selector('.ci-status-icon-running') - expect(page).to have_selector('.ci-action-icon-container .fa-ban') + expect(page).to have_selector('.js-ci-status-icon-running') + expect(page).to have_selector('.js-icon-action-cancel') expect(page).to have_content('deploy') end end @@ -82,12 +82,12 @@ describe 'Pipeline', :feature, :js do context 'when pipeline has successful builds' do it 'shows the success icon and a retry action for the successful build' do page.within('#ci-badge-build') do - expect(page).to have_selector('.ci-status-icon-success') + expect(page).to have_selector('.js-ci-status-icon-success') expect(page).to have_content('build') end page.within('#ci-badge-build .ci-action-icon-container') do - expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + expect(page).to have_selector('.js-icon-action-retry') end end @@ -101,12 +101,12 @@ describe 'Pipeline', :feature, :js do context 'when pipeline has failed builds' do it 'shows the failed icon and a retry action for the failed build' do page.within('#ci-badge-test') do - expect(page).to have_selector('.ci-status-icon-failed') + expect(page).to have_selector('.js-ci-status-icon-failed') expect(page).to have_content('test') end page.within('#ci-badge-test .ci-action-icon-container') do - expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + expect(page).to have_selector('.js-icon-action-retry') end end @@ -120,12 +120,12 @@ describe 'Pipeline', :feature, :js do context 'when pipeline has manual builds' do it 'shows the skipped icon and a play action for the manual build' do page.within('#ci-badge-manual-build') do - expect(page).to have_selector('.ci-status-icon-manual') + expect(page).to have_selector('.js-ci-status-icon-manual') expect(page).to have_content('manual') end page.within('#ci-badge-manual-build .ci-action-icon-container') do - expect(page).to have_selector('.ci-action-icon-container .fa-play') + expect(page).to have_selector('.js-icon-action-play') end end @@ -138,7 +138,7 @@ describe 'Pipeline', :feature, :js do context 'when pipeline has external build' do it 'shows the success icon and the generic comit status build' do - expect(page).to have_selector('.ci-status-icon-success') + expect(page).to have_selector('.js-ci-status-icon-success') expect(page).to have_content('jenkins') expect(page).to have_link('jenkins', href: 'http://gitlab.com/status') end diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 55d5d082c6e..5d0314d5c09 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -37,7 +37,7 @@ describe 'Edit Project Settings', feature: true do it 'shows errors for invalid project path/name' do visit edit_namespace_project_path(project.namespace, project) - fill_in 'Project name', with: 'foo&bar' + fill_in 'project_name', with: 'foo&bar' fill_in 'Path', with: 'foo&bar' click_button 'Rename project' @@ -53,7 +53,7 @@ describe 'Edit Project Settings', feature: true do it 'shows error for invalid project name' do visit edit_namespace_project_path(project.namespace, project) - fill_in 'Project name', with: '🚀 foo bar ☁️' + fill_in 'project_name', with: '🚀 foo bar ☁️' click_button 'Rename project' diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 86a07b2c679..042a1ccab51 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -99,6 +99,15 @@ feature 'Setup Mattermost slash commands', feature: true do expect(select_element.all('option').count).to eq(3) end + it 'shows an error alert with the error message if there is an error requesting teams' do + allow_any_instance_of(MattermostSlashCommandsService).to receive(:list_teams) { [[], 'test mattermost error message'] } + + click_link 'Add to Mattermost' + + expect(page).to have_selector('.alert') + expect(page).to have_content('test mattermost error message') + end + def stub_teams(count: 0) teams = create_teams(count) diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb index 3850e930b6d..1b352be9331 100644 --- a/spec/features/todos/todos_spec.rb +++ b/spec/features/todos/todos_spec.rb @@ -171,7 +171,7 @@ describe 'Dashboard Todos', feature: true do it 'links to the pipelines for the merge request' do href = pipelines_namespace_project_merge_request_path(project.namespace, project, todo.target) - expect(page).to have_link "merge request #{todo.target.to_reference}", href + expect(page).to have_link "merge request #{todo.target.to_reference(full: true)}", href end end end diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index a4f08dc4af0..df71680e44c 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -115,6 +115,46 @@ describe IssuablesHelper do end end + describe '#issuable_reference' do + context 'when show_full_reference truthy' do + it 'display issuable full reference' do + assign(:show_full_reference, true) + issue = build_stubbed(:issue) + + expect(helper.issuable_reference(issue)).to eql(issue.to_reference(full: true)) + end + end + + context 'when show_full_reference falsey' do + context 'when @group present' do + it 'display issuable reference to @group' do + project = build_stubbed(:project) + + assign(:show_full_reference, nil) + assign(:group, project.namespace) + + issue = build_stubbed(:issue) + + expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project.namespace)) + end + end + + context 'when @project present' do + it 'display issuable reference to @project' do + project = build_stubbed(:project) + + assign(:show_full_reference, nil) + assign(:group, nil) + assign(:project, project) + + issue = build_stubbed(:issue) + + expect(helper.issuable_reference(issue)).to eql(issue.to_reference(project)) + end + end + end + end + describe '#issuable_filter_present?' do it 'returns true when any key is present' do allow(helper).to receive(:params).and_return( diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index e51720f10ed..b7e547dc1f5 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -41,6 +41,11 @@ describe SearchHelper do expect(search_autocomplete_opts("gro").size).to eq(1) end + it "includes nested group" do + create(:group, :nested, name: 'foo').add_owner(user) + expect(search_autocomplete_opts('foo').size).to eq(1) + end + it "includes the user's projects" do project = create(:empty_project, namespace: create(:namespace, owner: user)) expect(search_autocomplete_opts(project.name).size).to eq(1) diff --git a/spec/javascripts/commits_spec.js.es6 b/spec/javascripts/commits_spec.js.es6 new file mode 100644 index 00000000000..bb9a9072f3a --- /dev/null +++ b/spec/javascripts/commits_spec.js.es6 @@ -0,0 +1,50 @@ +/* global CommitsList */ + +//= require jquery.endless-scroll +//= require pager +//= require commits + +(() => { + describe('Commits List', () => { + beforeEach(() => { + setFixtures(` + <form class="commits-search-form" action="/h5bp/html5-boilerplate/commits/master"> + <input id="commits-search"> + </form> + <ol id="commits-list"></ol> + `); + }); + + it('should be defined', () => { + expect(CommitsList).toBeDefined(); + }); + + describe('on entering input', () => { + let ajaxSpy; + + beforeEach(() => { + CommitsList.init(25); + CommitsList.searchField.val(''); + spyOn(history, 'replaceState').and.stub(); + ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => { + req.success({ + data: '<li>Result</li>', + }); + }); + }); + + it('should save the last search string', () => { + CommitsList.searchField.val('GitLab'); + CommitsList.filterResults(); + expect(ajaxSpy).toHaveBeenCalled(); + expect(CommitsList.lastSearch).toEqual('GitLab'); + }); + + it('should not make ajax call if the input does not change', () => { + CommitsList.filterResults(); + expect(ajaxSpy).not.toHaveBeenCalled(); + expect(CommitsList.lastSearch).toEqual(''); + }); + }); + }); +})(); diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_user_spec.js.es6 new file mode 100644 index 00000000000..5eba4343a1d --- /dev/null +++ b/spec/javascripts/filtered_search/dropdown_user_spec.js.es6 @@ -0,0 +1,40 @@ +//= require filtered_search/dropdown_utils +//= require filtered_search/filtered_search_tokenizer +//= require filtered_search/filtered_search_dropdown +//= require filtered_search/dropdown_user + +(() => { + describe('Dropdown User', () => { + describe('getSearchInput', () => { + let dropdownUser; + + beforeEach(() => { + spyOn(gl.FilteredSearchDropdown.prototype, 'constructor').and.callFake(() => {}); + spyOn(gl.DropdownUser.prototype, 'getProjectId').and.callFake(() => {}); + spyOn(gl.DropdownUtils, 'getSearchInput').and.callFake(() => {}); + + dropdownUser = new gl.DropdownUser(); + }); + + it('should not return the double quote found in value', () => { + spyOn(gl.FilteredSearchTokenizer, 'processTokens').and.returnValue({ + lastToken: { + value: '"johnny appleseed', + }, + }); + + expect(dropdownUser.getSearchInput()).toBe('johnny appleseed'); + }); + + it('should not return the single quote found in value', () => { + spyOn(gl.FilteredSearchTokenizer, 'processTokens').and.returnValue({ + lastToken: { + value: '\'larry boy', + }, + }); + + expect(dropdownUser.getSearchInput()).toBe('larry boy'); + }); + }); + }); +})(); diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 index 19bd8d53219..89e49b7c511 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 @@ -64,6 +64,68 @@ const updatedItem = gl.DropdownUtils.filterWithSymbol('@', input, item); expect(updatedItem.droplab_hidden).toBe(false); }); + + describe('filters multiple word title', () => { + const multipleWordItem = { + title: 'Community Contributions', + }; + + it('should filter with double quote', () => { + input.value = 'label:"'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with double quote and symbol', () => { + input.value = 'label:~"'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with double quote and multiple words', () => { + input.value = 'label:"community con'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with double quote, symbol and multiple words', () => { + input.value = 'label:~"community con'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with single quote', () => { + input.value = 'label:\''; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with single quote and symbol', () => { + input.value = 'label:~\''; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with single quote and multiple words', () => { + input.value = 'label:\'community con'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + + it('should filter with single quote, symbol and multiple words', () => { + input.value = 'label:~\'community con'; + + const updatedItem = gl.DropdownUtils.filterWithSymbol('~', input, multipleWordItem); + expect(updatedItem.droplab_hidden).toBe(false); + }); + }); }); describe('filterHint', () => { @@ -130,5 +192,99 @@ expect(result).toBe(false); }); }); + + describe('getInputSelectionPosition', () => { + describe('word with trailing spaces', () => { + const value = 'label:none '; + + it('should return selectionStart when cursor is at the trailing space', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 11, + value, + }); + + expect(left).toBe(11); + expect(right).toBe(11); + }); + + it('should return input when cursor is at the start of input', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 0, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(10); + }); + + it('should return input when cursor is at the middle of input', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 7, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(10); + }); + + it('should return input when cursor is at the end of input', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 10, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(10); + }); + }); + + describe('multiple words', () => { + const value = 'label:~"Community Contribution"'; + + it('should return input when cursor is after the first word', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 17, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(31); + }); + + it('should return input when cursor is before the second word', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 18, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(31); + }); + }); + + describe('incomplete multiple words', () => { + const value = 'label:~"Community Contribution'; + + it('should return entire input when cursor is at the start of input', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 0, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(30); + }); + + it('should return entire input when cursor is at the end of input', () => { + const { left, right } = gl.DropdownUtils.getInputSelectionPosition({ + selectionStart: 30, + value, + }); + + expect(left).toBe(0); + expect(right).toBe(30); + }); + }); + }); }); })(); diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 new file mode 100644 index 00000000000..c8b5c2b36ad --- /dev/null +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 @@ -0,0 +1,68 @@ +/* global Turbolinks */ + +//= require turbolinks +//= require lib/utils/common_utils +//= require filtered_search/filtered_search_token_keys +//= require filtered_search/filtered_search_tokenizer +//= require filtered_search/filtered_search_dropdown_manager +//= require filtered_search/filtered_search_manager + +(() => { + describe('Filtered Search Manager', () => { + describe('search', () => { + let manager; + const defaultParams = '?scope=all&utf8=✓&state=opened'; + + function getInput() { + return document.querySelector('.filtered-search'); + } + + beforeEach(() => { + setFixtures(` + <input type='text' class='filtered-search' /> + `); + + spyOn(gl.FilteredSearchManager.prototype, 'bindEvents').and.callFake(() => {}); + spyOn(gl.FilteredSearchManager.prototype, 'loadSearchParamsFromURL').and.callFake(() => {}); + spyOn(gl.FilteredSearchDropdownManager.prototype, 'setDropdown').and.callFake(() => {}); + spyOn(gl.utils, 'getParameterByName').and.returnValue(null); + + manager = new gl.FilteredSearchManager(); + }); + + afterEach(() => { + getInput().outerHTML = ''; + }); + + it('should search with a single word', () => { + getInput().value = 'searchTerm'; + + spyOn(Turbolinks, 'visit').and.callFake((url) => { + expect(url).toEqual(`${defaultParams}&search=searchTerm`); + }); + + manager.search(); + }); + + it('should search with multiple words', () => { + getInput().value = 'awesome search terms'; + + spyOn(Turbolinks, 'visit').and.callFake((url) => { + expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`); + }); + + manager.search(); + }); + + it('should search with special characters', () => { + getInput().value = '~!@#$%^&*()_+{}:<>,.?/'; + + spyOn(Turbolinks, 'visit').and.callFake((url) => { + expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`); + }); + + manager.search(); + }); + }); + }); +})(); diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 index 6df7c0e44ef..9d9097419ea 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 @@ -72,6 +72,12 @@ const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`); expect(result).toEqual(tokenKeys[0]); }); + + it('should return alternative tokenKey when found by key param', () => { + const tokenKeys = gl.FilteredSearchTokenKeys.getAlternatives(); + const result = gl.FilteredSearchTokenKeys.searchByKeyParam(`${tokenKeys[0].key}_${tokenKeys[0].param}`); + expect(result).toEqual(tokenKeys[0]); + }); }); describe('searchByConditionUrl', () => { diff --git a/spec/javascripts/gl_form_spec.js.es6 b/spec/javascripts/gl_form_spec.js.es6 new file mode 100644 index 00000000000..b5f99483bfb --- /dev/null +++ b/spec/javascripts/gl_form_spec.js.es6 @@ -0,0 +1,122 @@ +/* global autosize */ +/*= require gl_form */ +/*= require autosize */ +/*= require lib/utils/text_utility */ +/*= require lib/utils/common_utils */ + +describe('GLForm', () => { + const global = window.gl || (window.gl = {}); + const GLForm = global.GLForm; + + it('should be defined in the global scope', () => { + expect(GLForm).toBeDefined(); + }); + + describe('when instantiated', function () { + beforeEach((done) => { + this.form = $('<form class="gfm-form"><textarea class="js-gfm-input"></form>'); + this.textarea = this.form.find('textarea'); + spyOn($.prototype, 'off').and.returnValue(this.textarea); + spyOn($.prototype, 'on').and.returnValue(this.textarea); + spyOn($.prototype, 'css'); + spyOn(window, 'autosize'); + + this.glForm = new GLForm(this.form); + setTimeout(() => { + $.prototype.off.calls.reset(); + $.prototype.on.calls.reset(); + $.prototype.css.calls.reset(); + autosize.calls.reset(); + done(); + }); + }); + + describe('.setupAutosize', () => { + beforeEach((done) => { + this.glForm.setupAutosize(); + setTimeout(() => { + done(); + }); + }); + + it('should register an autosize event handler on the textarea', () => { + expect($.prototype.off).toHaveBeenCalledWith('autosize:resized'); + expect($.prototype.on).toHaveBeenCalledWith('autosize:resized', jasmine.any(Function)); + }); + + it('should register a mouseup event handler on the textarea', () => { + expect($.prototype.off).toHaveBeenCalledWith('mouseup.autosize'); + expect($.prototype.on).toHaveBeenCalledWith('mouseup.autosize', jasmine.any(Function)); + }); + + it('should autosize the textarea', () => { + expect(autosize).toHaveBeenCalledWith(jasmine.any(Object)); + }); + + it('should set the resize css property to vertical', () => { + expect($.prototype.css).toHaveBeenCalledWith('resize', 'vertical'); + }); + }); + + describe('.setHeightData', () => { + beforeEach(() => { + spyOn($.prototype, 'data'); + spyOn($.prototype, 'outerHeight').and.returnValue(200); + this.glForm.setHeightData(); + }); + + it('should set the height data attribute', () => { + expect($.prototype.data).toHaveBeenCalledWith('height', 200); + }); + + it('should call outerHeight', () => { + expect($.prototype.outerHeight).toHaveBeenCalled(); + }); + }); + + describe('.destroyAutosize', () => { + describe('when called', () => { + beforeEach(() => { + spyOn($.prototype, 'data'); + spyOn($.prototype, 'outerHeight').and.returnValue(200); + spyOn(window, 'outerHeight').and.returnValue(400); + spyOn(autosize, 'destroy'); + + this.glForm.destroyAutosize(); + }); + + it('should call outerHeight', () => { + expect($.prototype.outerHeight).toHaveBeenCalled(); + }); + + it('should get data-height attribute', () => { + expect($.prototype.data).toHaveBeenCalledWith('height'); + }); + + it('should call autosize destroy', () => { + expect(autosize.destroy).toHaveBeenCalledWith(this.textarea); + }); + + it('should set the data-height attribute', () => { + expect($.prototype.data).toHaveBeenCalledWith('height', 200); + }); + + it('should set the outerHeight', () => { + expect($.prototype.outerHeight).toHaveBeenCalledWith(200); + }); + + it('should set the css', () => { + expect($.prototype.css).toHaveBeenCalledWith('max-height', window.outerHeight); + }); + }); + + it('should return undefined if the data-height equals the outerHeight', () => { + spyOn($.prototype, 'outerHeight').and.returnValue(200); + spyOn($.prototype, 'data').and.returnValue(200); + spyOn(autosize, 'destroy'); + expect(this.glForm.destroyAutosize()).toBeUndefined(); + expect(autosize.destroy).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index 386fc8f514e..db11c2516a6 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -11,9 +11,9 @@ beforeEach(function() { loadFixtures(fixtureName); document.querySelector('.js-new-note-form').classList.add('js-main-target-form'); - return this.shortcut = new ShortcutsIssuable(); + this.shortcut = new ShortcutsIssuable(); }); - return describe('#replyWithSelectedText', function() { + describe('#replyWithSelectedText', function() { var stubSelection; // Stub window.gl.utils.getSelectedFragment to return a node with the provided HTML. stubSelection = function(html) { @@ -24,56 +24,61 @@ }; }; beforeEach(function() { - return this.selector = 'form.js-main-target-form textarea#note_note'; + this.selector = 'form.js-main-target-form textarea#note_note'; }); describe('with empty selection', function() { - return it('does nothing', function() { - stubSelection(''); + it('does not return an error', function() { this.shortcut.replyWithSelectedText(); - return expect($(this.selector).val()).toBe(''); + expect($(this.selector).val()).toBe(''); + }); + it('triggers `input`', function() { + var focused = false; + $(this.selector).on('focus', function() { + focused = true; + }); + this.shortcut.replyWithSelectedText(); + expect(focused).toBe(true); }); }); describe('with any selection', function() { beforeEach(function() { - return stubSelection('<p>Selected text.</p>'); + stubSelection('<p>Selected text.</p>'); }); it('leaves existing input intact', function() { $(this.selector).val('This text was already here.'); expect($(this.selector).val()).toBe('This text was already here.'); this.shortcut.replyWithSelectedText(); - return expect($(this.selector).val()).toBe("This text was already here.\n\n> Selected text.\n\n"); + expect($(this.selector).val()).toBe("This text was already here.\n\n> Selected text.\n\n"); }); it('triggers `input`', function() { - var triggered; - triggered = false; + var triggered = false; $(this.selector).on('input', function() { - return triggered = true; + triggered = true; }); this.shortcut.replyWithSelectedText(); - return expect(triggered).toBe(true); + expect(triggered).toBe(true); }); - return it('triggers `focus`', function() { - var focused; - focused = false; + it('triggers `focus`', function() { + var focused = false; $(this.selector).on('focus', function() { - return focused = true; + focused = true; }); this.shortcut.replyWithSelectedText(); - return expect(focused).toBe(true); + expect(focused).toBe(true); }); }); describe('with a one-line selection', function() { - return it('quotes the selection', function() { + it('quotes the selection', function() { stubSelection('<p>This text has been selected.</p>'); this.shortcut.replyWithSelectedText(); - return expect($(this.selector).val()).toBe("> This text has been selected.\n\n"); + expect($(this.selector).val()).toBe("> This text has been selected.\n\n"); }); }); - return describe('with a multi-line selection', function() { - return it('quotes the selected lines as a group', function() { + describe('with a multi-line selection', function() { + it('quotes the selected lines as a group', function() { stubSelection("<p>Selected line one.</p>\n\n<p>Selected line two.</p>\n\n<p>Selected line three.</p>"); this.shortcut.replyWithSelectedText(); - return expect($(this.selector).val()).toBe("> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n"); + expect($(this.selector).val()).toBe("> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n"); }); }); }); diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index f251c0dd25a..b234de4c772 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -58,58 +58,102 @@ describe Gitlab::Auth, lib: true do expect(gl_auth.find_for_git_client(user.username, 'password', project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities)) end - it 'recognizes user lfs tokens' do - user = create(:user) - token = Gitlab::LfsToken.new(user).token + context 'while using LFS authenticate' do + it 'recognizes user lfs tokens' do + user = create(:user) + token = Gitlab::LfsToken.new(user).token - expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username) - expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :lfs_token, full_authentication_abilities)) - end + expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.username) + expect(gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :lfs_token, full_authentication_abilities)) + end - it 'recognizes deploy key lfs tokens' do - key = create(:deploy_key) - token = Gitlab::LfsToken.new(key).token + it 'recognizes deploy key lfs tokens' do + key = create(:deploy_key) + token = Gitlab::LfsToken.new(key).token - expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}") - expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities)) - end + expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: "lfs+deploy-key-#{key.id}") + expect(gl_auth.find_for_git_client("lfs+deploy-key-#{key.id}", token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(key, nil, :lfs_deploy_token, read_authentication_abilities)) + end - context "while using OAuth tokens as passwords" do - it 'succeeds for OAuth tokens with the `api` scope' do + it 'does not try password auth before oauth' do user = create(:user) - application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) - token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api") + token = Gitlab::LfsToken.new(user).token + + expect(gl_auth).not_to receive(:find_with_user_password) + gl_auth.find_for_git_client(user.username, token, project: nil, ip: 'ip') + end + end + + context 'while using OAuth tokens as passwords' do + let(:user) { create(:user) } + let(:token_w_api_scope) { Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'api') } + let(:application) { Doorkeeper::Application.create!(name: 'MyApp', redirect_uri: 'https://app.com', owner: user) } + + it 'succeeds for OAuth tokens with the `api` scope' do expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'oauth2') - expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities)) + expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities)) end it 'fails for OAuth tokens with other scopes' do - user = create(:user) - application = Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) - token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "read_user") + token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: 'read_user') expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'oauth2') expect(gl_auth.find_for_git_client("oauth2", token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil)) end + + it 'does not try password auth before oauth' do + expect(gl_auth).not_to receive(:find_with_user_password) + + gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip') + end end - context "while using personal access tokens as passwords" do - it 'succeeds for personal access tokens with the `api` scope' do - user = create(:user) - personal_access_token = create(:personal_access_token, user: user, scopes: ['api']) + context 'while using personal access tokens as passwords' do + let(:user) { create(:user) } + let(:token_w_api_scope) { create(:personal_access_token, user: user, scopes: ['api']) } + it 'succeeds for personal access tokens with the `api` scope' do expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: user.email) - expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities)) + expect(gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :personal_token, full_authentication_abilities)) end it 'fails for personal access tokens with other scopes' do - user = create(:user) personal_access_token = create(:personal_access_token, user: user, scopes: ['read_user']) expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: user.email) expect(gl_auth.find_for_git_client(user.email, personal_access_token.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(nil, nil)) end + + it 'does not try password auth before personal access tokens' do + expect(gl_auth).not_to receive(:find_with_user_password) + + gl_auth.find_for_git_client(user.email, token_w_api_scope.token, project: nil, ip: 'ip') + end + end + + context 'while using regular user and password' do + it 'falls through lfs authentication' do + user = create( + :user, + username: 'normal_user', + password: 'my-secret', + ) + + expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) + .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities)) + end + + it 'falls through oauth authentication when the username is oauth2' do + user = create( + :user, + username: 'oauth2', + password: 'my-secret', + ) + + expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) + .to eq(Gitlab::Auth::Result.new(user, nil, :gitlab_or_ldap, full_authentication_abilities)) + end end it 'returns double nil for invalid credentials' do diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb index 1e81eaef18c..b6e924d67be 100644 --- a/spec/lib/gitlab/chat_commands/command_spec.rb +++ b/spec/lib/gitlab/chat_commands/command_spec.rb @@ -24,7 +24,7 @@ describe Gitlab::ChatCommands::Command, service: true do it 'displays the help message' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Available commands') + expect(subject[:text]).to start_with('Unknown command') expect(subject[:text]).to match('/gitlab issue show') end end @@ -34,47 +34,7 @@ describe Gitlab::ChatCommands::Command, service: true do it 'rejects the actions' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! That action is not allowed') - end - end - - context 'issue is successfully created' do - let(:params) { { text: "issue create my new issue" } } - - before do - project.team << [user, :master] - end - - it 'presents the issue' do - expect(subject[:text]).to match("my new issue") - end - - it 'shows a link to the new issue' do - expect(subject[:text]).to match(/\/issues\/\d+/) - end - end - - context 'searching for an issue' do - let(:params) { { text: 'issue search find me' } } - let!(:issue) { create(:issue, project: project, title: 'find me') } - - before do - project.team << [user, :master] - end - - context 'a single issue is found' do - it 'presents the issue' do - expect(subject[:text]).to match(issue.title) - end - end - - context 'multiple issues found' do - let!(:issue2) { create(:issue, project: project, title: "someone find me") } - - it 'shows a link to the new issue' do - expect(subject[:text]).to match(issue.title) - expect(subject[:text]).to match(issue2.title) - end + expect(subject[:text]).to start_with('Whoops! This action is not allowed') end end @@ -90,7 +50,7 @@ describe Gitlab::ChatCommands::Command, service: true do context 'and user can not create deployment' do it 'returns action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! That action is not allowed') + expect(subject[:text]).to start_with('Whoops! This action is not allowed') end end @@ -100,7 +60,7 @@ describe Gitlab::ChatCommands::Command, service: true do end it 'returns action' do - expect(subject[:text]).to include('Deployment from staging to production started.') + expect(subject[:text]).to include('Deployment started from staging to production') expect(subject[:response_type]).to be(:in_channel) end @@ -130,7 +90,7 @@ describe Gitlab::ChatCommands::Command, service: true do context 'IssueCreate is triggered' do let(:params) { { text: 'issue create my title' } } - it { is_expected.to eq(Gitlab::ChatCommands::IssueCreate) } + it { is_expected.to eq(Gitlab::ChatCommands::IssueNew) } end context 'IssueSearch is triggered' do diff --git a/spec/lib/gitlab/chat_commands/deploy_spec.rb b/spec/lib/gitlab/chat_commands/deploy_spec.rb index bd8099c92da..b3358a32161 100644 --- a/spec/lib/gitlab/chat_commands/deploy_spec.rb +++ b/spec/lib/gitlab/chat_commands/deploy_spec.rb @@ -15,8 +15,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do end context 'if no environment is defined' do - it 'returns nil' do - expect(subject).to be_nil + it 'does not execute an action' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to eq("No action found to be executed") end end @@ -26,8 +27,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do let!(:deployment) { create(:deployment, environment: staging, deployable: build) } context 'without actions' do - it 'returns nil' do - expect(subject).to be_nil + it 'does not execute an action' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to eq("No action found to be executed") end end @@ -37,8 +39,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do end it 'returns success result' do - expect(subject.type).to eq(:success) - expect(subject.message).to include('Deployment from staging to production started') + expect(subject[:response_type]).to be(:in_channel) + expect(subject[:text]).to start_with('Deployment started from staging to production') end context 'when duplicate action exists' do @@ -47,8 +49,8 @@ describe Gitlab::ChatCommands::Deploy, service: true do end it 'returns error' do - expect(subject.type).to eq(:error) - expect(subject.message).to include('Too many actions defined') + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to eq('Too many actions defined') end end @@ -59,9 +61,9 @@ describe Gitlab::ChatCommands::Deploy, service: true do name: 'teardown', environment: 'production') end - it 'returns success result' do - expect(subject.type).to eq(:success) - expect(subject.message).to include('Deployment from staging to production started') + it 'returns the success message' do + expect(subject[:response_type]).to be(:in_channel) + expect(subject[:text]).to start_with('Deployment started from staging to production') end end end diff --git a/spec/lib/gitlab/chat_commands/issue_create_spec.rb b/spec/lib/gitlab/chat_commands/issue_new_spec.rb index 6c71e79ff6d..84c22328064 100644 --- a/spec/lib/gitlab/chat_commands/issue_create_spec.rb +++ b/spec/lib/gitlab/chat_commands/issue_new_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::ChatCommands::IssueCreate, service: true do +describe Gitlab::ChatCommands::IssueNew, service: true do describe '#execute' do let(:project) { create(:empty_project) } let(:user) { create(:user) } @@ -18,7 +18,7 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do it 'creates the issue' do expect { subject }.to change { project.issues.count }.by(1) - expect(subject.title).to eq('bird is the word') + expect(subject[:response_type]).to be(:in_channel) end end @@ -41,6 +41,16 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do expect { subject }.to change { project.issues.count }.by(1) end end + + context 'issue cannot be created' do + let!(:issue) { create(:issue, project: project, title: 'bird is the word') } + let(:regex_match) { described_class.match("issue create #{'a' * 512}}") } + + it 'displays the errors' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("- Title is too long") + end + end end describe '.match' do diff --git a/spec/lib/gitlab/chat_commands/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/issue_search_spec.rb index 24c06a967fa..551ccb79a58 100644 --- a/spec/lib/gitlab/chat_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/chat_commands/issue_search_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe Gitlab::ChatCommands::IssueSearch, service: true do describe '#execute' do - let!(:issue) { create(:issue, title: 'find me') } + let!(:issue) { create(:issue, project: project, title: 'find me') } let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') } - let(:project) { issue.project } + let(:project) { create(:empty_project) } let(:user) { issue.author } let(:regex_match) { described_class.match("issue search find") } @@ -14,7 +14,8 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do context 'when the user has no access' do it 'only returns the open issues' do - expect(subject).not_to include(confidential) + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("not found") end end @@ -24,13 +25,14 @@ describe Gitlab::ChatCommands::IssueSearch, service: true do end it 'returns all results' do - expect(subject).to include(confidential, issue) + expect(subject).to have_key(:attachments) + expect(subject[:text]).to eq("Here are the 2 issues I found:") end end context 'without hits on the query' do it 'returns an empty collection' do - expect(subject).to be_empty + expect(subject[:text]).to match("not found") end end end diff --git a/spec/lib/gitlab/chat_commands/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/issue_show_spec.rb index 2eab73e49e5..1f20d0a44ce 100644 --- a/spec/lib/gitlab/chat_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/chat_commands/issue_show_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Gitlab::ChatCommands::IssueShow, service: true do describe '#execute' do - let(:issue) { create(:issue) } - let(:project) { issue.project } + let(:issue) { create(:issue, project: project) } + let(:project) { create(:empty_project) } let(:user) { issue.author } let(:regex_match) { described_class.match("issue show #{issue.iid}") } @@ -16,15 +16,19 @@ describe Gitlab::ChatCommands::IssueShow, service: true do end context 'the issue exists' do + let(:title) { subject[:attachments].first[:title] } + it 'returns the issue' do - expect(subject.iid).to be issue.iid + expect(subject[:response_type]).to be(:in_channel) + expect(title).to start_with(issue.title) end context 'when its reference is given' do let(:regex_match) { described_class.match("issue show #{issue.to_reference}") } it 'shows the issue' do - expect(subject.iid).to be issue.iid + expect(subject[:response_type]).to be(:in_channel) + expect(title).to start_with(issue.title) end end end @@ -32,17 +36,24 @@ describe Gitlab::ChatCommands::IssueShow, service: true do context 'the issue does not exist' do let(:regex_match) { described_class.match("issue show 2343242") } - it "returns nil" do - expect(subject).to be_nil + it "returns not found" do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to match("not found") end end end - describe 'self.match' do + describe '.match' do it 'matches the iid' do match = described_class.match("issue show 123") expect(match[:iid]).to eq("123") end + + it 'accepts a reference' do + match = described_class.match("issue show #{Issue.reference_prefix}123") + + expect(match[:iid]).to eq("123") + end end end diff --git a/spec/lib/gitlab/chat_commands/presenters/access_spec.rb b/spec/lib/gitlab/chat_commands/presenters/access_spec.rb new file mode 100644 index 00000000000..ae41d75ab0c --- /dev/null +++ b/spec/lib/gitlab/chat_commands/presenters/access_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe Gitlab::ChatCommands::Presenters::Access do + describe '#access_denied' do + subject { described_class.new.access_denied } + + it { is_expected.to be_a(Hash) } + + it 'displays an error message' do + expect(subject[:text]).to match("is not allowed") + expect(subject[:response_type]).to be(:ephemeral) + end + end + + describe '#not_found' do + subject { described_class.new.not_found } + + it { is_expected.to be_a(Hash) } + + it 'tells the user the resource was not found' do + expect(subject[:text]).to match("not found!") + expect(subject[:response_type]).to be(:ephemeral) + end + end + + describe '#authorize' do + context 'with an authorization URL' do + subject { described_class.new('http://authorize.me').authorize } + + it { is_expected.to be_a(Hash) } + + it 'tells the user to authorize' do + expect(subject[:text]).to match("connect your GitLab account") + expect(subject[:response_type]).to be(:ephemeral) + end + end + + context 'without authorization url' do + subject { described_class.new.authorize } + + it { is_expected.to be_a(Hash) } + + it 'tells the user to authorize' do + expect(subject[:text]).to match("Couldn't identify you") + expect(subject[:response_type]).to be(:ephemeral) + end + end + end +end diff --git a/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb new file mode 100644 index 00000000000..dc2dd300072 --- /dev/null +++ b/spec/lib/gitlab/chat_commands/presenters/deploy_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe Gitlab::ChatCommands::Presenters::Deploy do + let(:build) { create(:ci_build) } + + describe '#present' do + subject { described_class.new(build).present('staging', 'prod') } + + it { is_expected.to have_key(:text) } + it { is_expected.to have_key(:response_type) } + it { is_expected.to have_key(:status) } + it { is_expected.not_to have_key(:attachments) } + + it 'messages the channel of the deploy' do + expect(subject[:response_type]).to be(:in_channel) + expect(subject[:text]).to start_with("Deployment started from staging to prod") + end + end + + describe '#no_actions' do + subject { described_class.new(nil).no_actions } + + it { is_expected.to have_key(:text) } + it { is_expected.to have_key(:response_type) } + it { is_expected.to have_key(:status) } + it { is_expected.not_to have_key(:attachments) } + + it 'tells the user there is no action' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to eq("No action found to be executed") + end + end + + describe '#too_many_actions' do + subject { described_class.new([]).too_many_actions } + + it { is_expected.to have_key(:text) } + it { is_expected.to have_key(:response_type) } + it { is_expected.to have_key(:status) } + it { is_expected.not_to have_key(:attachments) } + + it 'tells the user there is no action' do + expect(subject[:response_type]).to be(:ephemeral) + expect(subject[:text]).to eq("Too many actions defined") + end + end +end diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb new file mode 100644 index 00000000000..17fcdbc2452 --- /dev/null +++ b/spec/lib/gitlab/chat_commands/presenters/issue_new_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Gitlab::ChatCommands::Presenters::IssueNew do + let(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + let(:attachment) { subject[:attachments].first } + + subject { described_class.new(issue).present } + + it { is_expected.to be_a(Hash) } + + it 'shows the issue' do + expect(subject[:response_type]).to be(:in_channel) + expect(subject).to have_key(:attachments) + expect(attachment[:title]).to start_with(issue.title) + end +end diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb new file mode 100644 index 00000000000..ec6d3e34a96 --- /dev/null +++ b/spec/lib/gitlab/chat_commands/presenters/issue_search_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Gitlab::ChatCommands::Presenters::IssueSearch do + let(:project) { create(:empty_project) } + let(:message) { subject[:text] } + + before { create_list(:issue, 2, project: project) } + + subject { described_class.new(project.issues).present } + + it 'formats the message correct' do + is_expected.to have_key(:text) + is_expected.to have_key(:status) + is_expected.to have_key(:response_type) + is_expected.to have_key(:attachments) + end + + it 'shows a list of results' do + expect(subject[:response_type]).to be(:ephemeral) + + expect(message).to start_with("Here are the 2 issues I found") + end +end diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb new file mode 100644 index 00000000000..5b678d31fce --- /dev/null +++ b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Gitlab::ChatCommands::Presenters::IssueShow do + let(:project) { create(:empty_project) } + let(:issue) { create(:issue, project: project) } + let(:attachment) { subject[:attachments].first } + + subject { described_class.new(issue).present } + + it { is_expected.to be_a(Hash) } + + it 'shows the issue' do + expect(subject[:response_type]).to be(:in_channel) + expect(subject).to have_key(:attachments) + expect(attachment[:title]).to start_with(issue.title) + end + + context 'with upvotes' do + before do + create(:award_emoji, :upvote, awardable: issue) + end + + it 'shows the upvote count' do + expect(subject[:response_type]).to be(:in_channel) + expect(attachment[:text]).to start_with("**Open** · :+1: 1") + end + end + + context 'confidential issue' do + let(:issue) { create(:issue, project: project) } + + it 'shows an ephemeral response' do + expect(subject[:response_type]).to be(:in_channel) + expect(attachment[:text]).to start_with("**Open**") + end + end +end diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb index b3c07347de1..8ad9b7cdf07 100644 --- a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb @@ -62,7 +62,7 @@ describe Gitlab::Ci::Status::Build::Cancelable do end describe '#action_icon' do - it { expect(subject.action_icon).to eq 'ban' } + it { expect(subject.action_icon).to eq 'icon_action_cancel' } end describe '#action_title' do diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb index f1b50a59ce6..f3e72ea1796 100644 --- a/spec/lib/gitlab/ci/status/build/play_spec.rb +++ b/spec/lib/gitlab/ci/status/build/play_spec.rb @@ -44,7 +44,7 @@ describe Gitlab::Ci::Status::Build::Play do end describe '#action_icon' do - it { expect(subject.action_icon).to eq 'play' } + it { expect(subject.action_icon).to eq 'icon_action_play' } end describe '#action_title' do diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb index 62036f8ec5d..2db0f8d29bd 100644 --- a/spec/lib/gitlab/ci/status/build/retryable_spec.rb +++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb @@ -62,7 +62,7 @@ describe Gitlab::Ci::Status::Build::Retryable do end describe '#action_icon' do - it { expect(subject.action_icon).to eq 'refresh' } + it { expect(subject.action_icon).to eq 'icon_action_retry' } end describe '#action_title' do diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb index 597e02e86e4..41c2b624774 100644 --- a/spec/lib/gitlab/ci/status/build/stop_spec.rb +++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb @@ -46,7 +46,7 @@ describe Gitlab::Ci::Status::Build::Stop do end describe '#action_icon' do - it { expect(subject.action_icon).to eq 'stop' } + it { expect(subject.action_icon).to eq 'icon_action_stop' } end describe '#action_title' do diff --git a/spec/lib/gitlab/ci/trace_reader_spec.rb b/spec/lib/gitlab/ci/trace_reader_spec.rb index f06d78694d6..ff5551bf703 100644 --- a/spec/lib/gitlab/ci/trace_reader_spec.rb +++ b/spec/lib/gitlab/ci/trace_reader_spec.rb @@ -11,13 +11,25 @@ describe Gitlab::Ci::TraceReader do last_lines = random_lines expected = lines.last(last_lines).join + result = subject.read(last_lines: last_lines) - expect(subject.read(last_lines: last_lines)).to eq(expected) + expect(result).to eq(expected) + expect(result.encoding).to eq(Encoding.default_external) end end it 'returns everything if trying to get too many lines' do - expect(build_subject.read(last_lines: lines.size * 2)).to eq(lines.join) + result = build_subject.read(last_lines: lines.size * 2) + + expect(result).to eq(lines.join) + expect(result.encoding).to eq(Encoding.default_external) + end + + it 'returns all contents if last_lines is not specified' do + result = build_subject.read + + expect(result).to eq(lines.join) + expect(result.encoding).to eq(Encoding.default_external) end it 'raises an error if not passing an integer for last_lines' do diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index 0b7984d6ca9..f2cb028206f 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -92,5 +92,29 @@ describe Gitlab::ImportExport::MembersMapper, services: true do expect(members_mapper.map[exported_user_id]).to eq(user2.id) end end + + context 'importer same as group member' do + let(:user2) { create(:admin, authorized_projects_populated: true) } + let(:group) { create(:group) } + let(:project) { create(:empty_project, :public, name: 'searchable_project', namespace: group) } + let(:members_mapper) do + described_class.new( + exported_members: exported_members, user: user2, project: project) + end + + before do + group.add_users([user, user2], GroupMember::DEVELOPER) + end + + it 'maps the project member' do + expect(members_mapper.map[exported_user_id]).to eq(user2.id) + end + + it 'maps the project member if it already exists' do + project.add_master(user2) + + expect(members_mapper.map[exported_user_id]).to eq(user2.id) + end + end end end diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 2c0750c3377..2e9f60432b4 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -6981,11 +6981,16 @@ ] } ], - "variables": [ - - ], "triggers": [ - + { + "id": 123, + "token": "cdbfasdf44a5958c83654733449e585", + "project_id": null, + "deleted_at": null, + "created_at": "2017-01-16T15:25:28.637Z", + "updated_at": "2017-01-16T15:25:28.637Z", + "gl_project_id": 123 + } ], "deploy_keys": [ diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index 4b07fa53bf5..40d7d59f03b 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -197,6 +197,20 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do expect(restored_project_json).to be true end end + + context 'tokens are regenerated' do + before do + restored_project_json + end + + it 'has a new CI trigger token' do + expect(Ci::Trigger.where(token: 'cdbfasdf44a5958c83654733449e585')).to be_empty + end + + it 'has a new CI build token' do + expect(Ci::Build.where(token: 'abcd')).to be_empty + end + end end end end diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index db0084d6823..57e412b0cef 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -55,8 +55,8 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do expect(created_object.project_id).to eq(project.id) end - it 'has a token' do - expect(created_object.token).to eq(token) + it 'has a nil token' do + expect(created_object.token).to eq(nil) end context 'original service exists' do @@ -178,4 +178,15 @@ describe Gitlab::ImportExport::RelationFactory, lib: true do expect(created_object.author).to eq(new_user) end end + + context 'encrypted attributes' do + let(:relation_sym) { 'Ci::Variable' } + let(:relation_hash) do + create(:ci_variable).as_json + end + + it 'has no value for the encrypted attribute' do + expect(created_object.value).to be_nil + end + end end diff --git a/spec/lib/gitlab/view/presenter/delegated_spec.rb b/spec/lib/gitlab/view/presenter/delegated_spec.rb index 888ab80cad5..e9d4af54389 100644 --- a/spec/lib/gitlab/view/presenter/delegated_spec.rb +++ b/spec/lib/gitlab/view/presenter/delegated_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::View::Presenter::Delegated do - let(:project) { double(:project, bar: 'baz') } + let(:project) { double(:project, user: 'John Doe') } let(:presenter_class) do Class.new(described_class) end @@ -12,10 +12,14 @@ describe Gitlab::View::Presenter::Delegated do describe '#initialize' do it 'takes arbitrary key/values and exposes them' do - presenter = presenter_class.new(project, user: 'user', foo: 'bar') + presenter = presenter_class.new(project, current_user: 'Jane Doe') - expect(presenter.user).to eq('user') - expect(presenter.foo).to eq('bar') + expect(presenter.current_user).to eq('Jane Doe') + end + + it 'raise an error if the presentee already respond to method' do + expect { presenter_class.new(project, user: 'Jane Doe') }. + to raise_error Gitlab::View::Presenter::CannotOverrideMethodError end end @@ -23,7 +27,7 @@ describe Gitlab::View::Presenter::Delegated do it 'forwards missing methods to subject' do presenter = presenter_class.new(project) - expect(presenter.bar).to eq('baz') + expect(presenter.user).to eq('John Doe') end end end diff --git a/spec/lib/gitlab/view/presenter/factory_spec.rb b/spec/lib/gitlab/view/presenter/factory_spec.rb index 55c5ecbf92f..70d2e22b48f 100644 --- a/spec/lib/gitlab/view/presenter/factory_spec.rb +++ b/spec/lib/gitlab/view/presenter/factory_spec.rb @@ -22,13 +22,6 @@ describe Gitlab::View::Presenter::Factory do end describe '#fabricate!' do - it 'exposes given params' do - presenter = described_class.new(build, user: 'user', foo: 'bar').fabricate! - - expect(presenter.user).to eq('user') - expect(presenter.foo).to eq('bar') - end - it 'detects the presenter based on the given subject' do presenter = described_class.new(build).fabricate! diff --git a/spec/lib/gitlab/view/presenter/simple_spec.rb b/spec/lib/gitlab/view/presenter/simple_spec.rb index b489bdf1981..1795ed2405b 100644 --- a/spec/lib/gitlab/view/presenter/simple_spec.rb +++ b/spec/lib/gitlab/view/presenter/simple_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::View::Presenter::Simple do - let(:project) { double(:project) } + let(:project) { double(:project, user: 'John Doe') } let(:presenter_class) do Class.new(described_class) end @@ -12,10 +12,15 @@ describe Gitlab::View::Presenter::Simple do describe '#initialize' do it 'takes arbitrary key/values and exposes them' do - presenter = presenter_class.new(project, user: 'user', foo: 'bar') + presenter = presenter_class.new(project, current_user: 'Jane Doe') - expect(presenter.user).to eq('user') - expect(presenter.foo).to eq('bar') + expect(presenter.current_user).to eq('Jane Doe') + end + + it 'override the presentee attributes' do + presenter = presenter_class.new(project, user: 'Jane Doe') + + expect(presenter.user).to eq('Jane Doe') end end @@ -23,7 +28,7 @@ describe Gitlab::View::Presenter::Simple do it 'does not forward missing methods to subject' do presenter = presenter_class.new(project) - expect { presenter.foo }.to raise_error(NoMethodError) + expect { presenter.user }.to raise_error(NoMethodError) end end end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index 4d57efd3c53..2f4a33a1868 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Ability, lib: true do describe '.can_edit_note?' do let(:project) { create(:empty_project) } - let!(:note) { create(:note_on_issue, project: project) } + let(:note) { create(:note_on_issue, project: project) } context 'using an anonymous user' do it 'returns false' do @@ -60,7 +60,7 @@ describe Ability, lib: true do describe '.users_that_can_read_project' do context 'using a public project' do it 'returns all the users' do - project = create(:project, :public) + project = create(:empty_project, :public) user = build(:user) expect(described_class.users_that_can_read_project([user], project)). @@ -69,7 +69,7 @@ describe Ability, lib: true do end context 'using an internal project' do - let(:project) { create(:project, :internal) } + let(:project) { create(:empty_project, :internal) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -120,7 +120,7 @@ describe Ability, lib: true do end context 'using a private project' do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -247,7 +247,7 @@ describe Ability, lib: true do end describe '.project_disabled_features_rules' do - let(:project) { create(:project, wiki_access_level: ProjectFeature::DISABLED) } + let(:project) { create(:empty_project, wiki_access_level: ProjectFeature::DISABLED) } subject { described_class.allowed(project.owner, project) } diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index f031876e812..47cd5075a7d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::Build, :models do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:test_trace) { 'This is a test' } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 2bdd611aeed..426be74cd02 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -284,7 +284,7 @@ describe Ci::Pipeline, models: true do end describe 'merge request metrics' do - let(:project) { FactoryGirl.create :project } + let(:project) { create(:project, :repository) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } let!(:merge_request) { create(:merge_request, source_project: project, source_branch: pipeline.ref) } @@ -339,7 +339,7 @@ describe Ci::Pipeline, models: true do end context 'with non-empty project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, @@ -890,7 +890,7 @@ describe Ci::Pipeline, models: true do end describe "#merge_requests" do - let(:project) { FactoryGirl.create :project } + let(:project) { create(:project, :repository) } let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) } it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do @@ -956,7 +956,7 @@ describe Ci::Pipeline, models: true do end describe 'notifications when pipeline success or failed' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 2b856ca7af7..3f32248e52b 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -91,8 +91,7 @@ describe Ci::Runner, models: true do end describe '#can_pick?' do - let(:project) { create(:project) } - let(:pipeline) { create(:ci_pipeline, project: project) } + let(:pipeline) { create(:ci_pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) } let(:runner) { create(:ci_runner) } @@ -321,8 +320,8 @@ describe Ci::Runner, models: true do describe '.assignable_for' do let(:runner) { create(:ci_runner) } - let(:project) { create(:project) } - let(:another_project) { create(:project) } + let(:project) { create(:empty_project) } + let(:another_project) { create(:empty_project) } before do project.runners << runner diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb index 30782ca75a0..e4bddf67096 100644 --- a/spec/models/commit_range_spec.rb +++ b/spec/models/commit_range_spec.rb @@ -7,7 +7,7 @@ describe CommitRange, models: true do it { is_expected.to include_module(Referable) } end - let!(:project) { create(:project, :public) } + let!(:project) { create(:project, :public, :repository) } let!(:commit1) { project.commit("HEAD~2") } let!(:commit2) { project.commit } diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index b2202f0fd44..32f9366a14c 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit, models: true do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:commit) { project.commit } describe 'modules' do @@ -34,7 +34,7 @@ describe Commit, models: true do end describe '#to_reference' do - let(:project) { create(:project, path: 'sample-project') } + let(:project) { create(:project, :repository, path: 'sample-project') } let(:commit) { project.commit } it 'returns a String reference to the object' do @@ -42,13 +42,13 @@ describe Commit, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace) expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}" end end describe '#reference_link_text' do - let(:project) { create(:project, path: 'sample-project') } + let(:project) { create(:project, :repository, path: 'sample-project') } let(:commit) { project.commit } it 'returns a String reference to the object' do @@ -56,7 +56,7 @@ describe Commit, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace) expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}" end end @@ -131,7 +131,7 @@ eos describe '#closes_issues' do let(:issue) { create :issue, project: project } - let(:other_project) { create :project, :public } + let(:other_project) { create(:empty_project, :public) } let(:other_issue) { create :issue, project: other_project } let(:commiter) { create :user } @@ -154,7 +154,7 @@ eos end it_behaves_like 'a mentionable' do - subject { create(:project).commit } + subject { create(:project, :repository).commit } let(:author) { create(:user, email: subject.author_email) } let(:backref_text) { "commit #{subject.id}" } diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 64ea607eb95..bf4394f7d5b 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe CommitStatus, models: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, project: project, sha: project.commit.id) diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb index 49ab3c4b6e9..da003dbf794 100644 --- a/spec/models/compare_spec.rb +++ b/spec/models/compare_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Compare, models: true do include RepoHelpers - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:commit) { project.commit } let(:start_commit) { sample_image_commit } diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index d7d31892e12..545a11912e3 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -301,7 +301,7 @@ describe Issue, "Issuable" do end describe '#labels_array' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:bug) { create(:label, project: project, title: 'bug') } let(:issue) { create(:issue, project: project) } @@ -315,7 +315,7 @@ describe Issue, "Issuable" do end describe '#user_notes_count' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } @@ -359,7 +359,7 @@ describe Issue, "Issuable" do end describe ".with_label" do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:bug) { create(:label, project: project, title: 'bug') } let(:feature) { create(:label, project: project, title: 'feature') } let(:enhancement) { create(:label, project: project, title: 'enhancement') } diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index b73028f0bc0..2092576e981 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -13,7 +13,7 @@ describe Mentionable do end describe 'references' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:mentionable) { Example.new } it 'excludes JIRA references' do @@ -83,13 +83,13 @@ describe Issue, "Mentionable" do end describe '#create_cross_references!' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:author) { build(:user) } let(:commit) { project.commit } let(:commit2) { project.commit } let!(:issue) do - create(:issue, project: project, description: commit.to_reference) + create(:issue, project: project, description: "See #{commit.to_reference}") end it 'correctly removes already-mentioned Commits' do @@ -100,7 +100,7 @@ describe Issue, "Mentionable" do end describe '#create_new_cross_references!' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:author) { create(:author) } let(:issues) { create_list(:issue, 2, project: project, author: author) } diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 0e097559b59..ad703a6c8bb 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do let(:member) { create(:user) } let(:guest) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:milestone) { create(:milestone, project: project) } let!(:issue) { create(:issue, project: project, milestone: milestone) } let!(:security_issue_1) { create(:issue, :confidential, project: project, author: author, milestone: milestone) } diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 9041690023f..6cf5877424d 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeaturesCompatibility do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:features) { %w(issues wiki builds merge_requests snippets) } # We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb index 70f985afefb..3b7cc7d9e2e 100644 --- a/spec/models/cycle_analytics/code_spec.rb +++ b/spec/models/cycle_analytics/code_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#code', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb index e4b6a8f4518..5c73edbbc53 100644 --- a/spec/models/cycle_analytics/issue_spec.rb +++ b/spec/models/cycle_analytics/issue_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#issue', models: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb index dc5b04852d6..55483fc876a 100644 --- a/spec/models/cycle_analytics/plan_spec.rb +++ b/spec/models/cycle_analytics/plan_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#plan', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index 3c59c624326..35222e031a0 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#production', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb index 45baa5f7006..33d2c0a7416 100644 --- a/spec/models/cycle_analytics/review_spec.rb +++ b/spec/models/cycle_analytics/review_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#review', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index 25c7b19b087..7688985c6a3 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -3,9 +3,10 @@ require 'spec_helper' describe 'CycleAnalytics#staging', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } + subject { CycleAnalytics.new(project, from: from_date) } generate_cycle_analytics_spec( diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb index 27a117d2d76..f857ea6cbec 100644 --- a/spec/models/cycle_analytics/test_spec.rb +++ b/spec/models/cycle_analytics/test_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'CycleAnalytics#test', feature: true do extend CycleAnalyticsHelpers::TestGeneration - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } subject { CycleAnalytics.new(project, from: from_date) } diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb index 8a1e337c1a3..aacc178a19e 100644 --- a/spec/models/deploy_keys_project_spec.rb +++ b/spec/models/deploy_keys_project_spec.rb @@ -12,7 +12,7 @@ describe DeployKeysProject, models: true do end describe "Destroying" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:deploy_keys_project, project: project) } let(:deploy_key) { subject.deploy_key } @@ -39,7 +39,7 @@ describe DeployKeysProject, models: true do end context "when the deploy key is used by more than one project" do - let!(:other_project) { create(:project) } + let!(:other_project) { create(:empty_project) } before do other_project.deploy_keys << deploy_key diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index ca594a320c0..fc4435a2f64 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -17,7 +17,7 @@ describe Deployment, models: true do it { is_expected.to validate_presence_of(:sha) } describe '#includes_commit?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } let(:deployment) do create(:deployment, environment: environment, sha: project.commit.id) diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 3db5937a4f3..9ea3a4b7020 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe DiffNote, models: true do include RepoHelpers - let(:project) { create(:project) } - let(:merge_request) { create(:merge_request, source_project: project) } + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } let(:commit) { project.commit(sample_commit.id) } let(:path) { "files/ruby/popen.rb" } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 96efe1696c3..eba392044bf 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -32,7 +32,7 @@ describe Environment, models: true do end describe '#includes_commit?' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } context 'without a last deployment' do it "returns false" do @@ -81,7 +81,7 @@ describe Environment, models: true do end describe '#first_deployment_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let(:head_commit) { project.commit } @@ -288,6 +288,11 @@ describe Environment, models: true do "1-foo" => "env-1-foo" + SUFFIX, "1/foo" => "env-1-foo" + SUFFIX, "foo-" => "foo" + SUFFIX, + "foo--bar" => "foo-bar" + SUFFIX, + "foo**bar" => "foo-bar" + SUFFIX, + "*-foo" => "env-foo" + SUFFIX, + "staging-12345678-" => "staging-12345678" + SUFFIX, + "staging-12345678-01234567" => "staging-12345678" + SUFFIX, }.each do |name, matcher| it "returns a slug matching #{matcher}, given #{name}" do slug = described_class.new(name: name).generate_slug diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index f8660da031d..349474bb656 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -27,7 +27,7 @@ describe Event, models: true do end describe "Push event" do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } let(:user) { project.owner } let(:event) { create_event(project, user) } @@ -187,7 +187,7 @@ describe Event, models: true do end context 'merge request diff note event' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) } let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) } let(:target) { note_on_merge_request } @@ -202,7 +202,7 @@ describe Event, models: true do end context 'private project' do - let(:project) { create(:project, :private) } + let(:project) { create(:empty_project, :private) } it do expect(event.visible_to_user?(non_member)).to eq false diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 1863581f57b..454550c9710 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ForkedProjectLink, "add link on fork" do - let(:project_from) { create(:project) } + let(:project_from) { create(:project, :repository) } let(:namespace) { create(:namespace) } let(:user) { create(:user, namespace: namespace) } @@ -21,7 +21,7 @@ end describe '#forked?' do let(:forked_project_link) { build(:forked_project_link) } - let(:project_from) { create(:project) } + let(:project_from) { create(:project, :repository) } let(:project_to) { create(:project, forked_project_link: forked_project_link) } before :each do diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index d87684fd49e..cacbab8bcb1 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -4,9 +4,9 @@ describe GlobalMilestone, models: true do let(:user) { create(:user) } let(:user2) { create(:user) } let(:group) { create(:group) } - let(:project1) { create(:project, group: group) } - let(:project2) { create(:project, path: 'gitlab-ci', group: group) } - let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } + let(:project1) { create(:empty_project, group: group) } + let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) } + let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) } describe '.build_collection' do let(:milestone1_due_date) { 2.weeks.from_now.to_date } diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index 601167c3bd3..916afb7aaf5 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GroupMilestone, models: true do let(:group) { create(:group) } - let(:project) { create(:project, group: group) } + let(:project) { create(:empty_project, group: group) } let(:project_milestone) do create(:milestone, title: "Milestone v1.2", project: project) end diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index d79f929f7a1..582b54c0712 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Guest, lib: true do - let(:public_project) { create(:project, :public) } - let(:private_project) { create(:project, :private) } - let(:internal_project) { create(:project, :internal) } + let(:public_project) { build_stubbed(:empty_project, :public) } + let(:private_project) { build_stubbed(:empty_project, :private) } + let(:internal_project) { build_stubbed(:empty_project, :internal) } describe '.can_pull?' do context 'when project is private' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index ad2b710041a..e8caad00c44 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -4,7 +4,7 @@ describe SystemHook, models: true do describe "execute" do let(:system_hook) { create(:system_hook) } let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:empty_project, namespace: user.namespace) } let(:group) { create(:group) } before do diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index e52b9d75cef..9d4db1bfb52 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -25,7 +25,7 @@ describe WebHook, models: true do end describe "execute" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:project_hook) { create(:project_hook) } before(:each) do diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb index 2459a49f095..08712f2a768 100644 --- a/spec/models/issue/metrics_spec.rb +++ b/spec/models/issue/metrics_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Issue::Metrics, models: true do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } subject { create(:issue, project: project) } diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index d742c814680..d8aed25c041 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe IssueCollection do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } let(:collection) { described_class.new([issue1, issue2]) } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 61d72925736..bba9058f394 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -23,21 +23,74 @@ describe Issue, models: true do end describe '#to_reference' do - let(:project) { build(:empty_project, name: 'sample-project') } - let(:issue) { build(:issue, iid: 1, project: project) } + let(:namespace) { build(:namespace, path: 'sample-namespace') } + let(:project) { build(:empty_project, name: 'sample-project', namespace: namespace) } + let(:issue) { build(:issue, iid: 1, project: project) } + let(:group) { create(:group, name: 'Group', path: 'sample-group') } + + context 'when nil argument' do + it 'returns issue id' do + expect(issue.to_reference).to eq "#1" + end + end - it 'returns a String reference to the object' do - expect(issue.to_reference).to eq "#1" + context 'when full is true' do + it 'returns complete path to the issue' do + expect(issue.to_reference(full: true)).to eq 'sample-namespace/sample-project#1' + expect(issue.to_reference(project, full: true)).to eq 'sample-namespace/sample-project#1' + expect(issue.to_reference(group, full: true)).to eq 'sample-namespace/sample-project#1' + end end - it 'returns a String reference with the full path' do - expect(issue.to_reference(full: true)).to eq(project.path_with_namespace + '#1') + context 'when same project argument' do + it 'returns issue id' do + expect(issue.to_reference(project)).to eq("#1") + end + end + + context 'when cross namespace project argument' do + let(:another_namespace_project) { create(:empty_project, name: 'another-project') } + + it 'returns complete path to the issue' do + expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1' + end end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(issue.to_reference(another_project)).to eq "sample-project#1" end + + context 'when same namespace / cross-project argument' do + let(:another_project) { create(:empty_project, namespace: namespace) } + + it 'returns path to the issue with the project name' do + expect(issue.to_reference(another_project)).to eq 'sample-project#1' + end + end + + context 'when different namespace / cross-project argument' do + let(:another_namespace) { create(:namespace, path: 'another-namespace') } + let(:another_project) { create(:empty_project, path: 'another-project', namespace: another_namespace) } + + it 'returns full path to the issue' do + expect(issue.to_reference(another_project)).to eq 'sample-namespace/sample-project#1' + end + end + + context 'when argument is a namespace' do + context 'with same project path' do + it 'returns path to the issue with the project name' do + expect(issue.to_reference(namespace)).to eq 'sample-project#1' + end + end + + context 'with different project path' do + it 'returns full path to the issue' do + expect(issue.to_reference(group)).to eq 'sample-namespace/sample-project#1' + end + end + end end describe '#is_being_reassigned?' do @@ -60,9 +113,9 @@ describe Issue, models: true do end describe '#closed_by_merge_requests' do - let(:project) { create(:project) } - let(:issue) { create(:issue, project: project, state: "opened")} - let(:closed_issue) { build(:issue, project: project, state: "closed")} + let(:project) { create(:project, :repository) } + let(:issue) { create(:issue, project: project)} + let(:closed_issue) { build(:issue, :closed, project: project)} let(:mr) do opts = { @@ -104,7 +157,7 @@ describe Issue, models: true do describe '#referenced_merge_requests' do it 'returns the referenced merge requests' do - project = create(:project, :public) + project = create(:empty_project, :public) mr1 = create(:merge_request, source_project: project, @@ -137,7 +190,7 @@ describe Issue, models: true do end context 'user is reporter in project issue belongs to' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:issue) { create(:issue, project: project) } before { project.team << [user, :reporter] } @@ -151,7 +204,7 @@ describe Issue, models: true do context 'checking destination project also' do subject { issue.can_move?(user, to_project) } - let(:to_project) { create(:project) } + let(:to_project) { create(:empty_project) } context 'destination project allowed' do before { to_project.team << [user, :reporter] } @@ -246,7 +299,7 @@ describe Issue, models: true do describe '#participants' do context 'using a public project' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:issue) { create(:issue, project: project) } let!(:note1) do @@ -268,7 +321,7 @@ describe Issue, models: true do context 'using a private project' do it 'does not include mentioned users that do not have access to the project' do - project = create(:project) + project = create(:empty_project) user = create(:user) issue = create(:issue, project: project) diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 4f7c8a36cb5..16e2144d6a1 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -481,7 +481,7 @@ describe Member, models: true do describe "destroying a record", truncate: true do it "refreshes user's authorized projects" do - project = create(:project, :private) + project = create(:empty_project, :private) user = create(:user) member = project.team << [user, :reporter] diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 68f72f5c86e..90d14c2c0b9 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -83,8 +83,8 @@ describe ProjectMember, models: true do describe '.import_team' do before do - @project_1 = create :project - @project_2 = create :project + @project_1 = create(:empty_project) + @project_2 = create(:empty_project) @user_1 = create :user @user_2 = create :user @@ -131,8 +131,8 @@ describe ProjectMember, models: true do describe '.truncate_teams' do before do - @project_1 = create :project - @project_2 = create :project + @project_1 = create(:empty_project) + @project_2 = create(:empty_project) @user_1 = create :user @user_2 = create :user diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb index 255db41cb19..9afed311e27 100644 --- a/spec/models/merge_request/metrics_spec.rb +++ b/spec/models/merge_request/metrics_spec.rb @@ -1,9 +1,7 @@ require 'spec_helper' describe MergeRequest::Metrics, models: true do - let(:project) { create(:project) } - - subject { create(:merge_request, source_project: project) } + subject { create(:merge_request) } describe "when recording the default set of metrics on merge request save" do it "records the merge time" do diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 064f29d2d66..3cee2b7714f 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -24,7 +24,7 @@ describe Milestone, models: true do it { is_expected.to have_many(:issues) } end - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:milestone) { create(:milestone, project: project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } @@ -44,7 +44,7 @@ describe Milestone, models: true do end it "accepts the same title in another project" do - project = build(:project) + project = build(:empty_project) new_milestone = Milestone.new(project: project, title: milestone.title) expect(new_milestone).to be_valid @@ -257,7 +257,7 @@ describe Milestone, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(milestone.to_reference(another_project)).to eq "sample-project%1" end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 8d613a88ca0..4e96f19eb6f 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -107,7 +107,7 @@ describe Namespace, models: true do describe '#move_dir' do before do @namespace = create :namespace - @project = create :project, namespace: @namespace + @project = create(:empty_project, namespace: @namespace) allow(@namespace).to receive(:path_changed?).and_return(true) end @@ -139,7 +139,7 @@ describe Namespace, models: true do end describe :rm_dir do - let!(:project) { create(:project, namespace: namespace) } + let!(:project) { create(:empty_project, namespace: namespace) } let!(:path) { File.join(Gitlab.config.repositories.storages.default, namespace.path) } it "removes its dirs when deleted" do diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb index b76513d2a3c..492c4e01bd8 100644 --- a/spec/models/network/graph_spec.rb +++ b/spec/models/network/graph_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Network::Graph, models: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:note_on_commit) { create(:note_on_commit, project: project) } it '#initialize' do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 6f9ae655fed..1cde9e04951 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -42,7 +42,7 @@ describe Note, models: true do context 'when noteable and note project differ' do subject do build(:note, noteable: build_stubbed(:issue), - project: build_stubbed(:project)) + project: build_stubbed(:empty_project)) end it { is_expected.to be_invalid } @@ -93,8 +93,8 @@ describe Note, models: true do describe 'authorization' do before do - @p1 = create(:project) - @p2 = create(:project) + @p1 = create(:empty_project) + @p2 = create(:empty_project) @u1 = create(:user) @u2 = create(:user) @u3 = create(:user) @@ -191,10 +191,10 @@ describe Note, models: true do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:project, namespace: private_user.namespace).tap { |p| p.team << [private_user, :master] } } + let(:private_project) { create(:empty_project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } let(:private_issue) { create(:issue, project: private_project) } - let(:ext_proj) { create(:project, :public) } + let(:ext_proj) { create(:empty_project, :public) } let(:ext_issue) { create(:issue, project: ext_proj) } let(:note) do @@ -237,7 +237,7 @@ describe Note, models: true do describe '#participants' do it 'includes the note author' do - project = create(:project, :public) + project = create(:empty_project, :public) issue = create(:issue, project: project) note = create(:note_on_issue, noteable: issue, project: project) diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index a55d43ab2f9..8589f1eb712 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeature do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:user) { create(:user) } describe '#feature_available?' do @@ -35,7 +35,7 @@ describe ProjectFeature do it "returns true when user is a member of project group" do group = create(:group) - project = create(:project, namespace: group) + project = create(:empty_project, namespace: group) group.add_developer(user) features.each do |feature| diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 47397a822c1..59a4ae1b799 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -17,7 +17,7 @@ describe ProjectGroupLink do describe "destroying a record", truncate: true do it "refreshes group users' authorized projects" do - project = create(:project, :private) + project = create(:empty_project, :private) group = create(:group) reporter = create(:user) group_users = group.users diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb index 4d538cac007..9cdbfa44e5b 100644 --- a/spec/models/project_label_spec.rb +++ b/spec/models/project_label_spec.rb @@ -100,7 +100,7 @@ describe ProjectLabel, models: true do end context 'cross project reference' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'using name' do it 'returns cross reference with label name' do diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 8e5145e824b..48aef3a93f2 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -18,7 +18,7 @@ describe AsanaService, models: true do describe 'Execute' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } def create_data_for_commits(*messages) { diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index 4c5acb7990b..96f00af898e 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -8,7 +8,7 @@ describe AssemblaService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @assembla_service = AssemblaService.new diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index a3b9d084a75..953e664fb66 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -22,7 +22,7 @@ describe CampfireService, models: true do describe "#execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @campfire_service = CampfireService.new diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 42c2ed668bc..f9307d6de7b 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -27,7 +27,7 @@ describe DroneCiService, models: true, caching: true do shared_context :drone_ci_service do let(:drone) { DroneCiService.new } - let(:project) { create(:project, name: 'project') } + let(:project) { create(:project, :repository, name: 'project') } let(:path) { "#{project.namespace.path}/#{project.path}" } let(:drone_url) { 'http://drone.example.com' } let(:sha) { '2ab7834c' } diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index 342d86aeca9..bdeea1db1e3 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -23,7 +23,7 @@ describe ExternalWikiService, models: true do end describe 'External wiki' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when it is active' do before do diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index d6db02d6e76..a97e8c6e4ce 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -22,7 +22,7 @@ describe FlowdockService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @flowdock_service = FlowdockService.new diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index 529044d1d8b..a13fbae03eb 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -24,7 +24,7 @@ describe GemnasiumService, models: true do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do @gemnasium_service = GemnasiumService.new diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index 9b80f0e7296..dcb70ee28a8 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -8,21 +8,21 @@ describe GitlabIssueTrackerService, models: true do describe 'Validations' do context 'when service is active' do - subject { described_class.new(project: create(:project), active: true) } + subject { described_class.new(project: create(:empty_project), active: true) } it { is_expected.to validate_presence_of(:issues_url) } it_behaves_like 'issue tracker service URL attribute', :issues_url end context 'when service is inactive' do - subject { described_class.new(project: create(:project), active: false) } + subject { described_class.new(project: create(:empty_project), active: false) } it { is_expected.not_to validate_presence_of(:issues_url) } end end describe 'project and issue urls' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'with absolute urls' do before do diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 2da3a9cb09f..bf422ac7ce1 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -22,8 +22,8 @@ describe HipchatService, models: true do describe "Execute" do let(:hipchat) { HipchatService.new } - let(:user) { create(:user, username: 'username') } - let(:project) { create(:project, name: 'project') } + let(:user) { create(:user) } + let(:project) { create(:project, :repository) } let(:api_url) { 'https://hipchat.example.com/v2/room/123456/notification?auth_token=verySecret' } let(:project_name) { project.name_with_namespace.gsub(/\s/, '') } let(:token) { 'verySecret' } @@ -165,7 +165,7 @@ describe HipchatService, models: true do context "Note events" do let(:user) { create(:user) } - let(:project) { create(:project, creator_id: user.id) } + let(:project) { create(:project, :repository, creator: user) } context 'when commit comment event triggered' do let(:commit_note) do diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index f8c45b37561..b9fb6f3f6f4 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -25,7 +25,7 @@ describe IrkerService, models: true do describe 'Execute' do let(:irker) { IrkerService.new } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:sample_data) do Gitlab::DataBuilder::Push.build_sample(project, user) end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 862e3a72a73..2f6b159d76e 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -71,7 +71,7 @@ describe JiraService, models: true do describe '#close_issue' do let(:custom_base_url) { 'http://custom_url' } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:merge_request) { create(:merge_request) } before do @@ -207,12 +207,12 @@ describe JiraService, models: true do end describe "Stored password invalidation" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context "when a password was previously set" do before do @jira_service = JiraService.create!( - project: create(:project), + project: project, properties: { url: 'http://jira.example.com/rest/api/2', username: 'mic', @@ -252,7 +252,7 @@ describe JiraService, models: true do context "when no password was previously set" do before do @jira_service = JiraService.create( - project: create(:project), + project: project, properties: { url: 'http://jira.example.com/rest/api/2', username: 'mic' @@ -281,7 +281,7 @@ describe JiraService, models: true do end describe 'description and title' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when it is not set' do before do @@ -316,7 +316,7 @@ describe JiraService, models: true do end describe 'project and issue urls' do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } context 'when gitlab.yml was initialized' do before do diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index c879edddfdd..98f3d420c8a 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -113,10 +113,7 @@ describe MattermostSlashCommandsService, :models do end it 'shows error messages' do - teams, message = subject - - expect(teams).to be_empty - expect(message).to eq('Failed to get team list.') + expect(subject).to eq([[], "Failed to get team list."]) end end end diff --git a/spec/models/project_services/pipeline_email_service_spec.rb b/spec/models/project_services/pipeline_email_service_spec.rb index 7c8824485f5..03932895b0e 100644 --- a/spec/models/project_services/pipeline_email_service_spec.rb +++ b/spec/models/project_services/pipeline_email_service_spec.rb @@ -7,7 +7,7 @@ describe PipelinesEmailService do create(:ci_pipeline, project: project, sha: project.commit('master').sha) end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:recipient) { 'test@gitlab.com' } let(:data) do diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 8fc92a9ab51..a7e7594a7d5 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -27,7 +27,7 @@ describe PushoverService, models: true do describe 'Execute' do let(:pushover) { PushoverService.new } let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:sample_data) do Gitlab::DataBuilder::Push.build_sample(project, user) end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 646a1311462..48b085781e7 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -282,9 +282,10 @@ describe Project, models: true do end describe '#to_reference' do - let(:owner) { create(:user, name: 'Gitlab') } + let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) } - let(:project) { create(:empty_project, path: 'sample-project', namespace: namespace) } + let(:project) { create(:empty_project, path: 'sample-project', namespace: namespace) } + let(:group) { create(:group, name: 'Group', path: 'sample-group', owner: owner) } context 'when nil argument' do it 'returns nil' do @@ -292,6 +293,14 @@ describe Project, models: true do end end + context 'when full is true' do + it 'returns complete path to the project' do + expect(project.to_reference(full: true)).to eq 'sample-namespace/sample-project' + expect(project.to_reference(project, full: true)).to eq 'sample-namespace/sample-project' + expect(project.to_reference(group, full: true)).to eq 'sample-namespace/sample-project' + end + end + context 'when same project argument' do it 'returns nil' do expect(project.to_reference(project)).to be_nil @@ -309,10 +318,33 @@ describe Project, models: true do context 'when same namespace / cross-project argument' do let(:another_project) { create(:empty_project, namespace: namespace) } - it 'returns complete path to the project' do + it 'returns path to the project' do expect(project.to_reference(another_project)).to eq 'sample-project' end end + + context 'when different namespace / cross-project argument' do + let(:another_namespace) { create(:namespace, path: 'another-namespace', owner: owner) } + let(:another_project) { create(:empty_project, path: 'another-project', namespace: another_namespace) } + + it 'returns full path to the project' do + expect(project.to_reference(another_project)).to eq 'sample-namespace/sample-project' + end + end + + context 'when argument is a namespace' do + context 'with same project path' do + it 'returns path to the project' do + expect(project.to_reference(namespace)).to eq 'sample-project' + end + end + + context 'with different project path' do + it 'returns full path to the project' do + expect(project.to_reference(group)).to eq 'sample-namespace/sample-project' + end + end + end end describe '#to_human_reference' do @@ -1801,6 +1833,14 @@ describe Project, models: true do end end + describe 'inside_path' do + let!(:project1) { create(:empty_project) } + let!(:project2) { create(:empty_project) } + let!(:path) { project1.namespace.path } + + it { expect(Project.inside_path(path)).to eq([project1]) } + end + def enable_lfs allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 0475cecaa2d..942eeab251d 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -265,10 +265,10 @@ describe ProjectTeam, models: true do let(:group) { create(:group) } let(:developer) { create(:user) } let(:master) { create(:user) } - let(:personal_project) { create(:project, namespace: developer.namespace) } - let(:group_project) { create(:project, namespace: group) } - let(:members_project) { create(:project) } - let(:shared_project) { create(:project) } + let(:personal_project) { create(:empty_project, namespace: developer.namespace) } + let(:group_project) { create(:empty_project, namespace: group) } + let(:members_project) { create(:empty_project) } + let(:shared_project) { create(:empty_project) } before do group.add_master(master) @@ -330,7 +330,7 @@ describe ProjectTeam, models: true do reporter = create(:user) promoted_guest = create(:user) guest = create(:user) - project = create(:project) + project = create(:empty_project) project.add_master(master) project.add_reporter(reporter) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 28100f2d0b3..901cfb907f2 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -4,7 +4,7 @@ describe Repository, models: true do include RepoHelpers TestBlob = Struct.new(:name) - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:user) { create(:user) } @@ -90,6 +90,30 @@ describe Repository, models: true do it { is_expected.to eq(['v1.1.0', 'v1.0.0']) } end + + context 'annotated tag pointing to a blob' do + let(:annotated_tag_name) { 'annotated-tag' } + + subject { repository.tags_sorted_by('updated_asc').map(&:name) } + + before do + options = { message: 'test tag message\n', + tagger: { name: 'John Smith', email: 'john@gmail.com' } } + repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options) + + double_first = double(committed_date: Time.now - 1.second) + double_last = double(committed_date: Time.now) + + allow(tag_a).to receive(:dereferenced_target).and_return(double_last) + allow(tag_b).to receive(:dereferenced_target).and_return(double_first) + end + + it { is_expected.to eq(['v1.1.0', 'v1.0.0', annotated_tag_name]) } + + after do + repository.rugged.tags.delete(annotated_tag_name) + end + end end end diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 691511cd93f..0e2f07e945f 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -12,7 +12,7 @@ describe Service, models: true do end describe "Testable" do - let(:project) { create :project } + let(:project) { create(:project, :repository) } before do allow(@service).to receive(:project).and_return(project) @@ -35,7 +35,7 @@ describe Service, models: true do end describe "With commits" do - let(:project) { create :project } + let(:project) { create(:project, :repository) } before do allow(@service).to receive(:project).and_return(project) @@ -60,7 +60,7 @@ describe Service, models: true do api_key: '123456789' }) end - let(:project) { create(:project) } + let(:project) { create(:empty_project) } describe 'is prefilled for projects pushover service' do it "has all fields prefilled" do @@ -79,7 +79,7 @@ describe Service, models: true do describe "{property}_changed?" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -119,7 +119,7 @@ describe Service, models: true do describe "{property}_touched?" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -159,7 +159,7 @@ describe Service, models: true do describe "{property}_was" do let(:service) do BambooService.create( - project: create(:project), + project: create(:empty_project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -199,7 +199,7 @@ describe Service, models: true do describe 'initialize service with no properties' do let(:service) do GitlabIssueTrackerService.create( - project: create(:project), + project: create(:empty_project), title: 'random title' ) end @@ -214,7 +214,7 @@ describe Service, models: true do end describe "callbacks" do - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let!(:service) do RedmineService.new( project: project, diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 7425a897769..219ab1989ea 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -42,7 +42,7 @@ describe Snippet, models: true do end it 'supports a cross-project reference' do - another_project = build(:project, name: 'another-project', namespace: project.namespace) + another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) expect(snippet.to_reference(another_project)).to eq "sample-project$1" end end @@ -55,7 +55,7 @@ describe Snippet, models: true do end it 'still returns shortest reference when project arg present' do - another_project = build(:project, name: 'another-project') + another_project = build(:empty_project, name: 'another-project') expect(snippet.to_reference(another_project)).to eq "$1" end end @@ -173,7 +173,7 @@ describe Snippet, models: true do end describe '#participants' do - let(:project) { create(:project, :public) } + let(:project) { create(:empty_project, :public) } let(:snippet) { create(:snippet, content: 'foo', project: project) } let!(:note1) do diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index 623b82c01d8..581305ad39f 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' describe Todo, models: true do - let(:project) { create(:project) } - let(:commit) { project.commit } let(:issue) { create(:issue) } describe 'relationships' do @@ -82,6 +80,9 @@ describe Todo, models: true do describe '#target' do context 'for commits' do + let(:project) { create(:project, :repository) } + let(:commit) { project.commit } + it 'returns an instance of Commit when exists' do subject.project = project subject.target_type = 'Commit' @@ -108,17 +109,20 @@ describe Todo, models: true do end describe '#target_reference' do - it 'returns the short commit id for commits' do + it 'returns commit full reference with short id' do + project = create(:project, :repository) + commit = project.commit + subject.project = project subject.target_type = 'Commit' subject.commit_id = commit.id - expect(subject.target_reference).to eq commit.short_id + expect(subject.target_reference).to eq commit.reference_link_text(full: true) end - it 'returns reference for issuables' do + it 'returns full reference for issuables' do subject.target = issue - expect(subject.target_reference).to eq issue.to_reference + expect(subject.target_reference).to eq issue.to_reference(full: true) end end end diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb index 0737999e125..a87983b7492 100644 --- a/spec/models/tree_spec.rb +++ b/spec/models/tree_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Tree, models: true do - let(:repository) { create(:project).repository } + let(:repository) { create(:project, :repository).repository } let(:sha) { repository.root_ref } subject { described_class.new(repository, '54fcc214') } diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 0adfc30fe58..6ca5ad747d1 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1382,14 +1382,14 @@ describe User, models: true do let!(:user) { create(:user) } let!(:group) { create(:group) } let!(:nested_group) { create(:group, parent: group) } - let!(:project) { create(:project, namespace: group) } - let!(:nested_project) { create(:project, namespace: nested_group) } + let!(:project) { create(:empty_project, namespace: group) } + let!(:nested_project) { create(:empty_project, namespace: nested_group) } before do group.add_owner(user) # Add more data to ensure method does not include wrong projects - other_project = create(:project, namespace: create(:group, :nested)) + other_project = create(:empty_project, namespace: create(:group, :nested)) other_project.add_developer(create(:user)) end diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb new file mode 100644 index 00000000000..0f280f32eac --- /dev/null +++ b/spec/policies/ci/build_policy_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +describe Ci::BuildPolicy, :models do + let(:user) { create(:user) } + let(:build) { create(:ci_build, pipeline: pipeline) } + let(:pipeline) { create(:ci_empty_pipeline, project: project) } + + let(:policies) do + described_class.abilities(user, build).to_set + end + + shared_context 'public pipelines disabled' do + before { project.update_attribute(:public_builds, false) } + end + + describe '#rules' do + context 'when user does not have access to the project' do + let(:project) { create(:empty_project, :private) } + + context 'when public builds are enabled' do + it 'does not include ability to read build' do + expect(policies).not_to include :read_build + end + end + + context 'when public builds are disabled' do + include_context 'public pipelines disabled' + + it 'does not include ability to read build' do + expect(policies).not_to include :read_build + end + end + end + + context 'when anonymous user has access to the project' do + let(:project) { create(:empty_project, :public) } + + context 'when public builds are enabled' do + it 'includes ability to read build' do + expect(policies).to include :read_build + end + end + + context 'when public builds are disabled' do + include_context 'public pipelines disabled' + + it 'does not include ability to read build' do + expect(policies).not_to include :read_build + end + end + end + + context 'when team member has access to the project' do + let(:project) { create(:empty_project, :public) } + + context 'team member is a guest' do + before { project.team << [user, :guest] } + + context 'when public builds are enabled' do + it 'includes ability to read build' do + expect(policies).to include :read_build + end + end + + context 'when public builds are disabled' do + include_context 'public pipelines disabled' + + it 'does not include ability to read build' do + expect(policies).not_to include :read_build + end + end + end + + context 'team member is a reporter' do + before { project.team << [user, :reporter] } + + context 'when public builds are enabled' do + it 'includes ability to read build' do + expect(policies).to include :read_build + end + end + + context 'when public builds are disabled' do + include_context 'public pipelines disabled' + + it 'does not include ability to read build' do + expect(policies).to include :read_build + end + end + end + end + end +end diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index 2878e0cb59b..5a3ffc284f2 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -6,7 +6,7 @@ describe API::Branches, api: true do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:project, creator_id: user.id) } + let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:guest) { create(:project_member, :guest, user: user2, project: project) } let!(:branch_name) { 'feature' } diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb index 7be7acebb19..645e36683bc 100644 --- a/spec/requests/api/builds_spec.rb +++ b/spec/requests/api/builds_spec.rb @@ -5,7 +5,7 @@ describe API::Builds, api: true do let(:user) { create(:user) } let(:api_user) { user } - let!(:project) { create(:project, creator_id: user.id, public_builds: false) } + let!(:project) { create(:project, :repository, creator: user, public_builds: false) } let!(:developer) { create(:project_member, :developer, user: user, project: project) } let(:reporter) { create(:project_member, :reporter, project: project) } let(:guest) { create(:project_member, :guest, project: project) } diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index c1c7c0882de..88361def3cf 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::CommitStatuses, api: true do include ApiHelpers - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:commit) { project.repository.commit } let(:commit_status) { create(:commit_status, pipeline: pipeline) } let(:guest) { create_user(:guest) } diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 7f8ea5251f0..af9028a8978 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -5,7 +5,7 @@ describe API::Commits, api: true do include ApiHelpers let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:guest) { create(:project_member, :guest, user: user2, project: project) } let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 685da28c673..5e26e779366 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe API::Files, api: true do include ApiHelpers let(:user) { create(:user) } - let!(:project) { create(:project, namespace: user.namespace ) } - let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } + let!(:project) { create(:project, :repository, namespace: user.namespace ) } + let(:guest) { create(:user) { |u| project.add_guest(u) } } let(:file_path) { 'files/ruby/popen.rb' } let(:params) do { diff --git a/spec/requests/api/fork_spec.rb b/spec/requests/api/fork_spec.rb index df29099bc2f..92ac4fd334d 100644 --- a/spec/requests/api/fork_spec.rb +++ b/spec/requests/api/fork_spec.rb @@ -4,7 +4,6 @@ describe API::Projects, api: true do include ApiHelpers let(:user) { create(:user) } let(:user2) { create(:user) } - let(:user3) { create(:user) } let(:admin) { create(:admin) } let(:group) { create(:group) } let(:group2) do @@ -13,17 +12,14 @@ describe API::Projects, api: true do group end - let(:project) do - create(:project, creator_id: user.id, namespace: user.namespace) - end - - let(:project_user2) do - create(:project_member, :reporter, user: user2, project: project) - end - describe 'POST /projects/fork/:id' do - before { project_user2 } - before { user3 } + let(:project) do + create(:project, :repository, creator: user, namespace: user.namespace) + end + + before do + project.add_reporter(user2) + end context 'when authenticated' do it 'forks if user has sufficient access to project' do @@ -49,7 +45,8 @@ describe API::Projects, api: true do end it 'fails on missing project access for the project to fork' do - post api("/projects/fork/#{project.id}", user3) + new_user = create(:user) + post api("/projects/fork/#{project.id}", new_user) expect(response).to have_http_status(404) expect(json_response['message']).to eq('404 Project Not Found') diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index edbf0140583..1187d2e609d 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -176,6 +176,9 @@ describe API::Groups, api: true do expect(json_response['visibility_level']).to eq(group1.visibility_level) expect(json_response['avatar_url']).to eq(group1.avatar_url) expect(json_response['web_url']).to eq(group1.web_url) + expect(json_response['request_access_enabled']).to eq(group1.request_access_enabled) + expect(json_response['full_name']).to eq(group1.full_name) + expect(json_response['full_path']).to eq(group1.full_path) expect(json_response['projects']).to be_an Array expect(json_response['projects'].length).to eq(2) expect(json_response['shared_projects']).to be_an Array diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 91202244227..ffeacb15f17 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -4,7 +4,7 @@ describe API::Internal, api: true do include ApiHelpers let(:user) { create(:user) } let(:key) { create(:key, user: user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:secret_token) { Gitlab::Shell.secret_token } describe "GET /internal/check", no_db: true do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 71a7994e544..21a2c583aa8 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -6,12 +6,10 @@ describe API::MergeRequests, api: true do let(:user) { create(:user) } let(:admin) { create(:user, :admin) } let(:non_member) { create(:user) } - let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace) } - let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test", created_at: base_time) } - let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, target_project: project, title: "Closed test", created_at: base_time + 1.second) } - let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, target_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } - let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") } - let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") } + let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) } + let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, title: "Test", created_at: base_time) } + let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, title: "Closed test", created_at: base_time + 1.second) } + let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') } let(:milestone) { create(:milestone, title: '1.0.0', project: project) } before do @@ -556,11 +554,12 @@ describe API::MergeRequests, api: true do original_count = merge_request.notes.size post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user), note: "My comment" + expect(response).to have_http_status(201) expect(json_response['note']).to eq('My comment') expect(json_response['author']['name']).to eq(user.name) expect(json_response['author']['username']).to eq(user.username) - expect(merge_request.notes.size).to eq(original_count + 1) + expect(merge_request.reload.notes.size).to eq(original_count + 1) end it "returns 400 if note is missing" do @@ -576,6 +575,9 @@ describe API::MergeRequests, api: true do end describe "GET :id/merge_requests/:merge_request_id/comments" do + let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") } + let!(:note2) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "another comment on a MR") } + it "returns merge_request comments ordered by created_at" do get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/comments", user) expect(response).to have_http_status(200) diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 9a01f7fa1c4..b7a0b5a9e13 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -5,7 +5,7 @@ describe API::Pipelines, api: true do let(:user) { create(:user) } let(:non_member) { create(:user) } - let(:project) { create(:project, creator_id: user.id) } + let(:project) { create(:project, :repository, creator: user) } let!(:pipeline) do create(:ci_empty_pipeline, project: project, sha: project.commit.id, diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index cc5c532de83..a1db81ce18c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -17,6 +17,7 @@ describe API::Projects, api: true do let(:project3) do create(:project, :private, + :repository, name: 'second_project', path: 'second_project', creator_id: user.id, diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 0b19fa38c55..c61208e395c 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -8,7 +8,7 @@ describe API::Repositories, api: true do let(:user) { create(:user) } let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } - let!(:project) { create(:project, creator_id: user.id) } + let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } describe "GET /projects/:id/repository/tree" do @@ -74,7 +74,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository tree' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -144,7 +144,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository blob' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -198,7 +198,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository raw blob' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -273,7 +273,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository archive' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -347,7 +347,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository compare' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -394,7 +394,7 @@ describe API::Repositories, api: true do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository contributors' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index a1c32ae65ba..898d2b27e5c 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -7,7 +7,7 @@ describe API::Tags, api: true do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:project, creator_id: user.id) } + let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:guest) { create(:project_member, :guest, user: user2, project: project) } @@ -29,7 +29,7 @@ describe API::Tags, api: true do context 'when unauthenticated' do it_behaves_like 'repository tags' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -88,7 +88,7 @@ describe API::Tags, api: true do context 'when unauthenticated' do it_behaves_like 'repository tag' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index cd01283b655..84104aa66ee 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -7,7 +7,7 @@ describe API::Triggers do let(:user2) { create(:user) } let!(:trigger_token) { 'secure_token' } let!(:trigger_token_2) { 'secure_token_2' } - let!(:project) { create(:project, creator_id: user.id) } + let!(:project) { create(:project, :repository, creator: user) } let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:developer) { create(:project_member, :developer, user: user2, project: project) } let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index 2d434ab5dd8..a30be767119 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -5,9 +5,9 @@ describe Ci::API::Triggers do describe 'POST /projects/:project_id/refs/:ref/trigger' do let!(:trigger_token) { 'secure token' } - let!(:project) { FactoryGirl.create(:project, ci_id: 10) } - let!(:project2) { FactoryGirl.create(:empty_project, ci_id: 11) } - let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) } + let!(:project) { create(:project, :repository, ci_id: 10) } + let!(:project2) { create(:empty_project, ci_id: 11) } + let!(:trigger) { create(:ci_trigger, project: project, token: trigger_token) } let(:options) do { token: trigger_token diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 6a5ad6deb74..4a16824de04 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -12,7 +12,7 @@ describe 'Git HTTP requests', lib: true do describe "User with no identities" do let(:user) { create(:user) } - let(:project) { create(:project, path: 'project.git-project') } + let(:project) { create(:project, :repository, path: 'project.git-project') } context "when the project doesn't exist" do context "when no authentication is provided" do diff --git a/spec/requests/projects/artifacts_controller_spec.rb b/spec/requests/projects/artifacts_controller_spec.rb index e02f0eacc93..d20866c0d44 100644 --- a/spec/requests/projects/artifacts_controller_spec.rb +++ b/spec/requests/projects/artifacts_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::ArtifactsController do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb index 28b485e4b15..0edbffbcd3b 100644 --- a/spec/requests/projects/cycle_analytics_events_spec.rb +++ b/spec/requests/projects/cycle_analytics_events_spec.rb @@ -4,7 +4,7 @@ describe 'cycle analytics events' do include ApiHelpers let(:user) { create(:user) } - let(:project) { create(:project, public_builds: false) } + let(:project) { create(:project, :repository, public_builds: false) } let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } describe 'GET /:namespace/:project/cycle_analytics/events/issues' do diff --git a/spec/serializers/analytics_build_serializer_spec.rb b/spec/serializers/analytics_build_serializer_spec.rb index f0551c78671..e3b1dd93dc2 100644 --- a/spec/serializers/analytics_build_serializer_spec.rb +++ b/spec/serializers/analytics_build_serializer_spec.rb @@ -1,17 +1,13 @@ require 'spec_helper' describe AnalyticsBuildSerializer do - let(:serializer) do - described_class - .new.represent(resource) - end - - let(:json) { serializer.as_json } let(:resource) { create(:ci_build) } + subject { described_class.new.represent(resource) } + context 'when there is a single object provided' do it 'contains important elements of analyticsBuild' do - expect(json) + expect(subject) .to include(:name, :branch, :short_sha, :date, :total_time, :url, :author) end end diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb index 6afbb2df35c..2f08958a783 100644 --- a/spec/serializers/analytics_issue_serializer_spec.rb +++ b/spec/serializers/analytics_issue_serializer_spec.rb @@ -1,14 +1,13 @@ require 'spec_helper' describe AnalyticsIssueSerializer do - let(:serializer) do + subject do described_class .new(project: project, entity: :merge_request) .represent(resource) end let(:user) { create(:user) } - let(:json) { serializer.as_json } let(:project) { create(:project) } let(:resource) do { @@ -23,7 +22,7 @@ describe AnalyticsIssueSerializer do context 'when there is a single object provided' do it 'contains important elements of the issue' do - expect(json).to include(:title, :iid, :created_at, :total_time, :url, :author) + expect(subject).to include(:title, :iid, :created_at, :total_time, :url, :author) end end end diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb index cdfae27193f..62067cc0ef2 100644 --- a/spec/serializers/analytics_merge_request_serializer_spec.rb +++ b/spec/serializers/analytics_merge_request_serializer_spec.rb @@ -1,14 +1,13 @@ require 'spec_helper' describe AnalyticsMergeRequestSerializer do - let(:serializer) do + subject do described_class .new(project: project, entity: :merge_request) .represent(resource) end let(:user) { create(:user) } - let(:json) { serializer.as_json } let(:project) { create(:project) } let(:resource) do { @@ -24,7 +23,7 @@ describe AnalyticsMergeRequestSerializer do context 'when there is a single object provided' do it 'contains important elements of the merge request' do - expect(json).to include(:title, :iid, :created_at, :total_time, :url, :author, :state) + expect(subject).to include(:title, :iid, :created_at, :total_time, :url, :author, :state) end end end diff --git a/spec/serializers/analytics_stage_serializer_spec.rb b/spec/serializers/analytics_stage_serializer_spec.rb index f9951826683..be6aa7c65c3 100644 --- a/spec/serializers/analytics_stage_serializer_spec.rb +++ b/spec/serializers/analytics_stage_serializer_spec.rb @@ -1,13 +1,13 @@ require 'spec_helper' describe AnalyticsStageSerializer do - let(:serializer) do - described_class - .new.represent(resource) + subject do + described_class.new.represent(resource) end - let(:json) { serializer.as_json } - let(:resource) { Gitlab::CycleAnalytics::CodeStage.new(project: double, options: {}) } + let(:resource) do + Gitlab::CycleAnalytics::CodeStage.new(project: double, options: {}) + end before do allow_any_instance_of(Gitlab::CycleAnalytics::BaseStage).to receive(:median).and_return(1.12) @@ -15,10 +15,10 @@ describe AnalyticsStageSerializer do end it 'it generates payload for single object' do - expect(json).to be_kind_of Hash + expect(subject).to be_kind_of Hash end it 'contains important elements of AnalyticsStage' do - expect(json).to include(:title, :description, :value) + expect(subject).to include(:title, :description, :value) end end diff --git a/spec/serializers/analytics_summary_serializer_spec.rb b/spec/serializers/analytics_summary_serializer_spec.rb index 7a84c8b0b40..5d7a94c2d02 100644 --- a/spec/serializers/analytics_summary_serializer_spec.rb +++ b/spec/serializers/analytics_summary_serializer_spec.rb @@ -1,29 +1,28 @@ require 'spec_helper' describe AnalyticsSummarySerializer do - let(:serializer) do - described_class - .new.represent(resource) + subject do + described_class.new.represent(resource) end - let(:json) { serializer.as_json } let(:project) { create(:empty_project) } let(:user) { create(:user) } + let(:resource) do - Gitlab::CycleAnalytics::Summary::Issue.new(project: double, - from: 1.day.ago, - current_user: user) + Gitlab::CycleAnalytics::Summary::Issue + .new(project: double, from: 1.day.ago, current_user: user) end before do - allow_any_instance_of(Gitlab::CycleAnalytics::Summary::Issue).to receive(:value).and_return(1.12) + allow_any_instance_of(Gitlab::CycleAnalytics::Summary::Issue) + .to receive(:value).and_return(1.12) end it 'it generates payload for single object' do - expect(json).to be_kind_of Hash + expect(subject).to be_kind_of Hash end it 'contains important elements of AnalyticsStage' do - expect(json).to include(:title, :value) + expect(subject).to include(:title, :value) end end diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index b7ed4eb0239..3c37660885d 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -1,16 +1,15 @@ require 'spec_helper' describe EnvironmentSerializer do - let(:serializer) do + let(:user) { create(:user) } + let(:project) { create(:project) } + + let(:json) do described_class .new(user: user, project: project) .represent(resource) end - let(:json) { serializer.as_json } - let(:user) { create(:user) } - let(:project) { create(:project) } - context 'when there is a single object provided' do before do create(:ci_build, :manual, name: 'manual1', diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 3a32cb394dd..7cbf131e41e 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -7,11 +7,7 @@ describe PipelineSerializer do described_class.new(user: user) end - let(:entity) do - serializer.represent(resource) - end - - subject { entity.as_json } + subject { serializer.represent(resource) } describe '#represent' do context 'when used without pagination' do diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb new file mode 100644 index 00000000000..4b90ad19640 --- /dev/null +++ b/spec/services/labels/promote_service_spec.rb @@ -0,0 +1,187 @@ +require 'spec_helper' + +describe Labels::PromoteService, services: true do + describe '#execute' do + let!(:user) { create(:user) } + + context 'project without group' do + let!(:project_1) { create(:empty_project) } + + let!(:project_label_1_1) { create(:label, project: project_1) } + + subject(:service) { described_class.new(project_1, user) } + + it 'fails on project without group' do + expect(service.execute(project_label_1_1)).to be_falsey + end + end + + context 'project with group' do + let!(:promoted_label_name) { "Promoted Label" } + let!(:untouched_label_name) { "Untouched Label" } + let!(:promoted_description) { "Promoted Description" } + let!(:promoted_color) { "#0000FF" } + let!(:label_2_1_priority) { 1 } + let!(:label_3_1_priority) { 2 } + + let!(:group_1) { create(:group) } + let!(:group_2) { create(:group) } + + let!(:project_1) { create(:empty_project, namespace: group_1) } + let!(:project_2) { create(:empty_project, namespace: group_1) } + let!(:project_3) { create(:empty_project, namespace: group_1) } + let!(:project_4) { create(:empty_project, namespace: group_2) } + + # Labels/issues can't be lazily created so we might as well eager initialize + # all other objects too since we use them inside + let!(:project_label_1_1) { create(:label, project: project_1, name: promoted_label_name, color: promoted_color, description: promoted_description) } + let!(:project_label_1_2) { create(:label, project: project_1, name: untouched_label_name) } + let!(:project_label_2_1) { create(:label, project: project_2, priority: label_2_1_priority, name: promoted_label_name, color: "#FF0000") } + let!(:project_label_3_1) { create(:label, project: project_3, priority: label_3_1_priority, name: promoted_label_name) } + let!(:project_label_3_2) { create(:label, project: project_3, priority: 1, name: untouched_label_name) } + let!(:project_label_4_1) { create(:label, project: project_4, name: promoted_label_name) } + + let!(:issue_1_1) { create(:labeled_issue, project: project_1, labels: [project_label_1_1, project_label_1_2]) } + let!(:issue_1_2) { create(:labeled_issue, project: project_1, labels: [project_label_1_2]) } + let!(:issue_2_1) { create(:labeled_issue, project: project_2, labels: [project_label_2_1]) } + let!(:issue_4_1) { create(:labeled_issue, project: project_4, labels: [project_label_4_1]) } + + let!(:merge_3_1) { create(:labeled_merge_request, source_project: project_3, target_project: project_3, labels: [project_label_3_1, project_label_3_2]) } + + let!(:issue_board_2_1) { create(:board, project: project_2) } + let!(:issue_board_list_2_1) { create(:list, board: issue_board_2_1, label: project_label_2_1) } + + let(:new_label) { group_1.labels.find_by(title: promoted_label_name) } + + subject(:service) { described_class.new(project_1, user) } + + it 'fails on group label' do + group_label = create(:group_label, group: group_1) + + expect(service.execute(group_label)).to be_falsey + end + + it 'is truthy on success' do + expect(service.execute(project_label_1_1)).to be_truthy + end + + it 'recreates the label as a group label' do + expect { service.execute(project_label_1_1) }. + to change(project_1.labels, :count).by(-1). + and change(group_1.labels, :count).by(1) + expect(new_label).not_to be_nil + end + + it 'copies title, description and color' do + service.execute(project_label_1_1) + + expect(new_label.title).to eq(promoted_label_name) + expect(new_label.description).to eq(promoted_description) + expect(new_label.color).to eq(promoted_color) + end + + it 'merges labels with the same name in group' do + expect { service.execute(project_label_1_1) }.to change(project_2.labels, :count).by(-1).and \ + change(project_3.labels, :count).by(-1) + end + + it 'recreates priorities' do + service.execute(project_label_1_1) + + expect(new_label.priority(project_1)).to be_nil + expect(new_label.priority(project_2)).to eq(label_2_1_priority) + expect(new_label.priority(project_3)).to eq(label_3_1_priority) + end + + it 'does not touch project out of promoted group' do + service.execute(project_label_1_1) + project_4_new_label = project_4.labels.find_by(title: promoted_label_name) + + expect(project_4_new_label).not_to be_nil + expect(project_4_new_label.id).to eq(project_label_4_1.id) + end + + it 'does not touch out of group priority' do + service.execute(project_label_1_1) + + expect(new_label.priority(project_4)).to be_nil + end + + it 'relinks issue with the promoted label' do + service.execute(project_label_1_1) + issue_label = issue_1_1.labels.find_by(title: promoted_label_name) + + expect(issue_label).not_to be_nil + expect(issue_label.id).to eq(new_label.id) + end + + it 'does not remove untouched labels from issue' do + expect { service.execute(project_label_1_1) }.not_to change(issue_1_1.labels, :count) + end + + it 'does not relink untouched label in issue' do + service.execute(project_label_1_1) + issue_label = issue_1_2.labels.find_by(title: untouched_label_name) + + expect(issue_label).not_to be_nil + expect(issue_label.id).to eq(project_label_1_2.id) + end + + it 'relinks issues with merged labels' do + service.execute(project_label_1_1) + issue_label = issue_2_1.labels.find_by(title: promoted_label_name) + + expect(issue_label).not_to be_nil + expect(issue_label.id).to eq(new_label.id) + end + + it 'does not relink issues from other group' do + service.execute(project_label_1_1) + issue_label = issue_4_1.labels.find_by(title: promoted_label_name) + + expect(issue_label).not_to be_nil + expect(issue_label.id).to eq(project_label_4_1.id) + end + + it 'updates merge request' do + service.execute(project_label_1_1) + merge_label = merge_3_1.labels.find_by(title: promoted_label_name) + + expect(merge_label).not_to be_nil + expect(merge_label.id).to eq(new_label.id) + end + + it 'updates board lists' do + service.execute(project_label_1_1) + list = issue_board_2_1.lists.find_by(label: new_label) + + expect(list).not_to be_nil + end + + # In case someone adds a new relation to Label.rb and forgets to relink it + # and the database doesn't have foreign key constraints + it 'relinks all relations' do + service.execute(project_label_1_1) + + Label.reflect_on_all_associations.each do |association| + expect(project_label_1_1.send(association.name).any?).to be_falsey + end + end + + context 'with invalid group label' do + before do + allow(service).to receive(:clone_label_to_group_label).and_wrap_original do |m, *args| + label = m.call(*args) + allow(label).to receive(:valid?).and_return(false) + + label + end + end + + it 'raises an exception' do + expect { service.execute(project_label_1_1) }.to raise_error(ActiveRecord::RecordInvalid) + end + end + end + end +end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index bfbee7ca35f..7cf2cd9968f 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -33,6 +33,49 @@ describe NotificationService, services: true do end end + # Next shared examples are intended to test notifications of "participants" + # + # they take the following parameters: + # * issuable + # * notification trigger + # * participant + # + shared_examples 'participating by note notification' do + it 'emails the participant' do + create(:note_on_issue, noteable: issuable, project_id: project.id, note: 'anything', author: participant) + + notification_trigger + + should_email(participant) + end + end + + shared_examples 'participating by assignee notification' do + it 'emails the participant' do + issuable.update_attribute(:assignee, participant) + + notification_trigger + + should_email(participant) + end + end + + shared_examples 'participating by author notification' do + it 'emails the participant' do + issuable.author = participant + + notification_trigger + + should_email(participant) + end + end + + shared_examples_for 'participating notifications' do + it_should_behave_like 'participating by note notification' + it_should_behave_like 'participating by author notification' + it_should_behave_like 'participating by assignee notification' + end + describe 'Keys' do describe '#new_key' do let!(:key) { create(:personal_key) } @@ -400,6 +443,8 @@ describe NotificationService, services: true do before do build_team(issue.project) + build_group(issue.project) + add_users_with_subscription(issue.project, issue) reset_delivered_emails! update_custom_notification(:new_issue, @u_guest_custom, project) @@ -416,6 +461,8 @@ describe NotificationService, services: true do should_email(@u_guest_custom) should_email(@u_custom_global) should_email(@u_participant_mentioned) + should_email(@g_global_watcher) + should_email(@g_watcher) should_not_email(@u_mentioned) should_not_email(@u_participating) should_not_email(@u_disabled) @@ -588,32 +635,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - issue.update_attribute(:assignee, @u_lazy_participant) - notification.reassigned_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } - - before { notification.reassigned_issue(issue, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - issue.author = @u_lazy_participant - notification.reassigned_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { issue } + let(:notification_trigger) { notification.reassigned_issue(issue, @u_disabled) } end end @@ -720,32 +745,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - issue.update_attribute(:assignee, @u_lazy_participant) - notification.close_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } - - before { notification.close_issue(issue, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - issue.author = @u_lazy_participant - notification.close_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { issue } + let(:notification_trigger) { notification.close_issue(issue, @u_disabled) } end end @@ -772,32 +775,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - issue.update_attribute(:assignee, @u_lazy_participant) - notification.reopen_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: 'anything', author: @u_lazy_participant) } - - before { notification.reopen_issue(issue, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - issue.author = @u_lazy_participant - notification.reopen_issue(issue, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { issue } + let(:notification_trigger) { notification.reopen_issue(issue, @u_disabled) } end end end @@ -858,31 +839,28 @@ describe NotificationService, services: true do end context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.new_merge_request(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } + it_should_behave_like 'participating by assignee notification' do + let(:participant) { create(:user, username: 'user-participant')} + let(:issuable) { merge_request } + let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) } end - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.new_merge_request(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } + it_should_behave_like 'participating by note notification' do + let(:participant) { create(:user, username: 'user-participant')} + let(:issuable) { merge_request } + let(:notification_trigger) { notification.new_merge_request(merge_request, @u_disabled) } end context 'by author' do + let(:participant) { create(:user, username: 'user-participant')} + before do - merge_request.author = @u_lazy_participant + merge_request.author = participant merge_request.save notification.new_merge_request(merge_request, @u_disabled) end - it { should_not_email(@u_lazy_participant) } + it { should_not_email(participant) } end end end @@ -917,33 +895,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.reassigned_merge_request(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.reassigned_merge_request(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - merge_request.author = @u_lazy_participant - merge_request.save - notification.reassigned_merge_request(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.reassigned_merge_request(merge_request, @u_disabled) } end end @@ -1014,33 +969,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.close_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.close_mr(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - merge_request.author = @u_lazy_participant - merge_request.save - notification.close_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.close_mr(merge_request, @u_disabled) } end end @@ -1081,33 +1013,10 @@ describe NotificationService, services: true do should_not_email(@u_watcher) end - context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.merge_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.merge_mr(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - merge_request.author = @u_lazy_participant - merge_request.save - notification.merge_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.merge_mr(merge_request, @u_disabled) } end end @@ -1134,33 +1043,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.reopen_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.reopen_mr(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - merge_request.author = @u_lazy_participant - merge_request.save - notification.reopen_mr(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.reopen_mr(merge_request, @u_disabled) } end end @@ -1180,33 +1066,10 @@ describe NotificationService, services: true do should_not_email(@u_lazy_participant) end - context 'participating' do - context 'by assignee' do - before do - merge_request.update_attribute(:assignee, @u_lazy_participant) - notification.resolve_all_discussions(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end - - context 'by note' do - let!(:note) { create(:note_on_issue, noteable: merge_request, project_id: project.id, note: 'anything', author: @u_lazy_participant) } - - before { notification.resolve_all_discussions(merge_request, @u_disabled) } - - it { should_email(@u_lazy_participant) } - end - - context 'by author' do - before do - merge_request.author = @u_lazy_participant - merge_request.save - notification.resolve_all_discussions(merge_request, @u_disabled) - end - - it { should_email(@u_lazy_participant) } - end + it_behaves_like 'participating notifications' do + let(:participant) { create(:user, username: 'user-participant') } + let(:issuable) { merge_request } + let(:notification_trigger) { notification.resolve_all_discussions(merge_request, @u_disabled) } end end end @@ -1359,6 +1222,22 @@ describe NotificationService, services: true do project.add_master(@u_custom_global) end + # Users in the project's group but not part of project's team + # with different notification settings + def build_group(project) + group = create(:group, :public) + project.group = group + + # Group member: global=disabled, group=watch + @g_watcher = create_user_with_notification(:watch, 'group_watcher', project.group) + @g_watcher.notification_settings_for(nil).disabled! + + # Group member: global=watch, group=global + @g_global_watcher = create_global_setting_for(create(:user), :watch) + group.add_users([@g_watcher, @g_global_watcher], :master) + group + end + def create_global_setting_for(user, level) setting = user.global_notification_setting setting.level = level @@ -1367,9 +1246,9 @@ describe NotificationService, services: true do user end - def create_user_with_notification(level, username) + def create_user_with_notification(level, username, resource = project) user = create(:user, username: username) - setting = user.notification_settings_for(project) + setting = user.notification_settings_for(resource) setting.level = level setting.save diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index bd89c4a7c11..bed1031e40a 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -41,6 +41,25 @@ describe 'Search::GlobalService', services: true do results = context.execute expect(results.objects('projects')).to match_array [found_project] end + + context 'nested group' do + let!(:nested_group) { create(:group, :nested) } + let!(:project) { create(:project, namespace: nested_group) } + + before { project.add_master(user) } + + it 'returns result from nested group' do + context = Search::GlobalService.new(user, search: project.path) + results = context.execute + expect(results.objects('projects')).to match_array [project] + end + + it 'returns result from descendants when search inside group' do + context = Search::GlobalService.new(user, search: project.path, group_id: nested_group.parent) + results = context.execute + expect(results.objects('projects')).to match_array [project] + end + end end end end diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index fef211ded50..db9f1231682 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -12,6 +12,7 @@ describe SystemHooksService, services: true do it { expect(event_data(user, :create)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :email, :user_id, :username) } it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } + it { expect(event_data(project, :update)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :updated_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) } it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) } it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :updated_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_username, :user_email, :user_id, :access_level, :project_visibility) } @@ -68,6 +69,7 @@ describe SystemHooksService, services: true do it { expect(event_name(project, :destroy)).to eq "project_destroy" } it { expect(event_name(project, :rename)).to eq "project_rename" } it { expect(event_name(project, :transfer)).to eq "project_transfer" } + it { expect(event_name(project, :update)).to eq "project_update" } it { expect(event_name(project_member, :create)).to eq "user_add_to_team" } it { expect(event_name(project_member, :destroy)).to eq "user_remove_from_team" } it { expect(event_name(key, :create)).to eq 'key_create' } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index 9f5a0ac4ec6..bd7269045e1 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -245,6 +245,8 @@ describe SystemNoteService, services: true do end describe '.change_title' do + let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum') } + subject { described_class.change_title(noteable, project, author, 'Old title') } context 'when noteable responds to `title`' do @@ -252,7 +254,7 @@ describe SystemNoteService, services: true do it 'sets the note text' do expect(subject.note). - to eq "changed title from **{-Old title-}** to **{+#{noteable.title}+}**" + to eq "changed title from **{-Old title-}** to **{+Lorem ipsum+}**" end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e160c11111b..ab38dac65c5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,6 +9,10 @@ require 'rspec/rails' require 'shoulda/matchers' require 'rspec/retry' +if ENV['RSPEC_PROFILING_POSTGRES_URL'] || ENV['RSPEC_PROFILING'] + require 'rspec_profiling/rspec' +end + if ENV['CI'] && !ENV['NO_KNAPSACK'] require 'knapsack' Knapsack::Adapters::RSpecAdapter.bind diff --git a/spec/support/cycle_analytics_helpers/test_generation.rb b/spec/support/cycle_analytics_helpers/test_generation.rb index 35b40d73191..10b90b40ba7 100644 --- a/spec/support/cycle_analytics_helpers/test_generation.rb +++ b/spec/support/cycle_analytics_helpers/test_generation.rb @@ -54,7 +54,7 @@ module CycleAnalyticsHelpers end context "when the data belongs to another project" do - let(:other_project) { create(:project) } + let(:other_project) { create(:project, :repository) } it "returns nil" do # Use a stub to "trick" the data/condition functions diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb index f57c82809a6..87936bb4859 100644 --- a/spec/support/mentionable_shared_examples.rb +++ b/spec/support/mentionable_shared_examples.rb @@ -12,7 +12,7 @@ shared_context 'mentionable context' do let!(:mentioned_mr) { create(:merge_request, source_project: project) } let(:mentioned_commit) { project.commit("HEAD~1") } - let(:ext_proj) { create(:project, :public) } + let(:ext_proj) { create(:project, :public, :repository) } let(:ext_issue) { create(:issue, project: ext_proj) } let(:ext_mr) { create(:merge_request, :simple, source_project: ext_proj) } let(:ext_commit) { ext_proj.commit("HEAD~2") } diff --git a/spec/support/mobile_helpers.rb b/spec/support/mobile_helpers.rb new file mode 100644 index 00000000000..20d5849bcab --- /dev/null +++ b/spec/support/mobile_helpers.rb @@ -0,0 +1,13 @@ +module MobileHelpers + def resize_screen_sm + resize_window(900, 768) + end + + def restore_window_size + resize_window(1366, 768) + end + + def resize_window(width, height) + page.driver.resize_window width, height + end +end diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb index 74d9b8c6313..704922b6cf4 100644 --- a/spec/support/slack_mattermost_notifications_shared_examples.rb +++ b/spec/support/slack_mattermost_notifications_shared_examples.rb @@ -26,7 +26,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do describe "#execute" do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:username) { 'slack_username' } let(:channel) { 'slack_channel' } @@ -196,7 +196,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do describe "Note events" do let(:user) { create(:user) } - let(:project) { create(:project, creator_id: user.id) } + let(:project) { create(:project, :repository, creator: user) } before do allow(chat_service).to receive_messages( @@ -269,7 +269,7 @@ RSpec.shared_examples 'slack or mattermost notifications' do describe 'Pipeline events' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_pipeline, diff --git a/spec/views/ci/lints/show.html.haml_spec.rb b/spec/views/ci/lints/show.html.haml_spec.rb index 2dac5ee23c8..3390ae247ff 100644 --- a/spec/views/ci/lints/show.html.haml_spec.rb +++ b/spec/views/ci/lints/show.html.haml_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'ci/lints/show' do - include Devise::TestHelpers + include Devise::Test::ControllerHelpers describe 'XSS protection' do let(:config_processor) { Ci::GitlabCiYamlProcessor.new(YAML.dump(content)) } diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb index 745d0c745bd..44870cfcfb3 100644 --- a/spec/views/projects/builds/show.html.haml_spec.rb +++ b/spec/views/projects/builds/show.html.haml_spec.rb @@ -15,6 +15,36 @@ describe 'projects/builds/show', :view do allow(view).to receive(:can?).and_return(true) end + describe 'build information in header' do + let(:build) do + create(:ci_build, :success, environment: 'staging') + end + + before do + render + end + + it 'shows status name' do + expect(rendered).to have_css('.ci-status.ci-success', text: 'passed') + end + + it 'does not render a link to the build' do + expect(rendered).not_to have_link('passed') + end + + it 'shows build id' do + expect(rendered).to have_css('.js-build-id', text: build.id) + end + + it 'shows a link to the pipeline' do + expect(rendered).to have_link(build.pipeline.id) + end + + it 'shows a link to the commit' do + expect(rendered).to have_link(build.pipeline.short_sha) + end + end + describe 'environment info in build view' do context 'build with latest deployment' do let(:build) do |