diff options
Diffstat (limited to 'spec')
540 files changed, 5954 insertions, 1519 deletions
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb new file mode 100644 index 00000000000..c19a752b07b --- /dev/null +++ b/spec/controllers/graphql_controller_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe GraphqlController do + before do + stub_feature_flags(graphql: true) + end + + describe 'POST #execute' do + context 'when user is logged in' do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + it 'returns 200 when user can access API' do + post :execute + + expect(response).to have_gitlab_http_status(200) + end + + it 'returns access denied template when user cannot access API' do + # User cannot access API in a couple of cases + # * When user is internal(like ghost users) + # * When user is blocked + expect(Ability).to receive(:allowed?).with(user, :access_api, :global).and_return(false) + + post :execute + + expect(response.status).to eq(403) + expect(response).to render_template('errors/access_denied') + end + end + + context 'when user is not logged in' do + it 'returns 200' do + post :execute + + expect(response).to have_gitlab_http_status(200) + end + end + end +end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 79f97aa4170..c8fa93a74ee 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -86,6 +86,10 @@ describe Projects::MergeRequestsController do end describe 'as json' do + before do + expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original + end + context 'with basic serializer param' do it 'renders basic MR entity as json' do go(serializer: 'basic', format: :json) diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index a73f330a7a9..abf0e6bccb7 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -46,10 +46,26 @@ FactoryBot.define do target_branch "improve/awesome" end + trait :merged_last_month do + merged + + after(:build) do |merge_request| + merge_request.build_metrics.merged_at = 1.month.ago + end + end + trait :closed do state :closed end + trait :closed_last_month do + closed + + after(:build) do |merge_request| + merge_request.build_metrics.latest_closed_at = 1.month.ago + end + end + trait :opened do state :opened end @@ -101,9 +117,20 @@ FactoryBot.define do end end + trait :with_legacy_detached_merge_request_pipeline do + after(:create) do |merge_request| + merge_request.merge_request_pipelines << create(:ci_pipeline, + source: :merge_request_event, + merge_request: merge_request, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.source_branch_sha) + end + end + trait :with_detached_merge_request_pipeline do - after(:build) do |merge_request| - merge_request.merge_request_pipelines << build(:ci_pipeline, + after(:create) do |merge_request| + merge_request.merge_request_pipelines << create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, project: merge_request.source_project, @@ -119,7 +146,7 @@ FactoryBot.define do target_sha { target_branch_sha } end - after(:build) do |merge_request, evaluator| + after(:create) do |merge_request, evaluator| merge_request.merge_request_pipelines << create(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, diff --git a/spec/factories/suggestions.rb b/spec/factories/suggestions.rb index 307523cc061..b1427e0211f 100644 --- a/spec/factories/suggestions.rb +++ b/spec/factories/suggestions.rb @@ -16,5 +16,11 @@ FactoryBot.define do applied true commit_id { RepoHelpers.sample_commit.id } end + + trait :content_from_repo do + after(:build) do |suggestion, evaluator| + suggestion.from_content = suggestion.fetch_from_content + end + end end end diff --git a/spec/features/clusters/cluster_detail_page_spec.rb b/spec/features/clusters/cluster_detail_page_spec.rb index b9fc52d0dce..d2e46d15730 100644 --- a/spec/features/clusters/cluster_detail_page_spec.rb +++ b/spec/features/clusters/cluster_detail_page_spec.rb @@ -53,12 +53,80 @@ describe 'Clusterable > Show page' do end end + shared_examples 'editing a GCP cluster' do + before do + clusterable.add_maintainer(current_user) + visit cluster_path + end + + it 'is not able to edit the name, API url, CA certificate nor token' do + within('#js-cluster-details') do + cluster_name_field = find('.cluster-name') + api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') + ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') + token_field = find('#cluster_platform_kubernetes_attributes_token') + + expect(cluster_name_field).to be_readonly + expect(api_url_field).to be_readonly + expect(ca_certificate_field).to be_readonly + expect(token_field).to be_readonly + end + end + + it 'displays GKE information' do + within('#advanced-settings-section') do + expect(page).to have_content('Google Kubernetes Engine') + expect(page).to have_content('Manage your Kubernetes cluster by visiting') + end + end + end + + shared_examples 'editing a user-provided cluster' do + before do + clusterable.add_maintainer(current_user) + visit cluster_path + end + + it 'is able to edit the name, API url, CA certificate and token' do + within('#js-cluster-details') do + cluster_name_field = find('#cluster_name') + api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') + ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') + token_field = find('#cluster_platform_kubernetes_attributes_token') + + expect(cluster_name_field).not_to be_readonly + expect(api_url_field).not_to be_readonly + expect(ca_certificate_field).not_to be_readonly + expect(token_field).not_to be_readonly + end + end + + it 'does not display GKE information' do + within('#advanced-settings-section') do + expect(page).not_to have_content('Google Kubernetes Engine') + expect(page).not_to have_content('Manage your Kubernetes cluster by visiting') + end + end + end + context 'when clusterable is a project' do it_behaves_like 'editing domain' do let(:clusterable) { create(:project) } let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) } let(:cluster_path) { project_cluster_path(clusterable, cluster) } end + + it_behaves_like 'editing a GCP cluster' do + let(:clusterable) { create(:project) } + let(:cluster) { create(:cluster, :provided_by_gcp, :project, projects: [clusterable]) } + let(:cluster_path) { project_cluster_path(clusterable, cluster) } + end + + it_behaves_like 'editing a user-provided cluster' do + let(:clusterable) { create(:project) } + let(:cluster) { create(:cluster, :provided_by_user, :project, projects: [clusterable]) } + let(:cluster_path) { project_cluster_path(clusterable, cluster) } + end end context 'when clusterable is a group' do @@ -67,5 +135,17 @@ describe 'Clusterable > Show page' do let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) } let(:cluster_path) { group_cluster_path(clusterable, cluster) } end + + it_behaves_like 'editing a GCP cluster' do + let(:clusterable) { create(:group) } + let(:cluster) { create(:cluster, :provided_by_gcp, :group, groups: [clusterable]) } + let(:cluster_path) { group_cluster_path(clusterable, cluster) } + end + + it_behaves_like 'editing a user-provided cluster' do + let(:clusterable) { create(:group) } + let(:cluster) { create(:cluster, :provided_by_user, :group, groups: [clusterable]) } + let(:cluster_path) { group_cluster_path(clusterable, cluster) } + end end end diff --git a/spec/features/issues/user_uses_quick_actions_spec.rb b/spec/features/issues/user_uses_quick_actions_spec.rb index b5e7c3954e2..362f8a468ec 100644 --- a/spec/features/issues/user_uses_quick_actions_spec.rb +++ b/spec/features/issues/user_uses_quick_actions_spec.rb @@ -3,8 +3,41 @@ require 'rails_helper' describe 'Issues > User uses quick actions', :js do include Spec::Support::Helpers::Features::NotesHelpers - it_behaves_like 'issuable record that supports quick actions in its description and notes', :issue do + context "issuable common quick actions" do + let(:new_url_opts) { {} } + let(:maintainer) { create(:user) } + let(:project) { create(:project, :public) } + let!(:label_bug) { create(:label, project: project, title: 'bug') } + let!(:label_feature) { create(:label, project: project, title: 'feature') } + let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let(:issuable) { create(:issue, project: project) } + let(:source_issuable) { create(:issue, project: project, milestone: milestone, labels: [label_bug, label_feature])} + + it_behaves_like 'assign quick action', :issue + it_behaves_like 'unassign quick action', :issue + it_behaves_like 'close quick action', :issue + it_behaves_like 'reopen quick action', :issue + it_behaves_like 'title quick action', :issue + it_behaves_like 'todo quick action', :issue + it_behaves_like 'done quick action', :issue + it_behaves_like 'subscribe quick action', :issue + it_behaves_like 'unsubscribe quick action', :issue + it_behaves_like 'lock quick action', :issue + it_behaves_like 'unlock quick action', :issue + it_behaves_like 'milestone quick action', :issue + it_behaves_like 'remove_milestone quick action', :issue + it_behaves_like 'label quick action', :issue + it_behaves_like 'unlabel quick action', :issue + it_behaves_like 'relabel quick action', :issue + it_behaves_like 'award quick action', :issue + it_behaves_like 'estimate quick action', :issue + it_behaves_like 'remove_estimate quick action', :issue + it_behaves_like 'spend quick action', :issue + it_behaves_like 'remove_time_spent quick action', :issue + it_behaves_like 'shrug quick action', :issue + it_behaves_like 'tableflip quick action', :issue + it_behaves_like 'copy_metadata quick action', :issue + it_behaves_like 'issuable time tracker', :issue end describe 'issue-only commands' do @@ -15,37 +48,17 @@ describe 'Issues > User uses quick actions', :js do project.add_maintainer(user) sign_in(user) visit project_issue_path(project, issue) + wait_for_all_requests end after do wait_for_requests end - describe 'time tracking' do - let(:issue) { create(:issue, project: project) } - - before do - visit project_issue_path(project, issue) - end - - it_behaves_like 'issuable time tracker' - end - describe 'adding a due date from note' do let(:issue) { create(:issue, project: project) } - context 'when the current user can update the due date' do - it 'does not create a note, and sets the due date accordingly' do - add_note("/due 2016-08-28") - - expect(page).not_to have_content '/due 2016-08-28' - expect(page).to have_content 'Commands applied' - - issue.reload - - expect(issue.due_date).to eq Date.new(2016, 8, 28) - end - end + it_behaves_like 'due quick action available and date can be added' context 'when the current user cannot update the due date' do let(:guest) { create(:user) } @@ -56,35 +69,14 @@ describe 'Issues > User uses quick actions', :js do visit project_issue_path(project, issue) end - it 'does not create a note, and sets the due date accordingly' do - add_note("/due 2016-08-28") - - expect(page).not_to have_content 'Commands applied' - - issue.reload - - expect(issue.due_date).to be_nil - end + it_behaves_like 'due quick action not available' end end describe 'removing a due date from note' do let(:issue) { create(:issue, project: project, due_date: Date.new(2016, 8, 28)) } - context 'when the current user can update the due date' do - it 'does not create a note, and removes the due date accordingly' do - expect(issue.due_date).to eq Date.new(2016, 8, 28) - - add_note("/remove_due_date") - - expect(page).not_to have_content '/remove_due_date' - expect(page).to have_content 'Commands applied' - - issue.reload - - expect(issue.due_date).to be_nil - end - end + it_behaves_like 'remove_due_date action available and due date can be removed' context 'when the current user cannot update the due date' do let(:guest) { create(:user) } @@ -95,15 +87,7 @@ describe 'Issues > User uses quick actions', :js do visit project_issue_path(project, issue) end - it 'does not create a note, and sets the due date accordingly' do - add_note("/remove_due_date") - - expect(page).not_to have_content 'Commands applied' - - issue.reload - - expect(issue.due_date).to eq Date.new(2016, 8, 28) - end + it_behaves_like 'remove_due_date action not available' end end @@ -200,6 +184,7 @@ describe 'Issues > User uses quick actions', :js do gitlab_sign_out sign_in(user) visit project_issue_path(project, issue) + wait_for_requests end it 'moves the issue' do @@ -221,6 +206,7 @@ describe 'Issues > User uses quick actions', :js do gitlab_sign_out sign_in(user) visit project_issue_path(project, issue) + wait_for_requests end it 'does not move the issue' do @@ -238,6 +224,7 @@ describe 'Issues > User uses quick actions', :js do gitlab_sign_out sign_in(user) visit project_issue_path(project, issue) + wait_for_requests end it 'does not move the issue' do diff --git a/spec/features/merge_request/user_uses_quick_actions_spec.rb b/spec/features/merge_request/user_uses_quick_actions_spec.rb index b81478a481f..a2b5859bd1e 100644 --- a/spec/features/merge_request/user_uses_quick_actions_spec.rb +++ b/spec/features/merge_request/user_uses_quick_actions_spec.rb @@ -9,9 +9,41 @@ describe 'Merge request > User uses quick actions', :js do let(:merge_request) { create(:merge_request, source_project: project) } let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } - it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do + context "issuable common quick actions" do + let!(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } } + let(:maintainer) { create(:user) } + let(:project) { create(:project, :public, :repository) } + let!(:label_bug) { create(:label, project: project, title: 'bug') } + let!(:label_feature) { create(:label, project: project, title: 'feature') } + let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let(:issuable) { create(:merge_request, source_project: project) } - let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } } + let(:source_issuable) { create(:issue, project: project, milestone: milestone, labels: [label_bug, label_feature])} + + it_behaves_like 'assign quick action', :merge_request + it_behaves_like 'unassign quick action', :merge_request + it_behaves_like 'close quick action', :merge_request + it_behaves_like 'reopen quick action', :merge_request + it_behaves_like 'title quick action', :merge_request + it_behaves_like 'todo quick action', :merge_request + it_behaves_like 'done quick action', :merge_request + it_behaves_like 'subscribe quick action', :merge_request + it_behaves_like 'unsubscribe quick action', :merge_request + it_behaves_like 'lock quick action', :merge_request + it_behaves_like 'unlock quick action', :merge_request + it_behaves_like 'milestone quick action', :merge_request + it_behaves_like 'remove_milestone quick action', :merge_request + it_behaves_like 'label quick action', :merge_request + it_behaves_like 'unlabel quick action', :merge_request + it_behaves_like 'relabel quick action', :merge_request + it_behaves_like 'award quick action', :merge_request + it_behaves_like 'estimate quick action', :merge_request + it_behaves_like 'remove_estimate quick action', :merge_request + it_behaves_like 'spend quick action', :merge_request + it_behaves_like 'remove_time_spent quick action', :merge_request + it_behaves_like 'shrug quick action', :merge_request + it_behaves_like 'tableflip quick action', :merge_request + it_behaves_like 'copy_metadata quick action', :merge_request + it_behaves_like 'issuable time tracker', :merge_request end describe 'merge-request-only commands' do @@ -24,20 +56,12 @@ describe 'Merge request > User uses quick actions', :js do project.add_maintainer(user) end - describe 'time tracking' do - before do - sign_in(user) - visit project_merge_request_path(project, merge_request) - end - - it_behaves_like 'issuable time tracker' - end - describe 'toggling the WIP prefix in the title from note' do context 'when the current user can toggle the WIP prefix' do before do sign_in(user) visit project_merge_request_path(project, merge_request) + wait_for_requests end it 'adds the WIP: prefix to the title' do @@ -135,11 +159,16 @@ describe 'Merge request > User uses quick actions', :js do visit project_merge_request_path(project, merge_request) end - it 'does not recognize the command nor create a note' do - add_note('/due 2016-08-28') + it_behaves_like 'due quick action not available' + end - expect(page).not_to have_content '/due 2016-08-28' + describe 'removing a due date from note' do + before do + sign_in(user) + visit project_merge_request_path(project, merge_request) end + + it_behaves_like 'remove_due_date action not available' end describe '/target_branch command in merge request' do diff --git a/spec/features/merge_request/user_views_open_merge_request_spec.rb b/spec/features/merge_request/user_views_open_merge_request_spec.rb index 71022c6bb08..849fab62fc6 100644 --- a/spec/features/merge_request/user_views_open_merge_request_spec.rb +++ b/spec/features/merge_request/user_views_open_merge_request_spec.rb @@ -13,7 +13,7 @@ describe 'User views an open merge request' do end it 'renders both the title and the description' do - node = find('.wiki h1 a#user-content-description-header') + node = find('.md h1 a#user-content-description-header') expect(node[:href]).to end_with('#description-header') # Work around a weird Capybara behavior where calling `parent` on a node diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index 6e349395017..adac59b89ef 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -122,4 +122,32 @@ describe 'Milestone' do expect(page).to have_selector('.popover') end end + + describe 'reopen closed milestones' do + before do + create(:milestone, :closed, project: project) + end + + describe 'group milestones page' do + it 'reopens the milestone' do + visit group_milestones_path(group, { state: 'closed' }) + + click_link 'Reopen Milestone' + + expect(page).not_to have_selector('.status-box-closed') + expect(page).to have_selector('.status-box-open') + end + end + + describe 'project milestones page' do + it 'reopens the milestone' do + visit project_milestones_path(project, { state: 'closed' }) + + click_link 'Reopen Milestone' + + expect(page).not_to have_selector('.status-box-closed') + expect(page).to have_selector('.status-box-open') + end + end + end end diff --git a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb index 5f630c9ffa4..a1fcd4024c0 100644 --- a/spec/features/projects/artifacts/user_browses_artifacts_spec.rb +++ b/spec/features/projects/artifacts/user_browses_artifacts_spec.rb @@ -19,6 +19,12 @@ describe "User browses artifacts" do visit(browse_project_job_artifacts_path(project, job)) end + it "renders a link to the job in the breadcrumbs" do + page.within('.js-breadcrumbs-list') do + expect(page).to have_link("##{job.id}", href: project_job_path(project, job)) + end + end + it "shows artifacts" do expect(page).not_to have_selector(".build-sidebar") diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index b1a7f167977..efb7b01f5ad 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -136,7 +136,7 @@ describe "User creates wiki page" do click_button("Create page") end - page.within ".wiki" do + page.within ".md" do expect(page).to have_selector(".katex", count: 3).and have_content("2+2 is 4") end end diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index eeacaf5f72a..fc6726985ae 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -70,7 +70,7 @@ describe 'Comments on personal snippets', :js do fill_in 'note[note]', with: 'This is **awesome**!' find('.js-md-preview-button').click - page.within('.new-note .md-preview') do + page.within('.new-note .md-preview-holder') do expect(page).to have_content('This is awesome!') expect(page).to have_selector('strong') end diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index 879c46d7c4e..1c97d5ec5b4 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -37,7 +37,7 @@ describe 'User creates snippet', :js do dropzone_file Rails.root.join('spec', 'fixtures', 'banana_sample.gif') find('.js-md-preview-button').click - page.within('#new_personal_snippet .md-preview') do + page.within('#new_personal_snippet .md-preview-holder') do expect(page).to have_content('My Snippet') link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index 8d567e925ef..bdbbe645779 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -37,7 +37,7 @@ describe 'Maintainer deletes tag' do context 'when pre-receive hook fails', :js do before do allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag) - .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags') + .and_raise(Gitlab::Git::PreReceiveError, 'GitLab: Do not delete tags') end it 'shows the error message' do diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 6fe840dccf6..33d9c10f5e8 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -79,7 +79,7 @@ describe 'Task Lists' do visit_issue(project, issue) wait_for_requests - expect(page).to have_selector(".wiki .task-list .task-list-item .task-list-item-checkbox") + expect(page).to have_selector(".md .task-list .task-list-item .task-list-item-checkbox") expect(page).to have_selector('a.btn-close') end @@ -87,14 +87,14 @@ describe 'Task Lists' do visit_issue(project, issue) wait_for_requests - expect(page).to have_selector(".wiki .task-list .task-list-item .task-list-item-checkbox") + expect(page).to have_selector(".md .task-list .task-list-item .task-list-item-checkbox") logout(:user) login_as(user2) visit current_path wait_for_requests - expect(page).to have_selector(".wiki .task-list .task-list-item .task-list-item-checkbox") + expect(page).to have_selector(".md .task-list .task-list-item .task-list-item-checkbox") end it 'provides a summary on Issues#index' do @@ -231,7 +231,7 @@ describe 'Task Lists' do container = '.detail-page-description .description.js-task-list-container' expect(page).to have_selector(container) - expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox") + expect(page).to have_selector("#{container} .md .task-list .task-list-item .task-list-item-checkbox") expect(page).to have_selector("#{container} .js-task-list-field") expect(page).to have_selector('form.js-issuable-update') expect(page).to have_selector('a.btn-close') diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb index 368a814874f..9d5780d29b0 100644 --- a/spec/features/users/login_spec.rb +++ b/spec/features/users/login_spec.rb @@ -447,7 +447,7 @@ describe 'Login' do 'You can leave Group 1 and leave Group 2. '\ 'You need to do this '\ 'before '\ - "#{(Time.zone.now + 2.days).strftime("%a, %-d %b %Y %H:%M:%S %z")}" + "#{(Time.zone.now + 2.days).strftime("%a, %d %b %Y %H:%M:%S %z")}" ) end end diff --git a/spec/frontend/.eslintrc.yml b/spec/frontend/.eslintrc.yml index 046215e4c93..054dc27cda6 100644 --- a/spec/frontend/.eslintrc.yml +++ b/spec/frontend/.eslintrc.yml @@ -2,8 +2,13 @@ env: jest/globals: true plugins: -- jest + - jest settings: import/resolver: jest: - jestConfigFile: "jest.config.js" + jestConfigFile: 'jest.config.js' +globals: + getJSONFixture: false + loadFixtures: false + preloadFixtures: false + setFixtures: false diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js new file mode 100644 index 00000000000..1067a53906a --- /dev/null +++ b/spec/frontend/environment.js @@ -0,0 +1,33 @@ +/* eslint-disable import/no-commonjs */ + +const { ErrorWithStack } = require('jest-util'); +const JSDOMEnvironment = require('jest-environment-jsdom'); + +class CustomEnvironment extends JSDOMEnvironment { + constructor(config, context) { + super(config, context); + + Object.assign(context.console, { + error(...args) { + throw new ErrorWithStack( + `Unexpected call of console.error() with:\n\n${args.join(', ')}`, + this.error, + ); + }, + + warn(...args) { + throw new ErrorWithStack( + `Unexpected call of console.warn() with:\n\n${args.join(', ')}`, + this.warn, + ); + }, + }); + + const { testEnvironmentOptions } = config; + this.global.gon = { + ee: testEnvironmentOptions.IS_EE, + }; + } +} + +module.exports = CustomEnvironment; diff --git a/spec/frontend/helpers/class_spec_helper.js b/spec/frontend/helpers/class_spec_helper.js new file mode 100644 index 00000000000..7a60d33b471 --- /dev/null +++ b/spec/frontend/helpers/class_spec_helper.js @@ -0,0 +1,9 @@ +export default class ClassSpecHelper { + static itShouldBeAStaticMethod(base, method) { + return it('should be a static method', () => { + expect(Object.prototype.hasOwnProperty.call(base, method)).toBeTruthy(); + }); + } +} + +window.ClassSpecHelper = ClassSpecHelper; diff --git a/spec/frontend/helpers/fixtures.js b/spec/frontend/helpers/fixtures.js index f96f27c4d80..f0351aa31c6 100644 --- a/spec/frontend/helpers/fixtures.js +++ b/spec/frontend/helpers/fixtures.js @@ -1,24 +1,36 @@ -/* eslint-disable import/prefer-default-export, global-require, import/no-dynamic-require */ - import fs from 'fs'; import path from 'path'; -// jest-util is part of Jest -// eslint-disable-next-line import/no-extraneous-dependencies import { ErrorWithStack } from 'jest-util'; const fixturesBasePath = path.join(process.cwd(), 'spec', 'javascripts', 'fixtures'); -export function getJSONFixture(relativePath, ee = false) { - const absolutePath = path.join(fixturesBasePath, ee ? 'ee' : '', relativePath); +export function getFixture(relativePath) { + const absolutePath = path.join(fixturesBasePath, relativePath); if (!fs.existsSync(absolutePath)) { throw new ErrorWithStack( `Fixture file ${relativePath} does not exist. Did you run bin/rake karma:fixtures?`, - getJSONFixture, + getFixture, ); } - return require(absolutePath); + return fs.readFileSync(absolutePath, 'utf8'); } + +export const getJSONFixture = relativePath => JSON.parse(getFixture(relativePath)); + +export const resetHTMLFixture = () => { + document.body.textContent = ''; +}; + +export const setHTMLFixture = (htmlContent, resetHook = afterEach) => { + document.body.outerHTML = htmlContent; + resetHook(resetHTMLFixture); +}; + +export const loadHTMLFixture = (relativePath, resetHook = afterEach) => { + const fileContent = getFixture(relativePath); + setHTMLFixture(fileContent, resetHook); +}; diff --git a/spec/frontend/helpers/locale_helper.js b/spec/frontend/helpers/locale_helper.js new file mode 100644 index 00000000000..80047b06003 --- /dev/null +++ b/spec/frontend/helpers/locale_helper.js @@ -0,0 +1,11 @@ +/* eslint-disable import/prefer-default-export */ + +export const setLanguage = languageCode => { + const htmlElement = document.querySelector('html'); + + if (languageCode) { + htmlElement.setAttribute('lang', languageCode); + } else { + htmlElement.removeAttribute('lang'); + } +}; diff --git a/spec/frontend/helpers/scroll_into_view_promise.js b/spec/frontend/helpers/scroll_into_view_promise.js new file mode 100644 index 00000000000..0edea2103da --- /dev/null +++ b/spec/frontend/helpers/scroll_into_view_promise.js @@ -0,0 +1,28 @@ +export default function scrollIntoViewPromise(intersectionTarget, timeout = 100, maxTries = 5) { + return new Promise((resolve, reject) => { + let intersectionObserver; + let retry = 0; + + const intervalId = setInterval(() => { + if (retry >= maxTries) { + intersectionObserver.disconnect(); + clearInterval(intervalId); + reject(new Error(`Could not scroll target into viewPort within ${timeout * maxTries} ms`)); + } + retry += 1; + intersectionTarget.scrollIntoView(); + }, timeout); + + intersectionObserver = new IntersectionObserver(entries => { + if (entries[0].isIntersecting) { + intersectionObserver.disconnect(); + clearInterval(intervalId); + resolve(); + } + }); + + intersectionObserver.observe(intersectionTarget); + + intersectionTarget.scrollIntoView(); + }); +} diff --git a/spec/frontend/helpers/set_timeout_promise_helper.js b/spec/frontend/helpers/set_timeout_promise_helper.js new file mode 100644 index 00000000000..47087619187 --- /dev/null +++ b/spec/frontend/helpers/set_timeout_promise_helper.js @@ -0,0 +1,4 @@ +export default (time = 0) => + new Promise(resolve => { + setTimeout(resolve, time); + }); diff --git a/spec/frontend/helpers/user_mock_data_helper.js b/spec/frontend/helpers/user_mock_data_helper.js new file mode 100644 index 00000000000..6999fa1f8a1 --- /dev/null +++ b/spec/frontend/helpers/user_mock_data_helper.js @@ -0,0 +1,14 @@ +export default { + createNumberRandomUsers(numberUsers) { + const users = []; + for (let i = 0; i < numberUsers; i += 1) { + users.push({ + avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + id: i + 1, + name: `GitLab User ${i}`, + username: `gitlab${i}`, + }); + } + return users; + }, +}; diff --git a/spec/frontend/helpers/vue_component_helper.js b/spec/frontend/helpers/vue_component_helper.js new file mode 100644 index 00000000000..e0fe18e5560 --- /dev/null +++ b/spec/frontend/helpers/vue_component_helper.js @@ -0,0 +1,18 @@ +/** + * Replaces line break with an empty space + * @param {*} data + */ +export const removeBreakLine = data => data.replace(/\r?\n|\r/g, ' '); + +/** + * Removes line breaks, spaces and trims the given text + * @param {String} str + * @returns {String} + */ +export const trimText = str => + str + .replace(/\r?\n|\r/g, '') + .replace(/\s\s+/g, ' ') + .trim(); + +export const removeWhitespace = str => str.replace(/\s\s+/g, ' '); diff --git a/spec/frontend/helpers/vue_resource_helper.js b/spec/frontend/helpers/vue_resource_helper.js new file mode 100644 index 00000000000..0f58af09933 --- /dev/null +++ b/spec/frontend/helpers/vue_resource_helper.js @@ -0,0 +1,11 @@ +// eslint-disable-next-line import/prefer-default-export +export const headersInterceptor = (request, next) => { + next(response => { + const headers = {}; + response.headers.forEach((value, key) => { + headers[key] = value; + }); + // eslint-disable-next-line no-param-reassign + response.headers = headers; + }); +}; diff --git a/spec/frontend/helpers/vue_test_utils_helper.js b/spec/frontend/helpers/vue_test_utils_helper.js new file mode 100644 index 00000000000..19e27388eeb --- /dev/null +++ b/spec/frontend/helpers/vue_test_utils_helper.js @@ -0,0 +1,19 @@ +/* eslint-disable import/prefer-default-export */ + +const vNodeContainsText = (vnode, text) => + (vnode.text && vnode.text.includes(text)) || + (vnode.children && vnode.children.filter(child => vNodeContainsText(child, text)).length); + +/** + * Determines whether a `shallowMount` Wrapper contains text + * within one of it's slots. This will also work on Wrappers + * acquired with `find()`, but only if it's parent Wrapper + * was shallowMounted. + * NOTE: Prefer checking the rendered output of a component + * wherever possible using something like `text()` instead. + * @param {Wrapper} shallowWrapper - Vue test utils wrapper (shallowMounted) + * @param {String} slotName + * @param {String} text + */ +export const shallowWrapperContainsSlotText = (shallowWrapper, slotName, text) => + !!shallowWrapper.vm.$slots[slotName].filter(vnode => vNodeContainsText(vnode, text)).length; diff --git a/spec/frontend/helpers/vuex_action_helper.js b/spec/frontend/helpers/vuex_action_helper.js new file mode 100644 index 00000000000..88652202a8e --- /dev/null +++ b/spec/frontend/helpers/vuex_action_helper.js @@ -0,0 +1,104 @@ +const noop = () => {}; + +/** + * Helper for testing action with expected mutations inspired in + * https://vuex.vuejs.org/en/testing.html + * + * @param {Function} action to be tested + * @param {Object} payload will be provided to the action + * @param {Object} state will be provided to the action + * @param {Array} [expectedMutations=[]] mutations expected to be committed + * @param {Array} [expectedActions=[]] actions expected to be dispatched + * @param {Function} [done=noop] to be executed after the tests + * @return {Promise} + * + * @example + * testAction( + * actions.actionName, // action + * { }, // mocked payload + * state, //state + * // expected mutations + * [ + * { type: types.MUTATION} + * { type: types.MUTATION_1, payload: jasmine.any(Number)} + * ], + * // expected actions + * [ + * { type: 'actionName', payload: {param: 'foobar'}}, + * { type: 'actionName1'} + * ] + * done, + * ); + * + * @example + * testAction( + * actions.actionName, // action + * { }, // mocked payload + * state, //state + * [ { type: types.MUTATION} ], // expected mutations + * [], // expected actions + * ).then(done) + * .catch(done.fail); + */ +export default ( + action, + payload, + state, + expectedMutations = [], + expectedActions = [], + done = noop, +) => { + const mutations = []; + const actions = []; + + // mock commit + const commit = (type, mutationPayload) => { + const mutation = { type }; + + if (typeof mutationPayload !== 'undefined') { + mutation.payload = mutationPayload; + } + + mutations.push(mutation); + }; + + // mock dispatch + const dispatch = (type, actionPayload) => { + const dispatchedAction = { type }; + + if (typeof actionPayload !== 'undefined') { + dispatchedAction.payload = actionPayload; + } + + actions.push(dispatchedAction); + }; + + const validateResults = () => { + expect({ + mutations, + actions, + }).toEqual({ + mutations: expectedMutations, + actions: expectedActions, + }); + done(); + }; + + const result = action( + { commit, state, dispatch, rootState: state, rootGetters: state, getters: state }, + payload, + ); + + return new Promise(resolve => { + setImmediate(resolve); + }) + .then(() => result) + .catch(error => { + validateResults(); + throw error; + }) + .then(data => { + validateResults(); + return data; + }); +}; diff --git a/spec/frontend/helpers/wait_for_attribute_change.js b/spec/frontend/helpers/wait_for_attribute_change.js new file mode 100644 index 00000000000..8f22d569222 --- /dev/null +++ b/spec/frontend/helpers/wait_for_attribute_change.js @@ -0,0 +1,16 @@ +export default (domElement, attributes, timeout = 1500) => + new Promise((resolve, reject) => { + let observer; + const timeoutId = setTimeout(() => { + observer.disconnect(); + reject(new Error(`Could not see an attribute update within ${timeout} ms`)); + }, timeout); + + observer = new MutationObserver(() => { + clearTimeout(timeoutId); + observer.disconnect(); + resolve(); + }); + + observer.observe(domElement, { attributes: true, attributeFilter: attributes }); + }); diff --git a/spec/frontend/helpers/wait_for_promises.js b/spec/frontend/helpers/wait_for_promises.js new file mode 100644 index 00000000000..1d2b53fc770 --- /dev/null +++ b/spec/frontend/helpers/wait_for_promises.js @@ -0,0 +1 @@ +export default () => new Promise(resolve => requestAnimationFrame(resolve)); diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js index 23d07056925..1e0bc708c31 100644 --- a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js +++ b/spec/frontend/pages/admin/abuse_reports/abuse_reports_spec.js @@ -3,7 +3,7 @@ import '~/lib/utils/text_utility'; import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports'; describe('Abuse Reports', () => { - const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw'; + const FIXTURE = 'abuse_reports/abuse_reports_list.html'; const MAX_MESSAGE_LENGTH = 500; let $messages; @@ -16,9 +16,9 @@ describe('Abuse Reports', () => { preloadFixtures(FIXTURE); - beforeEach(function() { + beforeEach(() => { loadFixtures(FIXTURE); - this.abuseReports = new AbuseReports(); + new AbuseReports(); // eslint-disable-line no-new $messages = $('.abuse-reports .message'); }); diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js index 006fc60ef57..1e3c28e25eb 100644 --- a/spec/frontend/test_setup.js +++ b/spec/frontend/test_setup.js @@ -2,6 +2,7 @@ import Vue from 'vue'; import Translate from '~/vue_shared/translate'; import axios from '~/lib/utils/axios_utils'; import { initializeTestTimeout } from './helpers/timeout'; +import { getJSONFixture, loadHTMLFixture, setHTMLFixture } from './helpers/fixtures'; // wait for pending setTimeout()s afterEach(() => { @@ -22,4 +23,24 @@ beforeEach(done => { done(); }); +Vue.config.devtools = false; +Vue.config.productionTip = false; + Vue.use(Translate); + +// workaround for JSDOM not supporting innerText +// see https://github.com/jsdom/jsdom/issues/1245 +Object.defineProperty(global.Element.prototype, 'innerText', { + get() { + return this.textContent; + }, + configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch +}); + +// convenience wrapper for migration from Karma +Object.assign(global, { + loadFixtures: loadHTMLFixture, + loadJSONFixtures: getJSONFixture, + preloadFixtures() {}, + setFixtures: setHTMLFixture, +}); diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb index 8d717b968dd..a3511e078ce 100644 --- a/spec/helpers/appearances_helper_spec.rb +++ b/spec/helpers/appearances_helper_spec.rb @@ -65,12 +65,10 @@ describe AppearancesHelper do end describe '#brand_title' do - it 'returns the default CE title when no appearance is present' do - allow(helper) - .to receive(:current_appearance) - .and_return(nil) + it 'returns the default title when no appearance is present' do + allow(helper).to receive(:current_appearance).and_return(nil) - expect(helper.brand_title).to eq('GitLab Community Edition') + expect(helper.brand_title).to eq(helper.default_brand_title) end end end diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index 2ba8b3dbf22..aae515def0c 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe AuthHelper do diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 540a8674ec2..91541a16c13 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupsHelper do diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb index 8b82dea2524..1d1446eaa30 100644 --- a/spec/helpers/issuables_helper_spec.rb +++ b/spec/helpers/issuables_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe IssuablesHelper do @@ -176,7 +178,7 @@ describe IssuablesHelper do stub_commonmark_sourcepos_disabled end - it 'returns the correct json for an issue' do + it 'returns the correct data for an issue' do issue = create(:issue, author: user, description: 'issue text') @project = issue.project @@ -198,7 +200,7 @@ describe IssuablesHelper do initialDescriptionText: 'issue text', initialTaskStatus: '0 of 0 tasks completed' } - expect(helper.issuable_initial_data(issue)).to eq(expected_data) + expect(helper.issuable_initial_data(issue)).to match(hash_including(expected_data)) end end end diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 885204062fe..193390d2f2c 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MergeRequestsHelper do diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 291eafece94..37c63807c82 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectsHelper do diff --git a/spec/javascripts/activities_spec.js b/spec/javascripts/activities_spec.js index 068b8eb65bc..23b6de7e4e0 100644 --- a/spec/javascripts/activities_spec.js +++ b/spec/javascripts/activities_spec.js @@ -7,7 +7,7 @@ import Pager from '~/pager'; describe('Activities', () => { window.gon || (window.gon = {}); - const fixtureTemplate = 'static/event_filter.html.raw'; + const fixtureTemplate = 'static/event_filter.html'; const filters = [ { id: 'all', diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 9389fc94f17..89195a4397f 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import AjaxLoadingSpinner from '~/ajax_loading_spinner'; describe('Ajax Loading Spinner', () => { - const fixtureTemplate = 'static/ajax_loading_spinner.html.raw'; + const fixtureTemplate = 'static/ajax_loading_spinner.html'; preloadFixtures(fixtureTemplate); beforeEach(() => { diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index e5b5707dcef..e10df1b45e7 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -24,13 +24,13 @@ const lazyAssert = function(done, assertFn) { describe('AwardsHandler', function() { const emojiData = getJSONFixture('emojis/emojis.json'); - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(function(done) { mock = new MockAdapter(axios); mock.onGet(`/-/emojis/${EMOJI_VERSION}/emojis.json`).reply(200, emojiData); - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); loadAwardsHandler(true) .then(obj => { awardsHandler = obj; diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 681463aab66..7af8c984841 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -4,10 +4,10 @@ import '~/behaviors/quick_submit'; describe('Quick Submit behavior', function() { const keydownEvent = (options = { keyCode: 13, metaKey: true }) => $.Event('keydown', options); - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(() => { - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); $('form').submit(e => { // Prevent a form submit from moving us off the testing page e.preventDefault(); diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 1bde2bb3024..617fe49b059 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -3,10 +3,10 @@ import '~/behaviors/requires_input'; describe('requiresInput', () => { let submitButton; - preloadFixtures('branches/new_branch.html.raw'); + preloadFixtures('branches/new_branch.html'); beforeEach(() => { - loadFixtures('branches/new_branch.html.raw'); + loadFixtures('branches/new_branch.html'); submitButton = $('button[type="submit"]'); }); diff --git a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js index 4843a0386b5..5e457a4e823 100644 --- a/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js +++ b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js @@ -9,7 +9,7 @@ import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; const FORM_SELECTOR = '.js-main-target-form .js-vue-comment-form'; describe('ShortcutsIssuable', function() { - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; preloadFixtures(fixtureName); beforeAll(done => { diff --git a/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js b/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js index 5f027f59fcf..68b4f261617 100644 --- a/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js +++ b/spec/javascripts/blob/balsamiq/balsamiq_viewer_integration_spec.js @@ -6,10 +6,10 @@ describe('Balsamiq integration spec', () => { let endpoint; let balsamiqViewer; - preloadFixtures('static/balsamiq_viewer.html.raw'); + preloadFixtures('static/balsamiq_viewer.html'); beforeEach(() => { - loadFixtures('static/balsamiq_viewer.html.raw'); + loadFixtures('static/balsamiq_viewer.html'); container = document.getElementById('js-balsamiq-viewer'); balsamiqViewer = new BalsamiqViewer(container); diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js index 432d8a65b0a..cab06a0a9be 100644 --- a/spec/javascripts/blob/blob_file_dropzone_spec.js +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import BlobFileDropzone from '~/blob/blob_file_dropzone'; describe('BlobFileDropzone', function() { - preloadFixtures('blob/show.html.raw'); + preloadFixtures('blob/show.html'); beforeEach(() => { - loadFixtures('blob/show.html.raw'); + loadFixtures('blob/show.html'); const form = $('.js-upload-blob-form'); this.blobFileDropzone = new BlobFileDropzone(form, 'POST'); this.dropzone = $('.js-upload-blob-form .dropzone').get(0).dropzone; diff --git a/spec/javascripts/blob/notebook/index_spec.js b/spec/javascripts/blob/notebook/index_spec.js index 28d3b2f5ea3..6bb5bac007f 100644 --- a/spec/javascripts/blob/notebook/index_spec.js +++ b/spec/javascripts/blob/notebook/index_spec.js @@ -3,10 +3,10 @@ import axios from '~/lib/utils/axios_utils'; import renderNotebook from '~/blob/notebook'; describe('iPython notebook renderer', () => { - preloadFixtures('static/notebook_viewer.html.raw'); + preloadFixtures('static/notebook_viewer.html'); beforeEach(() => { - loadFixtures('static/notebook_viewer.html.raw'); + loadFixtures('static/notebook_viewer.html'); }); it('shows loading icon', () => { diff --git a/spec/javascripts/blob/pdf/index_spec.js b/spec/javascripts/blob/pdf/index_spec.js index be917a0613f..acf87580777 100644 --- a/spec/javascripts/blob/pdf/index_spec.js +++ b/spec/javascripts/blob/pdf/index_spec.js @@ -15,10 +15,10 @@ describe('PDF renderer', () => { } }; - preloadFixtures('static/pdf_viewer.html.raw'); + preloadFixtures('static/pdf_viewer.html'); beforeEach(() => { - loadFixtures('static/pdf_viewer.html.raw'); + loadFixtures('static/pdf_viewer.html'); viewer = document.getElementById('js-pdf-viewer'); viewer.dataset.endpoint = testPDF; }); diff --git a/spec/javascripts/blob/sketch/index_spec.js b/spec/javascripts/blob/sketch/index_spec.js index 2b1e81e9cbc..3d3129e10da 100644 --- a/spec/javascripts/blob/sketch/index_spec.js +++ b/spec/javascripts/blob/sketch/index_spec.js @@ -13,10 +13,10 @@ describe('Sketch viewer', () => { }); }; - preloadFixtures('static/sketch_viewer.html.raw'); + preloadFixtures('static/sketch_viewer.html'); beforeEach(() => { - loadFixtures('static/sketch_viewer.html.raw'); + loadFixtures('static/sketch_viewer.html'); }); describe('with error message', () => { diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js index 93a942fe8d4..4ac15ca5aa2 100644 --- a/spec/javascripts/blob/viewer/index_spec.js +++ b/spec/javascripts/blob/viewer/index_spec.js @@ -9,12 +9,12 @@ describe('Blob viewer', () => { let blob; let mock; - preloadFixtures('snippets/show.html.raw'); + preloadFixtures('snippets/show.html'); beforeEach(() => { mock = new MockAdapter(axios); - loadFixtures('snippets/show.html.raw'); + loadFixtures('snippets/show.html'); $('#modal-upload-blob').remove(); blob = new BlobViewer(); diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js index dee7841c088..6e6b3e6950b 100644 --- a/spec/javascripts/boards/components/board_spec.js +++ b/spec/javascripts/boards/components/board_spec.js @@ -9,7 +9,7 @@ describe('Board component', () => { let el; beforeEach(done => { - loadFixtures('boards/show.html.raw'); + loadFixtures('boards/show.html'); el = document.createElement('div'); document.body.appendChild(el); diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js index c3e3d78ff63..1d21637ceae 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js @@ -1,10 +1,10 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs'; describe('Linked Tabs', () => { - preloadFixtures('static/linked_tabs.html.raw'); + preloadFixtures('static/linked_tabs.html'); beforeEach(() => { - loadFixtures('static/linked_tabs.html.raw'); + loadFixtures('static/linked_tabs.html'); }); describe('when is initialized', () => { diff --git a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js index 1fc0e206d5e..481b1a4d4b0 100644 --- a/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ajax_variable_list_spec.js @@ -7,8 +7,8 @@ const VARIABLE_PATCH_ENDPOINT = 'http://test.host/frontend-fixtures/builds-proje const HIDE_CLASS = 'hide'; describe('AjaxFormVariableList', () => { - preloadFixtures('projects/ci_cd_settings.html.raw'); - preloadFixtures('projects/ci_cd_settings_with_variables.html.raw'); + preloadFixtures('projects/ci_cd_settings.html'); + preloadFixtures('projects/ci_cd_settings_with_variables.html'); let container; let saveButton; @@ -18,7 +18,7 @@ describe('AjaxFormVariableList', () => { let ajaxVariableList; beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); container = document.querySelector('.js-ci-variable-list-section'); mock = new MockAdapter(axios); @@ -168,7 +168,7 @@ describe('AjaxFormVariableList', () => { describe('updateRowsWithPersistedVariables', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings_with_variables.html.raw'); + loadFixtures('projects/ci_cd_settings_with_variables.html'); container = document.querySelector('.js-ci-variable-list-section'); const ajaxVariableListEl = document.querySelector('.js-ci-variable-list-section'); diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js index bef59b86d0c..70f49469300 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -5,9 +5,9 @@ import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; const HIDE_CLASS = 'hide'; describe('VariableList', () => { - preloadFixtures('pipeline_schedules/edit.html.raw'); - preloadFixtures('pipeline_schedules/edit_with_variables.html.raw'); - preloadFixtures('projects/ci_cd_settings.html.raw'); + preloadFixtures('pipeline_schedules/edit.html'); + preloadFixtures('pipeline_schedules/edit_with_variables.html'); + preloadFixtures('projects/ci_cd_settings.html'); let $wrapper; let variableList; @@ -15,7 +15,7 @@ describe('VariableList', () => { describe('with only key/value inputs', () => { describe('with no variables', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit.html.raw'); + loadFixtures('pipeline_schedules/edit.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -82,7 +82,7 @@ describe('VariableList', () => { describe('with persisted variables', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit_with_variables.html.raw'); + loadFixtures('pipeline_schedules/edit_with_variables.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -115,7 +115,7 @@ describe('VariableList', () => { describe('with all inputs(key, value, protected)', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); $wrapper = $('.js-ci-variable-list-section'); $wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false'); @@ -149,7 +149,7 @@ describe('VariableList', () => { describe('toggleEnableRow method', () => { beforeEach(() => { - loadFixtures('pipeline_schedules/edit_with_variables.html.raw'); + loadFixtures('pipeline_schedules/edit_with_variables.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ @@ -198,7 +198,7 @@ describe('VariableList', () => { describe('hideValues', () => { beforeEach(() => { - loadFixtures('projects/ci_cd_settings.html.raw'); + loadFixtures('projects/ci_cd_settings.html'); $wrapper = $('.js-ci-variable-list-section'); variableList = new VariableList({ diff --git a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js index 997d0d54d79..4982b68fa81 100644 --- a/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/native_form_variable_list_spec.js @@ -2,12 +2,12 @@ import $ from 'jquery'; import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; describe('NativeFormVariableList', () => { - preloadFixtures('pipeline_schedules/edit.html.raw'); + preloadFixtures('pipeline_schedules/edit.html'); let $wrapper; beforeEach(() => { - loadFixtures('pipeline_schedules/edit.html.raw'); + loadFixtures('pipeline_schedules/edit.html'); $wrapper = $('.js-ci-variable-list-section'); setupNativeFormVariableList({ diff --git a/spec/javascripts/clusters/clusters_bundle_spec.js b/spec/javascripts/clusters/clusters_bundle_spec.js index 71f16dc259e..0d3dcc29f22 100644 --- a/spec/javascripts/clusters/clusters_bundle_spec.js +++ b/spec/javascripts/clusters/clusters_bundle_spec.js @@ -9,10 +9,10 @@ import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; describe('Clusters', () => { let cluster; - preloadFixtures('clusters/show_cluster.html.raw'); + preloadFixtures('clusters/show_cluster.html'); beforeEach(() => { - loadFixtures('clusters/show_cluster.html.raw'); + loadFixtures('clusters/show_cluster.html'); cluster = new Clusters(); }); diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js index dc5737558c0..bb90e53e525 100644 --- a/spec/javascripts/collapsed_sidebar_todo_spec.js +++ b/spec/javascripts/collapsed_sidebar_todo_spec.js @@ -6,7 +6,7 @@ import Sidebar from '~/right_sidebar'; import timeoutPromise from './helpers/set_timeout_promise_helper'; describe('Issuable right sidebar collapsed todo toggle', () => { - const fixtureName = 'issues/open-issue.html.raw'; + const fixtureName = 'issues/open-issue.html'; const jsonFixtureName = 'todos/todos.json'; let mock; diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js index 9cf72d7c55b..a814952faab 100644 --- a/spec/javascripts/create_item_dropdown_spec.js +++ b/spec/javascripts/create_item_dropdown_spec.js @@ -20,7 +20,7 @@ const DROPDOWN_ITEM_DATA = [ ]; describe('CreateItemDropdown', () => { - preloadFixtures('static/create_item_dropdown.html.raw'); + preloadFixtures('static/create_item_dropdown.html'); let $wrapperEl; let createItemDropdown; @@ -44,7 +44,7 @@ describe('CreateItemDropdown', () => { } beforeEach(() => { - loadFixtures('static/create_item_dropdown.html.raw'); + loadFixtures('static/create_item_dropdown.html'); $wrapperEl = $('.js-create-item-dropdown-fixture-root'); }); diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js index 2d10b8383e2..6614069f44d 100644 --- a/spec/javascripts/diffs/components/diff_file_header_spec.js +++ b/spec/javascripts/diffs/components/diff_file_header_spec.js @@ -23,9 +23,6 @@ describe('diff_file_header', () => { }); beforeEach(() => { - gon.features = { - expandDiffFullFile: true, - }; const diffFile = diffDiscussionMock.diff_file; diffFile.added_lines = 2; diff --git a/spec/javascripts/diffs/mock_data/diff_discussions.js b/spec/javascripts/diffs/mock_data/diff_discussions.js index fd5dd611383..711ab543411 100644 --- a/spec/javascripts/diffs/mock_data/diff_discussions.js +++ b/spec/javascripts/diffs/mock_data/diff_discussions.js @@ -496,7 +496,7 @@ export default { { text: 'line', rich_text: - '<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="1">\n1\n</td>\n<td class="line_content new noteable_line"><span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n</td>\n</tr>\n<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="2">\n2\n</td>\n<td class="line_content new noteable_line"><span id="LC2" class="line" lang="plaintext"></span>\n</td>\n</tr>\n', + '<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="1">\n1\n</td>\n<td class="line_content new"><span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n</td>\n</tr>\n<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="2">\n2\n</td>\n<td class="line_content new"><span id="LC2" class="line" lang="plaintext"></span>\n</td>\n</tr>\n', can_receive_suggestion: true, line_code: '6f209374f7e565f771b95720abf46024c41d1885_1_1', type: 'new', diff --git a/spec/javascripts/filtered_search/dropdown_user_spec.js b/spec/javascripts/filtered_search/dropdown_user_spec.js index e8fcc8592eb..f764800fff0 100644 --- a/spec/javascripts/filtered_search/dropdown_user_spec.js +++ b/spec/javascripts/filtered_search/dropdown_user_spec.js @@ -72,7 +72,7 @@ describe('Dropdown User', () => { }); describe('hideCurrentUser', () => { - const fixtureTemplate = 'issues/issue_list.html.raw'; + const fixtureTemplate = 'issues/issue_list.html'; preloadFixtures(fixtureTemplate); let dropdown; diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js index cfd0b96ec43..62d1bd69635 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js @@ -4,7 +4,7 @@ import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered import FilteredSearchSpecHelper from '../helpers/filtered_search_spec_helper'; describe('Dropdown Utils', () => { - const issueListFixture = 'issues/issue_list.html.raw'; + const issueListFixture = 'issues/issue_list.html'; preloadFixtures(issueListFixture); describe('getEscapedText', () => { diff --git a/spec/javascripts/fixtures/.gitignore b/spec/javascripts/fixtures/.gitignore index 0c35cdd778e..2507c8e7263 100644 --- a/spec/javascripts/fixtures/.gitignore +++ b/spec/javascripts/fixtures/.gitignore @@ -1,2 +1,3 @@ *.html.raw +*.html *.json diff --git a/spec/javascripts/fixtures/abuse_reports.rb b/spec/javascripts/fixtures/abuse_reports.rb index 387858cba77..54b6419bcdb 100644 --- a/spec/javascripts/fixtures/abuse_reports.rb +++ b/spec/javascripts/fixtures/abuse_reports.rb @@ -18,7 +18,7 @@ describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controll sign_in(admin) end - it 'abuse_reports/abuse_reports_list.html.raw' do |example| + it 'abuse_reports/abuse_reports_list.html' do |example| get :index expect(response).to be_success diff --git a/spec/javascripts/fixtures/admin_users.rb b/spec/javascripts/fixtures/admin_users.rb index 9989ac4fff2..76dbdf603da 100644 --- a/spec/javascripts/fixtures/admin_users.rb +++ b/spec/javascripts/fixtures/admin_users.rb @@ -17,7 +17,7 @@ describe Admin::UsersController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('admin/users') end - it 'admin/users/new_with_internal_user_regex.html.raw' do |example| + it 'admin/users/new_with_internal_user_regex.html' do |example| stub_application_setting(user_default_external: true) stub_application_setting(user_default_internal_regex: '^(?:(?!\.ext@).)*$\r?') diff --git a/spec/javascripts/fixtures/application_settings.rb b/spec/javascripts/fixtures/application_settings.rb index a9d3043f73d..c535e598e12 100644 --- a/spec/javascripts/fixtures/application_settings.rb +++ b/spec/javascripts/fixtures/application_settings.rb @@ -23,7 +23,7 @@ describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', type: :c remove_repository(project) end - it 'application_settings/accounts_and_limit.html.raw' do |example| + it 'application_settings/accounts_and_limit.html' do |example| stub_application_setting(user_default_external: false) get :show diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb index cd66d98f92a..db7749bc000 100644 --- a/spec/javascripts/fixtures/blob.rb +++ b/spec/javascripts/fixtures/blob.rb @@ -22,7 +22,7 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'blob/show.html.raw' do |example| + it 'blob/show.html' do |example| get(:show, params: { namespace_id: project.namespace, project_id: project, diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb index 1d675e008ba..c4390e89578 100644 --- a/spec/javascripts/fixtures/boards.rb +++ b/spec/javascripts/fixtures/boards.rb @@ -17,7 +17,7 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller sign_in(admin) end - it 'boards/show.html.raw' do |example| + it 'boards/show.html' do |example| get(:index, params: { namespace_id: project.namespace, project_id: project diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index 3cc713ef90f..5d2d6c7ec0e 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -21,7 +21,7 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'branches/new_branch.html.raw' do |example| + it 'branches/new_branch.html' do |example| get :new, params: { namespace_id: project.namespace.to_param, project_id: project diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb index 69dbe54ffc2..8ebd8a41366 100644 --- a/spec/javascripts/fixtures/clusters.rb +++ b/spec/javascripts/fixtures/clusters.rb @@ -22,7 +22,7 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'clusters/show_cluster.html.raw' do |example| + it 'clusters/show_cluster.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb index 295f13b34a4..ab10f559e4b 100644 --- a/spec/javascripts/fixtures/commit.rb +++ b/spec/javascripts/fixtures/commit.rb @@ -19,7 +19,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller allow(SecureRandom).to receive(:hex).and_return('securerandomhex:thereisnospoon') end - it 'commit/show.html.raw' do |example| + it 'commit/show.html' do |example| params = { namespace_id: project.namespace, project_id: project, diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb index 03136f4e661..16e31028b05 100644 --- a/spec/javascripts/fixtures/groups.rb +++ b/spec/javascripts/fixtures/groups.rb @@ -18,7 +18,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end describe GroupsController, '(JavaScript fixtures)', type: :controller do - it 'groups/edit.html.raw' do |example| + it 'groups/edit.html' do |example| get :edit, params: { id: group } expect(response).to be_success @@ -27,7 +27,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do end describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'groups/ci_cd_settings.html.raw' do |example| + it 'groups/ci_cd_settings.html' do |example| get :show, params: { group_id: group } expect(response).to be_success diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 9b8e90c2a43..645b3aa788a 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -21,26 +21,26 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller remove_repository(project) end - it 'issues/open-issue.html.raw' do |example| + it 'issues/open-issue.html' do |example| render_issue(example.description, create(:issue, project: project)) end - it 'issues/closed-issue.html.raw' do |example| + it 'issues/closed-issue.html' do |example| render_issue(example.description, create(:closed_issue, project: project)) end - it 'issues/issue-with-task-list.html.raw' do |example| + it 'issues/issue-with-task-list.html' do |example| issue = create(:issue, project: project, description: '- [ ] Task List Item') render_issue(example.description, issue) end - it 'issues/issue_with_comment.html.raw' do |example| + it 'issues/issue_with_comment.html' do |example| issue = create(:issue, project: project) create(:note, project: project, noteable: issue, note: '- [ ] Task List Item').save render_issue(example.description, issue) end - it 'issues/issue_list.html.raw' do |example| + it 'issues/issue_list.html' do |example| create(:issue, project: project) get :index, params: { diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb index 433bb690a1c..941235190b5 100644 --- a/spec/javascripts/fixtures/jobs.rb +++ b/spec/javascripts/fixtures/jobs.rb @@ -32,7 +32,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'builds/build-with-artifacts.html.raw' do |example| + it 'builds/build-with-artifacts.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index eb37be87e1d..7df1e5cb512 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -42,19 +42,19 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont remove_repository(project) end - it 'merge_requests/merge_request_of_current_user.html.raw' do |example| + it 'merge_requests/merge_request_of_current_user.html' do |example| merge_request.update(author: admin) render_merge_request(example.description, merge_request) end - it 'merge_requests/merge_request_with_task_list.html.raw' do |example| + it 'merge_requests/merge_request_with_task_list.html' do |example| create(:ci_build, :pending, pipeline: pipeline) render_merge_request(example.description, merge_request) end - it 'merge_requests/merged_merge_request.html.raw' do |example| + it 'merge_requests/merged_merge_request.html' do |example| expect_next_instance_of(MergeRequest) do |merge_request| allow(merge_request).to receive(:source_branch_exists?).and_return(true) allow(merge_request).to receive(:can_remove_source_branch?).and_return(true) @@ -62,13 +62,13 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont render_merge_request(example.description, merged_merge_request) end - it 'merge_requests/diff_comment.html.raw' do |example| + it 'merge_requests/diff_comment.html' do |example| create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request) create(:note_on_merge_request, author: admin, project: project, noteable: merge_request) render_merge_request(example.description, merge_request) end - it 'merge_requests/merge_request_with_comment.html.raw' do |example| + it 'merge_requests/merge_request_with_comment.html' do |example| create(:note_on_merge_request, author: admin, project: project, noteable: merge_request, note: '- [ ] Task List Item') render_merge_request(example.description, merge_request) end diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb index 05d79ec8de9..e5176a58273 100644 --- a/spec/javascripts/fixtures/pipeline_schedules.rb +++ b/spec/javascripts/fixtures/pipeline_schedules.rb @@ -21,7 +21,7 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : sign_in(admin) end - it 'pipeline_schedules/edit.html.raw' do |example| + it 'pipeline_schedules/edit.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, @@ -32,7 +32,7 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: : store_frontend_fixture(response, example.description) end - it 'pipeline_schedules/edit_with_variables.html.raw' do |example| + it 'pipeline_schedules/edit_with_variables.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, project_id: project, diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 85f02923804..446da83a7f9 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -28,7 +28,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end describe ProjectsController, '(JavaScript fixtures)', type: :controller do - it 'projects/dashboard.html.raw' do |example| + it 'projects/dashboard.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, id: project @@ -38,7 +38,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/overview.html.raw' do |example| + it 'projects/overview.html' do |example| get :show, params: { namespace_id: project_with_repo.namespace.to_param, id: project_with_repo @@ -48,7 +48,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/edit.html.raw' do |example| + it 'projects/edit.html' do |example| get :edit, params: { namespace_id: project.namespace.to_param, id: project @@ -60,7 +60,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do end describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do - it 'projects/ci_cd_settings.html.raw' do |example| + it 'projects/ci_cd_settings.html' do |example| get :show, params: { namespace_id: project.namespace.to_param, project_id: project @@ -70,7 +70,7 @@ describe 'Projects (JavaScript fixtures)', type: :controller do store_frontend_fixture(response, example.description) end - it 'projects/ci_cd_settings_with_variables.html.raw' do |example| + it 'projects/ci_cd_settings_with_variables.html' do |example| create(:ci_variable, project: project_variable_populated) create(:ci_variable, project: project_variable_populated) diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb index 746fbfd66dd..29dc95305b7 100644 --- a/spec/javascripts/fixtures/prometheus_service.rb +++ b/spec/javascripts/fixtures/prometheus_service.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/prometheus/prometheus_service.html.raw' do |example| + it 'services/prometheus/prometheus_service.html' do |example| get :edit, params: { namespace_id: namespace, project_id: project, diff --git a/spec/javascripts/fixtures/search.rb b/spec/javascripts/fixtures/search.rb index 703cd3d49fa..5f5b4d4e60d 100644 --- a/spec/javascripts/fixtures/search.rb +++ b/spec/javascripts/fixtures/search.rb @@ -9,7 +9,7 @@ describe SearchController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('search/') end - it 'search/show.html.raw' do |example| + it 'search/show.html' do |example| get :show expect(response).to be_success diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb index 6ccd74a07ff..dc7ee484c22 100644 --- a/spec/javascripts/fixtures/services.rb +++ b/spec/javascripts/fixtures/services.rb @@ -22,7 +22,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle remove_repository(project) end - it 'services/edit_service.html.raw' do |example| + it 'services/edit_service.html' do |example| get :edit, params: { namespace_id: namespace, project_id: project, diff --git a/spec/javascripts/fixtures/sessions.rb b/spec/javascripts/fixtures/sessions.rb index e90a58e8c54..8656dea696a 100644 --- a/spec/javascripts/fixtures/sessions.rb +++ b/spec/javascripts/fixtures/sessions.rb @@ -16,7 +16,7 @@ describe 'Sessions (JavaScript fixtures)' do set_devise_mapping(context: @request) end - it 'sessions/new.html.raw' do |example| + it 'sessions/new.html' do |example| get :new expect(response).to be_success diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb index bcd6546f3df..ebc5b793166 100644 --- a/spec/javascripts/fixtures/snippet.rb +++ b/spec/javascripts/fixtures/snippet.rb @@ -23,7 +23,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do remove_repository(project) end - it 'snippets/show.html.raw' do |example| + it 'snippets/show.html' do |example| create(:discussion_note_on_snippet, noteable: snippet, project: project, author: admin, note: '- [ ] Task List Item') get(:show, params: { id: snippet.to_param }) diff --git a/spec/javascripts/fixtures/static/ajax_loading_spinner.html.raw b/spec/javascripts/fixtures/static/ajax_loading_spinner.html index 0e1ebb32b1c..0e1ebb32b1c 100644 --- a/spec/javascripts/fixtures/static/ajax_loading_spinner.html.raw +++ b/spec/javascripts/fixtures/static/ajax_loading_spinner.html diff --git a/spec/javascripts/fixtures/static/balsamiq_viewer.html.raw b/spec/javascripts/fixtures/static/balsamiq_viewer.html index cdd723d1a84..cdd723d1a84 100644 --- a/spec/javascripts/fixtures/static/balsamiq_viewer.html.raw +++ b/spec/javascripts/fixtures/static/balsamiq_viewer.html diff --git a/spec/javascripts/fixtures/static/create_item_dropdown.html.raw b/spec/javascripts/fixtures/static/create_item_dropdown.html index d2d38370092..d2d38370092 100644 --- a/spec/javascripts/fixtures/static/create_item_dropdown.html.raw +++ b/spec/javascripts/fixtures/static/create_item_dropdown.html diff --git a/spec/javascripts/fixtures/static/event_filter.html.raw b/spec/javascripts/fixtures/static/event_filter.html index 8e9b6fb1b5c..8e9b6fb1b5c 100644 --- a/spec/javascripts/fixtures/static/event_filter.html.raw +++ b/spec/javascripts/fixtures/static/event_filter.html diff --git a/spec/javascripts/fixtures/static/gl_dropdown.html.raw b/spec/javascripts/fixtures/static/gl_dropdown.html index 08f6738414e..08f6738414e 100644 --- a/spec/javascripts/fixtures/static/gl_dropdown.html.raw +++ b/spec/javascripts/fixtures/static/gl_dropdown.html diff --git a/spec/javascripts/fixtures/static/gl_field_errors.html.raw b/spec/javascripts/fixtures/static/gl_field_errors.html index f8470e02b7c..f8470e02b7c 100644 --- a/spec/javascripts/fixtures/static/gl_field_errors.html.raw +++ b/spec/javascripts/fixtures/static/gl_field_errors.html diff --git a/spec/javascripts/fixtures/static/issuable_filter.html.raw b/spec/javascripts/fixtures/static/issuable_filter.html index 06b70fb43f1..06b70fb43f1 100644 --- a/spec/javascripts/fixtures/static/issuable_filter.html.raw +++ b/spec/javascripts/fixtures/static/issuable_filter.html diff --git a/spec/javascripts/fixtures/static/issue_sidebar_label.html.raw b/spec/javascripts/fixtures/static/issue_sidebar_label.html index ec8fb30f219..ec8fb30f219 100644 --- a/spec/javascripts/fixtures/static/issue_sidebar_label.html.raw +++ b/spec/javascripts/fixtures/static/issue_sidebar_label.html diff --git a/spec/javascripts/fixtures/static/line_highlighter.html.raw b/spec/javascripts/fixtures/static/line_highlighter.html index 897a25d6760..897a25d6760 100644 --- a/spec/javascripts/fixtures/static/line_highlighter.html.raw +++ b/spec/javascripts/fixtures/static/line_highlighter.html diff --git a/spec/javascripts/fixtures/static/linked_tabs.html.raw b/spec/javascripts/fixtures/static/linked_tabs.html index c25463bf1db..c25463bf1db 100644 --- a/spec/javascripts/fixtures/static/linked_tabs.html.raw +++ b/spec/javascripts/fixtures/static/linked_tabs.html diff --git a/spec/javascripts/fixtures/static/merge_requests_show.html.raw b/spec/javascripts/fixtures/static/merge_requests_show.html index e219d9462aa..87e36c9f315 100644 --- a/spec/javascripts/fixtures/static/merge_requests_show.html.raw +++ b/spec/javascripts/fixtures/static/merge_requests_show.html @@ -1,7 +1,7 @@ <a class="btn-close"></a> <div class="detail-page-description"> <div class="description js-task-list-container"> -<div class="wiki"> +<div class="md"> <ul class="task-list"> <li class="task-list-item"> <input class="task-list-item-checkbox" type="checkbox"> diff --git a/spec/javascripts/fixtures/static/mini_dropdown_graph.html.raw b/spec/javascripts/fixtures/static/mini_dropdown_graph.html index cd0b8dec3fc..cd0b8dec3fc 100644 --- a/spec/javascripts/fixtures/static/mini_dropdown_graph.html.raw +++ b/spec/javascripts/fixtures/static/mini_dropdown_graph.html diff --git a/spec/javascripts/fixtures/static/notebook_viewer.html.raw b/spec/javascripts/fixtures/static/notebook_viewer.html index 4bbb7bf1094..4bbb7bf1094 100644 --- a/spec/javascripts/fixtures/static/notebook_viewer.html.raw +++ b/spec/javascripts/fixtures/static/notebook_viewer.html diff --git a/spec/javascripts/fixtures/static/oauth_remember_me.html.raw b/spec/javascripts/fixtures/static/oauth_remember_me.html index 9ba1ffc72fe..9ba1ffc72fe 100644 --- a/spec/javascripts/fixtures/static/oauth_remember_me.html.raw +++ b/spec/javascripts/fixtures/static/oauth_remember_me.html diff --git a/spec/javascripts/fixtures/static/pdf_viewer.html.raw b/spec/javascripts/fixtures/static/pdf_viewer.html index 350d35a262f..350d35a262f 100644 --- a/spec/javascripts/fixtures/static/pdf_viewer.html.raw +++ b/spec/javascripts/fixtures/static/pdf_viewer.html diff --git a/spec/javascripts/fixtures/static/pipeline_graph.html.raw b/spec/javascripts/fixtures/static/pipeline_graph.html index 422372bb7d5..422372bb7d5 100644 --- a/spec/javascripts/fixtures/static/pipeline_graph.html.raw +++ b/spec/javascripts/fixtures/static/pipeline_graph.html diff --git a/spec/javascripts/fixtures/static/pipelines.html.raw b/spec/javascripts/fixtures/static/pipelines.html index 42333f94f2f..42333f94f2f 100644 --- a/spec/javascripts/fixtures/static/pipelines.html.raw +++ b/spec/javascripts/fixtures/static/pipelines.html diff --git a/spec/javascripts/fixtures/static/project_select_combo_button.html.raw b/spec/javascripts/fixtures/static/project_select_combo_button.html index 50c826051c0..50c826051c0 100644 --- a/spec/javascripts/fixtures/static/project_select_combo_button.html.raw +++ b/spec/javascripts/fixtures/static/project_select_combo_button.html diff --git a/spec/javascripts/fixtures/static/search_autocomplete.html.raw b/spec/javascripts/fixtures/static/search_autocomplete.html index 29db9020424..29db9020424 100644 --- a/spec/javascripts/fixtures/static/search_autocomplete.html.raw +++ b/spec/javascripts/fixtures/static/search_autocomplete.html diff --git a/spec/javascripts/fixtures/static/signin_tabs.html.raw b/spec/javascripts/fixtures/static/signin_tabs.html index 7e66ab9394b..7e66ab9394b 100644 --- a/spec/javascripts/fixtures/static/signin_tabs.html.raw +++ b/spec/javascripts/fixtures/static/signin_tabs.html diff --git a/spec/javascripts/fixtures/static/sketch_viewer.html.raw b/spec/javascripts/fixtures/static/sketch_viewer.html index e25e554e568..e25e554e568 100644 --- a/spec/javascripts/fixtures/static/sketch_viewer.html.raw +++ b/spec/javascripts/fixtures/static/sketch_viewer.html diff --git a/spec/javascripts/fixtures/static_fixtures.rb b/spec/javascripts/fixtures/static_fixtures.rb index b5188eeb994..cb4b90cdca5 100644 --- a/spec/javascripts/fixtures/static_fixtures.rb +++ b/spec/javascripts/fixtures/static_fixtures.rb @@ -4,7 +4,7 @@ describe ApplicationController, '(Static JavaScript fixtures)', type: :controlle include JavaScriptFixturesHelpers Dir.glob('{,ee/}spec/javascripts/fixtures/**/*.haml').map do |file_path| - it "static/#{file_path.sub(%r{\A(ee/)?spec/javascripts/fixtures/}, '').sub(/\.haml\z/, '.raw')}" do |example| + it "static/#{file_path.sub(%r{\A(ee/)?spec/javascripts/fixtures/}, '').sub(/\.haml\z/, '')}" do |example| store_frontend_fixture(render_template(file_path), example.description) end end diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index b5f6620873b..6e37a2e5a4c 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -26,7 +26,7 @@ describe 'Todos (JavaScript fixtures)' do sign_in(admin) end - it 'todos/todos.html.raw' do |example| + it 'todos/todos.html' do |example| get :index expect(response).to be_success diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb index 5cdbadef639..15866d65a4f 100644 --- a/spec/javascripts/fixtures/u2f.rb +++ b/spec/javascripts/fixtures/u2f.rb @@ -18,7 +18,7 @@ context 'U2F' do set_devise_mapping(context: @request) end - it 'u2f/authenticate.html.raw' do |example| + it 'u2f/authenticate.html' do |example| allow(controller).to receive(:find_user).and_return(user) post :create, params: { user: { login: user.username, password: user.password } } @@ -36,7 +36,7 @@ context 'U2F' do allow_any_instance_of(Profiles::TwoFactorAuthsController).to receive(:build_qr_code).and_return('qrcode:blackandwhitesquares') end - it 'u2f/register.html.raw' do |example| + it 'u2f/register.html' do |example| get :show expect(response).to be_success diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 85083653db8..57e31d933ca 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -5,7 +5,7 @@ import GLDropdown from '~/gl_dropdown'; import '~/lib/utils/common_utils'; describe('glDropdown', function describeDropdown() { - preloadFixtures('static/gl_dropdown.html.raw'); + preloadFixtures('static/gl_dropdown.html'); loadJSONFixtures('projects.json'); const NON_SELECTABLE_CLASSES = @@ -64,7 +64,7 @@ describe('glDropdown', function describeDropdown() { } beforeEach(() => { - loadFixtures('static/gl_dropdown.html.raw'); + loadFixtures('static/gl_dropdown.html'); this.dropdownContainerElement = $('.dropdown.inline'); this.$dropdownMenuElement = $('.dropdown-menu', this.dropdownContainerElement); this.projectsData = getJSONFixture('projects.json'); diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/javascripts/gl_field_errors_spec.js index b463c9afbee..294f219d6fe 100644 --- a/spec/javascripts/gl_field_errors_spec.js +++ b/spec/javascripts/gl_field_errors_spec.js @@ -4,10 +4,10 @@ import $ from 'jquery'; import GlFieldErrors from '~/gl_field_errors'; describe('GL Style Field Errors', function() { - preloadFixtures('static/gl_field_errors.html.raw'); + preloadFixtures('static/gl_field_errors.html'); beforeEach(function() { - loadFixtures('static/gl_field_errors.html.raw'); + loadFixtures('static/gl_field_errors.html'); const $form = $('form.gl-show-field-errors'); this.$form = $form; diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 2fe34e5a76f..0ddf589f368 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -3,7 +3,7 @@ import initTodoToggle from '~/header'; describe('Header', function() { const todosPendingCount = '.todos-count'; - const fixtureTemplate = 'issues/open-issue.html.raw'; + const fixtureTemplate = 'issues/open-issue.html'; function isTodosCountHidden() { return $(todosPendingCount).hasClass('hidden'); diff --git a/spec/javascripts/ide/components/error_message_spec.js b/spec/javascripts/ide/components/error_message_spec.js index 430e8e2baa3..80d6c7fd564 100644 --- a/spec/javascripts/ide/components/error_message_spec.js +++ b/spec/javascripts/ide/components/error_message_spec.js @@ -84,7 +84,7 @@ describe('IDE error message component', () => { expect(vm.isLoading).toBe(true); - vm.$nextTick(() => { + setTimeout(() => { expect(vm.isLoading).toBe(false); done(); diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js index 7ddc734ff56..1e5b55af4ba 100644 --- a/spec/javascripts/ide/stores/actions/file_spec.js +++ b/spec/javascripts/ide/stores/actions/file_spec.js @@ -121,68 +121,48 @@ describe('IDE store file actions', () => { store._actions.scrollToTab = oldScrollToTab; // eslint-disable-line }); - it('calls scrollToTab', done => { - store - .dispatch('setFileActive', localFile.path) - .then(() => { - expect(scrollToTabSpy).toHaveBeenCalled(); - - done(); - }) - .catch(done.fail); - }); + it('calls scrollToTab', () => { + const dispatch = jasmine.createSpy(); - it('sets the file active', done => { - store - .dispatch('setFileActive', localFile.path) - .then(() => { - expect(localFile.active).toBeTruthy(); + actions.setFileActive( + { commit() {}, state: store.state, getters: store.getters, dispatch }, + localFile.path, + ); - done(); - }) - .catch(done.fail); + expect(dispatch).toHaveBeenCalledWith('scrollToTab'); }); - it('returns early if file is already active', done => { - localFile.active = true; + it('commits SET_FILE_ACTIVE', () => { + const commit = jasmine.createSpy(); - store - .dispatch('setFileActive', localFile.path) - .then(() => { - expect(scrollToTabSpy).not.toHaveBeenCalled(); + actions.setFileActive( + { commit, state: store.state, getters: store.getters, dispatch() {} }, + localFile.path, + ); - done(); - }) - .catch(done.fail); + expect(commit).toHaveBeenCalledWith('SET_FILE_ACTIVE', { + path: localFile.path, + active: true, + }); }); - it('sets current active file to not active', done => { + it('sets current active file to not active', () => { const f = file('newActive'); store.state.entries[f.path] = f; localFile.active = true; store.state.openFiles.push(localFile); - store - .dispatch('setFileActive', f.path) - .then(() => { - expect(localFile.active).toBeFalsy(); + const commit = jasmine.createSpy(); - done(); - }) - .catch(done.fail); - }); - - it('resets location.hash for line highlighting', done => { - window.location.hash = 'test'; - - store - .dispatch('setFileActive', localFile.path) - .then(() => { - expect(window.location.hash).not.toBe('test'); + actions.setFileActive( + { commit, state: store.state, getters: store.getters, dispatch() {} }, + f.path, + ); - done(); - }) - .catch(done.fail); + expect(commit).toHaveBeenCalledWith('SET_FILE_ACTIVE', { + path: localFile.path, + active: false, + }); }); }); diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index 4f4c9a7b463..069e2cb07b5 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -4,7 +4,7 @@ import axios from '~/lib/utils/axios_utils'; import IntegrationSettingsForm from '~/integrations/integration_settings_form'; describe('IntegrationSettingsForm', () => { - const FIXTURE = 'services/edit_service.html.raw'; + const FIXTURE = 'services/edit_service.html'; preloadFixtures(FIXTURE); beforeEach(() => { diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js index 0ccf771c7ef..dfc889773c1 100644 --- a/spec/javascripts/issue_show/components/app_spec.js +++ b/spec/javascripts/issue_show/components/app_spec.js @@ -75,7 +75,7 @@ describe('Issuable output', () => { .then(() => { expect(document.querySelector('title').innerText).toContain('this is a title (#1)'); expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>this is a title</p>'); - expect(vm.$el.querySelector('.wiki').innerHTML).toContain('<p>this is a description!</p>'); + expect(vm.$el.querySelector('.md').innerHTML).toContain('<p>this is a description!</p>'); expect(vm.$el.querySelector('.js-task-list-field').value).toContain( 'this is a description', ); @@ -92,7 +92,7 @@ describe('Issuable output', () => { .then(() => { expect(document.querySelector('title').innerText).toContain('2 (#1)'); expect(vm.$el.querySelector('.title').innerHTML).toContain('<p>2</p>'); - expect(vm.$el.querySelector('.wiki').innerHTML).toContain('<p>42</p>'); + expect(vm.$el.querySelector('.md').innerHTML).toContain('<p>42</p>'); expect(vm.$el.querySelector('.js-task-list-field').value).toContain('42'); expect(vm.$el.querySelector('.edited-text')).toBeTruthy(); expect(formatText(vm.$el.querySelector('.edited-text').innerText)).toMatch( diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js index 2eeed6770be..7e00fbf2745 100644 --- a/spec/javascripts/issue_show/components/description_spec.js +++ b/spec/javascripts/issue_show/components/description_spec.js @@ -43,12 +43,12 @@ describe('Description component', () => { Vue.nextTick(() => { expect( - vm.$el.querySelector('.wiki').classList.contains('issue-realtime-pre-pulse'), + vm.$el.querySelector('.md').classList.contains('issue-realtime-pre-pulse'), ).toBeTruthy(); setTimeout(() => { expect( - vm.$el.querySelector('.wiki').classList.contains('issue-realtime-trigger-pulse'), + vm.$el.querySelector('.md').classList.contains('issue-realtime-trigger-pulse'), ).toBeTruthy(); done(); diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 7be495d1d35..11ab6c38a55 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -9,9 +9,9 @@ import '~/lib/utils/text_utility'; describe('Issue', function() { let $boxClosed, $boxOpen, $btn; - preloadFixtures('issues/closed-issue.html.raw'); - preloadFixtures('issues/issue-with-task-list.html.raw'); - preloadFixtures('issues/open-issue.html.raw'); + preloadFixtures('issues/closed-issue.html'); + preloadFixtures('issues/issue-with-task-list.html'); + preloadFixtures('issues/open-issue.html'); function expectErrorMessage() { const $flashMessage = $('div.flash-alert'); @@ -105,9 +105,9 @@ describe('Issue', function() { beforeEach(function() { if (isIssueInitiallyOpen) { - loadFixtures('issues/open-issue.html.raw'); + loadFixtures('issues/open-issue.html'); } else { - loadFixtures('issues/closed-issue.html.raw'); + loadFixtures('issues/closed-issue.html'); } mock = new MockAdapter(axios); diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js index e5678ee5379..ccf439aac74 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js +++ b/spec/javascripts/labels_issue_sidebar_spec.js @@ -16,10 +16,10 @@ let saveLabelCount = 0; let mock; describe('Issue dropdown sidebar', () => { - preloadFixtures('static/issue_sidebar_label.html.raw'); + preloadFixtures('static/issue_sidebar_label.html'); beforeEach(() => { - loadFixtures('static/issue_sidebar_label.html.raw'); + loadFixtures('static/issue_sidebar_label.html'); mock = new MockAdapter(axios); diff --git a/spec/javascripts/lazy_loader_spec.js b/spec/javascripts/lazy_loader_spec.js index cbdc1644430..f3fb792c62d 100644 --- a/spec/javascripts/lazy_loader_spec.js +++ b/spec/javascripts/lazy_loader_spec.js @@ -11,11 +11,11 @@ const execImmediately = callback => { describe('LazyLoader', function() { let lazyLoader = null; - preloadFixtures('issues/issue_with_comment.html.raw'); + preloadFixtures('issues/issue_with_comment.html'); describe('without IntersectionObserver', () => { beforeEach(function() { - loadFixtures('issues/issue_with_comment.html.raw'); + loadFixtures('issues/issue_with_comment.html'); lazyLoader = new LazyLoader({ observerNode: 'foobar', @@ -131,7 +131,7 @@ describe('LazyLoader', function() { describe('with IntersectionObserver', () => { beforeEach(function() { - loadFixtures('issues/issue_with_comment.html.raw'); + loadFixtures('issues/issue_with_comment.html'); lazyLoader = new LazyLoader({ observerNode: 'foobar', diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 4eea364bd69..a75470b4db8 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -5,7 +5,7 @@ import LineHighlighter from '~/line_highlighter'; describe('LineHighlighter', function() { var clickLine; - preloadFixtures('static/line_highlighter.html.raw'); + preloadFixtures('static/line_highlighter.html'); clickLine = function(number, eventData = {}) { if ($.isEmptyObject(eventData)) { return $('#L' + number).click(); @@ -15,7 +15,7 @@ describe('LineHighlighter', function() { } }; beforeEach(function() { - loadFixtures('static/line_highlighter.html.raw'); + loadFixtures('static/line_highlighter.html'); this['class'] = new LineHighlighter(); this.css = this['class'].highlightLineClass; return (this.spies = { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index ab809930804..431798c6ec3 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -11,9 +11,9 @@ describe('MergeRequest', function() { describe('task lists', function() { let mock; - preloadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + preloadFixtures('merge_requests/merge_request_with_task_list.html'); beforeEach(function() { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); spyOn(axios, 'patch').and.callThrough(); mock = new MockAdapter(axios); @@ -125,7 +125,7 @@ describe('MergeRequest', function() { describe('hideCloseButton', () => { describe('merge request of another user', () => { beforeEach(() => { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); this.el = document.querySelector('.js-issuable-actions'); new MergeRequest(); // eslint-disable-line no-new MergeRequest.hideCloseButton(); @@ -145,7 +145,7 @@ describe('MergeRequest', function() { describe('merge request of current_user', () => { beforeEach(() => { - loadFixtures('merge_requests/merge_request_of_current_user.html.raw'); + loadFixtures('merge_requests/merge_request_of_current_user.html'); this.el = document.querySelector('.js-issuable-actions'); MergeRequest.hideCloseButton(); }); diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index c8df05eccf5..1295d900de7 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -22,8 +22,8 @@ describe('MergeRequestTabs', function() { }; preloadFixtures( - 'merge_requests/merge_request_with_task_list.html.raw', - 'merge_requests/diff_comment.html.raw', + 'merge_requests/merge_request_with_task_list.html', + 'merge_requests/diff_comment.html', ); beforeEach(function() { @@ -48,7 +48,7 @@ describe('MergeRequestTabs', function() { var windowTarget = '_blank'; beforeEach(function() { - loadFixtures('merge_requests/merge_request_with_task_list.html.raw'); + loadFixtures('merge_requests/merge_request_with_task_list.html'); tabUrl = $('.commits-tab a').attr('href'); }); diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js index 092ca9e1dab..aa4a376caf7 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js @@ -5,10 +5,10 @@ import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; import timeoutPromise from './helpers/set_timeout_promise_helper'; describe('Mini Pipeline Graph Dropdown', () => { - preloadFixtures('static/mini_dropdown_graph.html.raw'); + preloadFixtures('static/mini_dropdown_graph.html'); beforeEach(() => { - loadFixtures('static/mini_dropdown_graph.html.raw'); + loadFixtures('static/mini_dropdown_graph.html'); }); describe('When is initialized', () => { diff --git a/spec/javascripts/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js index fb49290be19..549a7935c0f 100644 --- a/spec/javascripts/monitoring/charts/area_spec.js +++ b/spec/javascripts/monitoring/charts/area_spec.js @@ -203,6 +203,10 @@ describe('Area component', () => { .length, ).toBe(data.length); }); + + it('formats line width correctly', () => { + expect(chartData[0].lineStyle.width).toBe(2); + }); }); describe('scatterSeries', () => { diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js index 6078a0e7872..454777fa912 100644 --- a/spec/javascripts/monitoring/dashboard_spec.js +++ b/spec/javascripts/monitoring/dashboard_spec.js @@ -33,6 +33,11 @@ describe('Dashboard', () => { <div class="layout-page"></div> `); + window.gon = { + ...window.gon, + ee: false, + }; + mock = new MockAdapter(axios); DashboardComponent = Vue.extend(Dashboard); }); @@ -152,6 +157,25 @@ describe('Dashboard', () => { done(); }); }); + + it('hides the dropdown', done => { + const component = new DashboardComponent({ + el: document.querySelector('.prometheus-graphs'), + propsData: { + ...propsData, + hasMetrics: true, + showPanels: false, + environmentsEndpoint: '', + }, + }); + + Vue.nextTick(() => { + const dropdownIsActiveElement = component.$el.querySelectorAll('.environments'); + + expect(dropdownIsActiveElement.length).toEqual(0); + done(); + }); + }); }); describe('when the window resizes', () => { diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index ffc7148fde2..6d4ef960c1a 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -330,6 +330,11 @@ export const metricsGroupsAPIResponse = { weight: 1, queries: [ { + appearance: { + line: { + width: 2, + }, + }, query_range: 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', label: 'Core Usage', diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 1d7b885e64f..4e3140ce4f1 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -3,7 +3,7 @@ import NewBranchForm from '~/new_branch_form'; describe('Branch', function() { describe('create a new branch', function() { - preloadFixtures('branches/new_branch.html.raw'); + preloadFixtures('branches/new_branch.html'); function fillNameWith(value) { $('.js-branch-name') @@ -16,7 +16,7 @@ describe('Branch', function() { } beforeEach(function() { - loadFixtures('branches/new_branch.html.raw'); + loadFixtures('branches/new_branch.html'); $('form').on('submit', function(e) { return e.preventDefault(); }); diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js index d716ece3766..ef876dc2941 100644 --- a/spec/javascripts/notes/components/note_app_spec.js +++ b/spec/javascripts/notes/components/note_app_spec.js @@ -192,9 +192,9 @@ describe('note_app', () => { expect(service.updateNote).toHaveBeenCalled(); // Wait for the requests to finish before destroying - Vue.nextTick() - .then(done) - .catch(done.fail); + setTimeout(() => { + done(); + }); }); }); @@ -227,9 +227,9 @@ describe('note_app', () => { expect(service.updateNote).toHaveBeenCalled(); // Wait for the requests to finish before destroying - Vue.nextTick() - .then(done) - .catch(done.fail); + setTimeout(() => { + done(); + }); }); }); }); diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js index c48f8188105..b632ee6736d 100644 --- a/spec/javascripts/notes/components/note_form_spec.js +++ b/spec/javascripts/notes/components/note_form_spec.js @@ -41,8 +41,6 @@ describe('issue_note_form component', () => { noteBody: 'Magni suscipit eius consectetur enim et ex et commodi.', noteId: '545', }; - - wrapper = createComponentWrapper(); }); afterEach(() => { @@ -50,6 +48,10 @@ describe('issue_note_form component', () => { }); describe('noteHash', () => { + beforeEach(() => { + wrapper = createComponentWrapper(); + }); + it('returns note hash string based on `noteId`', () => { expect(wrapper.vm.noteHash).toBe(`#note_${props.noteId}`); }); @@ -71,6 +73,10 @@ describe('issue_note_form component', () => { }); describe('conflicts editing', () => { + beforeEach(() => { + wrapper = createComponentWrapper(); + }); + it('should show conflict message if note changes outside the component', done => { wrapper.setProps({ ...props, @@ -100,6 +106,10 @@ describe('issue_note_form component', () => { }); describe('form', () => { + beforeEach(() => { + wrapper = createComponentWrapper(); + }); + it('should render text area with placeholder', () => { const textarea = wrapper.find('textarea'); @@ -198,10 +208,6 @@ describe('issue_note_form component', () => { }); describe('with autosaveKey', () => { - beforeEach(() => { - wrapper.destroy(); - }); - describe('with draft', () => { beforeEach(done => { Object.assign(props, { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 7c869d4c326..3d2c617e479 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -34,7 +34,7 @@ const htmlEscape = comment => { describe('Notes', function() { const FLASH_TYPE_ALERT = 'alert'; const NOTES_POST_PATH = /(.*)\/notes\?html=true$/; - var fixture = 'snippets/show.html.raw'; + var fixture = 'snippets/show.html'; preloadFixtures(fixture); beforeEach(function() { diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js index 4125706a407..381be82697e 100644 --- a/spec/javascripts/oauth_remember_me_spec.js +++ b/spec/javascripts/oauth_remember_me_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me'; describe('OAuthRememberMe', () => { - preloadFixtures('static/oauth_remember_me.html.raw'); + preloadFixtures('static/oauth_remember_me.html'); beforeEach(() => { - loadFixtures('static/oauth_remember_me.html.raw'); + loadFixtures('static/oauth_remember_me.html'); new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents(); }); diff --git a/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js b/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js index 561bd2c96cb..6a239e307e9 100644 --- a/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js +++ b/spec/javascripts/pages/admin/application_settings/account_and_limits_spec.js @@ -5,7 +5,7 @@ import initUserInternalRegexPlaceholder, { } from '~/pages/admin/application_settings/account_and_limits'; describe('AccountAndLimits', () => { - const FIXTURE = 'application_settings/accounts_and_limit.html.raw'; + const FIXTURE = 'application_settings/accounts_and_limit.html'; let $userDefaultExternal; let $userInternalRegex; preloadFixtures(FIXTURE); diff --git a/spec/javascripts/pages/admin/users/new/index_spec.js b/spec/javascripts/pages/admin/users/new/index_spec.js index 5a849f34bc3..3896323eef7 100644 --- a/spec/javascripts/pages/admin/users/new/index_spec.js +++ b/spec/javascripts/pages/admin/users/new/index_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import UserInternalRegexHandler from '~/pages/admin/users/new/index'; describe('UserInternalRegexHandler', () => { - const FIXTURE = 'admin/users/new_with_internal_user_regex.html.raw'; + const FIXTURE = 'admin/users/new_with_internal_user_regex.html'; let $userExternal; let $userEmail; let $warningMessage; diff --git a/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js b/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js index 7a8227479d4..1809e92e1d9 100644 --- a/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js +++ b/spec/javascripts/pages/sessions/new/preserve_url_fragment_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import preserveUrlFragment from '~/pages/sessions/new/preserve_url_fragment'; describe('preserve_url_fragment', () => { - preloadFixtures('sessions/new.html.raw'); + preloadFixtures('sessions/new.html'); beforeEach(() => { - loadFixtures('sessions/new.html.raw'); + loadFixtures('sessions/new.html'); }); it('adds the url fragment to all login and sign up form actions', () => { diff --git a/spec/javascripts/pipelines/graph/action_component_spec.js b/spec/javascripts/pipelines/graph/action_component_spec.js index 3d2232ff239..95717d659b8 100644 --- a/spec/javascripts/pipelines/graph/action_component_spec.js +++ b/spec/javascripts/pipelines/graph/action_component_spec.js @@ -55,13 +55,16 @@ describe('pipeline graph action component', () => { component.$el.click(); - component - .$nextTick() - .then(() => { - expect(component.$emit).toHaveBeenCalledWith('pipelineActionRequestComplete'); - }) - .then(done) - .catch(done.fail); + setTimeout(() => { + component + .$nextTick() + .then(() => { + expect(component.$emit).toHaveBeenCalledWith('pipelineActionRequestComplete'); + }) + .catch(done.fail); + + done(); + }, 0); }); }); }); diff --git a/spec/javascripts/pipelines/graph/stage_column_component_spec.js b/spec/javascripts/pipelines/graph/stage_column_component_spec.js index dafb892da43..3240e8e4c1b 100644 --- a/spec/javascripts/pipelines/graph/stage_column_component_spec.js +++ b/spec/javascripts/pipelines/graph/stage_column_component_spec.js @@ -55,7 +55,7 @@ describe('stage column component', () => { id: 4259, name: '<img src=x onerror=alert(document.domain)>', status: { - icon: 'icon_status_success', + icon: 'status_success', label: 'success', tooltip: '<img src=x onerror=alert(document.domain)>', }, diff --git a/spec/javascripts/pipelines/stage_spec.js b/spec/javascripts/pipelines/stage_spec.js index 3c8b8032de8..19ae7860333 100644 --- a/spec/javascripts/pipelines/stage_spec.js +++ b/spec/javascripts/pipelines/stage_spec.js @@ -120,13 +120,15 @@ describe('Pipelines stage component', () => { setTimeout(() => { component.$el.querySelector('.js-ci-action').click(); - component - .$nextTick() - .then(() => { - expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable'); - }) - .then(done) - .catch(done.fail); + setTimeout(() => { + component + .$nextTick() + .then(() => { + expect(eventHub.$emit).toHaveBeenCalledWith('refreshPipelinesTable'); + }) + .then(done) + .catch(done.fail); + }, 0); }, 0); }); }); diff --git a/spec/javascripts/pipelines_spec.js b/spec/javascripts/pipelines_spec.js index 6b86f9ea437..6d4d634c575 100644 --- a/spec/javascripts/pipelines_spec.js +++ b/spec/javascripts/pipelines_spec.js @@ -1,10 +1,10 @@ import Pipelines from '~/pipelines'; describe('Pipelines', () => { - preloadFixtures('static/pipeline_graph.html.raw'); + preloadFixtures('static/pipeline_graph.html'); beforeEach(() => { - loadFixtures('static/pipeline_graph.html.raw'); + loadFixtures('static/pipeline_graph.html'); }); it('should be defined', () => { diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js index 109a5000f5d..dc85292c23e 100644 --- a/spec/javascripts/project_select_combo_button_spec.js +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import ProjectSelectComboButton from '~/project_select_combo_button'; -const fixturePath = 'static/project_select_combo_button.html.raw'; +const fixturePath = 'static/project_select_combo_button.html'; describe('Project Select Combo Button', function() { preloadFixtures(fixturePath); diff --git a/spec/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown_spec.js b/spec/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown_spec.js index 030662b4d90..1eb7cb4bd5b 100644 --- a/spec/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown_spec.js +++ b/spec/javascripts/projects/gke_cluster_dropdowns/components/gke_project_id_dropdown_spec.js @@ -53,36 +53,32 @@ describe('GkeProjectIdDropdown', () => { }); it('returns default toggle text', done => - vm - .$nextTick() - .then(() => { - vm.setItem(emptyProjectMock); + setTimeout(() => { + vm.setItem(emptyProjectMock); - expect(vm.toggleText).toBe(LABELS.DEFAULT); - done(); - }) - .catch(done.fail)); + expect(vm.toggleText).toBe(LABELS.DEFAULT); + + done(); + })); it('returns project name if project selected', done => - vm - .$nextTick() - .then(() => { - expect(vm.toggleText).toBe(selectedProjectMock.name); - done(); - }) - .catch(done.fail)); + setTimeout(() => { + vm.isLoading = false; + + expect(vm.toggleText).toBe(selectedProjectMock.name); + + done(); + })); it('returns empty toggle text', done => - vm - .$nextTick() - .then(() => { - vm.$store.commit(SET_PROJECTS, null); - vm.setItem(emptyProjectMock); + setTimeout(() => { + vm.$store.commit(SET_PROJECTS, null); + vm.setItem(emptyProjectMock); - expect(vm.toggleText).toBe(LABELS.EMPTY); - done(); - }) - .catch(done.fail)); + expect(vm.toggleText).toBe(LABELS.EMPTY); + + done(); + })); }); describe('selectItem', () => { diff --git a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js index 94e2f959d46..dca3e1553b9 100644 --- a/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js +++ b/spec/javascripts/prometheus_metrics/prometheus_metrics_spec.js @@ -5,7 +5,7 @@ import PANEL_STATE from '~/prometheus_metrics/constants'; import { metrics, missingVarMetrics } from './mock_data'; describe('PrometheusMetrics', () => { - const FIXTURE = 'services/prometheus/prometheus_service.html.raw'; + const FIXTURE = 'services/prometheus/prometheus_service.html'; preloadFixtures(FIXTURE); beforeEach(() => { diff --git a/spec/javascripts/read_more_spec.js b/spec/javascripts/read_more_spec.js index b1af0f80a50..d1d01272403 100644 --- a/spec/javascripts/read_more_spec.js +++ b/spec/javascripts/read_more_spec.js @@ -1,7 +1,7 @@ import initReadMore from '~/read_more'; describe('Read more click-to-expand functionality', () => { - const fixtureName = 'projects/overview.html.raw'; + const fixtureName = 'projects/overview.html'; preloadFixtures(fixtureName); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 992e17978c1..9565e3ce546 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -23,7 +23,7 @@ const assertSidebarState = function(state) { describe('RightSidebar', function() { describe('fixture tests', () => { - const fixtureName = 'issues/open-issue.html.raw'; + const fixtureName = 'issues/open-issue.html'; preloadFixtures(fixtureName); loadJSONFixtures('todos/todos.json'); let mock; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 7a4ca587313..ce7fa7a52ae 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -126,9 +126,9 @@ describe('Search autocomplete dropdown', () => { expect(list.find(mrsIHaveCreatedLink).text()).toBe("Merge requests I've created"); }; - preloadFixtures('static/search_autocomplete.html.raw'); + preloadFixtures('static/search_autocomplete.html'); beforeEach(function() { - loadFixtures('static/search_autocomplete.html.raw'); + loadFixtures('static/search_autocomplete.html'); window.gon = {}; window.gon.current_user_id = userId; diff --git a/spec/javascripts/search_spec.js b/spec/javascripts/search_spec.js index 40bdbac7451..32f60508fa3 100644 --- a/spec/javascripts/search_spec.js +++ b/spec/javascripts/search_spec.js @@ -3,7 +3,7 @@ import Api from '~/api'; import Search from '~/pages/search/show/search'; describe('Search', () => { - const fixturePath = 'search/show.html.raw'; + const fixturePath = 'search/show.html'; const searchTerm = 'some search'; const fillDropdownInput = dropdownSelector => { const dropdownElement = document.querySelector(dropdownSelector).parentNode; diff --git a/spec/javascripts/settings_panels_spec.js b/spec/javascripts/settings_panels_spec.js index 3b681a9ff28..2c5d91a45bc 100644 --- a/spec/javascripts/settings_panels_spec.js +++ b/spec/javascripts/settings_panels_spec.js @@ -2,10 +2,10 @@ import $ from 'jquery'; import initSettingsPanels from '~/settings_panels'; describe('Settings Panels', () => { - preloadFixtures('groups/edit.html.raw'); + preloadFixtures('groups/edit.html'); beforeEach(() => { - loadFixtures('groups/edit.html.raw'); + loadFixtures('groups/edit.html'); }); describe('initSettingsPane', () => { diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js index 3ca6ecaa938..df7012bb659 100644 --- a/spec/javascripts/shortcuts_spec.js +++ b/spec/javascripts/shortcuts_spec.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import Shortcuts from '~/behaviors/shortcuts/shortcuts'; describe('Shortcuts', () => { - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; const createEvent = (type, target) => $.Event(type, { target, diff --git a/spec/javascripts/sidebar/assignees_spec.js b/spec/javascripts/sidebar/assignees_spec.js index eced4925489..57b16b12cb0 100644 --- a/spec/javascripts/sidebar/assignees_spec.js +++ b/spec/javascripts/sidebar/assignees_spec.js @@ -210,6 +210,19 @@ describe('Assignee component', () => { expect(component.$el.querySelector('.user-list-more')).toBe(null); }); + it('sets tooltip container to body', () => { + const users = UsersMockHelper.createNumberRandomUsers(2); + component = new AssigneeComponent({ + propsData: { + rootPath: 'http://localhost:3000', + users, + editable: true, + }, + }).$mount(); + + expect(component.$el.querySelector('.user-link').getAttribute('data-container')).toBe('body'); + }); + it('Shows the "show-less" assignees label', done => { const users = UsersMockHelper.createNumberRandomUsers(6); component = new AssigneeComponent({ diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js index 3f0f67d71ca..016f5e033a5 100644 --- a/spec/javascripts/sidebar/sidebar_assignees_spec.js +++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js @@ -11,12 +11,12 @@ describe('sidebar assignees', () => { let vm; let mediator; let sidebarAssigneesEl; - preloadFixtures('issues/open-issue.html.raw'); + preloadFixtures('issues/open-issue.html'); beforeEach(() => { Vue.http.interceptors.push(Mock.sidebarMockInterceptor); - loadFixtures('issues/open-issue.html.raw'); + loadFixtures('issues/open-issue.html'); mediator = new SidebarMediator(Mock.mediator); spyOn(mediator, 'saveAssignees').and.callThrough(); diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js index 52da6a79939..ef5c774736b 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js +++ b/spec/javascripts/signin_tabs_memoizer_spec.js @@ -2,7 +2,7 @@ import AccessorUtilities from '~/lib/utils/accessor'; import SigninTabsMemoizer from '~/pages/sessions/new/signin_tabs_memoizer'; describe('SigninTabsMemoizer', () => { - const fixtureTemplate = 'static/signin_tabs.html.raw'; + const fixtureTemplate = 'static/signin_tabs.html'; const tabSelector = 'ul.new-session-tabs'; const currentTabKey = 'current_signin_tab'; let memo; diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index 69e43274250..802f54f6a7e 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -3,11 +3,11 @@ import Todos from '~/pages/dashboard/todos/index/todos'; import '~/lib/utils/common_utils'; describe('Todos', () => { - preloadFixtures('todos/todos.html.raw'); + preloadFixtures('todos/todos.html'); let todoItem; beforeEach(() => { - loadFixtures('todos/todos.html.raw'); + loadFixtures('todos/todos.html'); todoItem = document.querySelector('.todos-list .todo'); return new Todos(); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index ddb09811dda..8f9cb270729 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -4,10 +4,10 @@ import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; describe('U2FAuthenticate', function() { - preloadFixtures('u2f/authenticate.html.raw'); + preloadFixtures('u2f/authenticate.html'); beforeEach(() => { - loadFixtures('u2f/authenticate.html.raw'); + loadFixtures('u2f/authenticate.html'); this.u2fDevice = new MockU2FDevice(); this.container = $('#js-authenticate-u2f'); this.component = new U2FAuthenticate( diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 261db3d66d7..a75ceca9f4c 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -4,10 +4,10 @@ import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; describe('U2FRegister', function() { - preloadFixtures('u2f/register.html.raw'); + preloadFixtures('u2f/register.html'); beforeEach(done => { - loadFixtures('u2f/register.html.raw'); + loadFixtures('u2f/register.html'); this.u2fDevice = new MockU2FDevice(); this.container = $('#js-register-u2f'); this.component = new U2FRegister(this.container, $('#js-register-u2f-templates'), {}, 'token'); diff --git a/spec/javascripts/user_popovers_spec.js b/spec/javascripts/user_popovers_spec.js index b174a51c1a0..c0d5ee9c446 100644 --- a/spec/javascripts/user_popovers_spec.js +++ b/spec/javascripts/user_popovers_spec.js @@ -2,7 +2,7 @@ import initUserPopovers from '~/user_popovers'; import UsersCache from '~/lib/utils/users_cache'; describe('User Popovers', () => { - const fixtureTemplate = 'merge_requests/diff_comment.html.raw'; + const fixtureTemplate = 'merge_requests/diff_comment.html'; preloadFixtures(fixtureTemplate); const selector = '.js-user-link'; diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js index 3229ddd5e27..780bed1bf69 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js @@ -120,7 +120,7 @@ describe('MRWidgetFailedToMerge', () => { it('renders given error', () => { expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual( - 'Merge error happened.', + 'Merge error happened', ); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js index 30659ad16f3..368c997d318 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js @@ -415,7 +415,7 @@ describe('ReadyToMerge', () => { }); beforeEach(() => { - loadFixtures('merge_requests/merge_request_of_current_user.html.raw'); + loadFixtures('merge_requests/merge_request_of_current_user.html'); }); it('should call start and stop polling when MR merged', done => { diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js index 79e0e756a7a..02d73e1849a 100644 --- a/spec/javascripts/vue_shared/components/markdown/field_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js @@ -5,7 +5,7 @@ import fieldComponent from '~/vue_shared/components/markdown/field.vue'; function assertMarkdownTabs(isWrite, writeLink, previewLink, vm) { expect(writeLink.parentNode.classList.contains('active')).toEqual(isWrite); expect(previewLink.parentNode.classList.contains('active')).toEqual(!isWrite); - expect(vm.$el.querySelector('.md-preview').style.display).toEqual(isWrite ? 'none' : ''); + expect(vm.$el.querySelector('.md-preview-holder').style.display).toEqual(isWrite ? 'none' : ''); } describe('Markdown field component', () => { @@ -80,7 +80,9 @@ describe('Markdown field component', () => { previewLink.click(); Vue.nextTick(() => { - expect(vm.$el.querySelector('.md-preview').textContent.trim()).toContain('Loading…'); + expect(vm.$el.querySelector('.md-preview-holder').textContent.trim()).toContain( + 'Loading…', + ); done(); }); @@ -90,7 +92,7 @@ describe('Markdown field component', () => { previewLink.click(); setTimeout(() => { - expect(vm.$el.querySelector('.md-preview').innerHTML).toContain( + expect(vm.$el.querySelector('.md-preview-holder').innerHTML).toContain( '<p>markdown preview</p>', ); diff --git a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js index e8b41e8eeff..852558a83bc 100644 --- a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js +++ b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js @@ -17,7 +17,7 @@ const DEFAULT_PROPS = { const UserPopover = Vue.extend(userPopover); describe('User Popover Component', () => { - const fixtureTemplate = 'merge_requests/diff_comment.html.raw'; + const fixtureTemplate = 'merge_requests/diff_comment.html'; preloadFixtures(fixtureTemplate); let vm; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index e5f1e6ae937..8f662c71c7a 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -6,7 +6,7 @@ import ZenMode from '~/zen_mode'; describe('ZenMode', () => { let zen; let dropzoneForElementSpy; - const fixtureName = 'snippets/show.html.raw'; + const fixtureName = 'snippets/show.html'; preloadFixtures(fixtureName); diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb new file mode 100644 index 00000000000..4a81a37d341 --- /dev/null +++ b/spec/lib/gitlab/background_migration/populate_merge_request_assignees_table_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Gitlab::BackgroundMigration::PopulateMergeRequestAssigneesTable, :migration, schema: 20190315191339 do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:users) { table(:users) } + + let(:user) { users.create!(email: 'test@example.com', projects_limit: 100, username: 'test') } + let(:user_2) { users.create!(email: 'test2@example.com', projects_limit: 100, username: 'test') } + let(:user_3) { users.create!(email: 'test3@example.com', projects_limit: 100, username: 'test') } + + let(:namespace) { namespaces.create(name: 'gitlab', path: 'gitlab-org') } + let(:project) { projects.create(namespace_id: namespace.id, name: 'foo') } + let(:merge_requests) { table(:merge_requests) } + let(:merge_request_assignees) { table(:merge_request_assignees) } + + def create_merge_request(id, params = {}) + params.merge!(id: id, + target_project_id: project.id, + target_branch: 'master', + source_project_id: project.id, + source_branch: 'mr name', + title: "mr name#{id}") + + merge_requests.create(params) + end + + describe '#perform' do + it 'creates merge_request_assignees rows according to merge_requests' do + create_merge_request(2, assignee_id: user.id) + create_merge_request(3, assignee_id: user_2.id) + create_merge_request(4, assignee_id: user_3.id) + # Test filtering already migrated row + merge_request_assignees.create!(merge_request_id: 2, user_id: user_3.id) + + subject.perform(1, 4) + + rows = merge_request_assignees.order(:id).map { |row| row.attributes.slice('merge_request_id', 'user_id') } + existing_rows = [ + { 'merge_request_id' => 2, 'user_id' => user_3.id } + ] + created_rows = [ + { 'merge_request_id' => 3, 'user_id' => user_2.id }, + { 'merge_request_id' => 4, 'user_id' => user_3.id } + ] + expected_rows = existing_rows + created_rows + + expect(rows.size).to eq(expected_rows.size) + expected_rows.each do |expected_row| + expect(rows).to include(expected_row) + end + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb index dab0fb51bcc..5181e9c1583 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb @@ -48,6 +48,24 @@ describe Gitlab::Ci::Pipeline::Chain::Command do end end + describe '#merge_request_ref_exists?' do + subject { command.merge_request_ref_exists? } + + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + + context 'for existing merge request ref' do + let(:origin_ref) { merge_request.ref_path } + + it { is_expected.to eq(true) } + end + + context 'for branch ref' do + let(:origin_ref) { merge_request.source_branch } + + it { is_expected.to eq(false) } + end + end + describe '#ref' do subject { command.ref } diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb index 8ba56d73838..7d750877d09 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/abilities_spec.rb @@ -10,12 +10,33 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do let(:command) do Gitlab::Ci::Pipeline::Chain::Command.new( - project: project, current_user: user, origin_ref: ref) + project: project, current_user: user, origin_ref: origin_ref, merge_request: merge_request) end let(:step) { described_class.new(pipeline, command) } let(:ref) { 'master' } + let(:origin_ref) { ref } + let(:merge_request) { nil } + + shared_context 'detached merge request pipeline' do + let(:merge_request) do + create(:merge_request, + source_project: project, + source_branch: ref, + target_project: project, + target_branch: 'feature') + end + + let(:pipeline) do + build(:ci_pipeline, + source: :merge_request_event, + merge_request: merge_request, + project: project) + end + + let(:origin_ref) { merge_request.ref_path } + end context 'when users has no ability to run a pipeline' do before do @@ -58,6 +79,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do it { is_expected.to be_truthy } + context 'when pipeline is a detached merge request pipeline' do + include_context 'detached merge request pipeline' + + it { is_expected.to be_truthy } + end + context 'when the branch is protected' do let!(:protected_branch) do create(:protected_branch, project: project, name: ref) @@ -65,6 +92,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do it { is_expected.to be_falsey } + context 'when pipeline is a detached merge request pipeline' do + include_context 'detached merge request pipeline' + + it { is_expected.to be_falsey } + end + context 'when developers are allowed to merge' do let!(:protected_branch) do create(:protected_branch, @@ -74,6 +107,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do end it { is_expected.to be_truthy } + + context 'when pipeline is a detached merge request pipeline' do + include_context 'detached merge request pipeline' + + it { is_expected.to be_truthy } + end end end @@ -112,6 +151,12 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Abilities do end it { is_expected.to be_truthy } + + context 'when pipeline is a detached merge request pipeline' do + include_context 'detached merge request pipeline' + + it { is_expected.to be_truthy } + end end context 'when the tag is protected' do diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb index a7cad423d09..2e8c9d70098 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb @@ -42,6 +42,25 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do end end + context 'when origin ref is a merge request ref' do + let(:command) do + Gitlab::Ci::Pipeline::Chain::Command.new( + project: project, current_user: user, origin_ref: origin_ref, checkout_sha: checkout_sha) + end + + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } + let(:origin_ref) { merge_request.ref_path } + let(:checkout_sha) { project.repository.commit(merge_request.ref_path).id } + + it 'does not break the chain' do + expect(step.break?).to be false + end + + it 'does not append pipeline errors' do + expect(pipeline.errors).to be_empty + end + end + context 'when ref is ambiguous' do let(:project) do create(:project, :repository).tap do |proj| diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index 17d5eae24f5..909dbffa38f 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -115,9 +115,8 @@ describe Gitlab::CurrentSettings do shared_examples 'a non-persisted ApplicationSetting object' do let(:current_settings) { described_class.current_application_settings } - it 'returns a non-persisted ApplicationSetting object' do - expect(current_settings).to be_a(ApplicationSetting) - expect(current_settings).not_to be_persisted + it 'returns a FakeApplicationSettings object' do + expect(current_settings).to be_a(Gitlab::FakeApplicationSettings) end it 'uses the default value from ApplicationSetting.defaults' do @@ -146,6 +145,16 @@ describe Gitlab::CurrentSettings do it 'uses the value from the DB attribute if present and not overridden by an accessor' do expect(current_settings.home_page_url).to eq(db_settings.home_page_url) end + + context 'when a new column is used before being migrated' do + before do + allow(ApplicationSetting).to receive(:defaults).and_return({ foo: 'bar' }) + end + + it 'uses the default value if present' do + expect(current_settings.foo).to eq('bar') + end + end end end diff --git a/spec/lib/gitlab/diff/suggestion_spec.rb b/spec/lib/gitlab/diff/suggestion_spec.rb new file mode 100644 index 00000000000..71fd25df698 --- /dev/null +++ b/spec/lib/gitlab/diff/suggestion_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Diff::Suggestion do + shared_examples 'correct suggestion raw content' do + it 'returns correct raw data' do + expect(suggestion.to_hash).to include(from_content: expected_lines.join, + to_content: "#{text}\n", + lines_above: above, + lines_below: below) + end + end + + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } + let(:position) do + Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb", + new_path: "files/ruby/popen.rb", + old_line: nil, + new_line: 9, + diff_refs: merge_request.diff_refs) + end + let(:diff_file) do + position.diff_file(project.repository) + end + let(:text) { "# parsed suggestion content\n# with comments" } + + def blob_lines_data(from_line, to_line) + diff_file.new_blob_lines_between(from_line, to_line) + end + + def blob_data + blob = diff_file.new_blob + blob.load_all_data! + blob.data + end + + let(:suggestion) do + described_class.new(text, line: line, above: above, below: below, diff_file: diff_file) + end + + describe '#to_hash' do + context 'when changing content surpasses the top limit' do + let(:line) { 4 } + let(:above) { 5 } + let(:below) { 2 } + let(:expected_above) { line - 1 } + let(:expected_below) { below } + let(:expected_lines) { blob_lines_data(line - expected_above, line + expected_below) } + + it_behaves_like 'correct suggestion raw content' + end + + context 'when changing content surpasses the amount of lines in the blob (bottom)' do + let(:line) { 5 } + let(:above) { 1 } + let(:below) { blob_data.lines.size + 10 } + let(:expected_below) { below } + let(:expected_above) { above } + let(:expected_lines) { blob_lines_data(line - expected_above, line + expected_below) } + + it_behaves_like 'correct suggestion raw content' + end + + context 'when lines are within blob lines boundary' do + let(:line) { 5 } + let(:above) { 2 } + let(:below) { 3 } + let(:expected_below) { below } + let(:expected_above) { above } + let(:expected_lines) { blob_lines_data(line - expected_above, line + expected_below) } + + it_behaves_like 'correct suggestion raw content' + end + + context 'when no extra lines (single-line suggestion)' do + let(:line) { 5 } + let(:above) { 0 } + let(:below) { 0 } + let(:expected_below) { below } + let(:expected_above) { above } + let(:expected_lines) { blob_lines_data(line - expected_above, line + expected_below) } + + it_behaves_like 'correct suggestion raw content' + end + end +end diff --git a/spec/lib/gitlab/diff/suggestions_parser_spec.rb b/spec/lib/gitlab/diff/suggestions_parser_spec.rb new file mode 100644 index 00000000000..1119ea04995 --- /dev/null +++ b/spec/lib/gitlab/diff/suggestions_parser_spec.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::Diff::SuggestionsParser do + describe '.parse' do + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.project } + let(:position) do + Gitlab::Diff::Position.new(old_path: "files/ruby/popen.rb", + new_path: "files/ruby/popen.rb", + old_line: nil, + new_line: 9, + diff_refs: merge_request.diff_refs) + end + + let(:diff_file) do + position.diff_file(project.repository) + end + + subject do + described_class.parse(markdown, project: merge_request.project, + position: position) + end + + def blob_lines_data(from_line, to_line) + diff_file.new_blob_lines_between(from_line, to_line).join + end + + context 'single-line suggestions' do + let(:markdown) do + <<-MARKDOWN.strip_heredoc + ```suggestion + foo + bar + ``` + + ``` + nothing + ``` + + ```suggestion + xpto + baz + ``` + + ```thing + this is not a suggestion, it's a thing + ``` + MARKDOWN + end + + it 'returns a list of Gitlab::Diff::Suggestion' do + expect(subject).to all(be_a(Gitlab::Diff::Suggestion)) + expect(subject.size).to eq(2) + end + + it 'parsed suggestion has correct data' do + from_line, to_line = position.new_line, position.new_line + + expect(subject.first.to_hash).to include(from_content: blob_lines_data(from_line, to_line), + to_content: " foo\n bar\n", + lines_above: 0, + lines_below: 0) + + expect(subject.second.to_hash).to include(from_content: blob_lines_data(from_line, to_line), + to_content: " xpto\n baz\n", + lines_above: 0, + lines_below: 0) + end + end + end +end diff --git a/spec/lib/gitlab/git/pre_receive_error_spec.rb b/spec/lib/gitlab/git/pre_receive_error_spec.rb index 1b8be62dec6..cb030e38032 100644 --- a/spec/lib/gitlab/git/pre_receive_error_spec.rb +++ b/spec/lib/gitlab/git/pre_receive_error_spec.rb @@ -1,9 +1,19 @@ require 'spec_helper' describe Gitlab::Git::PreReceiveError do - it 'makes its message HTML-friendly' do - ex = described_class.new("hello\nworld\n") + Gitlab::Git::PreReceiveError::SAFE_MESSAGE_PREFIXES.each do |prefix| + context "error messages prefixed with #{prefix}" do + it 'accepts only errors lines with the prefix' do + ex = described_class.new("#{prefix} Hello,\nworld!") - expect(ex.message).to eq('hello<br>world<br>') + expect(ex.message).to eq('Hello,') + end + + it 'makes its message HTML-friendly' do + ex = described_class.new("#{prefix} Hello,\n#{prefix} world!\n") + + expect(ex.message).to eq('Hello,<br>world!') + end + end end end diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index d7bd757149d..6d6107ca3e7 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -221,6 +221,21 @@ describe Gitlab::GitalyClient::CommitService do expect(commit).to eq(commit_dbl) end end + + context 'when caching of the ref name is enabled' do + it 'returns a cached commit' do + expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commit).once.and_return(double(commit: commit_dbl)) + + commit = nil + 2.times do + ::Gitlab::GitalyClient.allow_ref_name_caching do + commit = described_class.new(repository).find_commit('master') + end + end + + expect(commit).to eq(commit_dbl) + end + end end end diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb index b37fe2686b6..7579a6577b9 100644 --- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb @@ -39,7 +39,7 @@ describe Gitlab::GitalyClient::OperationService do context "when pre_receive_error is present" do let(:response) do - Gitaly::UserCreateBranchResponse.new(pre_receive_error: "something failed") + Gitaly::UserCreateBranchResponse.new(pre_receive_error: "GitLab: something failed") end it "throws a PreReceive exception" do @@ -80,7 +80,7 @@ describe Gitlab::GitalyClient::OperationService do context "when pre_receive_error is present" do let(:response) do - Gitaly::UserUpdateBranchResponse.new(pre_receive_error: "something failed") + Gitaly::UserUpdateBranchResponse.new(pre_receive_error: "GitLab: something failed") end it "throws a PreReceive exception" do @@ -117,7 +117,7 @@ describe Gitlab::GitalyClient::OperationService do context "when pre_receive_error is present" do let(:response) do - Gitaly::UserDeleteBranchResponse.new(pre_receive_error: "something failed") + Gitaly::UserDeleteBranchResponse.new(pre_receive_error: "GitLab: something failed") end it "throws a PreReceive exception" do @@ -175,7 +175,7 @@ describe Gitlab::GitalyClient::OperationService do shared_examples 'cherry pick and revert errors' do context 'when a pre_receive_error is present' do - let(:response) { response_class.new(pre_receive_error: "something failed") } + let(:response) { response_class.new(pre_receive_error: "GitLab: something failed") } it 'raises a PreReceiveError' do expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed") @@ -313,7 +313,7 @@ describe Gitlab::GitalyClient::OperationService do end context 'when a pre_receive_error is present' do - let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "something failed") } + let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "GitLab: something failed") } it 'raises a PreReceiveError' do expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed") diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 400d426c949..0dab39575b9 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -89,6 +89,16 @@ describe Gitlab::GitalyClient::RefService do end end + describe '#list_new_blobs' do + it 'raises DeadlineExceeded when timeout is too small' do + newrev = '54fcc214b94e78d7a41a9a8fe6d87a5e59500e51' + + expect do + client.list_new_blobs(newrev, dynamic_timeout: 0.001) + end.to raise_error(GRPC::DeadlineExceeded) + end + end + describe '#local_branches' do it 'sends a find_local_branches message' do expect_any_instance_of(Gitaly::RefService::Stub) diff --git a/spec/lib/gitlab/gl_repository/repo_type_spec.rb b/spec/lib/gitlab/gl_repository/repo_type_spec.rb new file mode 100644 index 00000000000..f06a2448ff7 --- /dev/null +++ b/spec/lib/gitlab/gl_repository/repo_type_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +require 'spec_helper' + +describe Gitlab::GlRepository::RepoType do + set(:project) { create(:project) } + + shared_examples 'a repo type' do + describe "#identifier_for_subject" do + subject { described_class.identifier_for_subject(project) } + + it { is_expected.to eq(expected_identifier) } + end + + describe "#fetch_id" do + it "finds an id match in the identifier" do + expect(described_class.fetch_id(expected_identifier)).to eq(expected_id) + end + + it 'does not break on other identifiers' do + expect(described_class.fetch_id("wiki-noid")).to eq(nil) + end + end + + describe "#path_suffix" do + subject { described_class.path_suffix } + + it { is_expected.to eq(expected_suffix) } + end + + describe "#repository_for" do + it "finds the repository for the repo type" do + expect(described_class.repository_for(project)).to eq(expected_repository) + end + end + end + + describe Gitlab::GlRepository::PROJECT do + it_behaves_like 'a repo type' do + let(:expected_identifier) { "project-#{project.id}" } + let(:expected_id) { project.id.to_s } + let(:expected_suffix) { "" } + let(:expected_repository) { project.repository } + end + + it "knows its type" do + expect(described_class).not_to be_wiki + expect(described_class).to be_project + end + end + + describe Gitlab::GlRepository::WIKI do + it_behaves_like 'a repo type' do + let(:expected_identifier) { "wiki-#{project.id}" } + let(:expected_id) { project.id.to_s } + let(:expected_suffix) { ".wiki" } + let(:expected_repository) { project.wiki.repository } + end + + it "knows its type" do + expect(described_class).to be_wiki + expect(described_class).not_to be_project + end + end +end diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb index 4e09020471b..d4b6c629659 100644 --- a/spec/lib/gitlab/gl_repository_spec.rb +++ b/spec/lib/gitlab/gl_repository_spec.rb @@ -5,11 +5,11 @@ describe ::Gitlab::GlRepository do set(:project) { create(:project, :repository) } it 'parses a project gl_repository' do - expect(described_class.parse("project-#{project.id}")).to eq([project, false]) + expect(described_class.parse("project-#{project.id}")).to eq([project, Gitlab::GlRepository::PROJECT]) end it 'parses a wiki gl_repository' do - expect(described_class.parse("wiki-#{project.id}")).to eq([project, true]) + expect(described_class.parse("wiki-#{project.id}")).to eq([project, Gitlab::GlRepository::WIKI]) end it 'throws an argument error on an invalid gl_repository' do diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 01da3ea7081..e418516569a 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -100,6 +100,8 @@ merge_requests: - head_pipeline - latest_merge_request_diff - merge_request_pipelines +- merge_request_assignees +- suggestions merge_request_diff: - merge_request - merge_request_diff_commits @@ -351,3 +353,5 @@ resource_label_events: - label error_tracking_setting: - project +suggestions: +- note diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index ee96e5c4d42..496567b0036 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -608,3 +608,14 @@ ErrorTracking::ProjectErrorTrackingSetting: - project_id - project_name - organization_name +Suggestion: +- id +- note_id +- relative_order +- applied +- commit_id +- from_content +- to_content +- outdated +- lines_above +- lines_below diff --git a/spec/lib/gitlab/quick_actions/command_definition_spec.rb b/spec/lib/gitlab/quick_actions/command_definition_spec.rb index 136cfb5bcc5..b6e0adbc1c2 100644 --- a/spec/lib/gitlab/quick_actions/command_definition_spec.rb +++ b/spec/lib/gitlab/quick_actions/command_definition_spec.rb @@ -69,6 +69,36 @@ describe Gitlab::QuickActions::CommandDefinition do expect(subject.available?(opts)).to be true end end + + context "when the command has types" do + before do + subject.types = [Issue, Commit] + end + + context "when the command target type is allowed" do + it "returns true" do + opts[:quick_action_target] = Issue.new + expect(subject.available?(opts)).to be true + end + end + + context "when the command target type is not allowed" do + it "returns true" do + opts[:quick_action_target] = MergeRequest.new + expect(subject.available?(opts)).to be false + end + end + end + + context "when the command has no types" do + it "any target type is allowed" do + opts[:quick_action_target] = Issue.new + expect(subject.available?(opts)).to be true + + opts[:quick_action_target] = MergeRequest.new + expect(subject.available?(opts)).to be true + end + end end describe "#execute" do diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb index fd4df8694ba..185adab1ff6 100644 --- a/spec/lib/gitlab/quick_actions/dsl_spec.rb +++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb @@ -48,13 +48,19 @@ describe Gitlab::QuickActions::Dsl do substitution :something do |text| "#{text} Some complicated thing you want in here" end + + desc 'A command with types' + types Issue, Commit + command :has_types do + "Has Issue and Commit types" + end end end describe '.command_definitions' do it 'returns an array with commands definitions' do no_args_def, explanation_with_aliases_def, dynamic_description_def, - cc_def, cond_action_def, with_params_parsing_def, substitution_def = + cc_def, cond_action_def, with_params_parsing_def, substitution_def, has_types = DummyClass.command_definitions expect(no_args_def.name).to eq(:no_args) @@ -63,6 +69,7 @@ describe Gitlab::QuickActions::Dsl do expect(no_args_def.explanation).to eq('') expect(no_args_def.params).to eq([]) expect(no_args_def.condition_block).to be_nil + expect(no_args_def.types).to eq([]) expect(no_args_def.action_block).to be_a_kind_of(Proc) expect(no_args_def.parse_params_block).to be_nil expect(no_args_def.warning).to eq('') @@ -73,6 +80,7 @@ describe Gitlab::QuickActions::Dsl do expect(explanation_with_aliases_def.explanation).to eq('Static explanation') expect(explanation_with_aliases_def.params).to eq(['The first argument']) expect(explanation_with_aliases_def.condition_block).to be_nil + expect(explanation_with_aliases_def.types).to eq([]) expect(explanation_with_aliases_def.action_block).to be_a_kind_of(Proc) expect(explanation_with_aliases_def.parse_params_block).to be_nil expect(explanation_with_aliases_def.warning).to eq('Possible problem!') @@ -83,6 +91,7 @@ describe Gitlab::QuickActions::Dsl do expect(dynamic_description_def.explanation).to eq('') expect(dynamic_description_def.params).to eq(['The first argument', 'The second argument']) expect(dynamic_description_def.condition_block).to be_nil + expect(dynamic_description_def.types).to eq([]) expect(dynamic_description_def.action_block).to be_a_kind_of(Proc) expect(dynamic_description_def.parse_params_block).to be_nil expect(dynamic_description_def.warning).to eq('') @@ -93,6 +102,7 @@ describe Gitlab::QuickActions::Dsl do expect(cc_def.explanation).to eq('') expect(cc_def.params).to eq([]) expect(cc_def.condition_block).to be_nil + expect(cc_def.types).to eq([]) expect(cc_def.action_block).to be_nil expect(cc_def.parse_params_block).to be_nil expect(cc_def.warning).to eq('') @@ -103,6 +113,7 @@ describe Gitlab::QuickActions::Dsl do expect(cond_action_def.explanation).to be_a_kind_of(Proc) expect(cond_action_def.params).to eq([]) expect(cond_action_def.condition_block).to be_a_kind_of(Proc) + expect(cond_action_def.types).to eq([]) expect(cond_action_def.action_block).to be_a_kind_of(Proc) expect(cond_action_def.parse_params_block).to be_nil expect(cond_action_def.warning).to eq('') @@ -113,6 +124,7 @@ describe Gitlab::QuickActions::Dsl do expect(with_params_parsing_def.explanation).to eq('') expect(with_params_parsing_def.params).to eq([]) expect(with_params_parsing_def.condition_block).to be_nil + expect(with_params_parsing_def.types).to eq([]) expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc) expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc) expect(with_params_parsing_def.warning).to eq('') @@ -123,9 +135,21 @@ describe Gitlab::QuickActions::Dsl do expect(substitution_def.explanation).to eq('') expect(substitution_def.params).to eq(['<Comment>']) expect(substitution_def.condition_block).to be_nil + expect(substitution_def.types).to eq([]) expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here') expect(substitution_def.parse_params_block).to be_nil expect(substitution_def.warning).to eq('') + + expect(has_types.name).to eq(:has_types) + expect(has_types.aliases).to eq([]) + expect(has_types.description).to eq('A command with types') + expect(has_types.explanation).to eq('') + expect(has_types.params).to eq([]) + expect(has_types.condition_block).to be_nil + expect(has_types.types).to eq([Issue, Commit]) + expect(has_types.action_block).to be_a_kind_of(Proc) + expect(has_types.parse_params_block).to be_nil + expect(has_types.warning).to eq('') end end end diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb index 13940713dfc..4c7ca4e2b57 100644 --- a/spec/lib/gitlab/repo_path_spec.rb +++ b/spec/lib/gitlab/repo_path_spec.rb @@ -6,43 +6,47 @@ describe ::Gitlab::RepoPath do context 'a repository storage path' do it 'parses a full repository path' do - expect(described_class.parse(project.repository.full_path)).to eq([project, false, nil]) + expect(described_class.parse(project.repository.full_path)).to eq([project, Gitlab::GlRepository::PROJECT, nil]) end it 'parses a full wiki path' do - expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, true, nil]) + expect(described_class.parse(project.wiki.repository.full_path)).to eq([project, Gitlab::GlRepository::WIKI, nil]) end end context 'a relative path' do it 'parses a relative repository path' do - expect(described_class.parse(project.full_path + '.git')).to eq([project, false, nil]) + expect(described_class.parse(project.full_path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, nil]) end it 'parses a relative wiki path' do - expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, true, nil]) + expect(described_class.parse(project.full_path + '.wiki.git')).to eq([project, Gitlab::GlRepository::WIKI, nil]) end it 'parses a relative path starting with /' do - expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, false, nil]) + expect(described_class.parse('/' + project.full_path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, nil]) end context 'of a redirected project' do let(:redirect) { project.route.create_redirect('foo/bar') } it 'parses a relative repository path' do - expect(described_class.parse(redirect.path + '.git')).to eq([project, false, 'foo/bar']) + expect(described_class.parse(redirect.path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, 'foo/bar']) end it 'parses a relative wiki path' do - expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, true, 'foo/bar.wiki']) + expect(described_class.parse(redirect.path + '.wiki.git')).to eq([project, Gitlab::GlRepository::WIKI, 'foo/bar.wiki']) end it 'parses a relative path starting with /' do - expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, false, 'foo/bar']) + expect(described_class.parse('/' + redirect.path + '.git')).to eq([project, Gitlab::GlRepository::PROJECT, 'foo/bar']) end end end + + it "returns nil for non existent paths" do + expect(described_class.parse("path/non-existent.git")).to eq(nil) + end end describe '.find_project' do diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 7213eee5675..d88086b01b1 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -250,11 +250,11 @@ describe Gitlab::Workhorse do } end - subject { described_class.git_http_ok(repository, false, user, action) } + subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action) } it { expect(subject).to include(params) } - context 'when is_wiki' do + context 'when the repo_type is a wiki' do let(:params) do { GL_ID: "user-#{user.id}", @@ -264,7 +264,7 @@ describe Gitlab::Workhorse do } end - subject { described_class.git_http_ok(repository, true, user, action) } + subject { described_class.git_http_ok(repository, Gitlab::GlRepository::WIKI, user, action) } it { expect(subject).to include(params) } end @@ -304,7 +304,7 @@ describe Gitlab::Workhorse do end context 'show_all_refs enabled' do - subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) } + subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action, show_all_refs: true) } it { is_expected.to include(ShowAllRefs: true) } end @@ -322,7 +322,7 @@ describe Gitlab::Workhorse do it { expect(subject).to include(gitaly_params) } context 'show_all_refs enabled' do - subject { described_class.git_http_ok(repository, false, user, action, show_all_refs: true) } + subject { described_class.git_http_ok(repository, Gitlab::GlRepository::PROJECT, user, action, show_all_refs: true) } it { is_expected.to include(ShowAllRefs: true) } end diff --git a/spec/lib/gitlab_spec.rb b/spec/lib/gitlab_spec.rb index 8232715d00e..767b5779a79 100644 --- a/spec/lib/gitlab_spec.rb +++ b/spec/lib/gitlab_spec.rb @@ -10,7 +10,7 @@ describe Gitlab do end describe '.revision' do - let(:cmd) { %W[#{described_class.config.git.bin_path} log --pretty=format:%h -n 1] } + let(:cmd) { %W[#{described_class.config.git.bin_path} log --pretty=format:%h --abbrev=11 -n 1] } around do |example| described_class.instance_variable_set(:@_revision, nil) diff --git a/spec/lib/sentry/client_spec.rb b/spec/lib/sentry/client_spec.rb index 88e7e2e5ebb..3333f8307ae 100644 --- a/spec/lib/sentry/client_spec.rb +++ b/spec/lib/sentry/client_spec.rb @@ -65,7 +65,9 @@ describe Sentry::Client do let(:issue_status) { 'unresolved' } let(:limit) { 20 } - let!(:sentry_api_request) { stub_sentry_request(sentry_url + '/issues/?limit=20&query=is:unresolved', body: issues_sample_response) } + let(:sentry_api_response) { issues_sample_response } + + let!(:sentry_api_request) { stub_sentry_request(sentry_url + '/issues/?limit=20&query=is:unresolved', body: sentry_api_response) } subject { client.list_issues(issue_status: issue_status, limit: limit) } @@ -74,6 +76,14 @@ describe Sentry::Client do it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Error it_behaves_like 'has correct length', 1 + shared_examples 'has correct external_url' do + context 'external_url' do + it 'is constructed correctly' do + expect(subject[0].external_url).to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/11') + end + end + end + context 'error object created from sentry response' do using RSpec::Parameterized::TableSyntax @@ -96,14 +106,10 @@ describe Sentry::Client do end with_them do - it { expect(subject[0].public_send(error_object)).to eq(issues_sample_response[0].dig(*sentry_response)) } + it { expect(subject[0].public_send(error_object)).to eq(sentry_api_response[0].dig(*sentry_response)) } end - context 'external_url' do - it 'is constructed correctly' do - expect(subject[0].external_url).to eq('https://sentrytest.gitlab.com/sentry-org/sentry-project/issues/11') - end - end + it_behaves_like 'has correct external_url' end context 'redirects' do @@ -135,12 +141,42 @@ describe Sentry::Client do expect(valid_req_stub).to have_been_requested end end + + context 'Older sentry versions where keys are not present' do + let(:sentry_api_response) do + issues_sample_response[0...1].map do |issue| + issue[:project].delete(:id) + issue + end + end + + it_behaves_like 'calls sentry api' + + it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Error + it_behaves_like 'has correct length', 1 + + it_behaves_like 'has correct external_url' + end + + context 'essential keys missing in API response' do + let(:sentry_api_response) do + issues_sample_response[0...1].map do |issue| + issue.except(:id) + end + end + + it 'raises exception' do + expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') + end + end end describe '#list_projects' do let(:sentry_list_projects_url) { 'https://sentrytest.gitlab.com/api/0/projects/' } - let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: projects_sample_response) } + let(:sentry_api_response) { projects_sample_response } + + let!(:sentry_api_request) { stub_sentry_request(sentry_list_projects_url, body: sentry_api_response) } subject { client.list_projects } @@ -149,14 +185,31 @@ describe Sentry::Client do it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project it_behaves_like 'has correct length', 2 - context 'keys missing in API response' do - it 'raises exception' do - projects_sample_response[0].delete(:slug) + context 'essential keys missing in API response' do + let(:sentry_api_response) do + projects_sample_response[0...1].map do |project| + project.except(:slug) + end + end - stub_sentry_request(sentry_list_projects_url, body: projects_sample_response) + it 'raises exception' do + expect { subject }.to raise_error(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "slug"') + end + end - expect { subject }.to raise_error(Sentry::Client::SentryError, 'Sentry API response is missing keys. key not found: "slug"') + context 'optional keys missing in sentry response' do + let(:sentry_api_response) do + projects_sample_response[0...1].map do |project| + project[:organization].delete(:id) + project.delete(:id) + project.except(:status) + end end + + it_behaves_like 'calls sentry api' + + it_behaves_like 'has correct return type', Gitlab::ErrorTracking::Project + it_behaves_like 'has correct length', 1 end context 'error object created from sentry response' do @@ -173,7 +226,11 @@ describe Sentry::Client do end with_them do - it { expect(subject[0].public_send(sentry_project_object)).to eq(projects_sample_response[0].dig(*sentry_response)) } + it do + expect(subject[0].public_send(sentry_project_object)).to( + eq(sentry_api_response[0].dig(*sentry_response)) + ) + end end end diff --git a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb index b2d8f476bb2..a1f243651b5 100644 --- a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb +++ b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb @@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_co describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queue' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) described_class.new.up @@ -19,12 +20,12 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do it 'does not affect other queues under the same namespace' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1]) - stubbed_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1]) described_class.new.up @@ -39,7 +40,7 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do it 'correctly migrates queue when migrating down' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) + stub_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1]) described_class.new.down @@ -58,11 +59,4 @@ describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do expect { described_class.new.down }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb index c18ae3b76d3..66555118a43 100644 --- a/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb +++ b/spec/migrations/migrate_create_trace_artifact_sidekiq_queue_spec.rb @@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180306074045_migrate_create_tra describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queues' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:create_trace_artifact').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) described_class.new.up @@ -19,11 +20,11 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do it 'does not affect other queues under the same namespace' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) described_class.new.up @@ -37,7 +38,7 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do it 'correctly migrates queue when migrating down' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_background:archive_trace').perform_async('Something', [1]) described_class.new.down @@ -56,11 +57,4 @@ describe MigrateCreateTraceArtifactSidekiqQueue, :sidekiq, :redis do expect { described_class.new.down }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb index 1ee6c440cf4..6ce04805e5d 100644 --- a/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb +++ b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb @@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_sto describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queue' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'object_storage_upload').perform_async('Something', [1]) - stubbed_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1]) + stub_worker(queue: 'object_storage_upload').perform_async('Something', [1]) + stub_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1]) described_class.new.up @@ -23,11 +24,4 @@ describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do expect { described_class.new.up }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb b/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb index e02bcd2f4da..e38044ccceb 100644 --- a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb +++ b/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb @@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20170822101017_migrate_pipeline_s describe MigratePipelineSidekiqQueues, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queues' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: :pipeline).perform_async('Something', [1]) - stubbed_worker(queue: :build).perform_async('Something', [1]) + stub_worker(queue: :pipeline).perform_async('Something', [1]) + stub_worker(queue: :build).perform_async('Something', [1]) described_class.new.up @@ -20,10 +21,10 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do it 'correctly migrates queue when migrating down' do Sidekiq::Testing.disable! do - stubbed_worker(queue: :pipeline_default).perform_async('Class', [1]) - stubbed_worker(queue: :pipeline_processing).perform_async('Class', [2]) - stubbed_worker(queue: :pipeline_hooks).perform_async('Class', [3]) - stubbed_worker(queue: :pipeline_cache).perform_async('Class', [4]) + stub_worker(queue: :pipeline_default).perform_async('Class', [1]) + stub_worker(queue: :pipeline_processing).perform_async('Class', [2]) + stub_worker(queue: :pipeline_hooks).perform_async('Class', [3]) + stub_worker(queue: :pipeline_cache).perform_async('Class', [4]) described_class.new.down @@ -45,11 +46,4 @@ describe MigratePipelineSidekiqQueues, :sidekiq, :redis do expect { described_class.new.down }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb b/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb index f8cf76cb339..94de208e53e 100644 --- a/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb +++ b/spec/migrations/migrate_storage_migrator_sidekiq_queue_spec.rb @@ -3,11 +3,12 @@ require Rails.root.join('db', 'post_migrate', '20190124200344_migrate_storage_mi describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queues' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: :storage_migrator).perform_async(1, 5) + stub_worker(queue: :storage_migrator).perform_async(1, 5) described_class.new.up @@ -18,7 +19,7 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do it 'correctly migrates queue when migrating down' do Sidekiq::Testing.disable! do - stubbed_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5) + stub_worker(queue: :'hashed_storage:hashed_storage_migrator').perform_async(1, 5) described_class.new.down @@ -37,11 +38,4 @@ describe MigrateStorageMigratorSidekiqQueue, :sidekiq, :redis do expect { described_class.new.down }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb index 5e3b20ab4a8..976f3ce07d7 100644 --- a/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb +++ b/spec/migrations/migrate_update_head_pipeline_for_merge_request_sidekiq_queue_spec.rb @@ -3,12 +3,13 @@ require Rails.root.join('db', 'post_migrate', '20180307012445_migrate_update_hea describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis do include Gitlab::Database::MigrationHelpers + include StubWorker context 'when there are jobs in the queues' do it 'correctly migrates queue when migrating up' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:update_head_pipeline_for_merge_request').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) described_class.new.up @@ -19,10 +20,10 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis it 'does not affect other queues under the same namespace' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) - stubbed_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:build_coverage').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:build_trace_sections').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:pipeline_metrics').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_default:pipeline_notification').perform_async('Something', [1]) described_class.new.up @@ -35,7 +36,7 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis it 'correctly migrates queue when migrating down' do Sidekiq::Testing.disable! do - stubbed_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) + stub_worker(queue: 'pipeline_processing:update_head_pipeline_for_merge_request').perform_async('Something', [1]) described_class.new.down @@ -54,11 +55,4 @@ describe MigrateUpdateHeadPipelineForMergeRequestSidekiqQueue, :sidekiq, :redis expect { described_class.new.down }.not_to raise_error end end - - def stubbed_worker(queue:) - Class.new do - include Sidekiq::Worker - sidekiq_options queue: queue - end - end end diff --git a/spec/migrations/schedule_populate_merge_request_assignees_table_spec.rb b/spec/migrations/schedule_populate_merge_request_assignees_table_spec.rb new file mode 100644 index 00000000000..e397fbb7138 --- /dev/null +++ b/spec/migrations/schedule_populate_merge_request_assignees_table_spec.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20190322132835_schedule_populate_merge_request_assignees_table.rb') + +describe SchedulePopulateMergeRequestAssigneesTable, :migration, :sidekiq do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:namespace) { namespaces.create(name: 'gitlab', path: 'gitlab-org') } + let(:project) { projects.create(namespace_id: namespace.id, name: 'foo') } + let(:merge_requests) { table(:merge_requests) } + + def create_merge_request(id) + params = { + id: id, + target_project_id: project.id, + target_branch: 'master', + source_project_id: project.id, + source_branch: 'mr name', + title: "mr name#{id}" + } + + merge_requests.create!(params) + end + + it 'correctly schedules background migrations' do + create_merge_request(1) + create_merge_request(2) + create_merge_request(3) + + stub_const("#{described_class.name}::BATCH_SIZE", 2) + + Sidekiq::Testing.fake! do + Timecop.freeze do + migrate! + + expect(described_class::MIGRATION) + .to be_scheduled_delayed_migration(8.minutes, 1, 2) + + expect(described_class::MIGRATION) + .to be_scheduled_delayed_migration(16.minutes, 3, 3) + + expect(BackgroundMigrationWorker.jobs.size).to eq(2) + end + end + end +end diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index eee80e9bad7..d9d60e02a97 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ability do diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb index f49a61062c1..a5f8e999d5d 100644 --- a/spec/models/abuse_report_spec.rb +++ b/spec/models/abuse_report_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe AbuseReport do diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb index e128fe8a4b7..b523f393ece 100644 --- a/spec/models/active_session_spec.rb +++ b/spec/models/active_session_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe ActiveSession, :clean_gitlab_redis_shared_state do diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb index 3e95aa2b5dd..209d138f956 100644 --- a/spec/models/appearance_spec.rb +++ b/spec/models/appearance_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Appearance do diff --git a/spec/models/application_setting/term_spec.rb b/spec/models/application_setting/term_spec.rb index aa49594f4d1..dd263335b81 100644 --- a/spec/models/application_setting/term_spec.rb +++ b/spec/models/application_setting/term_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ApplicationSetting::Term do diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 314f0728b8e..c5579dafb4a 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ApplicationSetting do diff --git a/spec/models/award_emoji_spec.rb b/spec/models/award_emoji_spec.rb index 3f52091698c..8452ac69734 100644 --- a/spec/models/award_emoji_spec.rb +++ b/spec/models/award_emoji_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe AwardEmoji do diff --git a/spec/models/badge_spec.rb b/spec/models/badge_spec.rb index 33dc19e3432..314d7d1e9f4 100644 --- a/spec/models/badge_spec.rb +++ b/spec/models/badge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Badge do diff --git a/spec/models/badges/group_badge_spec.rb b/spec/models/badges/group_badge_spec.rb index ed7f83d0489..c297bc957ea 100644 --- a/spec/models/badges/group_badge_spec.rb +++ b/spec/models/badges/group_badge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupBadge do diff --git a/spec/models/badges/project_badge_spec.rb b/spec/models/badges/project_badge_spec.rb index 0e1a8159cb6..e683d110252 100644 --- a/spec/models/badges/project_badge_spec.rb +++ b/spec/models/badges/project_badge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectBadge do diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb index 05cf242e84d..d0e1688cce3 100644 --- a/spec/models/blob_spec.rb +++ b/spec/models/blob_spec.rb @@ -1,4 +1,6 @@ # encoding: utf-8 +# frozen_string_literal: true + require 'rails_helper' describe Blob do diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb index 7ba28f72215..39c7a34f052 100644 --- a/spec/models/blob_viewer/base_spec.rb +++ b/spec/models/blob_viewer/base_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::Base do diff --git a/spec/models/blob_viewer/changelog_spec.rb b/spec/models/blob_viewer/changelog_spec.rb index db41eca0fc8..0fcc94182af 100644 --- a/spec/models/blob_viewer/changelog_spec.rb +++ b/spec/models/blob_viewer/changelog_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::Changelog do diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb index 85b0d9668a0..eda34779679 100644 --- a/spec/models/blob_viewer/composer_json_spec.rb +++ b/spec/models/blob_viewer/composer_json_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::ComposerJson do diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb index d8c4490637f..b6cc82c03ba 100644 --- a/spec/models/blob_viewer/gemspec_spec.rb +++ b/spec/models/blob_viewer/gemspec_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::Gemspec do diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb index 16bf947b493..db405ceb4f1 100644 --- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb +++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::GitlabCiYml do diff --git a/spec/models/blob_viewer/license_spec.rb b/spec/models/blob_viewer/license_spec.rb index 222ed166ee0..e02bfae3829 100644 --- a/spec/models/blob_viewer/license_spec.rb +++ b/spec/models/blob_viewer/license_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::License do diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index fbaa8d47a71..b317278f3c8 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::PackageJson do diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb index 9a23877b23f..7f1fb8666fd 100644 --- a/spec/models/blob_viewer/podspec_json_spec.rb +++ b/spec/models/blob_viewer/podspec_json_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::PodspecJson do diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb index 02d06ea24d6..527ae79d766 100644 --- a/spec/models/blob_viewer/podspec_spec.rb +++ b/spec/models/blob_viewer/podspec_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::Podspec do diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb index 8d11d58cfca..958927bddb4 100644 --- a/spec/models/blob_viewer/readme_spec.rb +++ b/spec/models/blob_viewer/readme_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::Readme do diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb index c13662427b0..f7ce873c9d1 100644 --- a/spec/models/blob_viewer/route_map_spec.rb +++ b/spec/models/blob_viewer/route_map_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::RouteMap do diff --git a/spec/models/blob_viewer/server_side_spec.rb b/spec/models/blob_viewer/server_side_spec.rb index 63790486200..f95305abe78 100644 --- a/spec/models/blob_viewer/server_side_spec.rb +++ b/spec/models/blob_viewer/server_side_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BlobViewer::ServerSide do diff --git a/spec/models/board_spec.rb b/spec/models/board_spec.rb index 12d29540137..54452faa0e1 100644 --- a/spec/models/board_spec.rb +++ b/spec/models/board_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Board do diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index 30ca07d5d2c..3ab013ddc0e 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BroadcastMessage do diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb index 504bc710b25..82991937644 100644 --- a/spec/models/chat_name_spec.rb +++ b/spec/models/chat_name_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatName do diff --git a/spec/models/chat_team_spec.rb b/spec/models/chat_team_spec.rb index 70a9a206faa..76beb3d506b 100644 --- a/spec/models/chat_team_spec.rb +++ b/spec/models/chat_team_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatTeam do diff --git a/spec/models/ci/artifact_blob_spec.rb b/spec/models/ci/artifact_blob_spec.rb index 0014bbcf9f5..f63816fd92a 100644 --- a/spec/models/ci/artifact_blob_spec.rb +++ b/spec/models/ci/artifact_blob_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::ArtifactBlob do diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index b5ec8991720..aacfbe3f180 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Bridge do diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb index 016a5899eef..917a65ddf21 100644 --- a/spec/models/ci/build_metadata_spec.rb +++ b/spec/models/ci/build_metadata_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildMetadata do diff --git a/spec/models/ci/build_runner_session_spec.rb b/spec/models/ci/build_runner_session_spec.rb index 35622366829..a52c10019e6 100644 --- a/spec/models/ci/build_runner_session_spec.rb +++ b/spec/models/ci/build_runner_session_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildRunnerSession, model: true do diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 7500e6ae5b1..2c41dfa65cd 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Build do @@ -24,6 +26,8 @@ describe Ci::Build do it { is_expected.to respond_to(:has_trace?) } it { is_expected.to respond_to(:trace) } it { is_expected.to delegate_method(:merge_request_event?).to(:pipeline) } + it { is_expected.to delegate_method(:merge_request_ref?).to(:pipeline) } + it { is_expected.to delegate_method(:legacy_detached_merge_request_pipeline?).to(:pipeline) } it { is_expected.to be_a(ArtifactMigratable) } @@ -3626,6 +3630,24 @@ describe Ci::Build do it { is_expected.to be_falsey } end end + + context 'when refspecs feature is required by build' do + before do + allow(build).to receive(:merge_request_ref?) { true } + end + + context 'when runner provides given feature' do + let(:runner_features) { { refspecs: true } } + + it { is_expected.to be_truthy } + end + + context 'when runner does not provide given feature' do + let(:runner_features) { {} } + + it { is_expected.to be_falsey } + end + end end describe '#deployment_status' do diff --git a/spec/models/ci/build_trace_chunks/database_spec.rb b/spec/models/ci/build_trace_chunks/database_spec.rb index d8fc9d57e95..eb94d7dae38 100644 --- a/spec/models/ci/build_trace_chunks/database_spec.rb +++ b/spec/models/ci/build_trace_chunks/database_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildTraceChunks::Database do diff --git a/spec/models/ci/build_trace_chunks/fog_spec.rb b/spec/models/ci/build_trace_chunks/fog_spec.rb index 8f49190af13..b8d78bcd069 100644 --- a/spec/models/ci/build_trace_chunks/fog_spec.rb +++ b/spec/models/ci/build_trace_chunks/fog_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildTraceChunks::Fog do diff --git a/spec/models/ci/build_trace_chunks/redis_spec.rb b/spec/models/ci/build_trace_chunks/redis_spec.rb index 9da1e6a95ee..6cff33d24fa 100644 --- a/spec/models/ci/build_trace_chunks/redis_spec.rb +++ b/spec/models/ci/build_trace_chunks/redis_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildTraceChunks::Redis, :clean_gitlab_redis_shared_state do diff --git a/spec/models/ci/build_trace_section_name_spec.rb b/spec/models/ci/build_trace_section_name_spec.rb index 386ee6880cb..11e2d27ff79 100644 --- a/spec/models/ci/build_trace_section_name_spec.rb +++ b/spec/models/ci/build_trace_section_name_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildTraceSectionName, model: true do diff --git a/spec/models/ci/build_trace_section_spec.rb b/spec/models/ci/build_trace_section_spec.rb index 541a9a36fb8..5bd3a953ec0 100644 --- a/spec/models/ci/build_trace_section_spec.rb +++ b/spec/models/ci/build_trace_section_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::BuildTraceSection, model: true do diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb index 838fa63cb1f..36c65d92840 100644 --- a/spec/models/ci/group_spec.rb +++ b/spec/models/ci/group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Group do diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb index 21d96bf3454..b3999765e5f 100644 --- a/spec/models/ci/group_variable_spec.rb +++ b/spec/models/ci/group_variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::GroupVariable do diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb index c68ba02b8de..d7abd54eec1 100644 --- a/spec/models/ci/job_artifact_spec.rb +++ b/spec/models/ci/job_artifact_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::JobArtifact do diff --git a/spec/models/ci/legacy_stage_spec.rb b/spec/models/ci/legacy_stage_spec.rb index 0c33c1466b7..be0307518eb 100644 --- a/spec/models/ci/legacy_stage_spec.rb +++ b/spec/models/ci/legacy_stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::LegacyStage do diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index 8ee15f0e734..81913f4a3b6 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::PipelineSchedule do diff --git a/spec/models/ci/pipeline_schedule_variable_spec.rb b/spec/models/ci/pipeline_schedule_variable_spec.rb index dc8427f28bc..3c9379ecb0d 100644 --- a/spec/models/ci/pipeline_schedule_variable_spec.rb +++ b/spec/models/ci/pipeline_schedule_variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::PipelineScheduleVariable do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 5b8097621e0..e76cf376ed1 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Pipeline, :mailer do @@ -362,6 +364,42 @@ describe Ci::Pipeline, :mailer do end end + describe '#merge_request_ref?' do + subject { pipeline.merge_request_ref? } + + it 'calls MergeRequest#merge_request_ref?' do + expect(MergeRequest).to receive(:merge_request_ref?).with(pipeline.ref) + + subject + end + end + + describe '#legacy_detached_merge_request_pipeline?' do + subject { pipeline.legacy_detached_merge_request_pipeline? } + + set(:merge_request) { create(:merge_request) } + let(:ref) { 'feature' } + let(:target_sha) { nil } + + let(:pipeline) do + build(:ci_pipeline, source: :merge_request_event, merge_request: merge_request, ref: ref, target_sha: target_sha) + end + + it { is_expected.to be_truthy } + + context 'when pipeline ref is a merge request ref' do + let(:ref) { 'refs/merge-requests/1/head' } + + it { is_expected.to be_falsy } + end + + context 'when target sha is set' do + let(:target_sha) { 'target-sha' } + + it { is_expected.to be_falsy } + end + end + describe '#matches_sha_or_source_sha?' do subject { pipeline.matches_sha_or_source_sha?(sample_sha) } @@ -1460,6 +1498,14 @@ describe Ci::Pipeline, :mailer do end end + context 'with a branch name as the ref' do + it 'looks up commit with the full ref name' do + expect(pipeline.project).to receive(:commit).with('refs/heads/master').and_call_original + + expect(pipeline).to be_latest + end + end + context 'with not latest sha' do before do pipeline.update( diff --git a/spec/models/ci/pipeline_variable_spec.rb b/spec/models/ci/pipeline_variable_spec.rb index 03d09cb31d6..2ecb688299a 100644 --- a/spec/models/ci/pipeline_variable_spec.rb +++ b/spec/models/ci/pipeline_variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::PipelineVariable do diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index eb2daed7f32..b3ab63925dd 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Runner do diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 3228c400155..661958390e2 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Stage, :models do diff --git a/spec/models/ci/trigger_request_spec.rb b/spec/models/ci/trigger_request_spec.rb index 7dcf3528f73..d04349bec92 100644 --- a/spec/models/ci/trigger_request_spec.rb +++ b/spec/models/ci/trigger_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::TriggerRequest do diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index d4b72205203..fde8375f2a5 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Trigger do diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb index 02c07a2bd83..d2df6b3344e 100644 --- a/spec/models/ci/variable_spec.rb +++ b/spec/models/ci/variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Ci::Variable do diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb index cf5cbf8ec5c..af7eadfc74c 100644 --- a/spec/models/clusters/applications/cert_manager_spec.rb +++ b/spec/models/clusters/applications/cert_manager_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::CertManager do @@ -9,7 +11,27 @@ describe Clusters::Applications::CertManager do include_examples 'cluster application initial status specs' describe '#install_command' do - let(:cluster_issuer_file) { { "cluster_issuer.yaml": "---\napiVersion: certmanager.k8s.io/v1alpha1\nkind: ClusterIssuer\nmetadata:\n name: letsencrypt-prod\nspec:\n acme:\n server: https://acme-v02.api.letsencrypt.org/directory\n email: admin@example.com\n privateKeySecretRef:\n name: letsencrypt-prod\n http01: {}\n" } } + let(:cert_email) { 'admin@example.com' } + + let(:cluster_issuer_file) do + file_contents = <<~EOF + --- + apiVersion: certmanager.k8s.io/v1alpha1 + kind: ClusterIssuer + metadata: + name: letsencrypt-prod + spec: + acme: + server: https://acme-v02.api.letsencrypt.org/directory + email: #{cert_email} + privateKeySecretRef: + name: letsencrypt-prod + http01: {} + EOF + + { "cluster_issuer.yaml": file_contents } + end + subject { cert_manager.install_command } it { is_expected.to be_an_instance_of(Gitlab::Kubernetes::Helm::InstallCommand) } @@ -24,9 +46,10 @@ describe Clusters::Applications::CertManager do end context 'for a specific user' do + let(:cert_email) { 'abc@xyz.com' } + before do - cert_manager.email = 'abc@xyz.com' - cluster_issuer_file[:'cluster_issuer.yaml'].gsub! 'admin@example.com', 'abc@xyz.com' + cert_manager.email = cert_email end it 'should use his/her email to register issuer with certificate provider' do diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb index f16eff92167..f97d126d918 100644 --- a/spec/models/clusters/applications/helm_spec.rb +++ b/spec/models/clusters/applications/helm_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Helm do diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index a40fa988287..09e60b9a206 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Ingress do diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index 2967c4076c6..5970a1959b5 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Jupyter do diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb index bf425a2617c..25493689fbc 100644 --- a/spec/models/clusters/applications/knative_spec.rb +++ b/spec/models/clusters/applications/knative_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Knative do @@ -107,7 +109,7 @@ describe Clusters::Applications::Knative do subject { knative.install_command } it 'should be initialized with latest version' do - expect(subject.version).to eq('0.2.2') + expect(subject.version).to eq('0.3.0') end it_behaves_like 'a command' diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index 81708b0c2ed..82a502addd4 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Prometheus do diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index 3ce8aa1c7bc..7e2f5835279 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Clusters::Applications::Runner do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index acbcdc7d170..fabd2806d9a 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -620,4 +620,20 @@ describe Clusters::Cluster do end end end + + describe '#provided_by_user?' do + subject { cluster.provided_by_user? } + + context 'with a GCP provider' do + let(:cluster) { create(:cluster, :provided_by_gcp) } + + it { is_expected.to be_falsy } + end + + context 'with an user provider' do + let(:cluster) { create(:cluster, :provided_by_user) } + + it { is_expected.to be_truthy } + end + end end diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb index af65530e663..14bec17a2bd 100644 --- a/spec/models/clusters/platforms/kubernetes_spec.rb +++ b/spec/models/clusters/platforms/kubernetes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching do @@ -15,7 +17,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching it { is_expected.to delegate_method(:project).to(:cluster) } it { is_expected.to delegate_method(:enabled?).to(:cluster) } - it { is_expected.to delegate_method(:managed?).to(:cluster) } + it { is_expected.to delegate_method(:provided_by_user?).to(:cluster) } it { is_expected.to delegate_method(:kubernetes_namespace).to(:cluster) } it_behaves_like 'having unique enum values' diff --git a/spec/models/clusters/project_spec.rb b/spec/models/clusters/project_spec.rb index 82ef5a23c18..2f017e69251 100644 --- a/spec/models/clusters/project_spec.rb +++ b/spec/models/clusters/project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Clusters::Project do diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb index 5012e6f15c6..785db4febe0 100644 --- a/spec/models/clusters/providers/gcp_spec.rb +++ b/spec/models/clusters/providers/gcp_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Clusters::Providers::Gcp do diff --git a/spec/models/commit_collection_spec.rb b/spec/models/commit_collection_spec.rb index 30c504ebea8..8a7fcb39fe2 100644 --- a/spec/models/commit_collection_spec.rb +++ b/spec/models/commit_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CommitCollection do diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb index f2efcd9d0e9..b96ca89c893 100644 --- a/spec/models/commit_range_spec.rb +++ b/spec/models/commit_range_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CommitRange do diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 9d4e18534ae..14f4b4d692f 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Commit do diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index e2b7f5c6ee2..ca2f9e36c98 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CommitStatus do diff --git a/spec/models/compare_spec.rb b/spec/models/compare_spec.rb index 0bc3ee014e6..43c3580bed2 100644 --- a/spec/models/compare_spec.rb +++ b/spec/models/compare_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Compare do diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb index 04d6cfa2c02..de2bc3a387b 100644 --- a/spec/models/concerns/access_requestable_spec.rb +++ b/spec/models/concerns/access_requestable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe AccessRequestable do diff --git a/spec/models/concerns/avatarable_spec.rb b/spec/models/concerns/avatarable_spec.rb index 1ea7f2b9985..c750be6b75c 100644 --- a/spec/models/concerns/avatarable_spec.rb +++ b/spec/models/concerns/avatarable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Avatarable do diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb index 5713106418d..9e7106281ee 100644 --- a/spec/models/concerns/awardable_spec.rb +++ b/spec/models/concerns/awardable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Awardable do diff --git a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb index e5392fe0462..1fe90d3cc9a 100644 --- a/spec/models/concerns/batch_destroy_dependent_associations_spec.rb +++ b/spec/models/concerns/batch_destroy_dependent_associations_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BatchDestroyDependentAssociations do diff --git a/spec/models/concerns/blocks_json_serialization_spec.rb b/spec/models/concerns/blocks_json_serialization_spec.rb index 5906b588d0e..e8657c45a93 100644 --- a/spec/models/concerns/blocks_json_serialization_spec.rb +++ b/spec/models/concerns/blocks_json_serialization_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe BlocksJsonSerialization do diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb index 7d555f15e39..78637ff10c6 100644 --- a/spec/models/concerns/cache_markdown_field_spec.rb +++ b/spec/models/concerns/cache_markdown_field_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CacheMarkdownField do diff --git a/spec/models/concerns/cacheable_attributes_spec.rb b/spec/models/concerns/cacheable_attributes_spec.rb index 43a544cfe26..394fac52aa7 100644 --- a/spec/models/concerns/cacheable_attributes_spec.rb +++ b/spec/models/concerns/cacheable_attributes_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CacheableAttributes do diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb index 1bf6c9b3404..d6d41a25eac 100644 --- a/spec/models/concerns/case_sensitivity_spec.rb +++ b/spec/models/concerns/case_sensitivity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CaseSensitivity do diff --git a/spec/models/concerns/chronic_duration_attribute_spec.rb b/spec/models/concerns/chronic_duration_attribute_spec.rb index 51221e07ca3..e41d75568f7 100644 --- a/spec/models/concerns/chronic_duration_attribute_spec.rb +++ b/spec/models/concerns/chronic_duration_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'ChronicDurationAttribute reader' do diff --git a/spec/models/concerns/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb index 6951be903fe..42bed9434f5 100644 --- a/spec/models/concerns/deployable_spec.rb +++ b/spec/models/concerns/deployable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Deployable do diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb index 19ab4382b53..0e34d8fccf3 100644 --- a/spec/models/concerns/deployment_platform_spec.rb +++ b/spec/models/concerns/deployment_platform_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe DeploymentPlatform do diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb index 64bf04071e8..baddca47dfa 100644 --- a/spec/models/concerns/discussion_on_diff_spec.rb +++ b/spec/models/concerns/discussion_on_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DiscussionOnDiff do diff --git a/spec/models/concerns/each_batch_spec.rb b/spec/models/concerns/each_batch_spec.rb index 17224c09693..c4cf8e80f7a 100644 --- a/spec/models/concerns/each_batch_spec.rb +++ b/spec/models/concerns/each_batch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe EachBatch do diff --git a/spec/models/concerns/editable_spec.rb b/spec/models/concerns/editable_spec.rb index 49a9a8ebcbc..4a4a3ca5687 100644 --- a/spec/models/concerns/editable_spec.rb +++ b/spec/models/concerns/editable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Editable do diff --git a/spec/models/concerns/expirable_spec.rb b/spec/models/concerns/expirable_spec.rb index f7b436f32e6..f4f5eab5b86 100644 --- a/spec/models/concerns/expirable_spec.rb +++ b/spec/models/concerns/expirable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Expirable do diff --git a/spec/models/concerns/faster_cache_keys_spec.rb b/spec/models/concerns/faster_cache_keys_spec.rb index 8d3f94267fa..7830acbae3d 100644 --- a/spec/models/concerns/faster_cache_keys_spec.rb +++ b/spec/models/concerns/faster_cache_keys_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe FasterCacheKeys do diff --git a/spec/models/concerns/feature_gate_spec.rb b/spec/models/concerns/feature_gate_spec.rb index 3f601243245..276d3d9e1d5 100644 --- a/spec/models/concerns/feature_gate_spec.rb +++ b/spec/models/concerns/feature_gate_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe FeatureGate do diff --git a/spec/models/concerns/group_descendant_spec.rb b/spec/models/concerns/group_descendant_spec.rb index 28352d8c961..194caac3fce 100644 --- a/spec/models/concerns/group_descendant_spec.rb +++ b/spec/models/concerns/group_descendant_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupDescendant, :nested_groups do diff --git a/spec/models/concerns/has_status_spec.rb b/spec/models/concerns/has_status_spec.rb index e8b1eba67cc..a217dc42537 100644 --- a/spec/models/concerns/has_status_spec.rb +++ b/spec/models/concerns/has_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe HasStatus do diff --git a/spec/models/concerns/has_variable_spec.rb b/spec/models/concerns/has_variable_spec.rb index bff96e12ffa..2bb21d7934e 100644 --- a/spec/models/concerns/has_variable_spec.rb +++ b/spec/models/concerns/has_variable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe HasVariable do diff --git a/spec/models/concerns/ignorable_column_spec.rb b/spec/models/concerns/ignorable_column_spec.rb index b70f2331a0e..6b82825d2cc 100644 --- a/spec/models/concerns/ignorable_column_spec.rb +++ b/spec/models/concerns/ignorable_column_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe IgnorableColumn do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 72c6161424b..259ac6852a8 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Issuable do diff --git a/spec/models/concerns/loaded_in_group_list_spec.rb b/spec/models/concerns/loaded_in_group_list_spec.rb index 7a279547a3a..7c97b580779 100644 --- a/spec/models/concerns/loaded_in_group_list_spec.rb +++ b/spec/models/concerns/loaded_in_group_list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LoadedInGroupList do diff --git a/spec/models/concerns/manual_inverse_association_spec.rb b/spec/models/concerns/manual_inverse_association_spec.rb index ff4a04ea573..ee32e3b165b 100644 --- a/spec/models/concerns/manual_inverse_association_spec.rb +++ b/spec/models/concerns/manual_inverse_association_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ManualInverseAssociation do diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index a9b237fa9ea..f31e3e8821d 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Mentionable do diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index 81ca5b638fe..22d4b2cc517 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Milestone, 'Milestoneish' do diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb index 485a6e165a1..ee613b199ad 100644 --- a/spec/models/concerns/noteable_spec.rb +++ b/spec/models/concerns/noteable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Noteable do diff --git a/spec/models/concerns/participable_spec.rb b/spec/models/concerns/participable_spec.rb index 431f1482615..3d5937c4fc6 100644 --- a/spec/models/concerns/participable_spec.rb +++ b/spec/models/concerns/participable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Participable do diff --git a/spec/models/concerns/presentable_spec.rb b/spec/models/concerns/presentable_spec.rb index 941647a79fb..9db868dd348 100644 --- a/spec/models/concerns/presentable_spec.rb +++ b/spec/models/concerns/presentable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Presentable do diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 9041690023f..5aa43b58217 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectFeaturesCompatibility do diff --git a/spec/models/concerns/prometheus_adapter_spec.rb b/spec/models/concerns/prometheus_adapter_spec.rb index f4b9c57e71a..7148261b1e4 100644 --- a/spec/models/concerns/prometheus_adapter_spec.rb +++ b/spec/models/concerns/prometheus_adapter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PrometheusAdapter, :use_clean_rails_memory_store_caching do diff --git a/spec/models/concerns/protected_ref_access_spec.rb b/spec/models/concerns/protected_ref_access_spec.rb index ce602337647..94798f0590d 100644 --- a/spec/models/concerns/protected_ref_access_spec.rb +++ b/spec/models/concerns/protected_ref_access_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectedRefAccess do diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb index 03ae45e6b17..32e13d5abed 100644 --- a/spec/models/concerns/reactive_caching_spec.rb +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ReactiveCaching, :use_clean_rails_memory_store_caching do diff --git a/spec/models/concerns/redactable_spec.rb b/spec/models/concerns/redactable_spec.rb index 7feeaa54069..57c7d2cb767 100644 --- a/spec/models/concerns/redactable_spec.rb +++ b/spec/models/concerns/redactable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Redactable do diff --git a/spec/models/concerns/redis_cacheable_spec.rb b/spec/models/concerns/redis_cacheable_spec.rb index 23c6c6233e9..a9dca27f258 100644 --- a/spec/models/concerns/redis_cacheable_spec.rb +++ b/spec/models/concerns/redis_cacheable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe RedisCacheable do diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb index ac8da30b6c9..d0ae45f7871 100644 --- a/spec/models/concerns/relative_positioning_spec.rb +++ b/spec/models/concerns/relative_positioning_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe RelativePositioning do diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 97b046b0f21..9ea01ca9002 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Discussion, ResolvableDiscussion do diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb index fcb5250278e..4f46252a044 100644 --- a/spec/models/concerns/resolvable_note_spec.rb +++ b/spec/models/concerns/resolvable_note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Note, ResolvableNote do diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 565266321d3..1fb0dd5030c 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Group, 'Routable' do diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb index 0d3beb6a6e3..a4a81ae126d 100644 --- a/spec/models/concerns/sha_attribute_spec.rb +++ b/spec/models/concerns/sha_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ShaAttribute do diff --git a/spec/models/concerns/sortable_spec.rb b/spec/models/concerns/sortable_spec.rb index 0a9d2021a19..184f7986a6f 100644 --- a/spec/models/concerns/sortable_spec.rb +++ b/spec/models/concerns/sortable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Sortable do diff --git a/spec/models/concerns/spammable_spec.rb b/spec/models/concerns/spammable_spec.rb index e698207166c..650d49e41a1 100644 --- a/spec/models/concerns/spammable_spec.rb +++ b/spec/models/concerns/spammable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Spammable do diff --git a/spec/models/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb index 8c945686b66..5c0d1042e06 100644 --- a/spec/models/concerns/strip_attribute_spec.rb +++ b/spec/models/concerns/strip_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe StripAttribute do diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb index 45dfb136aea..2f88adf08dd 100644 --- a/spec/models/concerns/subscribable_spec.rb +++ b/spec/models/concerns/subscribable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Subscribable, 'Subscribable' do diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb index 40cb4eef60a..51e28974ae0 100644 --- a/spec/models/concerns/token_authenticatable_spec.rb +++ b/spec/models/concerns/token_authenticatable_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' shared_examples 'TokenAuthenticatable' do diff --git a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb index 2a0182b4294..7332da309d5 100644 --- a/spec/models/concerns/token_authenticatable_strategies/base_spec.rb +++ b/spec/models/concerns/token_authenticatable_strategies/base_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe TokenAuthenticatableStrategies::Base do diff --git a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb index ca38f86c5ab..70f41981b3b 100644 --- a/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb +++ b/spec/models/concerns/token_authenticatable_strategies/encrypted_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe TokenAuthenticatableStrategies::Encrypted do diff --git a/spec/models/concerns/triggerable_hooks_spec.rb b/spec/models/concerns/triggerable_hooks_spec.rb index 265abd6bd72..f28e5f56411 100644 --- a/spec/models/concerns/triggerable_hooks_spec.rb +++ b/spec/models/concerns/triggerable_hooks_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe TriggerableHooks do diff --git a/spec/models/concerns/uniquify_spec.rb b/spec/models/concerns/uniquify_spec.rb index 6cd2de6dcce..9ba35702ba6 100644 --- a/spec/models/concerns/uniquify_spec.rb +++ b/spec/models/concerns/uniquify_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Uniquify do diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index e46945e301e..013112d1d51 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ContainerRepository do diff --git a/spec/models/conversational_development_index/metric_spec.rb b/spec/models/conversational_development_index/metric_spec.rb index b3193619503..60b1a860dfd 100644 --- a/spec/models/conversational_development_index/metric_spec.rb +++ b/spec/models/conversational_development_index/metric_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe ConversationalDevelopmentIndex::Metric do diff --git a/spec/models/cycle_analytics/code_spec.rb b/spec/models/cycle_analytics/code_spec.rb index 6a6b58fb52b..b22a0340015 100644 --- a/spec/models/cycle_analytics/code_spec.rb +++ b/spec/models/cycle_analytics/code_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#code' do diff --git a/spec/models/cycle_analytics/issue_spec.rb b/spec/models/cycle_analytics/issue_spec.rb index 45f1b4fe8a3..07d60be091a 100644 --- a/spec/models/cycle_analytics/issue_spec.rb +++ b/spec/models/cycle_analytics/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#issue' do diff --git a/spec/models/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb index d366e2b723a..3d22a284264 100644 --- a/spec/models/cycle_analytics/plan_spec.rb +++ b/spec/models/cycle_analytics/plan_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#plan' do diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index 156eb96cfce..383727cd8f7 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#production' do diff --git a/spec/models/cycle_analytics/review_spec.rb b/spec/models/cycle_analytics/review_spec.rb index 0aedfb49cb5..1af5f9cc1f4 100644 --- a/spec/models/cycle_analytics/review_spec.rb +++ b/spec/models/cycle_analytics/review_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#review' do diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index 0cbda50c688..8375944f03c 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#staging' do diff --git a/spec/models/cycle_analytics/test_spec.rb b/spec/models/cycle_analytics/test_spec.rb index e58b8fdff58..b78258df564 100644 --- a/spec/models/cycle_analytics/test_spec.rb +++ b/spec/models/cycle_analytics/test_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe 'CycleAnalytics#test' do diff --git a/spec/models/cycle_analytics_spec.rb b/spec/models/cycle_analytics_spec.rb index 0fe24870f02..5d8b5b573cf 100644 --- a/spec/models/cycle_analytics_spec.rb +++ b/spec/models/cycle_analytics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CycleAnalytics do diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb index 41440c6d288..ec6cfb6b826 100644 --- a/spec/models/deploy_key_spec.rb +++ b/spec/models/deploy_key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DeployKey, :mailer do diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb index fca3090ff4a..c137444763b 100644 --- a/spec/models/deploy_keys_project_spec.rb +++ b/spec/models/deploy_keys_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DeployKeysProject do diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb index 3435f93c999..05320703e25 100644 --- a/spec/models/deploy_token_spec.rb +++ b/spec/models/deploy_token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DeployToken do diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index 5fce9504334..d9170d5fa07 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Deployment do diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb index 50b19000799..cfeb4382927 100644 --- a/spec/models/diff_discussion_spec.rb +++ b/spec/models/diff_discussion_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DiffDiscussion do diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index 67e5f4f7e41..fa19cb47a0d 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DiffNote do diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb index f4efe5a7b3a..b8bdeb781dc 100644 --- a/spec/models/diff_viewer/base_spec.rb +++ b/spec/models/diff_viewer/base_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DiffViewer::Base do diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb index 86b14b6ebf3..27de0584b8a 100644 --- a/spec/models/diff_viewer/server_side_spec.rb +++ b/spec/models/diff_viewer/server_side_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DiffViewer::ServerSide do diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb index a46f7ed6507..0d02165787a 100644 --- a/spec/models/discussion_spec.rb +++ b/spec/models/discussion_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Discussion do diff --git a/spec/models/email_spec.rb b/spec/models/email_spec.rb index 47eb0717c0c..cae88f39660 100644 --- a/spec/models/email_spec.rb +++ b/spec/models/email_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Email do diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index ab1b306e597..448ed35cb1e 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Environment do diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb index 2576a9aba06..c503c35305f 100644 --- a/spec/models/environment_status_spec.rb +++ b/spec/models/environment_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe EnvironmentStatus do diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index cbde13a2c7a..21e381d9fb7 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -167,7 +167,7 @@ describe ErrorTracking::ProjectErrorTrackingSetting do end end - context 'when sentry client raises exception' do + context 'when sentry client raises Sentry::Client::Error' do let(:sentry_client) { spy(:sentry_client) } before do @@ -179,7 +179,31 @@ describe ErrorTracking::ProjectErrorTrackingSetting do end it 'returns error' do - expect(result).to eq(error: 'error message') + expect(result).to eq( + error: 'error message', + error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE + ) + expect(subject).to have_received(:sentry_client) + expect(sentry_client).to have_received(:list_issues) + end + end + + context 'when sentry client raises Sentry::Client::MissingKeysError' do + let(:sentry_client) { spy(:sentry_client) } + + before do + synchronous_reactive_cache(subject) + + allow(subject).to receive(:sentry_client).and_return(sentry_client) + allow(sentry_client).to receive(:list_issues).with(opts) + .and_raise(Sentry::Client::MissingKeysError, 'Sentry API response is missing keys. key not found: "id"') + end + + it 'returns error' do + expect(result).to eq( + error: 'Sentry API response is missing keys. key not found: "id"', + error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_MISSING_KEYS + ) expect(subject).to have_received(:sentry_client) expect(sentry_client).to have_received(:list_issues) end diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb index 6078f429bdc..efe511042c3 100644 --- a/spec/models/event_collection_spec.rb +++ b/spec/models/event_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe EventCollection do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index ce4f8ee4705..d192fe70506 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Event do diff --git a/spec/models/external_issue_spec.rb b/spec/models/external_issue_spec.rb index 83ba22caa03..9d064d458f0 100644 --- a/spec/models/external_issue_spec.rb +++ b/spec/models/external_issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ExternalIssue do diff --git a/spec/models/fork_network_member_spec.rb b/spec/models/fork_network_member_spec.rb index 60d04562e6c..eab758248de 100644 --- a/spec/models/fork_network_member_spec.rb +++ b/spec/models/fork_network_member_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ForkNetworkMember do diff --git a/spec/models/fork_network_spec.rb b/spec/models/fork_network_spec.rb index a43baf1820a..5ec0f8d6b02 100644 --- a/spec/models/fork_network_spec.rb +++ b/spec/models/fork_network_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ForkNetwork do diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index a3e68d2e646..c851810ffb3 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GenericCommitStatus do diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index f93904065c7..9d901d01a52 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GlobalMilestone do diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 58a1d2e4ea2..479b39cd139 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe GpgKey do diff --git a/spec/models/gpg_key_subkey_spec.rb b/spec/models/gpg_key_subkey_spec.rb index 3c86837f47f..51d2f9cb9ac 100644 --- a/spec/models/gpg_key_subkey_spec.rb +++ b/spec/models/gpg_key_subkey_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe GpgKeySubkey do diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index e90319c39b1..47c343edf0e 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe GpgSignature do diff --git a/spec/models/group_custom_attribute_spec.rb b/spec/models/group_custom_attribute_spec.rb index 7ecb2022567..7d60c74b62b 100644 --- a/spec/models/group_custom_attribute_spec.rb +++ b/spec/models/group_custom_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupCustomAttribute do diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb index d0fc1eaa3ec..a3a5c631c3d 100644 --- a/spec/models/group_label_spec.rb +++ b/spec/models/group_label_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupLabel do diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index fcc33cd95fe..01856870fe0 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupMilestone do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 16624ce47d0..2c6abddca17 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Group do diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index fc30f3056e5..93862e98172 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Guest do diff --git a/spec/models/hooks/active_hook_filter_spec.rb b/spec/models/hooks/active_hook_filter_spec.rb index df7edda2213..1249c793f7f 100644 --- a/spec/models/hooks/active_hook_filter_spec.rb +++ b/spec/models/hooks/active_hook_filter_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ActiveHookFilter do diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index 5dd31b1b5de..a945f0d1516 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectHook do diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index e32eaafc13f..936c2fbad27 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ServiceHook do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index edd1cb455af..e0d4d2e4858 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe SystemHook do diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb index 744a6ccae8b..f812149c9be 100644 --- a/spec/models/hooks/web_hook_log_spec.rb +++ b/spec/models/hooks/web_hook_log_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe WebHookLog do diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index a308ac6e33a..fe08dc4f5e6 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe WebHook do diff --git a/spec/models/identity_spec.rb b/spec/models/identity_spec.rb index e1a7a59dfd1..74ddc2d6284 100644 --- a/spec/models/identity_spec.rb +++ b/spec/models/identity_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Identity do diff --git a/spec/models/import_export_upload_spec.rb b/spec/models/import_export_upload_spec.rb index 58af84b8a08..18a714f4d98 100644 --- a/spec/models/import_export_upload_spec.rb +++ b/spec/models/import_export_upload_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ImportExportUpload do diff --git a/spec/models/instance_configuration_spec.rb b/spec/models/instance_configuration_spec.rb index cb3d6c7cda2..e65f97df3c3 100644 --- a/spec/models/instance_configuration_spec.rb +++ b/spec/models/instance_configuration_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe InstanceConfiguration do @@ -30,8 +32,8 @@ describe InstanceConfiguration do end def stub_pub_file(exist: true) - path = 'spec/fixtures/ssh_host_example_key.pub' - path << 'random' unless exist + path = exist ? 'spec/fixtures/ssh_host_example_key.pub' : 'spec/fixtures/ssh_host_example_key.pub.random' + allow(subject).to receive(:ssh_algorithm_file).and_return(Rails.root.join(path)) end end diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb index d32f163f05b..ff2382838ae 100644 --- a/spec/models/internal_id_spec.rb +++ b/spec/models/internal_id_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe InternalId do diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb index b7291eebe64..07858fe8a70 100644 --- a/spec/models/issue/metrics_spec.rb +++ b/spec/models/issue/metrics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Issue::Metrics do diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index 580a98193af..7fc635f100f 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe IssueCollection do diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index 6101df2e099..892dd053e39 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Issue do diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index 06d26ef89f1..a0b6eff88d5 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Key, :mailer do diff --git a/spec/models/label_link_spec.rb b/spec/models/label_link_spec.rb index e2b49bc2de7..b160e72e759 100644 --- a/spec/models/label_link_spec.rb +++ b/spec/models/label_link_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LabelLink do diff --git a/spec/models/label_priority_spec.rb b/spec/models/label_priority_spec.rb index 9dcb0f06b20..1a93468290f 100644 --- a/spec/models/label_priority_spec.rb +++ b/spec/models/label_priority_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LabelPriority do diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb index 3fc6c06b7fa..5174c590a10 100644 --- a/spec/models/label_spec.rb +++ b/spec/models/label_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Label do diff --git a/spec/models/legacy_diff_discussion_spec.rb b/spec/models/legacy_diff_discussion_spec.rb index dae97b69c84..49ea319fbd1 100644 --- a/spec/models/legacy_diff_discussion_spec.rb +++ b/spec/models/legacy_diff_discussion_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LegacyDiffDiscussion do diff --git a/spec/models/lfs_download_object_spec.rb b/spec/models/lfs_download_object_spec.rb index 88838b127d2..effd8b08124 100644 --- a/spec/models/lfs_download_object_spec.rb +++ b/spec/models/lfs_download_object_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe LfsDownloadObject do diff --git a/spec/models/lfs_file_lock_spec.rb b/spec/models/lfs_file_lock_spec.rb index 41ca1578b94..aa64d66944b 100644 --- a/spec/models/lfs_file_lock_spec.rb +++ b/spec/models/lfs_file_lock_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe LfsFileLock do diff --git a/spec/models/lfs_object_spec.rb b/spec/models/lfs_object_spec.rb index 3f929710862..3d4d4b7d795 100644 --- a/spec/models/lfs_object_spec.rb +++ b/spec/models/lfs_object_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LfsObject do diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb index 0a3180f43e8..3e86ee38566 100644 --- a/spec/models/lfs_objects_project_spec.rb +++ b/spec/models/lfs_objects_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe LfsObjectsProject do diff --git a/spec/models/license_template_spec.rb b/spec/models/license_template_spec.rb index dd912eefac1..7037277e580 100644 --- a/spec/models/license_template_spec.rb +++ b/spec/models/license_template_spec.rb @@ -1,16 +1,19 @@ +# frozen_string_literal: true + require 'spec_helper' describe LicenseTemplate do describe '#content' do it 'calls a proc exactly once if provided' do - lazy = build_template(-> { 'bar' }) - content = lazy.content + content_proc = -> { 'bar' } + expect(content_proc).to receive(:call).once.and_call_original + + lazy = build_template(content_proc) - expect(content).to eq('bar') - expect(content.object_id).to eq(lazy.content.object_id) + expect(lazy.content).to eq('bar') - content.replace('foo') - expect(lazy.content).to eq('foo') + # Subsequent calls should not call proc again + expect(lazy.content).to eq('bar') end it 'returns a string if provided' do diff --git a/spec/models/list_spec.rb b/spec/models/list_spec.rb index a51580f8292..18d4549977c 100644 --- a/spec/models/list_spec.rb +++ b/spec/models/list_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe List do diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 188beac1582..c68c3ce2abe 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Member do diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index a3451c67bd8..f227abd3dae 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -1,6 +1,24 @@ +# frozen_string_literal: true + require 'spec_helper' describe GroupMember do + describe '.count_users_by_group_id' do + it 'counts users by group ID' do + user_1 = create(:user) + user_2 = create(:user) + group_1 = create(:group) + group_2 = create(:group) + + group_1.add_owner(user_1) + group_1.add_owner(user_2) + group_2.add_owner(user_1) + + expect(described_class.count_users_by_group_id).to eq(group_1.id => 2, + group_2.id => 1) + end + end + describe '.access_level_roles' do it 'returns Gitlab::Access.options_with_owner' do expect(described_class.access_level_roles).to eq(Gitlab::Access.options_with_owner) diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 36bfff2c339..497764b6825 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectMember do diff --git a/spec/models/merge_request/metrics_spec.rb b/spec/models/merge_request/metrics_spec.rb index 02ff7839739..49573af0fed 100644 --- a/spec/models/merge_request/metrics_spec.rb +++ b/spec/models/merge_request/metrics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MergeRequest::Metrics do diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb index 10487190a44..ab2aadf7d88 100644 --- a/spec/models/merge_request_diff_commit_spec.rb +++ b/spec/models/merge_request_diff_commit_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe MergeRequestDiffCommit do diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb index faa47660a74..66957c24fdc 100644 --- a/spec/models/merge_request_diff_file_spec.rb +++ b/spec/models/merge_request_diff_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe MergeRequestDiffFile do diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 53f5307ea0b..a53add67066 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MergeRequestDiff do @@ -51,7 +53,104 @@ describe MergeRequestDiff do end end - describe '#latest' do + describe '.ids_for_external_storage_migration' do + set(:merge_request) { create(:merge_request) } + set(:outdated) { merge_request.merge_request_diff } + set(:latest) { merge_request.create_merge_request_diff } + + set(:closed_mr) { create(:merge_request, :closed_last_month) } + let(:closed) { closed_mr.merge_request_diff } + + set(:merged_mr) { create(:merge_request, :merged_last_month) } + let(:merged) { merged_mr.merge_request_diff } + + set(:recently_closed_mr) { create(:merge_request, :closed) } + let(:closed_recently) { recently_closed_mr.merge_request_diff } + + set(:recently_merged_mr) { create(:merge_request, :merged) } + let(:merged_recently) { recently_merged_mr.merge_request_diff } + + before do + merge_request.update!(latest_merge_request_diff: latest) + end + + subject { described_class.ids_for_external_storage_migration(limit: 1000) } + + context 'external diffs are disabled' do + before do + stub_external_diffs_setting(enabled: false) + end + + it { is_expected.to be_empty } + end + + context 'external diffs are misconfigured' do + before do + stub_external_diffs_setting(enabled: true, when: 'every second tuesday') + end + + it { is_expected.to be_empty } + end + + context 'external diffs are enabled unconditionally' do + before do + stub_external_diffs_setting(enabled: true) + end + + it { is_expected.to contain_exactly(outdated.id, latest.id, closed.id, merged.id, closed_recently.id, merged_recently.id) } + end + + context 'external diffs are enabled for outdated diffs' do + before do + stub_external_diffs_setting(enabled: true, when: 'outdated') + end + + it 'returns records for outdated merge request versions' do + is_expected.to contain_exactly(outdated.id, closed.id, merged.id) + end + end + + context 'with limit' do + it 'respects the limit' do + stub_external_diffs_setting(enabled: true) + + expect(described_class.ids_for_external_storage_migration(limit: 3).count).to eq(3) + end + end + end + + describe '#migrate_files_to_external_storage!' do + let(:diff) { create(:merge_request).merge_request_diff } + + it 'converts from in-database to external storage' do + expect(diff).not_to be_stored_externally + + stub_external_diffs_setting(enabled: true) + expect(diff).to receive(:save!) + + diff.migrate_files_to_external_storage! + + expect(diff).to be_stored_externally + end + + it 'does nothing with an external diff' do + stub_external_diffs_setting(enabled: true) + + expect(diff).to be_stored_externally + expect(diff).not_to receive(:save!) + + diff.migrate_files_to_external_storage! + end + + it 'does nothing if external diffs are disabled' do + expect(diff).not_to be_stored_externally + expect(diff).not_to receive(:save!) + + diff.migrate_files_to_external_storage! + end + end + + describe '#latest?' do let!(:mr) { create(:merge_request, :with_diffs) } let!(:first_diff) { mr.merge_request_diff } let!(:last_diff) { mr.create_merge_request_diff } @@ -222,12 +321,56 @@ describe MergeRequestDiff do include_examples 'merge request diffs' end - describe 'external diffs configured' do + describe 'external diffs always enabled' do before do - stub_external_diffs_setting(enabled: true) + stub_external_diffs_setting(enabled: true, when: 'always') + end + + include_examples 'merge request diffs' + end + + describe 'exernal diffs enabled for outdated diffs' do + before do + stub_external_diffs_setting(enabled: true, when: 'outdated') end include_examples 'merge request diffs' + + it 'stores up-to-date diffs in the database' do + expect(diff).not_to be_stored_externally + end + + it 'stores diffs for recently closed MRs in the database' do + mr = create(:merge_request, :closed) + + expect(mr.merge_request_diff).not_to be_stored_externally + end + + it 'stores diffs for recently merged MRs in the database' do + mr = create(:merge_request, :merged) + + expect(mr.merge_request_diff).not_to be_stored_externally + end + + it 'stores diffs for old MR versions in external storage' do + old_diff = diff + merge_request.create_merge_request_diff + old_diff.migrate_files_to_external_storage! + + expect(old_diff).to be_stored_externally + end + + it 'stores diffs for old closed MRs in external storage' do + mr = create(:merge_request, :closed_last_month) + + expect(mr.merge_request_diff).to be_stored_externally + end + + it 'stores diffs for old merged MRs in external storage' do + mr = create(:merge_request, :merged_last_month) + + expect(mr.merge_request_diff).to be_stored_externally + end end describe '#commit_shas' do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 2bcc8a77224..4b3a77e6bc2 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MergeRequest do @@ -179,6 +181,31 @@ describe MergeRequest do expect(MergeRequest::Metrics.count).to eq(1) end end + + describe '#refresh_merge_request_assignees' do + set(:user) { create(:user) } + + it 'creates merge request assignees relation upon MR creation' do + merge_request = create(:merge_request, assignee: nil) + + expect(merge_request.merge_request_assignees).to be_empty + + expect { merge_request.update!(assignee: user) } + .to change { merge_request.reload.merge_request_assignees.count } + .from(0).to(1) + end + + it 'updates merge request assignees relation upon MR assignee change' do + another_user = create(:user) + merge_request = create(:merge_request, assignee: user) + + expect { merge_request.update!(assignee: another_user) } + .to change { merge_request.reload.merge_request_assignees.first.assignee } + .from(user).to(another_user) + + expect(merge_request.merge_request_assignees.count).to eq(1) + end + end end describe 'respond to' do @@ -2687,14 +2714,21 @@ describe MergeRequest do end describe '#has_commits?' do - before do + it 'returns true when merge request diff has commits' do allow(subject.merge_request_diff).to receive(:commits_count) .and_return(2) - end - it 'returns true when merge request diff has commits' do expect(subject.has_commits?).to be_truthy end + + context 'when commits_count is nil' do + it 'returns false' do + allow(subject.merge_request_diff).to receive(:commits_count) + .and_return(nil) + + expect(subject.has_commits?).to be_falsey + end + end end describe '#has_no_commits?' do @@ -3090,4 +3124,32 @@ describe MergeRequest do end end end + + describe '.merge_request_ref?' do + subject { described_class.merge_request_ref?(ref) } + + context 'when ref is ref name of a branch' do + let(:ref) { 'feature' } + + it { is_expected.to be_falsey } + end + + context 'when ref is HEAD ref path of a branch' do + let(:ref) { 'refs/heads/feature' } + + it { is_expected.to be_falsey } + end + + context 'when ref is HEAD ref path of a merge request' do + let(:ref) { 'refs/merge-requests/1/head' } + + it { is_expected.to be_truthy } + end + + context 'when ref is merge ref path of a merge request' do + let(:ref) { 'refs/merge-requests/1/merge' } + + it { is_expected.to be_truthy } + end + end end diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index 717d4ae4ec0..b82368318f2 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Milestone do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index aadc298ae0b..62e7dd3231b 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Namespace do diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb index c364dd6643b..d1a2bedf542 100644 --- a/spec/models/network/graph_spec.rb +++ b/spec/models/network/graph_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Network::Graph do diff --git a/spec/models/note_diff_file_spec.rb b/spec/models/note_diff_file_spec.rb index 591c1a89748..99eeac8d778 100644 --- a/spec/models/note_diff_file_spec.rb +++ b/spec/models/note_diff_file_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe NoteDiffFile do diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index eb6f6ff5faf..7a1ab20186a 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Note do diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb index 13fe47799ed..3710f2be287 100644 --- a/spec/models/notification_recipient_spec.rb +++ b/spec/models/notification_recipient_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe NotificationRecipient do diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index c8ab564e3bc..85128456918 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe NotificationSetting do diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb index 4b85c5e8720..142ddebbbf8 100644 --- a/spec/models/pages_domain_spec.rb +++ b/spec/models/pages_domain_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PagesDomain do diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb index c82ab9c9e62..e0e1101ffc6 100644 --- a/spec/models/personal_access_token_spec.rb +++ b/spec/models/personal_access_token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PersonalAccessToken do diff --git a/spec/models/programming_language_spec.rb b/spec/models/programming_language_spec.rb index 99cd358f863..b327d360461 100644 --- a/spec/models/programming_language_spec.rb +++ b/spec/models/programming_language_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProgrammingLanguage do diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb index c289ee0859a..6f06fe4e55a 100644 --- a/spec/models/project_authorization_spec.rb +++ b/spec/models/project_authorization_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectAuthorization do diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 7ff64c76e37..8ad28ce68cc 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectAutoDevops do diff --git a/spec/models/project_custom_attribute_spec.rb b/spec/models/project_custom_attribute_spec.rb index 669de5506bc..80638676b49 100644 --- a/spec/models/project_custom_attribute_spec.rb +++ b/spec/models/project_custom_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectCustomAttribute do diff --git a/spec/models/project_deploy_token_spec.rb b/spec/models/project_deploy_token_spec.rb index 9e2e40c2e8f..2a5fefc1ab0 100644 --- a/spec/models/project_deploy_token_spec.rb +++ b/spec/models/project_deploy_token_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe ProjectDeployToken, type: :model do diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index fee7d65c217..50c9d5968ac 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectFeature do diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 5bea21427d4..dad5506900b 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectGroupLink do diff --git a/spec/models/project_import_state_spec.rb b/spec/models/project_import_state_spec.rb index e3b2d971419..472bf8f9713 100644 --- a/spec/models/project_import_state_spec.rb +++ b/spec/models/project_import_state_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe ProjectImportState, type: :model do diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb index 689d4e505e5..330aab9f856 100644 --- a/spec/models/project_label_spec.rb +++ b/spec/models/project_label_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectLabel do diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index e66109fd98f..18e839bcc64 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe AsanaService do diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index 5cb6d63659e..7742e33e901 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe AssemblaService do diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index b880d90d28f..08c510f09df 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BambooService, :use_clean_rails_memory_store_caching do diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb index 43f7bcb1a19..6818db48fee 100644 --- a/spec/models/project_services/bugzilla_service_spec.rb +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BugzillaService do diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index 1615a93a4ca..091d4d8f695 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe BuildkiteService, :use_clean_rails_memory_store_caching do diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index ed8347edffd..bf4c52fc7ab 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CampfireService do diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb index f7a35fdc88a..d3adc62c38e 100644 --- a/spec/models/project_services/chat_message/issue_message_spec.rb +++ b/spec/models/project_services/chat_message/issue_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::IssueMessage do diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb index 7997b5bb6b9..b56eb19dd55 100644 --- a/spec/models/project_services/chat_message/merge_message_spec.rb +++ b/spec/models/project_services/chat_message/merge_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::MergeMessage do diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb index 5abbd7bec18..5e7987dc0f6 100644 --- a/spec/models/project_services/chat_message/note_message_spec.rb +++ b/spec/models/project_services/chat_message/note_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::NoteMessage do diff --git a/spec/models/project_services/chat_message/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb index 0ff20400999..8f9fa310ad4 100644 --- a/spec/models/project_services/chat_message/pipeline_message_spec.rb +++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::PipelineMessage do diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index 973d6bdb2a0..a89645a3ea8 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::PushMessage do diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index 7efcba9bcfd..c3db516f253 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatMessage::WikiPageMessage do diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb index 46713df77da..6f4ddd223f6 100644 --- a/spec/models/project_services/chat_notification_service_spec.rb +++ b/spec/models/project_services/chat_notification_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ChatNotificationService do diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb index 7e1b1a4f2af..f0e7551693d 100644 --- a/spec/models/project_services/custom_issue_tracker_service_spec.rb +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe CustomIssueTrackerService do diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 26597d9b83c..22df19d943f 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe DroneCiService, :use_clean_rails_memory_store_caching do diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb index d9b7010e5e5..0a58eb367e3 100644 --- a/spec/models/project_services/emails_on_push_service_spec.rb +++ b/spec/models/project_services/emails_on_push_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe EmailsOnPushService do diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index 62fd97b038b..bdd8605436f 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ExternalWikiService do diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index fabcb142858..c1ebe69ee66 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe FlowdockService do 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 3237b660a16..11f96c03d46 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe GitlabIssueTrackerService do diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index cb9ca76fc3f..2e1f6964692 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'socket' require 'json' diff --git a/spec/models/project_services/issue_tracker_service_spec.rb b/spec/models/project_services/issue_tracker_service_spec.rb index e6a1752576b..2fc4d69c2db 100644 --- a/spec/models/project_services/issue_tracker_service_spec.rb +++ b/spec/models/project_services/issue_tracker_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe IssueTrackerService do diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 5428fcb1271..4a7eee1fbf3 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe JiraService do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 56e587262ef..7bf093b71e7 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe KubernetesService, :use_clean_rails_memory_store_caching do diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb index 10c62ca55a7..6261c70f266 100644 --- a/spec/models/project_services/mattermost_service_spec.rb +++ b/spec/models/project_services/mattermost_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MattermostService 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 1983e0cc967..87e482059f2 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MattermostSlashCommandsService do diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index 3351c6280b4..521d5265753 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe MicrosoftTeamsService do diff --git a/spec/models/project_services/packagist_service_spec.rb b/spec/models/project_services/packagist_service_spec.rb index 6acee311700..53f18a1bdd9 100644 --- a/spec/models/project_services/packagist_service_spec.rb +++ b/spec/models/project_services/packagist_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PackagistService do diff --git a/spec/models/project_services/pipelines_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb index 75ae2207910..ca17e7453b8 100644 --- a/spec/models/project_services/pipelines_email_service_spec.rb +++ b/spec/models/project_services/pipelines_email_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PipelinesEmailService, :mailer do diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb index f7d2372eca2..de2c8790405 100644 --- a/spec/models/project_services/pivotaltracker_service_spec.rb +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PivotaltrackerService do diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 54b8c658ff6..d2a45f48705 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PushoverService do diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb index 2ac14eab5e1..ac570ac27e1 100644 --- a/spec/models/project_services/redmine_service_spec.rb +++ b/spec/models/project_services/redmine_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe RedmineService do diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 13cf4d1915e..01f580c5d01 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SlackService do diff --git a/spec/models/project_services/slack_slash_commands_service_spec.rb b/spec/models/project_services/slack_slash_commands_service_spec.rb index 5c4bce90ace..8c57907d064 100644 --- a/spec/models/project_services/slack_slash_commands_service_spec.rb +++ b/spec/models/project_services/slack_slash_commands_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SlackSlashCommandsService do diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index 64b4efca43a..96dccae733b 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe TeamcityService, :use_clean_rails_memory_store_caching do diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb index 9524b526a46..bf9d892f66c 100644 --- a/spec/models/project_services/youtrack_service_spec.rb +++ b/spec/models/project_services/youtrack_service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe YoutrackService do diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb index 1b439bcfad1..e87b4f41f4d 100644 --- a/spec/models/project_snippet_spec.rb +++ b/spec/models/project_snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectSnippet do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1ea54eeb4f7..2158d3cf3e6 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Project do @@ -2710,7 +2712,7 @@ describe Project do end describe '#any_lfs_file_locks?', :request_store do - set(:project) { create(:project) } + let!(:project) { create(:project) } it 'returns false when there are no LFS file locks' do expect(project.any_lfs_file_locks?).to be_falsey @@ -3148,6 +3150,53 @@ describe Project do expect(projects).to eq([public_project]) end end + + context 'with requested visibility levels' do + set(:internal_project) { create(:project, :internal, :repository) } + set(:private_project_2) { create(:project, :private) } + + context 'with admin user' do + set(:admin) { create(:admin) } + + it 'returns all projects' do + projects = described_class.all.public_or_visible_to_user(admin, []) + + expect(projects).to match_array([public_project, private_project, private_project_2, internal_project]) + end + + it 'returns all public and private projects' do + projects = described_class.all.public_or_visible_to_user(admin, [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::PRIVATE]) + + expect(projects).to match_array([public_project, private_project, private_project_2]) + end + + it 'returns all private projects' do + projects = described_class.all.public_or_visible_to_user(admin, [Gitlab::VisibilityLevel::PRIVATE]) + + expect(projects).to match_array([private_project, private_project_2]) + end + end + + context 'with regular user' do + it 'returns authorized projects' do + projects = described_class.all.public_or_visible_to_user(user, []) + + expect(projects).to match_array([public_project, private_project, internal_project]) + end + + it "returns user's public and private projects" do + projects = described_class.all.public_or_visible_to_user(user, [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::PRIVATE]) + + expect(projects).to match_array([public_project, private_project]) + end + + it 'returns one private project' do + projects = described_class.all.public_or_visible_to_user(user, [Gitlab::VisibilityLevel::PRIVATE]) + + expect(projects).to eq([private_project]) + end + end + end end describe '.with_feature_available_for_user' do @@ -3428,7 +3477,7 @@ describe Project do end it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the project repo is in use' do - Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: false)).increase + Gitlab::ReferenceCounter.new(Gitlab::GlRepository::PROJECT.identifier_for_subject(project)).increase expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in) @@ -3436,7 +3485,7 @@ describe Project do end it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do - Gitlab::ReferenceCounter.new(project.gl_repository(is_wiki: true)).increase + Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_subject(project)).increase expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in) @@ -3569,16 +3618,6 @@ describe Project do end end - describe '#gl_repository' do - let(:project) { create(:project) } - - it 'delegates to Gitlab::GlRepository.gl_repository' do - expect(Gitlab::GlRepository).to receive(:gl_repository).with(project, true) - - project.gl_repository(is_wiki: true) - end - end - describe '#has_ci?' do set(:project) { create(:project) } let(:repository) { double } diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb index 64c39f09e33..c670b6aac56 100644 --- a/spec/models/project_statistics_spec.rb +++ b/spec/models/project_statistics_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe ProjectStatistics do diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 3537dead5d1..a2d4fad9292 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe ProjectTeam do diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 7be8d67ba9e..7ea67f31534 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -1,4 +1,6 @@ # coding: utf-8 +# frozen_string_literal: true + require "spec_helper" describe ProjectWiki do diff --git a/spec/models/protectable_dropdown_spec.rb b/spec/models/protectable_dropdown_spec.rb index d4433a88a15..aca3df9fdde 100644 --- a/spec/models/protectable_dropdown_spec.rb +++ b/spec/models/protectable_dropdown_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectableDropdown do diff --git a/spec/models/protected_branch/merge_access_level_spec.rb b/spec/models/protected_branch/merge_access_level_spec.rb index 612e4a0e332..39dd586b157 100644 --- a/spec/models/protected_branch/merge_access_level_spec.rb +++ b/spec/models/protected_branch/merge_access_level_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectedBranch::MergeAccessLevel do diff --git a/spec/models/protected_branch/push_access_level_spec.rb b/spec/models/protected_branch/push_access_level_spec.rb index 9ccdc22fd41..628c8d29ecd 100644 --- a/spec/models/protected_branch/push_access_level_spec.rb +++ b/spec/models/protected_branch/push_access_level_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectedBranch::PushAccessLevel do diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index dafe7646366..267434a4148 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectedBranch do diff --git a/spec/models/protected_tag_spec.rb b/spec/models/protected_tag_spec.rb index e5a0f6ec23f..79120d17d39 100644 --- a/spec/models/protected_tag_spec.rb +++ b/spec/models/protected_tag_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProtectedTag do diff --git a/spec/models/push_event_payload_spec.rb b/spec/models/push_event_payload_spec.rb index 69a4922b6fd..6b59ee5ee57 100644 --- a/spec/models/push_event_payload_spec.rb +++ b/spec/models/push_event_payload_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PushEventPayload do diff --git a/spec/models/push_event_spec.rb b/spec/models/push_event_spec.rb index bfe7a30b96a..f86500f91cd 100644 --- a/spec/models/push_event_spec.rb +++ b/spec/models/push_event_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe PushEvent do diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb index 106ae59af29..6ecb5c31c7e 100644 --- a/spec/models/redirect_route_spec.rb +++ b/spec/models/redirect_route_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe RedirectRoute do diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb index 157c96c1f65..b4b32c95dee 100644 --- a/spec/models/release_spec.rb +++ b/spec/models/release_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe Release do diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb index c06e9a08ab4..0478094034a 100644 --- a/spec/models/remote_mirror_spec.rb +++ b/spec/models/remote_mirror_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe RemoteMirror, :mailer do diff --git a/spec/models/repository_language_spec.rb b/spec/models/repository_language_spec.rb index e2e4beb512f..13a4cd1e7cf 100644 --- a/spec/models/repository_language_spec.rb +++ b/spec/models/repository_language_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe RepositoryLanguage do diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 6599b4e765a..2578208659a 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Repository do diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 48799781b87..20289afbeb5 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Route do diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb index 6c35ed8f649..09be90b82ed 100644 --- a/spec/models/sent_notification_spec.rb +++ b/spec/models/sent_notification_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SentNotification do diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 25eecb3f909..2f025038bab 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Service do diff --git a/spec/models/snippet_blob_spec.rb b/spec/models/snippet_blob_spec.rb index 7c71c458fcc..88441e39d45 100644 --- a/spec/models/snippet_blob_spec.rb +++ b/spec/models/snippet_blob_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SnippetBlob do diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 664dc3fa145..3524cdae3b8 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Snippet do diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb index 90a2caaeb88..e9ea234f75d 100644 --- a/spec/models/spam_log_spec.rb +++ b/spec/models/spam_log_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SpamLog do diff --git a/spec/models/ssh_host_key_spec.rb b/spec/models/ssh_host_key_spec.rb index 4c677569561..a17cd8ba345 100644 --- a/spec/models/ssh_host_key_spec.rb +++ b/spec/models/ssh_host_key_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SshHostKey do diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb index 9e4c2620d82..41bd48810b2 100644 --- a/spec/models/subscription_spec.rb +++ b/spec/models/subscription_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Subscription do diff --git a/spec/models/system_note_metadata_spec.rb b/spec/models/system_note_metadata_spec.rb index 1e3f587e460..bcd3c03f947 100644 --- a/spec/models/system_note_metadata_spec.rb +++ b/spec/models/system_note_metadata_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe SystemNoteMetadata do diff --git a/spec/models/term_agreement_spec.rb b/spec/models/term_agreement_spec.rb index 950dfa09a6a..42a48048b67 100644 --- a/spec/models/term_agreement_spec.rb +++ b/spec/models/term_agreement_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe TermAgreement do diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb index a0c93c531ea..9d69a0ab148 100644 --- a/spec/models/timelog_spec.rb +++ b/spec/models/timelog_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' RSpec.describe Timelog do diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb index 3682e21ca40..b5bf294790a 100644 --- a/spec/models/todo_spec.rb +++ b/spec/models/todo_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Todo do diff --git a/spec/models/tree_spec.rb b/spec/models/tree_spec.rb index 6bdb62a0864..c2d5dfdf9c4 100644 --- a/spec/models/tree_spec.rb +++ b/spec/models/tree_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Tree do diff --git a/spec/models/trending_project_spec.rb b/spec/models/trending_project_spec.rb index 3b5e7ca0d39..619fc8e7d38 100644 --- a/spec/models/trending_project_spec.rb +++ b/spec/models/trending_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe TrendingProject do diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index 5a0df9fbbb0..02702cb2497 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe Upload do diff --git a/spec/models/user_agent_detail_spec.rb b/spec/models/user_agent_detail_spec.rb index b4669f8c1c2..f191d245045 100644 --- a/spec/models/user_agent_detail_spec.rb +++ b/spec/models/user_agent_detail_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe UserAgentDetail do diff --git a/spec/models/user_callout_spec.rb b/spec/models/user_callout_spec.rb index d54355afe12..b87f6f03d6f 100644 --- a/spec/models/user_callout_spec.rb +++ b/spec/models/user_callout_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'rails_helper' describe UserCallout do diff --git a/spec/models/user_custom_attribute_spec.rb b/spec/models/user_custom_attribute_spec.rb index 37fc3cb64f0..d0981b2d771 100644 --- a/spec/models/user_custom_attribute_spec.rb +++ b/spec/models/user_custom_attribute_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe UserCustomAttribute do diff --git a/spec/models/user_interacted_project_spec.rb b/spec/models/user_interacted_project_spec.rb index cb4bb3372d4..47d919c1d12 100644 --- a/spec/models/user_interacted_project_spec.rb +++ b/spec/models/user_interacted_project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe UserInteractedProject do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 1be29d039a7..b7e36748fa2 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe User do diff --git a/spec/models/wiki_directory_spec.rb b/spec/models/wiki_directory_spec.rb index fb8575cfe2b..5fbcccf897e 100644 --- a/spec/models/wiki_directory_spec.rb +++ b/spec/models/wiki_directory_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' RSpec.describe WikiDirectory do diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index cba22b2cc4e..e68da67818a 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe WikiPage do diff --git a/spec/policies/board_policy_spec.rb b/spec/policies/board_policy_spec.rb index 4b76d65ef69..52c23951e37 100644 --- a/spec/policies/board_policy_spec.rb +++ b/spec/policies/board_policy_spec.rb @@ -17,14 +17,6 @@ describe BoardPolicy do ] end - def expect_allowed(*permissions) - permissions.each { |p| is_expected.to be_allowed(p) } - end - - def expect_disallowed(*permissions) - permissions.each { |p| is_expected.not_to be_allowed(p) } - end - context 'group board' do subject { described_class.new(user, group_board) } diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 92bdaa8b8b8..dc98baca6dc 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -1,63 +1,7 @@ require 'spec_helper' describe GroupPolicy do - let(:guest) { create(:user) } - let(:reporter) { create(:user) } - let(:developer) { create(:user) } - let(:maintainer) { create(:user) } - let(:owner) { create(:user) } - let(:admin) { create(:admin) } - let(:group) { create(:group, :private) } - - let(:guest_permissions) do - [:read_label, :read_group, :upload_file, :read_namespace, :read_group_activity, - :read_group_issues, :read_group_boards, :read_group_labels, :read_group_milestones, - :read_group_merge_requests] - end - - let(:reporter_permissions) { [:admin_label] } - - let(:developer_permissions) { [:admin_milestone] } - - let(:maintainer_permissions) do - [ - :create_projects, - :read_cluster, - :create_cluster, - :update_cluster, - :admin_cluster, - :add_cluster - ] - end - - let(:owner_permissions) do - [ - :admin_group, - :admin_namespace, - :admin_group_member, - :change_visibility_level, - :set_note_created_at, - (Gitlab::Database.postgresql? ? :create_subgroup : nil) - ].compact - end - - before do - group.add_guest(guest) - group.add_reporter(reporter) - group.add_developer(developer) - group.add_maintainer(maintainer) - group.add_owner(owner) - end - - subject { described_class.new(current_user, group) } - - def expect_allowed(*permissions) - permissions.each { |p| is_expected.to be_allowed(p) } - end - - def expect_disallowed(*permissions) - permissions.each { |p| is_expected.not_to be_allowed(p) } - end + include_context 'GroupPolicy context' context 'with no user' do let(:group) { create(:group, :public) } diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespace_policy_spec.rb index 1fdf95ad716..99fa8b1fe44 100644 --- a/spec/policies/namespace_policy_spec.rb +++ b/spec/policies/namespace_policy_spec.rb @@ -30,7 +30,7 @@ describe NamespacePolicy do context 'user who has exceeded project limit' do let(:owner) { create(:user, projects_limit: 0) } - it { is_expected.not_to be_allowed(:create_projects) } + it { is_expected.to be_disallowed(:create_projects) } end end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 772d1fbee2b..726ccba8807 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -1,96 +1,7 @@ require 'spec_helper' describe ProjectPolicy do - set(:guest) { create(:user) } - set(:reporter) { create(:user) } - set(:developer) { create(:user) } - set(:maintainer) { create(:user) } - set(:owner) { create(:user) } - set(:admin) { create(:admin) } - let(:project) { create(:project, :public, namespace: owner.namespace) } - - let(:base_guest_permissions) do - %i[ - read_project read_board read_list read_wiki read_issue - read_project_for_iids read_issue_iid read_label - read_milestone read_project_snippet read_project_member read_note - create_project create_issue create_note upload_file create_merge_request_in - award_emoji read_release - ] - end - - let(:base_reporter_permissions) do - %i[ - download_code fork_project create_project_snippet update_issue - admin_issue admin_label admin_list read_commit_status read_build - read_container_image read_pipeline read_environment read_deployment - read_merge_request download_wiki_code read_sentry_issue - ] - end - - let(:team_member_reporter_permissions) do - %i[build_download_code build_read_container_image] - end - - let(:developer_permissions) do - %i[ - admin_milestone admin_merge_request update_merge_request create_commit_status - update_commit_status create_build update_build create_pipeline - update_pipeline create_merge_request_from create_wiki push_code - resolve_note create_container_image update_container_image - create_environment create_deployment create_release update_release - ] - end - - let(:base_maintainer_permissions) do - %i[ - push_to_delete_protected_branch update_project_snippet update_environment - update_deployment admin_project_snippet admin_project_member admin_note admin_wiki admin_project - admin_commit_status admin_build admin_container_image - admin_pipeline admin_environment admin_deployment destroy_release add_cluster - daily_statistics - ] - end - - let(:public_permissions) do - %i[ - download_code fork_project read_commit_status read_pipeline - read_container_image build_download_code build_read_container_image - download_wiki_code read_release - ] - end - - let(:owner_permissions) do - %i[ - change_namespace change_visibility_level rename_project remove_project - archive_project remove_fork_project destroy_merge_request destroy_issue - set_issue_iid set_issue_created_at set_note_created_at - ] - end - - # Used in EE specs - let(:additional_guest_permissions) { [] } - let(:additional_reporter_permissions) { [] } - let(:additional_maintainer_permissions) { [] } - - let(:guest_permissions) { base_guest_permissions + additional_guest_permissions } - let(:reporter_permissions) { base_reporter_permissions + additional_reporter_permissions } - let(:maintainer_permissions) { base_maintainer_permissions + additional_maintainer_permissions } - - before do - project.add_guest(guest) - project.add_maintainer(maintainer) - project.add_developer(developer) - project.add_reporter(reporter) - end - - def expect_allowed(*permissions) - permissions.each { |p| is_expected.to be_allowed(p) } - end - - def expect_disallowed(*permissions) - permissions.each { |p| is_expected.not_to be_allowed(p) } - end + include_context 'ProjectPolicy context' it 'does not include the read_issue permission when the issue author is not a member of the private project' do project = create(:project, :private) @@ -140,7 +51,7 @@ describe ProjectPolicy do end it 'disables boards and lists permissions' do - expect_disallowed :read_board, :create_board, :update_board, :admin_board + expect_disallowed :read_board, :create_board, :update_board expect_disallowed :read_list, :create_list, :update_list, :admin_list end @@ -237,237 +148,6 @@ describe ProjectPolicy do end end - shared_examples 'archived project policies' do - let(:feature_write_abilities) do - described_class::READONLY_FEATURES_WHEN_ARCHIVED.flat_map do |feature| - described_class.create_update_admin_destroy(feature) - end - end - - let(:other_write_abilities) do - %i[ - create_merge_request_in - create_merge_request_from - push_to_delete_protected_branch - push_code - request_access - upload_file - resolve_note - award_emoji - ] - end - - context 'when the project is archived' do - before do - project.archived = true - end - - it 'disables write actions on all relevant project features' do - expect_disallowed(*feature_write_abilities) - end - - it 'disables some other important write actions' do - expect_disallowed(*other_write_abilities) - end - - it 'does not disable other abilities' do - expect_allowed(*(regular_abilities - feature_write_abilities - other_write_abilities)) - end - end - end - - shared_examples 'project policies as anonymous' do - context 'abilities for public projects' do - context 'when a project has pending invites' do - let(:group) { create(:group, :public) } - let(:project) { create(:project, :public, namespace: group) } - let(:user_permissions) { [:create_merge_request_in, :create_project, :create_issue, :create_note, :upload_file, :award_emoji] } - let(:anonymous_permissions) { guest_permissions - user_permissions } - - subject { described_class.new(nil, project) } - - before do - create(:group_member, :invited, group: group) - end - - it 'does not grant owner access' do - expect_allowed(*anonymous_permissions) - expect_disallowed(*user_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { anonymous_permissions } - end - end - end - - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(nil, project) } - - it { is_expected.to be_banned } - end - end - - shared_examples 'project policies as guest' do - subject { described_class.new(guest, project) } - - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - let(:reporter_public_build_permissions) do - reporter_permissions - [:read_build, :read_pipeline] - end - - it do - expect_allowed(*guest_permissions) - expect_disallowed(*reporter_public_build_permissions) - expect_disallowed(*team_member_reporter_permissions) - expect_disallowed(*developer_permissions) - expect_disallowed(*maintainer_permissions) - expect_disallowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { guest_permissions } - end - - context 'public builds enabled' do - it do - expect_allowed(*guest_permissions) - expect_allowed(:read_build, :read_pipeline) - end - end - - context 'when public builds disabled' do - before do - project.update(public_builds: false) - end - - it do - expect_allowed(*guest_permissions) - expect_disallowed(:read_build, :read_pipeline) - end - end - - context 'when builds are disabled' do - before do - project.project_feature.update(builds_access_level: ProjectFeature::DISABLED) - end - - it do - expect_disallowed(:read_build) - expect_allowed(:read_pipeline) - end - end - end - end - - shared_examples 'project policies as reporter' do - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(reporter, project) } - - it do - expect_allowed(*guest_permissions) - expect_allowed(*reporter_permissions) - expect_allowed(*team_member_reporter_permissions) - expect_disallowed(*developer_permissions) - expect_disallowed(*maintainer_permissions) - expect_disallowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { reporter_permissions } - end - end - end - - shared_examples 'project policies as developer' do - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(developer, project) } - - it do - expect_allowed(*guest_permissions) - expect_allowed(*reporter_permissions) - expect_allowed(*team_member_reporter_permissions) - expect_allowed(*developer_permissions) - expect_disallowed(*maintainer_permissions) - expect_disallowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { developer_permissions } - end - end - end - - shared_examples 'project policies as maintainer' do - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(maintainer, project) } - - it do - expect_allowed(*guest_permissions) - expect_allowed(*reporter_permissions) - expect_allowed(*team_member_reporter_permissions) - expect_allowed(*developer_permissions) - expect_allowed(*maintainer_permissions) - expect_disallowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { maintainer_permissions } - end - end - end - - shared_examples 'project policies as owner' do - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(owner, project) } - - it do - expect_allowed(*guest_permissions) - expect_allowed(*reporter_permissions) - expect_allowed(*team_member_reporter_permissions) - expect_allowed(*developer_permissions) - expect_allowed(*maintainer_permissions) - expect_allowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { owner_permissions } - end - end - end - - shared_examples 'project policies as admin' do - context 'abilities for non-public projects' do - let(:project) { create(:project, namespace: owner.namespace) } - - subject { described_class.new(admin, project) } - - it do - expect_allowed(*guest_permissions) - expect_allowed(*reporter_permissions) - expect_disallowed(*team_member_reporter_permissions) - expect_allowed(*developer_permissions) - expect_allowed(*maintainer_permissions) - expect_allowed(*owner_permissions) - end - - it_behaves_like 'archived project policies' do - let(:regular_abilities) { owner_permissions } - end - end - end - it_behaves_like 'project policies as anonymous' it_behaves_like 'project policies as guest' it_behaves_like 'project policies as reporter' diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index d6329e84579..2e9ef1e89fd 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -5,7 +5,7 @@ describe ProjectSnippetPolicy do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } let(:project) { create(:project, :public) } - + let(:snippet) { create(:project_snippet, snippet_visibility, project: project) } let(:author_permissions) do [ :update_project_snippet, @@ -13,23 +13,13 @@ describe ProjectSnippetPolicy do ] end - def abilities(user, snippet_visibility) - snippet = create(:project_snippet, snippet_visibility, project: project) - - described_class.new(user, snippet) - end - - def expect_allowed(*permissions) - permissions.each { |p| is_expected.to be_allowed(p) } - end - - def expect_disallowed(*permissions) - permissions.each { |p| is_expected.not_to be_allowed(p) } - end + subject { described_class.new(current_user, snippet) } context 'public snippet' do + let(:snippet_visibility) { :public } + context 'no user' do - subject { abilities(nil, :public) } + let(:current_user) { nil } it do expect_allowed(:read_project_snippet) @@ -38,7 +28,7 @@ describe ProjectSnippetPolicy do end context 'regular user' do - subject { abilities(regular_user, :public) } + let(:current_user) { regular_user } it do expect_allowed(:read_project_snippet, :create_note) @@ -47,7 +37,7 @@ describe ProjectSnippetPolicy do end context 'external user' do - subject { abilities(external_user, :public) } + let(:current_user) { external_user } it do expect_allowed(:read_project_snippet, :create_note) @@ -57,8 +47,10 @@ describe ProjectSnippetPolicy do end context 'internal snippet' do + let(:snippet_visibility) { :internal } + context 'no user' do - subject { abilities(nil, :internal) } + let(:current_user) { nil } it do expect_disallowed(:read_project_snippet) @@ -67,7 +59,7 @@ describe ProjectSnippetPolicy do end context 'regular user' do - subject { abilities(regular_user, :internal) } + let(:current_user) { regular_user } it do expect_allowed(:read_project_snippet, :create_note) @@ -76,31 +68,31 @@ describe ProjectSnippetPolicy do end context 'external user' do - subject { abilities(external_user, :internal) } + let(:current_user) { external_user } it do expect_disallowed(:read_project_snippet, :create_note) expect_disallowed(*author_permissions) end - end - context 'project team member external user' do - subject { abilities(external_user, :internal) } - - before do - project.add_developer(external_user) - end + context 'project team member' do + before do + project.add_developer(external_user) + end - it do - expect_allowed(:read_project_snippet, :create_note) - expect_disallowed(*author_permissions) + it do + expect_allowed(:read_project_snippet, :create_note) + expect_disallowed(*author_permissions) + end end end end context 'private snippet' do + let(:snippet_visibility) { :private } + context 'no user' do - subject { abilities(nil, :private) } + let(:current_user) { nil } it do expect_disallowed(:read_project_snippet) @@ -109,53 +101,52 @@ describe ProjectSnippetPolicy do end context 'regular user' do - subject { abilities(regular_user, :private) } + let(:current_user) { regular_user } it do expect_disallowed(:read_project_snippet, :create_note) expect_disallowed(*author_permissions) end - end - - context 'snippet author' do - let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) } - subject { described_class.new(regular_user, snippet) } + context 'snippet author' do + let(:snippet) { create(:project_snippet, :private, author: regular_user, project: project) } - it do - expect_allowed(:read_project_snippet, :create_note) - expect_allowed(*author_permissions) + it do + expect_allowed(:read_project_snippet, :create_note) + expect_allowed(*author_permissions) + end end - end - context 'project team member normal user' do - subject { abilities(regular_user, :private) } - - before do - project.add_developer(regular_user) - end + context 'project team member normal user' do + before do + project.add_developer(regular_user) + end - it do - expect_allowed(:read_project_snippet, :create_note) - expect_disallowed(*author_permissions) + it do + expect_allowed(:read_project_snippet, :create_note) + expect_disallowed(*author_permissions) + end end end - context 'project team member external user' do - subject { abilities(external_user, :private) } + context 'external user' do + context 'project team member' do + let(:current_user) { external_user } - before do - project.add_developer(external_user) - end + before do + project.add_developer(external_user) + end - it do - expect_allowed(:read_project_snippet, :create_note) - expect_disallowed(*author_permissions) + it do + expect_allowed(:read_project_snippet, :create_note) + expect_disallowed(*author_permissions) + end end end context 'admin user' do - subject { abilities(create(:admin), :private) } + let(:snippet_visibility) { :private } + let(:current_user) { create(:admin) } it do expect_allowed(:read_project_snippet, :create_note) diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb index f50bcf54b46..ad6cb012d0b 100644 --- a/spec/presenters/ci/build_runner_presenter_spec.rb +++ b/spec/presenters/ci/build_runner_presenter_spec.rb @@ -136,6 +136,24 @@ describe Ci::BuildRunnerPresenter do is_expected.to eq(1) end end + + context 'when pipeline is detached merge request pipeline' do + let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) } + let(:pipeline) { merge_request.all_pipelines.first } + let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) } + + it 'returns the default git depth for pipelines for merge requests' do + is_expected.to eq(described_class::DEFAULT_GIT_DEPTH_MERGE_REQUEST) + end + + context 'when pipeline is legacy detached merge request pipeline' do + let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) } + + it 'behaves as branch pipeline' do + is_expected.to eq(0) + end + end + end end describe '#refspecs' do @@ -165,5 +183,25 @@ describe Ci::BuildRunnerPresenter do end end end + + context 'when pipeline is detached merge request pipeline' do + let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) } + let(:pipeline) { merge_request.all_pipelines.first } + let(:build) { create(:ci_build, ref: pipeline.ref, pipeline: pipeline) } + + it 'returns the correct refspecs' do + is_expected + .to contain_exactly('+refs/merge-requests/1/head:refs/merge-requests/1/head') + end + + context 'when pipeline is legacy detached merge request pipeline' do + let(:merge_request) { create(:merge_request, :with_legacy_detached_merge_request_pipeline) } + + it 'returns the correct refspecs' do + is_expected.to contain_exactly('+refs/tags/*:refs/tags/*', + '+refs/heads/*:refs/remotes/origin/*') + end + end + end end end diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb index 754ba0a594c..a9d786bc872 100644 --- a/spec/presenters/clusters/cluster_presenter_spec.rb +++ b/spec/presenters/clusters/cluster_presenter_spec.rb @@ -228,4 +228,20 @@ describe Clusters::ClusterPresenter do it { is_expected.to eq(group_cluster_path(group, cluster)) } end end + + describe '#read_only_kubernetes_platform_fields?' do + subject { described_class.new(cluster).read_only_kubernetes_platform_fields? } + + context 'with a user-provided cluster' do + let(:cluster) { build_stubbed(:cluster, :provided_by_user) } + + it { is_expected.to be_falsy } + end + + context 'with a GCP-provided cluster' do + let(:cluster) { build_stubbed(:cluster, :provided_by_gcp) } + + it { is_expected.to be_truthy } + end + end end diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb index b38cd66986f..8b503777443 100644 --- a/spec/requests/api/branches_spec.rb +++ b/spec/requests/api/branches_spec.rb @@ -20,9 +20,9 @@ describe API::Branches do let(:route) { "/projects/#{project_id}/repository/branches" } shared_examples_for 'repository branches' do - RSpec::Matchers.define :has_merged_branch_names_count do |expected| + RSpec::Matchers.define :has_up_to_merged_branch_names_count do |expected| match do |actual| - actual[:merged_branch_names].count == expected + expected >= actual[:merged_branch_names].count end end @@ -36,10 +36,30 @@ describe API::Branches do expect(branch_names).to match_array(project.repository.branch_names) end + def check_merge_status(json_response) + merged, unmerged = json_response.partition { |branch| branch['merged'] } + merged_branches = merged.map { |branch| branch['name'] } + unmerged_branches = unmerged.map { |branch| branch['name'] } + expect(Set.new(merged_branches)).to eq(project.repository.merged_branch_names(merged_branches + unmerged_branches)) + expect(project.repository.merged_branch_names(unmerged_branches)).to be_empty + end + it 'determines only a limited number of merged branch names' do - expect(API::Entities::Branch).to receive(:represent).with(anything, has_merged_branch_names_count(2)) + expect(API::Entities::Branch).to receive(:represent).with(anything, has_up_to_merged_branch_names_count(2)).and_call_original get api(route, current_user), params: { per_page: 2 } + + expect(response).to have_gitlab_http_status(200) + + check_merge_status(json_response) + end + + it 'merge status matches reality on paginated input' do + get api(route, current_user), params: { per_page: 20, page: 2 } + + expect(response).to have_gitlab_http_status(200) + + check_merge_status(json_response) end context 'when repository is disabled' do diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index b184c92824a..537194b8e11 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -321,7 +321,7 @@ describe API::Internal do end context 'with env passed as a JSON' do - let(:gl_repository) { project.gl_repository(is_wiki: true) } + let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_subject(project) } it 'sets env in RequestStore' do obj_dir_relative = './objects' @@ -975,9 +975,9 @@ describe API::Internal do def gl_repository_for(project_or_wiki) case project_or_wiki when ProjectWiki - project_or_wiki.project.gl_repository(is_wiki: true) + Gitlab::GlRepository::WIKI.identifier_for_subject(project_or_wiki.project) when Project - project_or_wiki.gl_repository(is_wiki: false) + Gitlab::GlRepository::PROJECT.identifier_for_subject(project_or_wiki) else nil end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 60d9d7fed13..4c3c088b307 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1183,6 +1183,16 @@ describe API::Projects do expect(response).to have_gitlab_http_status(200) expect(json_response).to include 'statistics' end + + it "includes statistics also when repository is disabled" do + project.add_developer(user) + project.project_feature.update_attribute(:repository_access_level, ProjectFeature::DISABLED) + + get api("/projects/#{project.id}", user), params: { statistics: true } + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to include 'statistics' + end end it "includes import_error if user can admin project" do diff --git a/spec/requests/api/suggestions_spec.rb b/spec/requests/api/suggestions_spec.rb index 3c2842e5725..5b07e598b8d 100644 --- a/spec/requests/api/suggestions_spec.rb +++ b/spec/requests/api/suggestions_spec.rb @@ -42,8 +42,7 @@ describe API::Suggestions do expect(response).to have_gitlab_http_status(200) expect(json_response) - .to include('id', 'from_original_line', 'to_original_line', - 'from_line', 'to_line', 'appliable', 'applied', + .to include('id', 'from_line', 'to_line', 'appliable', 'applied', 'from_content', 'to_content') end end diff --git a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb index 1c8ab0ad5d2..cba01400d85 100644 --- a/spec/rubocop/cop/migration/update_column_in_batches_spec.rb +++ b/spec/rubocop/cop/migration/update_column_in_batches_spec.rb @@ -93,4 +93,22 @@ describe RuboCop::Cop::Migration::UpdateColumnInBatches do it_behaves_like 'a migration file with no spec file' it_behaves_like 'a migration file with a spec file' end + + context 'EE migrations' do + let(:spec_filepath) { tmp_rails_root.join('ee', 'spec', 'migrations', 'my_super_migration_spec.rb') } + + context 'in a migration' do + let(:migration_filepath) { tmp_rails_root.join('ee', 'db', 'migrate', '20121220064453_my_super_migration.rb') } + + it_behaves_like 'a migration file with no spec file' + it_behaves_like 'a migration file with a spec file' + end + + context 'in a post migration' do + let(:migration_filepath) { tmp_rails_root.join('ee', 'db', 'post_migrate', '20121220064453_my_super_migration.rb') } + + it_behaves_like 'a migration file with no spec file' + it_behaves_like 'a migration file with a spec file' + end + end end diff --git a/spec/serializers/suggestion_entity_spec.rb b/spec/serializers/suggestion_entity_spec.rb index 047571f161c..d38fc2b132b 100644 --- a/spec/serializers/suggestion_entity_spec.rb +++ b/spec/serializers/suggestion_entity_spec.rb @@ -13,8 +13,8 @@ describe SuggestionEntity do subject { entity.as_json } it 'exposes correct attributes' do - expect(subject).to include(:id, :from_original_line, :to_original_line, :from_line, - :to_line, :appliable, :applied, :from_content, :to_content) + expect(subject).to include(:id, :from_line, :to_line, :appliable, + :applied, :from_content, :to_content) end it 'exposes current user abilities' do diff --git a/spec/services/error_tracking/list_issues_service_spec.rb b/spec/services/error_tracking/list_issues_service_spec.rb index 9d4fc62f923..3a8f3069911 100644 --- a/spec/services/error_tracking/list_issues_service_spec.rb +++ b/spec/services/error_tracking/list_issues_service_spec.rb @@ -53,7 +53,10 @@ describe ErrorTracking::ListIssuesService do before do allow(error_tracking_setting) .to receive(:list_sentry_issues) - .and_return(error: 'Sentry response status code: 401') + .and_return( + error: 'Sentry response status code: 401', + error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_NON_20X_RESPONSE + ) end it 'returns the error' do @@ -64,6 +67,25 @@ describe ErrorTracking::ListIssuesService do ) end end + + context 'when list_sentry_issues returns error with http_status' do + before do + allow(error_tracking_setting) + .to receive(:list_sentry_issues) + .and_return( + error: 'Sentry API response is missing keys. key not found: "id"', + error_type: ErrorTracking::ProjectErrorTrackingSetting::SENTRY_API_ERROR_TYPE_MISSING_KEYS + ) + end + + it 'returns the error with correct http_status' do + expect(result).to eq( + status: :error, + http_status: :internal_server_error, + message: 'Sentry API response is missing keys. key not found: "id"' + ) + end + end end context 'with unauthorized user' do diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index 715b1168bfb..d50412b6d2c 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -138,6 +138,20 @@ describe Issues::CreateService do end end + context 'when duplicate label titles are given' do + let(:label) { create(:label, project: project) } + + let(:opts) do + { title: 'Title', + description: 'Description', + labels: [label.title, label.title] } + end + + it 'assigns the label once' do + expect(issue.labels).to contain_exactly(label) + end + end + it 'executes issue hooks when issue is not confidential' do opts = { title: 'Title', description: 'Description', confidential: false } diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index f1684209729..1c8a4b608d5 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -592,6 +592,16 @@ describe Issues::UpdateService, :mailer do expect(result.label_ids).not_to include(label.id) end end + + context 'when duplicate label titles are given' do + let(:params) do + { labels: [label3.title, label3.title] } + end + + it 'assigns the label once' do + expect(result.labels).to contain_exactly(label3) + end + end end context 'updating asssignee_id' do diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index a04a4d5fc36..55e7b46248b 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -173,7 +173,7 @@ describe MergeRequests::CreateService do end end - describe 'Merge request pipelines' do + describe 'Pipelines for merge requests' do before do stub_ci_pipeline_yaml_file(YAML.dump(config)) end @@ -189,12 +189,46 @@ describe MergeRequests::CreateService do } end - it 'creates a merge request pipeline and sets it as a head pipeline' do + it 'creates a detached merge request pipeline and sets it as a head pipeline' do expect(merge_request).to be_persisted merge_request.reload expect(merge_request.merge_request_pipelines.count).to eq(1) - expect(merge_request.actual_head_pipeline).to be_merge_request_event + expect(merge_request.actual_head_pipeline).to be_detached_merge_request_pipeline + end + + context 'when merge request is submitted from forked project' do + let(:target_project) { fork_project(project, nil, repository: true) } + + let(:opts) do + { + title: 'Awesome merge_request', + source_branch: 'feature', + target_branch: 'master', + target_project_id: target_project.id + } + end + + before do + target_project.add_developer(assignee) + target_project.add_maintainer(user) + end + + it 'create legacy detached merge request pipeline for fork merge request' do + expect(merge_request.actual_head_pipeline) + .to be_legacy_detached_merge_request_pipeline + end + end + + context 'when ci_use_merge_request_ref feature flag is false' do + before do + stub_feature_flags(ci_use_merge_request_ref: false) + end + + it 'create legacy detached merge request pipeline for non-fork merge request' do + expect(merge_request.actual_head_pipeline) + .to be_legacy_detached_merge_request_pipeline + end end context 'when there are no commits between source branch and target branch' do @@ -207,7 +241,7 @@ describe MergeRequests::CreateService do } end - it 'does not create a merge request pipeline' do + it 'does not create a detached merge request pipeline' do expect(merge_request).to be_persisted merge_request.reload @@ -225,7 +259,7 @@ describe MergeRequests::CreateService do merge_request end - it 'sets the latest merge request pipeline as the head pipeline' do + it 'sets the latest detached merge request pipeline as the head pipeline' do expect(merge_request.actual_head_pipeline).to be_merge_request_event end end @@ -235,7 +269,7 @@ describe MergeRequests::CreateService do stub_feature_flags(ci_merge_request_pipeline: false) end - it 'does not create a merge request pipeline' do + it 'does not create a detached merge request pipeline' do expect(merge_request).to be_persisted merge_request.reload @@ -254,7 +288,7 @@ describe MergeRequests::CreateService do } end - it 'does not create a merge request pipeline' do + it 'does not create a detached merge request pipeline' do expect(merge_request).to be_persisted merge_request.reload diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index fe673de46aa..1430e12a07e 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -72,7 +72,7 @@ describe MergeRequests::FfMergeService do it 'logs and saves error if there is an PreReceiveError exception' do error_message = 'error message' - allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message) + allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}") allow(service).to receive(:execute_hooks) service.execute(merge_request) diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index ede79b87bcc..887ec17171e 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -239,7 +239,7 @@ describe MergeRequests::MergeService do it 'logs and saves error if there is an PreReceiveError exception' do error_message = 'error message' - allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message) + allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, "GitLab: #{error_message}") allow(service).to receive(:execute_hooks) service.execute(merge_request) diff --git a/spec/services/merge_requests/migrate_external_diffs_service_spec.rb b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb new file mode 100644 index 00000000000..40ac747e66f --- /dev/null +++ b/spec/services/merge_requests/migrate_external_diffs_service_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MergeRequests::MigrateExternalDiffsService do + let(:merge_request) { create(:merge_request) } + let(:diff) { merge_request.merge_request_diff } + + describe '.enqueue!', :sidekiq do + around do |example| + Sidekiq::Testing.fake! { example.run } + end + + it 'enqueues nothing if external diffs are disabled' do + expect(diff).not_to be_stored_externally + + expect { described_class.enqueue! } + .not_to change { MigrateExternalDiffsWorker.jobs.count } + end + + it 'enqueues eligible in-database diffs if external diffs are enabled' do + expect(diff).not_to be_stored_externally + + stub_external_diffs_setting(enabled: true) + + expect { described_class.enqueue! } + .to change { MigrateExternalDiffsWorker.jobs.count } + .by(1) + end + end + + describe '#execute' do + it 'migrates an in-database diff to the external store' do + expect(diff).not_to be_stored_externally + + stub_external_diffs_setting(enabled: true) + + described_class.new(diff).execute + + expect(diff).to be_stored_externally + end + end +end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 43ceb1dcbee..25cbac6d7ee 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -97,6 +97,15 @@ describe MergeRequests::RefreshService do } end + it 'outdates MR suggestions' do + expect_next_instance_of(Suggestions::OutdateService) do |service| + expect(service).to receive(:execute).with(@merge_request).and_call_original + expect(service).to receive(:execute).with(@another_merge_request).and_call_original + end + + refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') + end + context 'when source branch ref does not exists' do before do DeleteBranchService.new(@project, @user).execute(@merge_request.source_branch) @@ -132,7 +141,7 @@ describe MergeRequests::RefreshService do end end - describe 'Merge request pipelines' do + describe 'Pipelines for merge requests' do before do stub_ci_pipeline_yaml_file(YAML.dump(config)) end @@ -150,7 +159,7 @@ describe MergeRequests::RefreshService do } end - it 'create merge request pipeline with commits' do + it 'create detached merge request pipeline with commits' do expect { subject } .to change { @merge_request.merge_request_pipelines.count }.by(1) .and change { @fork_merge_request.merge_request_pipelines.count }.by(1) @@ -161,7 +170,34 @@ describe MergeRequests::RefreshService do expect(@another_merge_request.has_commits?).to be_falsy end - context "when branch pipeline was created before a merge request pipline has been created" do + it 'create detached merge request pipeline for non-fork merge request' do + subject + + expect(@merge_request.merge_request_pipelines.first) + .to be_detached_merge_request_pipeline + end + + it 'create legacy detached merge request pipeline for fork merge request' do + subject + + expect(@fork_merge_request.merge_request_pipelines.first) + .to be_legacy_detached_merge_request_pipeline + end + + context 'when ci_use_merge_request_ref feature flag is false' do + before do + stub_feature_flags(ci_use_merge_request_ref: false) + end + + it 'create legacy detached merge request pipeline for non-fork merge request' do + subject + + expect(@merge_request.merge_request_pipelines.first) + .to be_legacy_detached_merge_request_pipeline + end + end + + context "when branch pipeline was created before a detaced merge request pipeline has been created" do before do create(:ci_pipeline, project: @merge_request.source_project, sha: @merge_request.diff_head_sha, @@ -171,7 +207,7 @@ describe MergeRequests::RefreshService do subject end - it 'sets the latest merge request pipeline as a head pipeline' do + it 'sets the latest detached merge request pipeline as a head pipeline' do @merge_request.reload expect(@merge_request.actual_head_pipeline).to be_merge_request_event end @@ -184,7 +220,7 @@ describe MergeRequests::RefreshService do end context "when MergeRequestUpdateWorker is retried by an exception" do - it 'does not re-create a duplicate merge request pipeline' do + it 'does not re-create a duplicate detached merge request pipeline' do expect do service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/master') end.to change { @merge_request.merge_request_pipelines.count }.by(1) @@ -200,7 +236,7 @@ describe MergeRequests::RefreshService do stub_feature_flags(ci_merge_request_pipeline: false) end - it 'does not create a merge request pipeline' do + it 'does not create a detached merge request pipeline' do expect { subject } .not_to change { @merge_request.merge_request_pipelines.count } end @@ -217,7 +253,7 @@ describe MergeRequests::RefreshService do } end - it 'does not create a merge request pipeline' do + it 'does not create a detached merge request pipeline' do expect { subject } .not_to change { @merge_request.merge_request_pipelines.count } end @@ -329,14 +365,16 @@ describe MergeRequests::RefreshService do context 'push to fork repo source branch' do let(:refresh_service) { service.new(@fork_project, @user) } - context 'open fork merge request' do - before do - allow(refresh_service).to receive(:execute_hooks) - refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') - reload_mrs - end + def refresh + allow(refresh_service).to receive(:execute_hooks) + refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') + reload_mrs + end + context 'open fork merge request' do it 'executes hooks with update action' do + refresh + expect(refresh_service).to have_received(:execute_hooks) .with(@fork_merge_request, 'update', old_rev: @oldrev) @@ -347,21 +385,30 @@ describe MergeRequests::RefreshService do expect(@build_failed_todo).to be_pending expect(@fork_build_failed_todo).to be_pending end + + it 'outdates opened forked MR suggestions' do + expect_next_instance_of(Suggestions::OutdateService) do |service| + expect(service).to receive(:execute).with(@fork_merge_request).and_call_original + end + + refresh + end end context 'closed fork merge request' do before do @fork_merge_request.close! - allow(refresh_service).to receive(:execute_hooks) - refresh_service.execute(@oldrev, @newrev, 'refs/heads/master') - reload_mrs end it 'do not execute hooks with update action' do + refresh + expect(refresh_service).not_to have_received(:execute_hooks) end it 'updates merge request to closed state' do + refresh + expect(@merge_request.notes).to be_empty expect(@merge_request).to be_open expect(@fork_merge_request.notes).to be_empty diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 6040f9100f8..4b6d0c51363 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -2,29 +2,56 @@ require 'spec_helper' describe Projects::ParticipantsService do describe '#groups' do + set(:user) { create(:user) } + set(:project) { create(:project, :public) } + let(:service) { described_class.new(project, user) } + + it 'avoids N+1 queries' do + group_1 = create(:group) + group_1.add_owner(user) + + service.groups # Run general application warmup queries + control_count = ActiveRecord::QueryRecorder.new { service.groups }.count + + group_2 = create(:group) + group_2.add_owner(user) + + expect { service.groups }.not_to exceed_query_limit(control_count) + end + + it 'returns correct user counts for groups' do + group_1 = create(:group) + group_1.add_owner(user) + group_1.add_owner(create(:user)) + + group_2 = create(:group) + group_2.add_owner(user) + create(:group_member, :access_request, group: group_2, user: create(:user)) + + expect(service.groups).to contain_exactly( + a_hash_including(name: group_1.full_name, count: 2), + a_hash_including(name: group_2.full_name, count: 1) + ) + end + describe 'avatar_url' do - let(:project) { create(:project, :public) } let(:group) { create(:group, avatar: fixture_file_upload('spec/fixtures/dk.png')) } - let(:user) { create(:user) } - let!(:group_member) { create(:group_member, group: group, user: user) } - it 'should return an url for the avatar' do - participants = described_class.new(project, user) - groups = participants.groups + before do + group.add_owner(user) + end - expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/uploads/-/system/group/avatar/#{group.id}/dk.png") + it 'should return an url for the avatar' do + expect(service.groups.size).to eq 1 + expect(service.groups.first[:avatar_url]).to eq("/uploads/-/system/group/avatar/#{group.id}/dk.png") end it 'should return an url for the avatar with relative url' do stub_config_setting(relative_url_root: '/gitlab') stub_config_setting(url: Settings.send(:build_gitlab_url)) - participants = described_class.new(project, user) - groups = participants.groups - - expect(groups.size).to eq 1 - expect(groups.first[:avatar_url]).to eq("/gitlab/uploads/-/system/group/avatar/#{group.id}/dk.png") + expect(service.groups.size).to eq 1 + expect(service.groups.first[:avatar_url]).to eq("/gitlab/uploads/-/system/group/avatar/#{group.id}/dk.png") end end end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index ea33d156c8a..8b0f9c8ade2 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -15,6 +15,7 @@ describe QuickActions::InterpretService do let(:service) { described_class.new(project, developer) } before do + stub_licensed_features(multiple_issue_assignees: false) project.add_developer(developer) end diff --git a/spec/services/suggestions/apply_service_spec.rb b/spec/services/suggestions/apply_service_spec.rb index fe85b5c9065..80b5dcac6c7 100644 --- a/spec/services/suggestions/apply_service_spec.rb +++ b/spec/services/suggestions/apply_service_spec.rb @@ -5,6 +5,41 @@ require 'spec_helper' describe Suggestions::ApplyService do include ProjectForksHelper + shared_examples 'successfully creates commit and updates suggestion' do + def apply(suggestion) + result = subject.execute(suggestion) + expect(result[:status]).to eq(:success) + end + + it 'updates the file with the new contents' do + apply(suggestion) + + blob = project.repository.blob_at_branch(merge_request.source_branch, + position.new_path) + + expect(blob.data).to eq(expected_content) + end + + it 'updates suggestion applied and commit_id columns' do + expect { apply(suggestion) } + .to change(suggestion, :applied) + .from(false).to(true) + .and change(suggestion, :commit_id) + .from(nil) + end + + it 'created commit has users email and name' do + apply(suggestion) + + commit = project.repository.commit + + expect(user.commit_email).not_to eq(user.email) + expect(commit.author_email).to eq(user.commit_email) + expect(commit.committer_email).to eq(user.commit_email) + expect(commit.author_name).to eq(user.name) + end + end + let(:project) { create(:project, :repository) } let(:user) { create(:user, :commit_email) } @@ -17,9 +52,8 @@ describe Suggestions::ApplyService do end let(:suggestion) do - create(:suggestion, note: diff_note, - from_content: " raise RuntimeError, \"System commands must be given as an array of strings\"\n", - to_content: " raise RuntimeError, 'Explosion'\n # explosion?\n") + create(:suggestion, :content_from_repo, note: diff_note, + to_content: " raise RuntimeError, 'Explosion'\n # explosion?\n") end subject { described_class.new(user) } @@ -84,39 +118,7 @@ describe Suggestions::ApplyService do project.add_maintainer(user) end - it 'updates the file with the new contents' do - subject.execute(suggestion) - - blob = project.repository.blob_at_branch(merge_request.source_branch, - position.new_path) - - expect(blob.data).to eq(expected_content) - end - - it 'returns success status' do - result = subject.execute(suggestion) - - expect(result[:status]).to eq(:success) - end - - it 'updates suggestion applied and commit_id columns' do - expect { subject.execute(suggestion) } - .to change(suggestion, :applied) - .from(false).to(true) - .and change(suggestion, :commit_id) - .from(nil) - end - - it 'created commit has users email and name' do - subject.execute(suggestion) - - commit = project.repository.commit - - expect(user.commit_email).not_to eq(user.email) - expect(commit.author_email).to eq(user.commit_email) - expect(commit.committer_email).to eq(user.commit_email) - expect(commit.author_name).to eq(user.name) - end + it_behaves_like 'successfully creates commit and updates suggestion' context 'when it fails to apply because the file was changed' do it 'returns error message' do @@ -212,11 +214,13 @@ describe Suggestions::ApplyService do end def apply_suggestion(suggestion) - suggestion.note.reload + suggestion.reload merge_request.reload merge_request.clear_memoized_shas result = subject.execute(suggestion) + expect(result[:status]).to eq(:success) + refresh = MergeRequests::RefreshService.new(project, user) refresh.execute(merge_request.diff_head_sha, suggestion.commit_id, @@ -241,7 +245,7 @@ describe Suggestions::ApplyService do suggestion_2_changes = { old_line: 24, new_line: 31, - from_content: " @cmd_output << stderr.read\n", + from_content: " @cmd_output << stderr.read\n", to_content: "# v2 change\n", path: path } @@ -368,7 +372,18 @@ describe Suggestions::ApplyService do result = subject.execute(suggestion) - expect(result).to eq(message: 'The file was not found', + expect(result).to eq(message: 'Suggestion is not appliable', + status: :error) + end + end + + context 'suggestion is eligible to be outdated' do + it 'returns error message' do + expect(suggestion).to receive(:outdated?) { true } + + result = subject.execute(suggestion) + + expect(result).to eq(message: 'Suggestion is not appliable', status: :error) end end diff --git a/spec/services/suggestions/create_service_spec.rb b/spec/services/suggestions/create_service_spec.rb index 1b4b15b8eaa..ce4990a34a4 100644 --- a/spec/services/suggestions/create_service_spec.rb +++ b/spec/services/suggestions/create_service_spec.rb @@ -40,6 +40,14 @@ describe Suggestions::CreateService do ```thing this is not a suggestion, it's a thing ``` + + ```suggestion:-3+2 + # multi-line suggestion 1 + ``` + + ```suggestion:-5 + # multi-line suggestion 1 + ``` MARKDOWN end @@ -54,7 +62,7 @@ describe Suggestions::CreateService do end it 'does not try to parse suggestions' do - expect(Banzai::SuggestionsParser).not_to receive(:parse) + expect(Gitlab::Diff::SuggestionsParser).not_to receive(:parse) subject.execute end @@ -71,7 +79,7 @@ describe Suggestions::CreateService do it 'does not try to parse suggestions' do allow(note).to receive(:on_text?) { false } - expect(Banzai::SuggestionsParser).not_to receive(:parse) + expect(Gitlab::Diff::SuggestionsParser).not_to receive(:parse) subject.execute end @@ -87,7 +95,9 @@ describe Suggestions::CreateService do end it 'creates no suggestion when diff file is not found' do - expect(note).to receive(:latest_diff_file) { nil } + expect_next_instance_of(DiffNote) do |diff_note| + expect(diff_note).to receive(:latest_diff_file).twice { nil } + end expect { subject.execute }.not_to change(Suggestion, :count) end @@ -101,43 +111,44 @@ describe Suggestions::CreateService do note: markdown) end - context 'single line suggestions' do - it 'persists suggestion records' do - expect { subject.execute } - .to change { note.suggestions.count } - .from(0) - .to(2) - end + let(:expected_suggestions) do + Gitlab::Diff::SuggestionsParser.parse(markdown, + project: note.project, + position: note.position) + end - it 'persists original from_content lines and suggested lines' do - subject.execute + it 'persists suggestion records' do + expect { subject.execute }.to change { note.suggestions.count } + .from(0).to(expected_suggestions.size) + end - suggestions = note.suggestions.order(:relative_order) + it 'persists suggestions data correctly' do + subject.execute - suggestion_1 = suggestions.first - suggestion_2 = suggestions.last + suggestions = note.suggestions.order(:relative_order) - expect(suggestion_1).to have_attributes(from_content: " vars = {\n", - to_content: " foo\n bar\n") + suggestions.zip(expected_suggestions) do |suggestion, expected_suggestion| + expected_data = expected_suggestion.to_hash - expect(suggestion_2).to have_attributes(from_content: " vars = {\n", - to_content: " xpto\n baz\n") + expect(suggestion.from_content).to eq(expected_data[:from_content]) + expect(suggestion.to_content).to eq(expected_data[:to_content]) + expect(suggestion.lines_above).to eq(expected_data[:lines_above]) + expect(suggestion.lines_below).to eq(expected_data[:lines_below]) end + end - context 'outdated position note' do - let!(:outdated_diff) { merge_request.merge_request_diff } - let!(:latest_diff) { merge_request.create_merge_request_diff } - let(:outdated_position) { build_position(diff_refs: outdated_diff.diff_refs) } - let(:position) { build_position(diff_refs: latest_diff.diff_refs) } + context 'outdated position note' do + let!(:outdated_diff) { merge_request.merge_request_diff } + let!(:latest_diff) { merge_request.create_merge_request_diff } + let(:outdated_position) { build_position(diff_refs: outdated_diff.diff_refs) } + let(:position) { build_position(diff_refs: latest_diff.diff_refs) } - it 'uses the correct position when creating the suggestion' do - expect(note.position) - .to receive(:diff_file) - .with(project_with_repo.repository) - .and_call_original + it 'uses the correct position when creating the suggestion' do + expect(Gitlab::Diff::SuggestionsParser).to receive(:parse) + .with(note.note, project: note.project, position: note.position) + .and_call_original - subject.execute - end + subject.execute end end end diff --git a/spec/services/suggestions/outdate_service_spec.rb b/spec/services/suggestions/outdate_service_spec.rb new file mode 100644 index 00000000000..bcc627013d8 --- /dev/null +++ b/spec/services/suggestions/outdate_service_spec.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Suggestions::OutdateService do + describe '#execute' do + let(:merge_request) { create(:merge_request) } + let(:project) { merge_request.target_project } + let(:user) { merge_request.author } + let(:file_path) { 'files/ruby/popen.rb' } + let(:branch_name) { project.default_branch } + let(:diff_file) { suggestion.diff_file } + let(:position) { build_position(file_path, comment_line) } + let(:note) do + create(:diff_note_on_merge_request, noteable: merge_request, + position: position, + project: project) + end + + def build_position(path, line) + Gitlab::Diff::Position.new(old_path: path, + new_path: path, + old_line: nil, + new_line: line, + diff_refs: merge_request.diff_refs) + end + + def commit_changes(file_path, new_content) + params = { + file_path: file_path, + commit_message: "Update File", + file_content: new_content, + start_project: project, + start_branch: project.default_branch, + branch_name: branch_name + } + + Files::UpdateService.new(project, user, params).execute + end + + def update_file_line(diff_file, change_line, content) + new_lines = diff_file.new_blob.data.lines + new_lines[change_line..change_line] = content + result = commit_changes(diff_file.file_path, new_lines.join) + newrev = result[:result] + + expect(result[:status]).to eq(:success) + expect(newrev).to be_present + + # Ensure all memoized data is cleared in order + # to generate the new merge_request_diff. + MergeRequest.find(merge_request.id).reload_diff(user) + + note.reload + end + + before do + project.add_maintainer(user) + end + + subject { described_class.new.execute(merge_request) } + + context 'when there is a change within multi-line suggestion range' do + let(:comment_line) { 9 } + let(:lines_above) { 8 } # suggesting to change lines 1..9 + let(:change_line) { 2 } # line 2 is within the range + let!(:suggestion) do + create(:suggestion, :content_from_repo, note: note, lines_above: lines_above) + end + + it 'updates the outdatable suggestion record' do + update_file_line(diff_file, change_line, "# foo\nbar\n") + + # Make sure note is still active + expect(note.active?).to be(true) + + expect { subject }.to change { suggestion.reload.outdated } + .from(false).to(true) + end + end + + context 'when there is no change within multi-line suggestion range' do + let(:comment_line) { 9 } + let(:lines_above) { 3 } # suggesting to change lines 6..9 + let(:change_line) { 2 } # line 2 is not within the range + let!(:suggestion) do + create(:suggestion, :content_from_repo, note: note, lines_above: lines_above) + end + + subject { described_class.new.execute(merge_request) } + + it 'does not outdates suggestion record' do + update_file_line(diff_file, change_line, "# foo\nbar\n") + + # Make sure note is still active + expect(note.active?).to be(true) + + expect { subject }.not_to change { suggestion.reload.outdated }.from(false) + end + end + end +end diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb index 0cbe57352be..e112cdc8881 100644 --- a/spec/services/tags/create_service_spec.rb +++ b/spec/services/tags/create_service_spec.rb @@ -41,7 +41,7 @@ describe Tags::CreateService do it 'returns an error' do expect(repository).to receive(:add_tag) .with(user, 'v1.1.0', 'master', 'Foo') - .and_raise(Gitlab::Git::PreReceiveError, 'something went wrong') + .and_raise(Gitlab::Git::PreReceiveError, 'GitLab: something went wrong') response = service.execute('v1.1.0', 'master', 'Foo') diff --git a/spec/services/verify_pages_domain_service_spec.rb b/spec/services/verify_pages_domain_service_spec.rb index d974cc0226f..ddf9d2b4917 100644 --- a/spec/services/verify_pages_domain_service_spec.rb +++ b/spec/services/verify_pages_domain_service_spec.rb @@ -9,88 +9,130 @@ describe VerifyPagesDomainService do subject(:service) { described_class.new(domain) } describe '#execute' do - context 'verification code recognition (verified domain)' do - where(:domain_sym, :code_sym) do - :domain | :verification_code - :domain | :keyed_verification_code + where(:domain_sym, :code_sym) do + :domain | :verification_code + :domain | :keyed_verification_code - :verification_domain | :verification_code - :verification_domain | :keyed_verification_code - end - - with_them do - set(:domain) { create(:pages_domain) } + :verification_domain | :verification_code + :verification_domain | :keyed_verification_code + end - let(:domain_name) { domain.send(domain_sym) } - let(:verification_code) { domain.send(code_sym) } + with_them do + let(:domain_name) { domain.send(domain_sym) } + let(:verification_code) { domain.send(code_sym) } + shared_examples 'verifies and enables the domain' do it 'verifies and enables the domain' do - stub_resolver(domain_name => ['something else', verification_code]) - expect(service.execute).to eq(status: :success) + expect(domain).to be_verified expect(domain).to be_enabled end + end - it 'verifies and enables when the code is contained partway through a TXT record' do - stub_resolver(domain_name => "something #{verification_code} else") + shared_examples 'successful enablement and verification' do + context 'when txt record contains verification code' do + before do + stub_resolver(domain_name => ['something else', verification_code]) + end - expect(service.execute).to eq(status: :success) - expect(domain).to be_verified - expect(domain).to be_enabled + include_examples 'verifies and enables the domain' end - it 'does not verify when the code is not present' do - stub_resolver(domain_name => 'something else') - - expect(service.execute).to eq(error_status) + context 'when txt record contains verification code with other text' do + before do + stub_resolver(domain_name => "something #{verification_code} else") + end - expect(domain).not_to be_verified - expect(domain).to be_enabled + include_examples 'verifies and enables the domain' end end - context 'verified domain' do - set(:domain) { create(:pages_domain) } + context 'when domain is disabled(or new)' do + let(:domain) { create(:pages_domain, :disabled) } - it 'unverifies (but does not disable) when the right code is not present' do - stub_resolver(domain.domain => 'something else') + include_examples 'successful enablement and verification' - expect(service.execute).to eq(error_status) - expect(domain).not_to be_verified - expect(domain).to be_enabled + shared_examples 'unverifies and disables domain' do + it 'unverifies and disables domain' do + expect(service.execute).to eq(error_status) + + expect(domain).not_to be_verified + expect(domain).not_to be_enabled + end end - it 'unverifies (but does not disable) when no records are present' do - stub_resolver + context 'when txt record does not contain verification code' do + before do + stub_resolver(domain_name => 'something else') + end - expect(service.execute).to eq(error_status) - expect(domain).not_to be_verified - expect(domain).to be_enabled + include_examples 'unverifies and disables domain' + end + + context 'when no txt records are present' do + before do + stub_resolver + end + + include_examples 'unverifies and disables domain' end end - context 'expired domain' do - set(:domain) { create(:pages_domain, :expired) } + context 'when domain is verified' do + let(:domain) { create(:pages_domain) } - it 'verifies and enables when the right code is present' do - stub_resolver(domain.domain => domain.keyed_verification_code) + include_examples 'successful enablement and verification' - expect(service.execute).to eq(status: :success) + context 'when txt record does not contain verification code' do + before do + stub_resolver(domain_name => 'something else') + end - expect(domain).to be_verified - expect(domain).to be_enabled + it 'unverifies but does not disable domain' do + expect(service.execute).to eq(error_status) + expect(domain).not_to be_verified + expect(domain).to be_enabled + end end - it 'disables when the right code is not present' do - error_status[:message] += '. It is now disabled.' + context 'when no txt records are present' do + before do + stub_resolver + end - stub_resolver + it 'unverifies but does not disable domain' do + expect(service.execute).to eq(error_status) + expect(domain).not_to be_verified + expect(domain).to be_enabled + end + end + end - expect(service.execute).to eq(error_status) + context 'when domain is expired' do + let(:domain) { create(:pages_domain, :expired) } - expect(domain).not_to be_verified - expect(domain).not_to be_enabled + context 'when the right code is present' do + before do + stub_resolver(domain_name => domain.keyed_verification_code) + end + + include_examples 'verifies and enables the domain' + end + + context 'when the right code is not present' do + before do + stub_resolver + end + + it 'disables domain' do + error_status[:message] += '. It is now disabled.' + + expect(service.execute).to eq(error_status) + + expect(domain).not_to be_verified + expect(domain).not_to be_enabled + end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e8d7b18bf04..60db3e1bc46 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -66,6 +66,7 @@ RSpec.configure do |config| metadata[:type] = match[1].singularize.to_sym if match end + config.include LicenseHelpers config.include ActiveJob::TestHelper config.include ActiveSupport::Testing::TimeHelpers config.include CycleAnalyticsHelpers @@ -96,6 +97,7 @@ RSpec.configure do |config| config.include MigrationsHelpers, :migration config.include RedisHelpers config.include Rails.application.routes.url_helpers, type: :routing + config.include PolicyHelpers, type: :policy if ENV['CI'] # This includes the first try, i.e. tests will be run 4 times before failing. diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb index 5f709831ce1..63b719be03e 100644 --- a/spec/support/api/milestones_shared_examples.rb +++ b/spec/support/api/milestones_shared_examples.rb @@ -72,6 +72,15 @@ shared_examples_for 'group and project milestones' do |route_definition| expect(json_response.first['id']).to eq closed_milestone.id end + it 'returns a milestone by title' do + get api(route, user), params: { title: 'version2' } + + expect(response).to have_gitlab_http_status(200) + expect(json_response.size).to eq(1) + expect(json_response.first['title']).to eq milestone.title + expect(json_response.first['id']).to eq milestone.id + end + it 'returns a milestone by searching for title' do get api(route, user), params: { search: 'version2' } diff --git a/spec/support/features/issuable_quick_actions_shared_examples.rb b/spec/support/features/issuable_quick_actions_shared_examples.rb deleted file mode 100644 index 2a883ce1074..00000000000 --- a/spec/support/features/issuable_quick_actions_shared_examples.rb +++ /dev/null @@ -1,389 +0,0 @@ -# Specifications for behavior common to all objects with executable attributes. -# It takes a `issuable_type`, and expect an `issuable`. - -shared_examples 'issuable record that supports quick actions in its description and notes' do |issuable_type| - include Spec::Support::Helpers::Features::NotesHelpers - - let(:maintainer) { create(:user) } - let(:project) do - case issuable_type - when :merge_request - create(:project, :public, :repository) - when :issue - create(:project, :public) - end - end - let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } - let!(:label_bug) { create(:label, project: project, title: 'bug') } - let!(:label_feature) { create(:label, project: project, title: 'feature') } - let(:new_url_opts) { {} } - - before do - project.add_maintainer(maintainer) - - gitlab_sign_in(maintainer) - end - - after do - # Ensure all outstanding Ajax requests are complete to avoid database deadlocks - wait_for_requests - end - - describe "new #{issuable_type}", :js do - context 'with commands in the description' do - it "creates the #{issuable_type} and interpret commands accordingly" do - case issuable_type - when :merge_request - visit public_send("namespace_project_new_merge_request_path", project.namespace, project, new_url_opts) - when :issue - visit public_send("new_namespace_project_issue_path", project.namespace, project, new_url_opts) - end - fill_in "#{issuable_type}_title", with: 'bug 345' - fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug\n/milestone %\"ASAP\"" - click_button "Submit #{issuable_type}".humanize - - issuable = project.public_send(issuable_type.to_s.pluralize).first - - expect(issuable.description).to eq "bug description" - expect(issuable.labels).to eq [label_bug] - expect(issuable.milestone).to eq milestone - expect(page).to have_content 'bug 345' - expect(page).to have_content 'bug description' - end - end - end - - describe "note on #{issuable_type}", :js do - before do - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - context 'with a note containing commands' do - it 'creates a note without the commands and interpret the commands accordingly' do - assignee = create(:user, username: 'bob') - add_note("Awesome!\n\n/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"") - - expect(page).to have_content 'Awesome!' - expect(page).not_to have_content '/assign @bob' - expect(page).not_to have_content '/label ~bug' - expect(page).not_to have_content '/milestone %"ASAP"' - - wait_for_requests - issuable.reload - note = issuable.notes.user.first - - expect(note.note).to eq "Awesome!" - expect(issuable.assignees).to eq [assignee] - expect(issuable.labels).to eq [label_bug] - expect(issuable.milestone).to eq milestone - end - - it 'removes the quick action from note and explains it in the preview' do - preview_note("Awesome!\n\n/close") - - expect(page).to have_content 'Awesome!' - expect(page).not_to have_content '/close' - issuable_name = issuable.is_a?(Issue) ? 'issue' : 'merge request' - expect(page).to have_content "Closes this #{issuable_name}." - end - end - - context 'with a note containing only commands' do - it 'does not create a note but interpret the commands accordingly' do - assignee = create(:user, username: 'bob') - add_note("/assign @bob\n\n/label ~bug\n\n/milestone %\"ASAP\"") - - expect(page).not_to have_content '/assign @bob' - expect(page).not_to have_content '/label ~bug' - expect(page).not_to have_content '/milestone %"ASAP"' - expect(page).to have_content 'Commands applied' - - issuable.reload - - expect(issuable.notes.user).to be_empty - expect(issuable.assignees).to eq [assignee] - expect(issuable.labels).to eq [label_bug] - expect(issuable.milestone).to eq milestone - end - end - - context "with a note closing the #{issuable_type}" do - before do - expect(issuable).to be_open - end - - context "when current user can close #{issuable_type}" do - it "closes the #{issuable_type}" do - add_note("/close") - - expect(page).not_to have_content '/close' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload).to be_closed - end - end - - context "when current user cannot close #{issuable_type}" do - before do - guest = create(:user) - project.add_guest(guest) - - gitlab_sign_out - gitlab_sign_in(guest) - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - it "does not close the #{issuable_type}" do - add_note("/close") - - expect(page).not_to have_content 'Commands applied' - - expect(issuable).to be_open - end - end - end - - context "with a note reopening the #{issuable_type}" do - before do - issuable.close - expect(issuable).to be_closed - end - - context "when current user can reopen #{issuable_type}" do - it "reopens the #{issuable_type}" do - add_note("/reopen") - - expect(page).not_to have_content '/reopen' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload).to be_open - end - end - - context "when current user cannot reopen #{issuable_type}" do - before do - guest = create(:user) - project.add_guest(guest) - - gitlab_sign_out - gitlab_sign_in(guest) - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - it "does not reopen the #{issuable_type}" do - add_note("/reopen") - - expect(page).not_to have_content 'Commands applied' - - expect(issuable).to be_closed - end - end - end - - context "with a note changing the #{issuable_type}'s title" do - context "when current user can change title of #{issuable_type}" do - it "reopens the #{issuable_type}" do - add_note("/title Awesome new title") - - expect(page).not_to have_content '/title' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload.title).to eq 'Awesome new title' - end - end - - context "when current user cannot change title of #{issuable_type}" do - before do - guest = create(:user) - project.add_guest(guest) - - gitlab_sign_out - gitlab_sign_in(guest) - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - it "does not change the #{issuable_type} title" do - add_note("/title Awesome new title") - - expect(page).not_to have_content 'Commands applied' - - expect(issuable.reload.title).not_to eq 'Awesome new title' - end - end - end - - context "with a note marking the #{issuable_type} as todo" do - it "creates a new todo for the #{issuable_type}" do - add_note("/todo") - - expect(page).not_to have_content '/todo' - expect(page).to have_content 'Commands applied' - - todos = TodosFinder.new(maintainer).execute - todo = todos.first - - expect(todos.size).to eq 1 - expect(todo).to be_pending - expect(todo.target).to eq issuable - expect(todo.author).to eq maintainer - expect(todo.user).to eq maintainer - end - end - - context "with a note marking the #{issuable_type} as done" do - before do - TodoService.new.mark_todo(issuable, maintainer) - end - - it "creates a new todo for the #{issuable_type}" do - todos = TodosFinder.new(maintainer).execute - todo = todos.first - - expect(todos.size).to eq 1 - expect(todos.first).to be_pending - expect(todo.target).to eq issuable - expect(todo.author).to eq maintainer - expect(todo.user).to eq maintainer - - add_note("/done") - - expect(page).not_to have_content '/done' - expect(page).to have_content 'Commands applied' - - expect(todo.reload).to be_done - end - end - - context "with a note subscribing to the #{issuable_type}" do - it "creates a new todo for the #{issuable_type}" do - expect(issuable.subscribed?(maintainer, project)).to be_falsy - - add_note("/subscribe") - - expect(page).not_to have_content '/subscribe' - expect(page).to have_content 'Commands applied' - - expect(issuable.subscribed?(maintainer, project)).to be_truthy - end - end - - context "with a note unsubscribing to the #{issuable_type} as done" do - before do - issuable.subscribe(maintainer, project) - end - - it "creates a new todo for the #{issuable_type}" do - expect(issuable.subscribed?(maintainer, project)).to be_truthy - - add_note("/unsubscribe") - - expect(page).not_to have_content '/unsubscribe' - expect(page).to have_content 'Commands applied' - - expect(issuable.subscribed?(maintainer, project)).to be_falsy - end - end - - context "with a note assigning the #{issuable_type} to the current user" do - it "assigns the #{issuable_type} to the current user" do - add_note("/assign me") - - expect(page).not_to have_content '/assign me' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload.assignees).to eq [maintainer] - end - end - - context "with a note locking the #{issuable_type} discussion" do - before do - issuable.update(discussion_locked: false) - expect(issuable).not_to be_discussion_locked - end - - context "when current user can lock #{issuable_type} discussion" do - it "locks the #{issuable_type} discussion" do - add_note("/lock") - - expect(page).not_to have_content '/lock' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload).to be_discussion_locked - end - end - - context "when current user cannot lock #{issuable_type}" do - before do - guest = create(:user) - project.add_guest(guest) - - gitlab_sign_out - sign_in(guest) - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - it "does not lock the #{issuable_type} discussion" do - add_note("/lock") - - expect(page).not_to have_content 'Commands applied' - - expect(issuable).not_to be_discussion_locked - end - end - end - - context "with a note unlocking the #{issuable_type} discussion" do - before do - issuable.update(discussion_locked: true) - expect(issuable).to be_discussion_locked - end - - context "when current user can unlock #{issuable_type} discussion" do - it "unlocks the #{issuable_type} discussion" do - add_note("/unlock") - - expect(page).not_to have_content '/unlock' - expect(page).to have_content 'Commands applied' - - expect(issuable.reload).not_to be_discussion_locked - end - end - - context "when current user cannot unlock #{issuable_type}" do - before do - guest = create(:user) - project.add_guest(guest) - - gitlab_sign_out - sign_in(guest) - visit public_send("project_#{issuable_type}_path", project, issuable) - end - - it "does not unlock the #{issuable_type} discussion" do - add_note("/unlock") - - expect(page).not_to have_content 'Commands applied' - - expect(issuable).to be_discussion_locked - end - end - end - end - - describe "preview of note on #{issuable_type}", :js do - it 'removes quick actions from note and explains them' do - create(:user, username: 'bob') - - visit public_send("project_#{issuable_type}_path", project, issuable) - - page.within('.js-main-target-form') do - fill_in 'note[note]', with: "Awesome!\n/assign @bob " - click_on 'Preview' - - expect(page).to have_content 'Awesome!' - expect(page).not_to have_content '/assign @bob' - expect(page).to have_content 'Assigns @bob.' - end - end - end -end diff --git a/spec/support/helpers/javascript_fixtures_helpers.rb b/spec/support/helpers/javascript_fixtures_helpers.rb index cceb179d53e..9cae8f934db 100644 --- a/spec/support/helpers/javascript_fixtures_helpers.rb +++ b/spec/support/helpers/javascript_fixtures_helpers.rb @@ -24,7 +24,7 @@ module JavaScriptFixturesHelpers # def clean_frontend_fixtures(directory_name) full_directory_name = File.expand_path(directory_name, fixture_root_path) - Dir[File.expand_path('*.html.raw', full_directory_name)].each do |file_name| + Dir[File.expand_path('*.html', full_directory_name)].each do |file_name| FileUtils.rm(file_name) end end diff --git a/spec/support/helpers/license_helper.rb b/spec/support/helpers/license_helper.rb new file mode 100644 index 00000000000..4aaad55a8ef --- /dev/null +++ b/spec/support/helpers/license_helper.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# Placeholder module for EE implementation needed for CE specs to be run in EE codebase +module LicenseHelpers + def stub_licensed_features(features) + # do nothing + end +end diff --git a/spec/support/helpers/policy_helpers.rb b/spec/support/helpers/policy_helpers.rb new file mode 100644 index 00000000000..3d780eb5fb1 --- /dev/null +++ b/spec/support/helpers/policy_helpers.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module PolicyHelpers + def expect_allowed(*permissions) + permissions.each { |p| is_expected.to be_allowed(p) } + end + + def expect_disallowed(*permissions) + permissions.each { |p| is_expected.not_to be_allowed(p) } + end +end diff --git a/spec/support/helpers/stub_worker.rb b/spec/support/helpers/stub_worker.rb new file mode 100644 index 00000000000..58b7ee93dff --- /dev/null +++ b/spec/support/helpers/stub_worker.rb @@ -0,0 +1,9 @@ +# Inspired by https://github.com/ljkbennett/stub_env/blob/master/lib/stub_env/helpers.rb +module StubWorker + def stub_worker(queue:) + Class.new do + include Sidekiq::Worker + sidekiq_options queue: queue + end + end +end diff --git a/spec/support/matchers/issuable_matchers.rb b/spec/support/matchers/issuable_matchers.rb index f5d9a97051a..62f510b0fbd 100644 --- a/spec/support/matchers/issuable_matchers.rb +++ b/spec/support/matchers/issuable_matchers.rb @@ -1,4 +1,4 @@ -RSpec::Matchers.define :have_header_with_correct_id_and_link do |level, text, id, parent = ".wiki"| +RSpec::Matchers.define :have_header_with_correct_id_and_link do |level, text, id, parent = ".md"| match do |actual| node = find("#{parent} h#{level} a#user-content-#{id}") diff --git a/spec/support/shared_context/policies/project_policy_shared_context.rb b/spec/support/shared_context/policies/project_policy_shared_context.rb new file mode 100644 index 00000000000..8bcd26ec0cd --- /dev/null +++ b/spec/support/shared_context/policies/project_policy_shared_context.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +RSpec.shared_context 'ProjectPolicy context' do + set(:guest) { create(:user) } + set(:reporter) { create(:user) } + set(:developer) { create(:user) } + set(:maintainer) { create(:user) } + set(:owner) { create(:user) } + set(:admin) { create(:admin) } + let(:project) { create(:project, :public, namespace: owner.namespace) } + + let(:base_guest_permissions) do + %i[ + read_project read_board read_list read_wiki read_issue + read_project_for_iids read_issue_iid read_label + read_milestone read_project_snippet read_project_member read_note + create_project create_issue create_note upload_file create_merge_request_in + award_emoji read_release + ] + end + + let(:base_reporter_permissions) do + %i[ + download_code fork_project create_project_snippet update_issue + admin_issue admin_label admin_list read_commit_status read_build + read_container_image read_pipeline read_environment read_deployment + read_merge_request download_wiki_code read_sentry_issue + ] + end + + let(:team_member_reporter_permissions) do + %i[build_download_code build_read_container_image] + end + + let(:developer_permissions) do + %i[ + admin_milestone admin_merge_request update_merge_request create_commit_status + update_commit_status create_build update_build create_pipeline + update_pipeline create_merge_request_from create_wiki push_code + resolve_note create_container_image update_container_image + create_environment create_deployment create_release update_release + ] + end + + let(:base_maintainer_permissions) do + %i[ + push_to_delete_protected_branch update_project_snippet update_environment + update_deployment admin_project_snippet admin_project_member admin_note admin_wiki admin_project + admin_commit_status admin_build admin_container_image + admin_pipeline admin_environment admin_deployment destroy_release add_cluster + daily_statistics + ] + end + + let(:public_permissions) do + %i[ + download_code fork_project read_commit_status read_pipeline + read_container_image build_download_code build_read_container_image + download_wiki_code read_release + ] + end + + let(:base_owner_permissions) do + %i[ + change_namespace change_visibility_level rename_project remove_project + archive_project remove_fork_project destroy_merge_request destroy_issue + set_issue_iid set_issue_created_at set_note_created_at + ] + end + + # Used in EE specs + let(:additional_guest_permissions) { [] } + let(:additional_reporter_permissions) { [] } + let(:additional_maintainer_permissions) { [] } + let(:additional_owner_permissions) { [] } + + let(:guest_permissions) { base_guest_permissions + additional_guest_permissions } + let(:reporter_permissions) { base_reporter_permissions + additional_reporter_permissions } + let(:maintainer_permissions) { base_maintainer_permissions + additional_maintainer_permissions } + let(:owner_permissions) { base_owner_permissions + additional_owner_permissions } + + before do + project.add_guest(guest) + project.add_maintainer(maintainer) + project.add_developer(developer) + project.add_reporter(reporter) + end +end diff --git a/spec/support/shared_contexts/policies/group_policy_shared_context.rb b/spec/support/shared_contexts/policies/group_policy_shared_context.rb new file mode 100644 index 00000000000..b4808ac0068 --- /dev/null +++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +RSpec.shared_context 'GroupPolicy context' do + let(:guest) { create(:user) } + let(:reporter) { create(:user) } + let(:developer) { create(:user) } + let(:maintainer) { create(:user) } + let(:owner) { create(:user) } + let(:admin) { create(:admin) } + let(:group) { create(:group, :private) } + + let(:guest_permissions) do + %i[ + read_label read_group upload_file read_namespace read_group_activity + read_group_issues read_group_boards read_group_labels read_group_milestones + read_group_merge_requests + ] + end + let(:reporter_permissions) { [:admin_label] } + let(:developer_permissions) { [:admin_milestone] } + let(:maintainer_permissions) do + %i[ + create_projects + read_cluster create_cluster update_cluster admin_cluster add_cluster + ] + end + let(:owner_permissions) do + [ + :admin_group, + :admin_namespace, + :admin_group_member, + :change_visibility_level, + :set_note_created_at, + (Gitlab::Database.postgresql? ? :create_subgroup : nil) + ].compact + end + + before do + group.add_guest(guest) + group.add_reporter(reporter) + group.add_developer(developer) + group.add_maintainer(maintainer) + group.add_owner(owner) + end + + subject { described_class.new(current_user, group) } +end diff --git a/spec/support/shared_examples/policies/project_policy_shared_examples.rb b/spec/support/shared_examples/policies/project_policy_shared_examples.rb new file mode 100644 index 00000000000..7a71e2ee370 --- /dev/null +++ b/spec/support/shared_examples/policies/project_policy_shared_examples.rb @@ -0,0 +1,231 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'archived project policies' do + let(:feature_write_abilities) do + described_class::READONLY_FEATURES_WHEN_ARCHIVED.flat_map do |feature| + described_class.create_update_admin_destroy(feature) + end + additional_reporter_permissions + additional_maintainer_permissions + end + + let(:other_write_abilities) do + %i[ + create_merge_request_in + create_merge_request_from + push_to_delete_protected_branch + push_code + request_access + upload_file + resolve_note + award_emoji + ] + end + + context 'when the project is archived' do + before do + project.archived = true + end + + it 'disables write actions on all relevant project features' do + expect_disallowed(*feature_write_abilities) + end + + it 'disables some other important write actions' do + expect_disallowed(*other_write_abilities) + end + + it 'does not disable other abilities' do + expect_allowed(*(regular_abilities - feature_write_abilities - other_write_abilities)) + end + end +end + +RSpec.shared_examples 'project policies as anonymous' do + context 'abilities for public projects' do + context 'when a project has pending invites' do + let(:group) { create(:group, :public) } + let(:project) { create(:project, :public, namespace: group) } + let(:user_permissions) { [:create_merge_request_in, :create_project, :create_issue, :create_note, :upload_file, :award_emoji] } + let(:anonymous_permissions) { guest_permissions - user_permissions } + + subject { described_class.new(nil, project) } + + before do + create(:group_member, :invited, group: group) + end + + it 'does not grant owner access' do + expect_allowed(*anonymous_permissions) + expect_disallowed(*user_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { anonymous_permissions } + end + end + end + + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + + subject { described_class.new(nil, project) } + + it { is_expected.to be_banned } + end +end + +RSpec.shared_examples 'project policies as guest' do + subject { described_class.new(guest, project) } + + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + let(:reporter_public_build_permissions) do + reporter_permissions - [:read_build, :read_pipeline] + end + + it do + expect_allowed(*guest_permissions) + expect_disallowed(*reporter_public_build_permissions) + expect_disallowed(*team_member_reporter_permissions) + expect_disallowed(*developer_permissions) + expect_disallowed(*maintainer_permissions) + expect_disallowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { guest_permissions } + end + + context 'public builds enabled' do + it do + expect_allowed(*guest_permissions) + expect_allowed(:read_build, :read_pipeline) + end + end + + context 'when public builds disabled' do + before do + project.update(public_builds: false) + end + + it do + expect_allowed(*guest_permissions) + expect_disallowed(:read_build, :read_pipeline) + end + end + + context 'when builds are disabled' do + before do + project.project_feature.update(builds_access_level: ProjectFeature::DISABLED) + end + + it do + expect_disallowed(:read_build) + expect_allowed(:read_pipeline) + end + end + end +end + +RSpec.shared_examples 'project policies as reporter' do + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + + subject { described_class.new(reporter, project) } + + it do + expect_allowed(*guest_permissions) + expect_allowed(*reporter_permissions) + expect_allowed(*team_member_reporter_permissions) + expect_disallowed(*developer_permissions) + expect_disallowed(*maintainer_permissions) + expect_disallowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { reporter_permissions } + end + end +end + +RSpec.shared_examples 'project policies as developer' do + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + subject { described_class.new(developer, project) } + + it do + expect_allowed(*guest_permissions) + expect_allowed(*reporter_permissions) + expect_allowed(*team_member_reporter_permissions) + expect_allowed(*developer_permissions) + expect_disallowed(*maintainer_permissions) + expect_disallowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { developer_permissions } + end + end +end + +RSpec.shared_examples 'project policies as maintainer' do + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + + subject { described_class.new(maintainer, project) } + + it do + expect_allowed(*guest_permissions) + expect_allowed(*reporter_permissions) + expect_allowed(*team_member_reporter_permissions) + expect_allowed(*developer_permissions) + expect_allowed(*maintainer_permissions) + expect_disallowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { maintainer_permissions } + end + end +end + +RSpec.shared_examples 'project policies as owner' do + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + + subject { described_class.new(owner, project) } + + it do + expect_allowed(*guest_permissions) + expect_allowed(*reporter_permissions) + expect_allowed(*team_member_reporter_permissions) + expect_allowed(*developer_permissions) + expect_allowed(*maintainer_permissions) + expect_allowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { owner_permissions } + end + end +end + +RSpec.shared_examples 'project policies as admin' do + context 'abilities for non-public projects' do + let(:project) { create(:project, namespace: owner.namespace) } + + subject { described_class.new(admin, project) } + + it do + expect_allowed(*guest_permissions) + expect_allowed(*reporter_permissions) + expect_disallowed(*team_member_reporter_permissions) + expect_allowed(*developer_permissions) + expect_allowed(*maintainer_permissions) + expect_allowed(*owner_permissions) + end + + it_behaves_like 'archived project policies' do + let(:regular_abilities) { owner_permissions } + end + end +end diff --git a/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb new file mode 100644 index 00000000000..4604d867507 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/commit/tag_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'tag quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb new file mode 100644 index 00000000000..d97da6be192 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/assign_quick_action_shared_examples.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +shared_examples 'assign quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets assign quick action accordingly" do + assignee = create(:user, username: 'bob') + + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/assign @bob" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable.assignees).to eq [assignee] + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + + it "creates the #{issuable_type} and interprets assign quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/assign me" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable.assignees).to eq [maintainer] + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the assign quick action accordingly' do + assignee = create(:user, username: 'bob') + add_note("Awesome!\n\n/assign @bob") + + expect(page).to have_content 'Awesome!' + expect(page).not_to have_content '/assign @bob' + + wait_for_requests + issuable.reload + note = issuable.notes.user.first + + expect(note.note).to eq 'Awesome!' + expect(issuable.assignees).to eq [assignee] + end + + it "assigns the #{issuable_type} to the current user" do + add_note("/assign me") + + expect(page).not_to have_content '/assign me' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload.assignees).to eq [maintainer] + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains assign quick action to bob' do + create(:user, username: 'bob') + + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "Awesome!\n/assign @bob " + click_on 'Preview' + + expect(page).not_to have_content '/assign @bob' + expect(page).to have_content 'Awesome!' + expect(page).to have_content 'Assigns @bob.' + end + end + + it 'explains assign quick action to me' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "Awesome!\n/assign me" + click_on 'Preview' + + expect(page).not_to have_content '/assign me' + expect(page).to have_content 'Awesome!' + expect(page).to have_content "Assigns @#{maintainer.username}." + end + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb new file mode 100644 index 00000000000..74cbfa3f4b4 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/award_quick_action_shared_examples.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +shared_examples 'award quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets award quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/award :100:" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.award_emoji).to eq [] + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + expect(issuable.award_emoji).to eq [] + end + + it 'creates the note and interprets the award quick action accordingly' do + add_note("/award :100:") + + wait_for_requests + expect(page).not_to have_content '/award' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.award_emoji.last.name).to eq('100') + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains label quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/award :100:') + + expect(page).not_to have_content '/award' + expect(page).to have_selector "gl-emoji[data-name='100']" + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb new file mode 100644 index 00000000000..e0d0b790a0e --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/close_quick_action_shared_examples.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +shared_examples 'close quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets close quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/close" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + + context "post note to existing #{issuable_type}" do + before do + expect(issuable).to be_opened + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the close quick action accordingly' do + add_note("this is done, close\n\n/close") + + wait_for_requests + expect(page).not_to have_content '/close' + expect(page).to have_content 'this is done, close' + + issuable.reload + note = issuable.notes.user.first + + expect(note.note).to eq 'this is done, close' + expect(issuable).to be_closed + end + + context "when current user cannot close #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it "does not close the #{issuable_type}" do + add_note('/close') + + expect(page).not_to have_content 'Commands applied' + expect(issuable).to be_open + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains close quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "this is done, close\n/close" + click_on 'Preview' + + expect(page).not_to have_content '/close' + expect(page).to have_content 'this is done, close' + expect(page).to have_content "Closes this #{issuable_type.to_s.humanize.downcase}." + end + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb new file mode 100644 index 00000000000..1e1e3c7bc95 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/copy_metadata_quick_action_shared_examples.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +shared_examples 'copy_metadata quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets copy_metadata quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/copy_metadata #{source_issuable.to_reference(project)}" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).last + + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + issuable.reload + expect(issuable.description).to eq 'bug description' + expect(issuable.milestone).to eq milestone + expect(issuable.labels).to match_array([label_bug, label_feature]) + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets copy_metadata quick action accordingly' do + add_note("/copy_metadata #{source_issuable.to_reference(project)}") + + wait_for_requests + expect(page).not_to have_content '/copy_metadata' + expect(page).to have_content 'Commands applied' + issuable.reload + expect(issuable.milestone).to eq milestone + expect(issuable.labels).to match_array([label_bug, label_feature]) + end + + context "when current user cannot copy_metadata" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not copy_metadata' do + add_note("/copy_metadata #{source_issuable.to_reference(project)}") + + wait_for_requests + expect(page).not_to have_content '/copy_metadata' + expect(page).not_to have_content 'Commands applied' + issuable.reload + expect(issuable.milestone).not_to eq milestone + expect(issuable.labels).to eq [] + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains copy_metadata quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note("/copy_metadata #{source_issuable.to_reference(project)}") + + expect(page).not_to have_content '/copy_metadata' + expect(page).to have_content "Copy labels and milestone from #{source_issuable.to_reference(project)}." + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb new file mode 100644 index 00000000000..8a72bbc13bf --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/done_quick_action_shared_examples.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +shared_examples 'done quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets done quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/done" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + + todos = TodosFinder.new(maintainer).execute + expect(todos.size).to eq 0 + end + end + + context "post note to existing #{issuable_type}" do + before do + TodoService.new.mark_todo(issuable, maintainer) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the done quick action accordingly' do + todos = TodosFinder.new(maintainer).execute + todo = todos.first + expect(todo.reload).to be_pending + + expect(todos.size).to eq 1 + expect(todo.target).to eq issuable + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer + + add_note('/done') + + wait_for_requests + expect(page).not_to have_content '/done' + expect(page).to have_content 'Commands applied' + expect(todo.reload).to be_done + end + + context "when current user cannot mark #{issuable_type} todo as done" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not set the #{issuable_type} todo as done" do + todos = TodosFinder.new(maintainer).execute + todo = todos.first + expect(todo.reload).to be_pending + + expect(todos.size).to eq 1 + expect(todo.target).to eq issuable + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer + + add_note('/done') + + expect(page).not_to have_content 'Commands applied' + expect(todo.reload).to be_pending + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains done quick action' do + TodoService.new.mark_todo(issuable, maintainer) + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/done') + + expect(page).not_to have_content '/done' + expect(page).to have_content "Marks todo as done." + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb new file mode 100644 index 00000000000..648755d7e55 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/estimate_quick_action_shared_examples.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +shared_examples 'estimate quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets estimate quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/estimate 1d 2h 3m" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.time_estimate).to eq 36180 + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the estimate quick action accordingly' do + add_note("/estimate 1d 2h 3m") + + wait_for_requests + expect(page).not_to have_content '/estimate' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.time_estimate).to eq 36180 + end + + context "when current user cannot set estimate to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not set estimate' do + add_note("/estimate ~bug ~feature") + + wait_for_requests + expect(page).not_to have_content '/estimate' + expect(issuable.reload.time_estimate).to eq 0 + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains estimate quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/estimate 1d 2h 3m') + + expect(page).not_to have_content '/estimate' + expect(page).to have_content 'Sets time estimate to 1d 2h 3m.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb new file mode 100644 index 00000000000..9066e382b70 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/label_quick_action_shared_examples.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +shared_examples 'label quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets label quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug ~feature" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.labels).to match_array([label_bug, label_feature]) + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + expect(issuable.labels).to eq [] + end + + it 'creates the note and interprets the label quick action accordingly' do + add_note("/label ~bug ~feature") + + wait_for_requests + expect(page).not_to have_content '/label' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.labels).to match_array([label_bug, label_feature]) + end + + context "when current user cannot set label to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not set label' do + add_note("/label ~bug ~feature") + + wait_for_requests + expect(page).not_to have_content '/label' + expect(issuable.labels).to eq [] + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains label quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/label ~bug ~feature') + + expect(page).not_to have_content '/label' + expect(page).to have_content 'Adds bug feature labels.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb new file mode 100644 index 00000000000..d3197f2a459 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/lock_quick_action_shared_examples.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +shared_examples 'lock quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets lock quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/lock" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable).not_to be_discussion_locked + end + end + + context "post note to existing #{issuable_type}" do + before do + issuable.update(discussion_locked: false) + expect(issuable).not_to be_discussion_locked + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the lock quick action accordingly' do + add_note('/lock') + + wait_for_requests + expect(page).not_to have_content '/lock' + expect(page).to have_content 'Commands applied' + expect(issuable.reload).to be_discussion_locked + end + + context "when current user cannot lock to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not lock the #{issuable_type}" do + add_note('/lock') + + wait_for_requests + expect(page).not_to have_content '/lock' + expect(issuable).not_to be_discussion_locked + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains lock quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/lock') + + expect(page).not_to have_content '/lock' + expect(page).to have_content "Locks the discussion" + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb new file mode 100644 index 00000000000..7f16ce93b6a --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/milestone_quick_action_shared_examples.rb @@ -0,0 +1,83 @@ +# frozen_string_literal: true + +shared_examples 'milestone quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets milestone quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/milestone %\"ASAP\"" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.milestone).to eq milestone + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + expect(issuable.milestone).to be_nil + end + + it 'creates the note and interprets the milestone quick action accordingly' do + add_note("/milestone %\"ASAP\"") + + wait_for_requests + expect(page).not_to have_content '/milestone' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.milestone).to eq milestone + end + + context "when current user cannot set milestone to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not set milestone' do + add_note('/milestone') + + wait_for_requests + expect(page).not_to have_content '/milestone' + expect(issuable.reload.milestone).to be_nil + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains milestone quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note("/milestone %\"ASAP\"") + + expect(page).not_to have_content '/milestone' + expect(page).to have_content 'Sets the milestone to %ASAP' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb new file mode 100644 index 00000000000..643ae77516a --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/relabel_quick_action_shared_examples.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +shared_examples 'relabel quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets relabel quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug /relabel ~feature" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.labels).to eq [label_bug, label_feature] + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + issuable.update(labels: [label_bug]) + end + + it 'creates the note and interprets the relabel quick action accordingly' do + add_note('/relabel ~feature') + + wait_for_requests + expect(page).not_to have_content '/relabel' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.labels).to match_array([label_feature]) + end + + it 'creates the note and interprets the relabel quick action with empty param' do + add_note('/relabel') + + wait_for_requests + expect(page).not_to have_content '/relabel' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.labels).to match_array([label_bug]) + end + + context "when current user cannot relabel to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not relabel' do + add_note('/relabel ~feature') + + wait_for_requests + expect(page).not_to have_content '/relabel' + expect(issuable.labels).to match_array([label_bug]) + end + end + end + + context "preview of note on #{issuable_type}", :js do + before do + issuable.update(labels: [label_bug]) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it 'explains relabel all quick action' do + preview_note('/relabel ~feature') + + expect(page).not_to have_content '/relabel' + expect(page).to have_content 'Replaces all labels with feature label.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb new file mode 100644 index 00000000000..24f6f8d5bf4 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/remove_estimate_quick_action_shared_examples.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +shared_examples 'remove_estimate quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets estimate quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/remove_estimate" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.time_estimate).to eq 0 + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + issuable.update_attribute(:time_estimate, 36180) + end + + it 'creates the note and interprets the remove_estimate quick action accordingly' do + add_note("/remove_estimate") + + wait_for_requests + expect(page).not_to have_content '/remove_estimate' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.time_estimate).to eq 0 + end + + context "when current user cannot remove_estimate" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not remove_estimate' do + add_note('/remove_estimate') + + wait_for_requests + expect(page).not_to have_content '/remove_estimate' + expect(issuable.reload.time_estimate).to eq 36180 + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains remove_estimate quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/remove_estimate') + + expect(page).not_to have_content '/remove_estimate' + expect(page).to have_content 'Removes time estimate.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb new file mode 100644 index 00000000000..edd92d5cdbc --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/remove_milestone_quick_action_shared_examples.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +shared_examples 'remove_milestone quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets remove_milestone quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/remove_milestone" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.milestone).to be_nil + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + issuable.update(milestone: milestone) + expect(issuable.milestone).to eq(milestone) + end + + it 'creates the note and interprets the remove_milestone quick action accordingly' do + add_note("/remove_milestone") + + wait_for_requests + expect(page).not_to have_content '/remove_milestone' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.milestone).to be_nil + end + + context "when current user cannot remove milestone to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not remove milestone' do + add_note('/remove_milestone') + + wait_for_requests + expect(page).not_to have_content '/remove_milestone' + expect(issuable.reload.milestone).to eq(milestone) + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains remove_milestone quick action' do + issuable.update(milestone: milestone) + expect(issuable.milestone).to eq(milestone) + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note("/remove_milestone") + + expect(page).not_to have_content '/remove_milestone' + expect(page).to have_content 'Removes %ASAP milestone.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb new file mode 100644 index 00000000000..6d5894b2318 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/remove_time_spent_quick_action_shared_examples.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +shared_examples 'remove_time_spent quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets remove_time_spent quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/remove_time_spent" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.total_time_spent).to eq 0 + end + end + + context "post note to existing #{issuable_type}" do + before do + issuable.update!(spend_time: { duration: 36180, user_id: maintainer.id }) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the remove_time_spent quick action accordingly' do + add_note("/remove_time_spent") + + wait_for_requests + expect(page).not_to have_content '/remove_time_spent' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.total_time_spent).to eq 0 + end + + context "when current user cannot set remove_time_spent time" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not set remove_time_spent time' do + add_note("/remove_time_spent") + + wait_for_requests + expect(page).not_to have_content '/remove_time_spent' + expect(issuable.reload.total_time_spent).to eq 36180 + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains remove_time_spent quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/remove_time_spent') + + expect(page).not_to have_content '/remove_time_spent' + expect(page).to have_content 'Removes spent time.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb new file mode 100644 index 00000000000..af173e93bb5 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/reopen_quick_action_shared_examples.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +shared_examples 'reopen quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets reopen quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/reopen" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + + context "post note to existing #{issuable_type}" do + before do + issuable.close + expect(issuable).to be_closed + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the reopen quick action accordingly' do + add_note('/reopen') + + wait_for_requests + expect(page).not_to have_content '/reopen' + expect(page).to have_content 'Commands applied' + + issuable.reload + expect(issuable).to be_opened + end + + context "when current user cannot reopen #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not reopen the #{issuable_type}" do + add_note('/reopen') + + expect(page).not_to have_content 'Commands applied' + expect(issuable).to be_closed + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains reopen quick action' do + issuable.close + expect(issuable).to be_closed + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/reopen') + + expect(page).not_to have_content '/reopen' + expect(page).to have_content "Reopens this #{issuable_type.to_s.humanize.downcase}." + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb new file mode 100644 index 00000000000..0a526808585 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/shrug_quick_action_shared_examples.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +shared_examples 'shrug quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets shrug quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/shrug oops" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq "bug description\noops ¯\\_(ツ)_/¯" + expect(page).to have_content 'bug 345' + expect(page).to have_content "bug description\noops ¯\\_(ツ)_/¯" + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets shrug quick action accordingly' do + add_note("/shrug oops") + + wait_for_requests + expect(page).not_to have_content '/shrug oops' + expect(page).to have_content "oops ¯\\_(ツ)_/¯" + expect(issuable.notes.last.note).to eq "oops ¯\\_(ツ)_/¯" + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains shrug quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/shrug oops') + + expect(page).not_to have_content '/shrug' + expect(page).to have_content "oops ¯\\_(ツ)_/¯" + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb new file mode 100644 index 00000000000..97b4885eba0 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/spend_quick_action_shared_examples.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +shared_examples 'spend quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets spend quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/spend 1d 2h 3m" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.total_time_spent).to eq 36180 + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the spend quick action accordingly' do + add_note("/spend 1d 2h 3m") + + wait_for_requests + expect(page).not_to have_content '/spend' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.total_time_spent).to eq 36180 + end + + context "when current user cannot set spend time" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not set spend time' do + add_note("/spend 1s 2h 3m") + + wait_for_requests + expect(page).not_to have_content '/spend' + expect(issuable.reload.total_time_spent).to eq 0 + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains spend quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/spend 1d 2h 3m') + + expect(page).not_to have_content '/spend' + expect(page).to have_content 'Adds 1d 2h 3m spent time.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb new file mode 100644 index 00000000000..15aefd511a5 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/subscribe_quick_action_shared_examples.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +shared_examples 'subscribe quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets subscribe quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/subscribe" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + expect(issuable.subscribed?(maintainer, project)).to be_falsy + end + + it 'creates the note and interprets the subscribe quick action accordingly' do + add_note('/subscribe') + + wait_for_requests + expect(page).not_to have_content '/subscribe' + expect(page).to have_content 'Commands applied' + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + + context "when current user cannot subscribe to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not subscribe to the #{issuable_type}" do + add_note('/subscribe') + + wait_for_requests + expect(page).not_to have_content '/subscribe' + expect(page).to have_content 'Commands applied' + expect(issuable.subscribed?(maintainer, project)).to be_falsy + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains subscribe quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/subscribe') + + expect(page).not_to have_content '/subscribe' + expect(page).to have_content "Subscribes to this #{issuable_type.to_s.humanize.downcase}" + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb new file mode 100644 index 00000000000..ef831e39872 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/tableflip_quick_action_shared_examples.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +shared_examples 'tableflip quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets tableflip quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/tableflip oops" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq "bug description\noops (╯°□°)╯︵ ┻━┻" + expect(page).to have_content 'bug 345' + expect(page).to have_content "bug description\noops (╯°□°)╯︵ ┻━┻" + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets tableflip quick action accordingly' do + add_note("/tableflip oops") + + wait_for_requests + expect(page).not_to have_content '/tableflip oops' + expect(page).to have_content "oops (╯°□°)╯︵ ┻━┻" + expect(issuable.notes.last.note).to eq "oops (╯°□°)╯︵ ┻━┻" + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains tableflip quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/tableflip oops') + + expect(page).not_to have_content '/tableflip' + expect(page).to have_content "oops (╯°□°)╯︵ ┻━┻" + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb new file mode 100644 index 00000000000..ed904c8d539 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/time_tracking_quick_action_shared_examples.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +shared_examples 'issuable time tracker' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + after do + wait_for_requests + end + + it 'renders the sidebar component empty state' do + page.within '.time-tracking-no-tracking-pane' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'updates the sidebar component when estimate is added' do + submit_time('/estimate 3w 1d 1h') + + wait_for_requests + page.within '.time-tracking-estimate-only-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'updates the sidebar component when spent is added' do + submit_time('/spend 3w 1d 1h') + + wait_for_requests + page.within '.time-tracking-spend-only-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'shows the comparison when estimate and spent are added' do + submit_time('/estimate 3w 1d 1h') + submit_time('/spend 3w 1d 1h') + + wait_for_requests + page.within '.time-tracking-comparison-pane' do + expect(page).to have_content '3w 1d 1h' + end + end + + it 'updates the sidebar component when estimate is removed' do + submit_time('/estimate 3w 1d 1h') + submit_time('/remove_estimate') + + page.within '.time-tracking-component-wrap' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'updates the sidebar component when spent is removed' do + submit_time('/spend 3w 1d 1h') + submit_time('/remove_time_spent') + + page.within '.time-tracking-component-wrap' do + expect(page).to have_content 'No estimate or time spent' + end + end + + it 'shows the help state when icon is clicked' do + page.within '.time-tracking-component-wrap' do + find('.help-button').click + expect(page).to have_content 'Track time with quick actions' + expect(page).to have_content 'Learn more' + end + end + + it 'hides the help state when close icon is clicked' do + page.within '.time-tracking-component-wrap' do + find('.help-button').click + find('.close-help-button').click + + expect(page).not_to have_content 'Track time with quick actions' + expect(page).not_to have_content 'Learn more' + end + end + + it 'displays the correct help url' do + page.within '.time-tracking-component-wrap' do + find('.help-button').click + + expect(find_link('Learn more')[:href]).to have_content('/help/workflow/time_tracking.md') + end + end +end + +def submit_time(quick_action) + fill_in 'note[note]', with: quick_action + find('.js-comment-submit-button').click + wait_for_requests +end diff --git a/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb new file mode 100644 index 00000000000..93a69093dde --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/title_quick_action_shared_examples.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +shared_examples 'title quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets title quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/title new title" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(issuable.title).to eq 'bug 345' + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the title quick action accordingly' do + add_note('/title New title') + + wait_for_requests + expect(page).not_to have_content '/title new title' + expect(page).to have_content 'Commands applied' + expect(page).to have_content 'New title' + + issuable.reload + expect(issuable.title).to eq 'New title' + end + + context "when current user cannot set title #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not set title to the #{issuable_type}" do + add_note('/title New title') + + expect(page).not_to have_content 'Commands applied' + expect(issuable.title).not_to eq 'New title' + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains title quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/title New title') + wait_for_requests + + expect(page).not_to have_content '/title New title' + expect(page).to have_content 'Changes the title to "New title".' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb new file mode 100644 index 00000000000..cccc28127ce --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/todo_quick_action_shared_examples.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +shared_examples 'todo quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets todo quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/todo" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + + todos = TodosFinder.new(maintainer).execute + expect(todos.size).to eq 0 + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the todo quick action accordingly' do + add_note('/todo') + + wait_for_requests + expect(page).not_to have_content '/todo' + expect(page).to have_content 'Commands applied' + + todos = TodosFinder.new(maintainer).execute + todo = todos.first + + expect(todos.size).to eq 1 + expect(todo).to be_pending + expect(todo.target).to eq issuable + expect(todo.author).to eq maintainer + expect(todo.user).to eq maintainer + end + + context "when current user cannot add todo #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not add todo the #{issuable_type}" do + add_note('/todo') + + expect(page).not_to have_content 'Commands applied' + todos = TodosFinder.new(maintainer).execute + expect(todos.size).to eq 0 + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains todo quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/todo') + + expect(page).not_to have_content '/todo' + expect(page).to have_content "Adds a todo." + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb new file mode 100644 index 00000000000..0b1a52bc860 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/unassign_quick_action_shared_examples.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +shared_examples 'unassign quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets unassign quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/unassign @bob" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable.assignees).to eq [] + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + + it "creates the #{issuable_type} and interprets unassign quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/unassign me" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable.assignees).to eq [] + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the unassign quick action accordingly' do + assignee = create(:user, username: 'bob') + issuable.update(assignee_ids: [assignee.id]) + expect(issuable.assignees).to eq [assignee] + + add_note("Awesome!\n\n/unassign @bob") + + expect(page).to have_content 'Awesome!' + expect(page).not_to have_content '/unassign @bob' + + wait_for_requests + issuable.reload + note = issuable.notes.user.first + + expect(note.note).to eq 'Awesome!' + expect(issuable.assignees).to eq [] + end + + it "unassigns the #{issuable_type} from current user" do + issuable.update(assignee_ids: [maintainer.id]) + expect(issuable.reload.assignees).to eq [maintainer] + expect(issuable.assignees).to eq [maintainer] + + add_note("/unassign me") + + expect(page).not_to have_content '/unassign me' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload.assignees).to eq [] + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains unassign quick action: from bob' do + assignee = create(:user, username: 'bob') + issuable.update(assignee_ids: [assignee.id]) + expect(issuable.assignees).to eq [assignee] + + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "Awesome!\n/unassign @bob " + click_on 'Preview' + + expect(page).not_to have_content '/unassign @bob' + expect(page).to have_content 'Awesome!' + expect(page).to have_content 'Removes assignee @bob.' + end + end + + it 'explains unassign quick action: from me' do + issuable.update(assignee_ids: [maintainer.id]) + expect(issuable.assignees).to eq [maintainer] + + visit public_send("project_#{issuable_type}_path", project, issuable) + + page.within('.js-main-target-form') do + fill_in 'note[note]', with: "Awesome!\n/unassign me" + click_on 'Preview' + + expect(page).not_to have_content '/unassign me' + expect(page).to have_content 'Awesome!' + expect(page).to have_content "Removes assignee @#{maintainer.username}." + end + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb new file mode 100644 index 00000000000..1a1ee05841f --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/unlabel_quick_action_shared_examples.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +shared_examples 'unlabel quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets unlabel quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/label ~bug /unlabel" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.labels).to eq [label_bug] + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + issuable.update(labels: [label_bug, label_feature]) + end + + it 'creates the note and interprets the unlabel all quick action accordingly' do + add_note("/unlabel") + + wait_for_requests + expect(page).not_to have_content '/unlabel' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.labels).to eq [] + end + + it 'creates the note and interprets the unlabel some quick action accordingly' do + add_note("/unlabel ~bug") + + wait_for_requests + expect(page).not_to have_content '/unlabel' + expect(page).to have_content 'Commands applied' + expect(issuable.reload.labels).to match_array([label_feature]) + end + + context "when current user cannot unlabel to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'does not unlabel' do + add_note("/unlabel") + + wait_for_requests + expect(page).not_to have_content '/unlabel' + expect(issuable.labels).to match_array([label_bug, label_feature]) + end + end + end + + context "preview of note on #{issuable_type}", :js do + before do + issuable.update(labels: [label_bug, label_feature]) + visit public_send("project_#{issuable_type}_path", project, issuable) + end + + it 'explains unlabel all quick action' do + preview_note('/unlabel') + + expect(page).not_to have_content '/unlabel' + expect(page).to have_content 'Removes all labels.' + end + + it 'explains unlabel some quick action' do + preview_note('/unlabel ~bug') + + expect(page).not_to have_content '/unlabel' + expect(page).to have_content 'Removes bug label.' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb new file mode 100644 index 00000000000..998ff99b32e --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/unlock_quick_action_shared_examples.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +shared_examples 'unlock quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets unlock quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/unlock" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable).not_to be_discussion_locked + end + end + + context "post note to existing #{issuable_type}" do + before do + issuable.update(discussion_locked: true) + expect(issuable).to be_discussion_locked + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it 'creates the note and interprets the unlock quick action accordingly' do + add_note('/unlock') + + wait_for_requests + expect(page).not_to have_content '/unlock' + expect(page).to have_content 'Commands applied' + expect(issuable.reload).not_to be_discussion_locked + end + + context "when current user cannot unlock to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not lock the #{issuable_type}" do + add_note('/unlock') + + wait_for_requests + expect(page).not_to have_content '/unlock' + expect(issuable).to be_discussion_locked + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains unlock quick action' do + issuable.update(discussion_locked: true) + expect(issuable).to be_discussion_locked + + visit public_send("project_#{issuable_type}_path", project, issuable) + + preview_note('/unlock') + + expect(page).not_to have_content '/unlock' + expect(page).to have_content 'Unlocks the discussion' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb new file mode 100644 index 00000000000..bd92f133889 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issuable/unsubscribe_quick_action_shared_examples.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +shared_examples 'unsubscribe quick action' do |issuable_type| + before do + project.add_maintainer(maintainer) + gitlab_sign_in(maintainer) + end + + context "new #{issuable_type}", :js do + before do + case issuable_type + when :merge_request + visit public_send('namespace_project_new_merge_request_path', project.namespace, project, new_url_opts) + wait_for_all_requests + when :issue + visit public_send('new_namespace_project_issue_path', project.namespace, project, new_url_opts) + wait_for_all_requests + end + end + + it "creates the #{issuable_type} and interprets unsubscribe quick action accordingly" do + fill_in "#{issuable_type}_title", with: 'bug 345' + fill_in "#{issuable_type}_description", with: "bug description\n/unsubscribe" + click_button "Submit #{issuable_type}".humanize + + issuable = project.public_send(issuable_type.to_s.pluralize).first + + expect(issuable.description).to eq 'bug description' + expect(issuable).to be_opened + expect(page).to have_content 'bug 345' + expect(page).to have_content 'bug description' + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + end + + context "post note to existing #{issuable_type}" do + before do + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + issuable.subscribe(maintainer, project) + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + + it 'creates the note and interprets the unsubscribe quick action accordingly' do + add_note('/unsubscribe') + + wait_for_requests + expect(page).not_to have_content '/unsubscribe' + expect(page).to have_content 'Commands applied' + expect(issuable.subscribed?(maintainer, project)).to be_falsey + end + + context "when current user cannot unsubscribe to #{issuable_type}" do + before do + guest = create(:user) + project.add_guest(guest) + + gitlab_sign_out + gitlab_sign_in(guest) + visit public_send("project_#{issuable_type}_path", project, issuable) + wait_for_all_requests + end + + it "does not unsubscribe to the #{issuable_type}" do + add_note('/unsubscribe') + + wait_for_requests + expect(page).not_to have_content '/unsubscribe' + expect(issuable.subscribed?(maintainer, project)).to be_truthy + end + end + end + + context "preview of note on #{issuable_type}", :js do + it 'explains unsubscribe quick action' do + visit public_send("project_#{issuable_type}_path", project, issuable) + issuable.subscribe(maintainer, project) + expect(issuable.subscribed?(maintainer, project)).to be_truthy + + preview_note('/unsubscribe') + + expect(page).not_to have_content '/unsubscribe' + expect(page).to have_content "Unsubscribes from this #{issuable_type.to_s.humanize.downcase}." + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb new file mode 100644 index 00000000000..6edd20bb024 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/board_move_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'board_move quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb new file mode 100644 index 00000000000..c68e5aee842 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/confidential_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'confidential quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb new file mode 100644 index 00000000000..5bfc3bb222f --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/create_merge_request_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'create_merge_request quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb new file mode 100644 index 00000000000..db3ecccc339 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/due_quick_action_shared_examples.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +shared_examples 'due quick action not available' do + it 'does not set the due date' do + add_note('/due 2016-08-28') + + expect(page).not_to have_content 'Commands applied' + expect(page).not_to have_content '/due 2016-08-28' + end +end + +shared_examples 'due quick action available and date can be added' do + it 'sets the due date accordingly' do + add_note('/due 2016-08-28') + + expect(page).not_to have_content '/due 2016-08-28' + expect(page).to have_content 'Commands applied' + + visit project_issue_path(project, issue) + + page.within '.due_date' do + expect(page).to have_content 'Aug 28, 2016' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb new file mode 100644 index 00000000000..24576fe0021 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/duplicate_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'duplicate quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb new file mode 100644 index 00000000000..953e67b0423 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/move_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'move quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb new file mode 100644 index 00000000000..5904164fcfc --- /dev/null +++ b/spec/support/shared_examples/quick_actions/issue/remove_due_date_quick_action_shared_examples.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +shared_examples 'remove_due_date action not available' do + it 'does not remove the due date' do + add_note("/remove_due_date") + + expect(page).not_to have_content 'Commands applied' + expect(page).not_to have_content '/remove_due_date' + end +end + +shared_examples 'remove_due_date action available and due date can be removed' do + it 'removes the due date accordingly' do + add_note('/remove_due_date') + + expect(page).not_to have_content '/remove_due_date' + expect(page).to have_content 'Commands applied' + + visit project_issue_path(project, issue) + + page.within '.due_date' do + expect(page).to have_content 'No due date' + end + end +end diff --git a/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb new file mode 100644 index 00000000000..31d88183f0d --- /dev/null +++ b/spec/support/shared_examples/quick_actions/merge_request/merge_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'merge quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb new file mode 100644 index 00000000000..ccb4a85325b --- /dev/null +++ b/spec/support/shared_examples/quick_actions/merge_request/target_branch_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'target_branch quick action' do +end diff --git a/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb b/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb new file mode 100644 index 00000000000..6abb12b41b2 --- /dev/null +++ b/spec/support/shared_examples/quick_actions/merge_request/wip_quick_action_shared_examples.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +shared_examples 'wip quick action' do +end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 533e9d87ea6..9ce9a353913 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -375,7 +375,7 @@ describe ObjectStorage do describe '#fog_public' do subject { uploader.fog_public } - it { is_expected.to eq(false) } + it { is_expected.to eq(nil) } end describe '.workhorse_authorize' do diff --git a/spec/workers/migrate_external_diffs_worker_spec.rb b/spec/workers/migrate_external_diffs_worker_spec.rb new file mode 100644 index 00000000000..88d48cad14b --- /dev/null +++ b/spec/workers/migrate_external_diffs_worker_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe MigrateExternalDiffsWorker do + let(:worker) { described_class.new } + let(:diff) { create(:merge_request).merge_request_diff } + + describe '#perform' do + it 'migrates the listed diff' do + expect_next_instance_of(MergeRequests::MigrateExternalDiffsService) do |instance| + expect(instance.diff).to eq(diff) + expect(instance).to receive(:execute) + end + + worker.perform(diff.id) + end + + it 'does nothing if the diff is missing' do + diff.destroy + + worker.perform(diff.id) + end + end +end diff --git a/spec/workers/schedule_migrate_external_diffs_worker_spec.rb b/spec/workers/schedule_migrate_external_diffs_worker_spec.rb new file mode 100644 index 00000000000..9d6fecc9f4e --- /dev/null +++ b/spec/workers/schedule_migrate_external_diffs_worker_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ScheduleMigrateExternalDiffsWorker do + include ExclusiveLeaseHelpers + + let(:worker) { described_class.new } + + describe '#perform' do + it 'triggers a scan for diffs to migrate' do + expect(MergeRequests::MigrateExternalDiffsService).to receive(:enqueue!) + + worker.perform + end + + it 'will not run if the lease is already taken' do + stub_exclusive_lease_taken('schedule_migrate_external_diffs_worker', timeout: 2.hours) + + expect(MergeRequests::MigrateExternalDiffsService).not_to receive(:enqueue!) + + worker.perform + end + end +end |