diff options
Diffstat (limited to 'spec')
109 files changed, 1036 insertions, 234 deletions
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index 0202149f335..293e76798ae 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -27,7 +27,7 @@ describe Projects::Settings::CiCdController do allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(true) end - subject { post :reset_cache, namespace_id: project.namespace, project_id: project } + subject { post :reset_cache, namespace_id: project.namespace, project_id: project, format: :json } it 'calls reset project cache service' do expect(ResetProjectCacheService).to receive_message_chain(:new, :execute) @@ -35,19 +35,11 @@ describe Projects::Settings::CiCdController do subject end - it 'redirects to project pipelines path' do - subject - - expect(response).to have_gitlab_http_status(:redirect) - expect(response).to redirect_to(project_pipelines_path(project)) - end - context 'when service returns successfully' do - it 'sets the flash notice variable' do + it 'returns a success header' do subject - expect(controller).to set_flash[:notice] - expect(controller).not_to set_flash[:error] + expect(response).to have_gitlab_http_status(:ok) end end @@ -56,11 +48,10 @@ describe Projects::Settings::CiCdController do allow(ResetProjectCacheService).to receive_message_chain(:new, :execute).and_return(false) end - it 'sets the flash error variable' do + it 'returns an error header' do subject - expect(controller).not_to set_flash[:notice] - expect(controller).to set_flash[:error] + expect(response).to have_gitlab_http_status(:bad_request) end end end diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb index 7ee379ca2ec..8544d54ccaa 100644 --- a/spec/factories/ci/job_artifacts.rb +++ b/spec/factories/ci/job_artifacts.rb @@ -35,5 +35,11 @@ FactoryBot.define do Rails.root.join('spec/fixtures/trace/sample_trace'), 'text/plain') end end + + trait :correct_checksum do + after(:build) do |artifact, evaluator| + artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest + end + end end end diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index 3d13f806b11..52ff47d57f9 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -343,7 +343,7 @@ describe 'Issue Boards', :js do wait_for_requests - click_link 'Create new label' + click_link 'Create project label' fill_in('new_label_name', with: 'Testing New Label') diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index b2dbfcd0031..d4c44c1adf9 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -312,12 +312,12 @@ describe 'Issue Boards', :js do expect(card).not_to have_content(stretch.title) end - it 'creates new label' do + it 'creates project label' do click_card(card) page.within('.labels') do click_link 'Edit' - click_link 'Create new label' + click_link 'Create project label' fill_in 'new_label_name', with: 'test label' first('.suggest-colors-dropdown a').click click_button 'Create' diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index 11a54079f4f..5fdb8044db2 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -24,7 +24,7 @@ describe 'Sub-group project issue boards', :js do page.within '.labels' do click_link 'Edit' - click_link 'Create new label' + click_link 'Create project label' end page.within '.dropdown-new-label' do diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index ef6b8edd0ad..38c618d300e 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -306,10 +306,10 @@ describe 'New/edit issue', :js do visit new_project_issue_path(sub_group_project) end - it 'creates new label from dropdown' do + it 'creates project label from dropdown' do click_button 'Labels' - click_link 'Create new label' + click_link 'Create project label' page.within '.dropdown-new-label' do fill_in 'new_label_name', with: 'test label' diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 64b4f9e7e67..b835558b142 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -117,22 +117,22 @@ feature 'Issue Sidebar' do end end - it 'shows option to create a new label' do + it 'shows option to create a project label' do page.within('.block.labels') do - expect(page).to have_content 'Create new' + expect(page).to have_content 'Create project' end end - context 'creating a new label', :js do + context 'creating a project label', :js do before do page.within('.block.labels') do - click_link 'Create new' + click_link 'Create project' end end it 'shows dropdown switches to "create label" section' do page.within('.block.labels') do - expect(page).to have_content 'Create new label' + expect(page).to have_content 'Create project label' end end diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb index 890774922aa..db92a3504f3 100644 --- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb @@ -125,6 +125,12 @@ describe 'Merge request > User merges when pipeline succeeds', :js do expect(page).to have_content "canceled the automatic merge" end + it 'allows to remove source branch' do + click_link "Remove source branch" + + expect(page).to have_content "The source branch will be removed" + end + context 'when pipeline succeeds' do before do build.success diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb index 56224e505d9..51a65407aec 100644 --- a/spec/features/merge_request/user_sees_merge_widget_spec.rb +++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' describe 'Merge request > User sees merge widget', :js do + include ProjectForksHelper + let(:project) { create(:project, :repository) } let(:project_only_mwps) { create(:project, :repository, only_allow_merge_if_pipeline_succeeds: true) } let(:user) { project.creator } @@ -285,7 +287,29 @@ describe 'Merge request > User sees merge widget', :js do end it 'user cannot remove source branch' do - expect(page).to have_field('remove-source-branch-input', disabled: true) + expect(page).not_to have_field('remove-source-branch-input') + end + end + + context 'user cannot merge project and cannot push to fork', :js do + let(:forked_project) { fork_project(project, nil, repository: true) } + let(:user2) { create(:user) } + + before do + project.add_developer(user2) + sign_out(:user) + sign_in(user2) + merge_request.update( + source_project: forked_project, + target_project: project, + merge_params: { 'force_remove_source_branch' => '1' } + ) + visit project_merge_request_path(project, merge_request) + end + + it 'user cannot remove source branch' do + expect(page).not_to have_field('remove-source-branch-input') + expect(page).to have_content('Removes source branch') end end diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index cc12a1005ba..19152bf1f0f 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -97,4 +97,15 @@ feature 'Milestone' do end end end + + feature 'Deleting a milestone' do + scenario "The delete milestone button does not show for unauthorized users" do + create(:milestone, project: project, title: 8.7) + sign_out(user) + + visit group_milestones_path(group) + + expect(page).to have_selector('.js-delete-milestone-button', count: 0) + end + end end diff --git a/spec/features/projects/actve_tabs_spec.rb b/spec/features/projects/actve_tabs_spec.rb new file mode 100644 index 00000000000..0bda68b83e7 --- /dev/null +++ b/spec/features/projects/actve_tabs_spec.rb @@ -0,0 +1,137 @@ +require 'spec_helper' + +describe 'Project active tab' do + let(:user) { create :user } + let(:project) { create(:project, :repository) } + + before do + project.add_master(user) + sign_in(user) + end + + def click_tab(title) + page.within '.sidebar-top-level-items > .active' do + click_link(title) + end + end + + shared_examples 'page has active tab' do |title| + it "activates #{title} tab" do + expect(page).to have_selector('.sidebar-top-level-items > li.active', count: 1) + expect(find('.sidebar-top-level-items > li.active')).to have_content(title) + end + end + + shared_examples 'page has active sub tab' do |title| + it "activates #{title} sub tab" do + expect(page).to have_selector('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)', count: 1) + expect(find('.sidebar-sub-level-items > li.active:not(.fly-out-top-item)')) + .to have_content(title) + end + end + + context 'on project Home' do + before do + visit project_path(project) + end + + it_behaves_like 'page has active tab', 'Overview' + it_behaves_like 'page has active sub tab', 'Details' + + context 'on project Home/Activity' do + before do + click_tab('Activity') + end + + it_behaves_like 'page has active tab', 'Overview' + it_behaves_like 'page has active sub tab', 'Activity' + end + end + + context 'on project Repository' do + before do + root_ref = project.repository.root_ref + visit project_tree_path(project, root_ref) + end + + it_behaves_like 'page has active tab', 'Repository' + + %w(Files Commits Graph Compare Charts Branches Tags).each do |sub_menu| + context "on project Repository/#{sub_menu}" do + before do + click_tab(sub_menu) + end + + it_behaves_like 'page has active tab', 'Repository' + it_behaves_like 'page has active sub tab', sub_menu + end + end + end + + context 'on project Issues' do + before do + visit project_issues_path(project) + end + + it_behaves_like 'page has active tab', 'Issues' + + %w(Milestones Labels).each do |sub_menu| + context "on project Issues/#{sub_menu}" do + before do + click_tab(sub_menu) + end + + it_behaves_like 'page has active tab', 'Issues' + it_behaves_like 'page has active sub tab', sub_menu + end + end + end + + context 'on project Merge Requests' do + before do + visit project_merge_requests_path(project) + end + + it_behaves_like 'page has active tab', 'Merge Requests' + end + + context 'on project Wiki' do + before do + visit project_wiki_path(project, :home) + end + + it_behaves_like 'page has active tab', 'Wiki' + end + + context 'on project Members' do + before do + visit project_project_members_path(project) + end + + it_behaves_like 'page has active tab', 'Members' + end + + context 'on project Settings' do + before do + visit edit_project_path(project) + end + + context 'on project Settings/Integrations' do + before do + click_tab('Integrations') + end + + it_behaves_like 'page has active tab', 'Settings' + it_behaves_like 'page has active sub tab', 'Integrations' + end + + context 'on project Settings/Repository' do + before do + click_tab('Repository') + end + + it_behaves_like 'page has active tab', 'Settings' + it_behaves_like 'page has active sub tab', 'Repository' + end + end +end diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb index 842840cc04c..1743b1e083f 100644 --- a/spec/features/projects/fork_spec.rb +++ b/spec/features/projects/fork_spec.rb @@ -25,6 +25,110 @@ describe 'Project fork' do expect(page).to have_css('a.disabled', text: 'Fork') end + it 'forks the project' do + visit project_path(project) + + click_link 'Fork' + + page.within '.fork-thumbnail-container' do + click_link user.name + end + + expect(page).to have_content 'Forked from' + + visit project_path(project) + + expect(page).to have_content(/new merge request/i) + + page.within '.nav-sidebar' do + first(:link, 'Merge Requests').click + end + + expect(page).to have_content(/new merge request/i) + + page.within '#content-body' do + click_link('New merge request') + end + + expect(current_path).to have_content(/#{user.namespace.name}/i) + end + + it 'shows the forked project on the list' do + visit project_path(project) + + click_link 'Fork' + + page.within '.fork-thumbnail-container' do + click_link user.name + end + + visit project_forks_path(project) + + forked_project = user.fork_of(project.reload) + + page.within('.js-projects-list-holder') do + expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}") + end + + forked_project.update!(path: 'test-crappy-path') + + visit project_forks_path(project) + + page.within('.js-projects-list-holder') do + expect(page).to have_content("#{forked_project.namespace.human_name} / #{forked_project.name}") + end + end + + context 'when the project is private' do + let(:project) { create(:project, :repository) } + let(:another_user) { create(:user, name: 'Mike') } + + before do + project.add_reporter(user) + project.add_reporter(another_user) + end + + it 'renders private forks of the project' do + visit project_path(project) + + another_project_fork = Projects::ForkService.new(project, another_user).execute + + click_link 'Fork' + + page.within '.fork-thumbnail-container' do + click_link user.name + end + + visit project_forks_path(project) + + page.within('.js-projects-list-holder') do + user_project_fork = user.fork_of(project.reload) + expect(page).to have_content("#{user_project_fork.namespace.human_name} / #{user_project_fork.name}") + end + + expect(page).not_to have_content("#{another_project_fork.namespace.human_name} / #{another_project_fork.name}") + expect(page).to have_content("1 private fork") + end + end + + context 'when the user already forked the project' do + before do + create(:project, :repository, name: project.name, namespace: user.namespace) + end + + it 'renders error' do + visit project_path(project) + + click_link 'Fork' + + page.within '.fork-thumbnail-container' do + click_link user.name + end + + expect(page).to have_content "Name has already been taken" + end + end + context 'master in group' do let(:group) { create(:group) } diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz Binary files differindex 12bfcc177c7..0cc68aff494 100644 --- a/spec/features/projects/import_export/test_project_export.tar.gz +++ b/spec/features/projects/import_export/test_project_export.tar.gz diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 849d85061df..33ad59abfdf 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -557,7 +557,7 @@ describe 'Pipelines', :js do end it 'has a clear caches button' do - expect(page).to have_link 'Clear Runner Caches' + expect(page).to have_button 'Clear Runner Caches' end describe 'user clicks the button' do @@ -567,14 +567,16 @@ describe 'Pipelines', :js do end it 'increments jobs_cache_index' do - click_link 'Clear Runner Caches' + click_button 'Clear Runner Caches' + wait_for_requests expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' end end context 'when project does not have jobs_cache_index' do it 'sets jobs_cache_index to 1' do - click_link 'Clear Runner Caches' + click_button 'Clear Runner Caches' + wait_for_requests expect(page.find('.flash-notice')).to have_content 'Project cache successfully reset.' end end diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index 619baa78bfa..a2cda58e5d2 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -139,4 +139,76 @@ describe LabelsHelper do expect(text_color_for_bg('#000')).to eq '#FFFFFF' end end + + describe 'create_label_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "Create group label"' do + expect(create_label_title(group)).to eq 'Create group label' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "Create project label"' do + expect(create_label_title(project)).to eq 'Create project label' + end + end + + context 'with no subject' do + it 'returns "Create new label"' do + expect(create_label_title(nil)).to eq 'Create new label' + end + end + end + + describe 'manage_labels_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "Manage group labels"' do + expect(manage_labels_title(group)).to eq 'Manage group labels' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "Manage project labels"' do + expect(manage_labels_title(project)).to eq 'Manage project labels' + end + end + + context 'with no subject' do + it 'returns "Manage labels"' do + expect(manage_labels_title(nil)).to eq 'Manage labels' + end + end + end + + describe 'view_labels_title' do + set(:group) { create(:group) } + + context 'with a group as subject' do + it 'returns "View group labels"' do + expect(view_labels_title(group)).to eq 'View group labels' + end + end + + context 'with a project as subject' do + set(:project) { create(:project, namespace: group) } + + it 'returns "View project labels"' do + expect(view_labels_title(project)).to eq 'View project labels' + end + end + + context 'with no subject' do + it 'returns "View labels"' do + expect(view_labels_title(nil)).to eq 'View labels' + end + end + end end diff --git a/spec/javascripts/activities_spec.js b/spec/javascripts/activities_spec.js index 7a9c539e9d0..909a1bf76bc 100644 --- a/spec/javascripts/activities_spec.js +++ b/spec/javascripts/activities_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-unused-expressions, no-prototype-builtins, no-new, no-shadow, max-len */ +import $ from 'jquery'; import 'vendor/jquery.endless-scroll'; import Activities from '~/activities'; diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 95c2c122403..261375d3a0e 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import AjaxLoadingSpinner from '~/ajax_loading_spinner'; describe('Ajax Loading Spinner', () => { @@ -10,7 +11,7 @@ describe('Ajax Loading Spinner', () => { }); it('change current icon with spinner icon and disable link while waiting ajax response', (done) => { - spyOn(jQuery, 'ajax').and.callFake((req) => { + spyOn($, 'ajax').and.callFake((req) => { const xhr = new XMLHttpRequest(); const ajaxLoadingSpinner = document.querySelector('.js-ajax-loading-spinner'); const icon = ajaxLoadingSpinner.querySelector('i'); @@ -33,7 +34,7 @@ describe('Ajax Loading Spinner', () => { }); it('use original icon again and enabled the link after complete the ajax request', (done) => { - spyOn(jQuery, 'ajax').and.callFake((req) => { + spyOn($, 'ajax').and.callFake((req) => { const xhr = new XMLHttpRequest(); const ajaxLoadingSpinner = document.querySelector('.js-ajax-loading-spinner'); diff --git a/spec/javascripts/autosave_spec.js b/spec/javascripts/autosave_spec.js index b568d7fa8b0..38ae5b7e00c 100644 --- a/spec/javascripts/autosave_spec.js +++ b/spec/javascripts/autosave_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Autosave from '~/autosave'; import AccessorUtilities from '~/lib/utils/accessor'; diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 8e4bbb90ccb..e81055bc08f 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */ +import $ from 'jquery'; import Cookies from 'js-cookie'; import loadAwardsHandler from '~/awards_handler'; diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index 960b731892a..c411c5174fb 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/autosize'; function load() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index d5300d9c63d..c37c62c63dd 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/quick_submit'; describe('Quick Submit behavior', () => { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index e500bbe750f..a434949b9da 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/behaviors/requires_input'; describe('requiresInput', () => { diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js index 47de63e6690..0b1de504435 100644 --- a/spec/javascripts/blob/blob_file_dropzone_spec.js +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import BlobFileDropzone from '~/blob/blob_file_dropzone'; describe('BlobFileDropzone', () => { @@ -27,7 +28,7 @@ describe('BlobFileDropzone', () => { name: 'some-file.jpg', type: 'jpg', }; - const fakeEvent = jQuery.Event('drop', { + const fakeEvent = $.Event('drop', { dataTransfer: { files: [file] }, }); diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js index 892411a6a40..f920c4ca945 100644 --- a/spec/javascripts/blob/viewer/index_spec.js +++ b/spec/javascripts/blob/viewer/index_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import BlobViewer from '~/blob/viewer/index'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/bootstrap_jquery_spec.js b/spec/javascripts/bootstrap_jquery_spec.js index 48994b7c523..0fd6f9dc810 100644 --- a/spec/javascripts/bootstrap_jquery_spec.js +++ b/spec/javascripts/bootstrap_jquery_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var */ +import $ from 'jquery'; import '~/commons/bootstrap'; (function() { 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 270f925e699..2fa50975f0f 100644 --- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js +++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VariableList from '~/ci_variable_list/ci_variable_list'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper'; 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 eb508a7f059..1ea8d86cb7e 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 @@ -1,3 +1,4 @@ +import $ from 'jquery'; import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list'; describe('NativeFormVariableList', () => { diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js index 1daccc8dd02..977298b9221 100644 --- a/spec/javascripts/commits_spec.js +++ b/spec/javascripts/commits_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import 'vendor/jquery.endless-scroll'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/create_item_dropdown_spec.js b/spec/javascripts/create_item_dropdown_spec.js index 143137c23ec..ee26122be12 100644 --- a/spec/javascripts/create_item_dropdown_spec.js +++ b/spec/javascripts/create_item_dropdown_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import CreateItemDropdown from '~/create_item_dropdown'; const DROPDOWN_ITEM_DATA = [{ diff --git a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js index 1b1f28f3ddb..480c138b9db 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_helper_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { diff --git a/spec/javascripts/feature_highlight/feature_highlight_spec.js b/spec/javascripts/feature_highlight/feature_highlight_spec.js index f3f80cb3771..d2dd39d49d1 100644 --- a/spec/javascripts/feature_highlight/feature_highlight_spec.js +++ b/spec/javascripts/feature_highlight/feature_highlight_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import * as featureHighlightHelper from '~/feature_highlight/feature_highlight_helper'; import * as featureHighlight from '~/feature_highlight/feature_highlight'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js index 71c14582329..8c5a0961a02 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js @@ -1,8 +1,9 @@ +import $ from 'jquery'; import FilteredSearchDropdownManager from '~/filtered_search/filtered_search_dropdown_manager'; describe('Filtered Search Dropdown Manager', () => { beforeEach(() => { - spyOn(jQuery, 'ajax'); + spyOn($, 'ajax'); }); describe('addWordToInput', () => { diff --git a/spec/javascripts/gfm_auto_complete_spec.js b/spec/javascripts/gfm_auto_complete_spec.js index 50a587ef351..dc0a5bc275c 100644 --- a/spec/javascripts/gfm_auto_complete_spec.js +++ b/spec/javascripts/gfm_auto_complete_spec.js @@ -1,5 +1,6 @@ /* eslint no-param-reassign: "off" */ +import $ from 'jquery'; import GfmAutoComplete from '~/gfm_auto_complete'; import 'vendor/jquery.caret'; diff --git a/spec/javascripts/gl_dropdown_spec.js b/spec/javascripts/gl_dropdown_spec.js index 67b854f61c0..0e4a7017406 100644 --- a/spec/javascripts/gl_dropdown_spec.js +++ b/spec/javascripts/gl_dropdown_spec.js @@ -1,5 +1,6 @@ /* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */ +import $ from 'jquery'; import '~/gl_dropdown'; import '~/lib/utils/common_utils'; import * as urlUtils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/javascripts/gl_field_errors_spec.js index 2779686a6f5..4e93fd91751 100644 --- a/spec/javascripts/gl_field_errors_spec.js +++ b/spec/javascripts/gl_field_errors_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, arrow-body-style */ +import $ from 'jquery'; import GlFieldErrors from '~/gl_field_errors'; describe('GL Style Field Errors', function() { diff --git a/spec/javascripts/gl_form_spec.js b/spec/javascripts/gl_form_spec.js index 9c1fc0fda9e..74383f901b2 100644 --- a/spec/javascripts/gl_form_spec.js +++ b/spec/javascripts/gl_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import autosize from 'autosize'; import GLForm from '~/gl_form'; import '~/lib/utils/text_utility'; diff --git a/spec/javascripts/groups/components/app_spec.js b/spec/javascripts/groups/components/app_spec.js index 46c7b9f54f2..d8428bd0e08 100644 --- a/spec/javascripts/groups/components/app_spec.js +++ b/spec/javascripts/groups/components/app_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import * as utils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 2443ffd48f3..16ac438f7ac 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initTodoToggle from '~/header'; describe('Header', function () { diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js index d0fba908e34..050b1f2074e 100644 --- a/spec/javascripts/integrations/integration_settings_form_spec.js +++ b/spec/javascripts/integrations/integration_settings_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdaptor from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IntegrationSettingsForm from '~/integrations/integration_settings_form'; diff --git a/spec/javascripts/issuable_spec.js b/spec/javascripts/issuable_spec.js index d53ffecbd35..57bf746f080 100644 --- a/spec/javascripts/issuable_spec.js +++ b/spec/javascripts/issuable_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdaptor from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IssuableIndex from '~/issuable_index'; diff --git a/spec/javascripts/issuable_time_tracker_spec.js b/spec/javascripts/issuable_time_tracker_spec.js index 365e9fe6a4b..ba9040524b1 100644 --- a/spec/javascripts/issuable_time_tracker_spec.js +++ b/spec/javascripts/issuable_time_tracker_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-unused-vars, space-before-function-paren, func-call-spacing, no-spaced-func, semi, max-len, quotes, space-infix-ops, padded-blocks */ +import $ from 'jquery'; import Vue from 'vue'; import timeTracker from '~/sidebar/components/time_tracking/time_tracker.vue'; diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js index ff7f99eec14..d96151a8a3a 100644 --- a/spec/javascripts/issue_show/components/description_spec.js +++ b/spec/javascripts/issue_show/components/description_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import descriptionComponent from '~/issue_show/components/description.vue'; import * as taskList from '~/task_list'; diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 177962ecf82..f37426a72d4 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,4 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import Issue from '~/issue'; diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index b4599688c6d..c6bbacf237a 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils'; diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js index 7d992f62f64..5aafb6ad8f0 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js +++ b/spec/javascripts/labels_issue_sidebar_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-new */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import IssuableContext from '~/issuable_context'; diff --git a/spec/javascripts/labels_select_spec.js b/spec/javascripts/labels_select_spec.js index b8f7b1dc855..a2b89c0aef5 100644 --- a/spec/javascripts/labels_select_spec.js +++ b/spec/javascripts/labels_select_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import LabelsSelect from '~/labels_select'; const mockUrl = '/foo/bar/url'; diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 89f4b85541d..d2bdc9e160c 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, jasmine/no-spec-dupes, no-underscore-dangle, max-len */ +import $ from 'jquery'; import LineHighlighter from '~/line_highlighter'; (function() { diff --git a/spec/javascripts/merge_request_notes_spec.js b/spec/javascripts/merge_request_notes_spec.js index 0d16b23302f..eb644e698da 100644 --- a/spec/javascripts/merge_request_notes_spec.js +++ b/spec/javascripts/merge_request_notes_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import 'autosize'; import '~/gl_form'; diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index bdfd16ac995..74ceff76d37 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,4 +1,6 @@ /* eslint-disable space-before-function-paren, no-return-assign */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import MergeRequest from '~/merge_request'; @@ -27,7 +29,7 @@ import IssuablesHelper from '~/helpers/issuables_helper'; }); it('modifies the Markdown field', function() { - spyOn(jQuery, 'ajax').and.stub(); + spyOn($, 'ajax').and.stub(); const changeEvent = document.createEvent('HTMLEvents'); changeEvent.initEvent('change', true, true); $('input[type=checkbox]').attr('checked', true)[0].dispatchEvent(changeEvent); @@ -48,7 +50,7 @@ import IssuablesHelper from '~/helpers/issuables_helper'; describe('class constructor', () => { beforeEach(() => { - spyOn(jQuery, 'ajax').and.stub(); + spyOn($, 'ajax').and.stub(); }); it('calls .initCloseReopenReport', () => { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index fda24db98b4..79c8cf0ba32 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,4 +1,6 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ + +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import * as urlUtils from '~/lib/utils/url_utility'; diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js index 6fa6f44f953..009b3fd75b7 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown'; diff --git a/spec/javascripts/namespace_select_spec.js b/spec/javascripts/namespace_select_spec.js index 9d7625ca269..3b2641f7646 100644 --- a/spec/javascripts/namespace_select_spec.js +++ b/spec/javascripts/namespace_select_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import NamespaceSelect from '~/namespace_select'; describe('NamespaceSelect', () => { diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 50a5e4ff056..5e5d8f8f34f 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, max-len */ +import $ from 'jquery'; import NewBranchForm from '~/new_branch_form'; (function() { diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js index 6a7131528a3..90016436cb7 100644 --- a/spec/javascripts/notes/components/comment_form_spec.js +++ b/spec/javascripts/notes/components/comment_form_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import Autosize from 'autosize'; import store from '~/notes/stores'; diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js index e1c612f5100..ac39418c3e6 100644 --- a/spec/javascripts/notes/components/note_app_spec.js +++ b/spec/javascripts/notes/components/note_app_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import notesApp from '~/notes/components/notes_app.vue'; diff --git a/spec/javascripts/notes/components/noteable_note_spec.js b/spec/javascripts/notes/components/noteable_note_spec.js index 88a7ffb0b9c..cfd037633e9 100644 --- a/spec/javascripts/notes/components/noteable_note_spec.js +++ b/spec/javascripts/notes/components/noteable_note_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import store from '~/notes/stores'; diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index d4a148e6ab1..ba0a70bed17 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,4 +1,5 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */ +import $ from 'jquery'; import _ from 'underscore'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js index b24563f738b..8816fe6defb 100644 --- a/spec/javascripts/oauth_remember_me_spec.js +++ b/spec/javascripts/oauth_remember_me_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import OAuthRememberMe from '~/pages/sessions/new/oauth_remember_me'; describe('OAuthRememberMe', () => { diff --git a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js index 349549b9e1f..b0dc6ccc3d4 100644 --- a/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js +++ b/spec/javascripts/pages/admin/abuse_reports/abuse_reports_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import '~/lib/utils/text_utility'; import AbuseReports from '~/pages/admin/abuse_reports/abuse_reports'; diff --git a/spec/javascripts/pipelines/nav_controls_spec.js b/spec/javascripts/pipelines/nav_controls_spec.js index 77c5258f74c..d6232f5c567 100644 --- a/spec/javascripts/pipelines/nav_controls_spec.js +++ b/spec/javascripts/pipelines/nav_controls_spec.js @@ -39,19 +39,6 @@ describe('Pipelines Nav Controls', () => { expect(component.$el.querySelector('.js-run-pipeline')).toEqual(null); }); - it('should render link for resetting runner caches', () => { - const mockData = { - newPipelinePath: 'foo', - ciLintPath: 'foo', - resetCachePath: 'foo', - }; - - component = mountComponent(NavControlsComponent, mockData); - - expect(component.$el.querySelector('.js-clear-cache').textContent.trim()).toContain('Clear Runner Caches'); - expect(component.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(mockData.resetCachePath); - }); - it('should render link for CI lint', () => { const mockData = { newPipelinePath: 'foo', @@ -65,4 +52,28 @@ describe('Pipelines Nav Controls', () => { expect(component.$el.querySelector('.js-ci-lint').textContent.trim()).toContain('CI Lint'); expect(component.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(mockData.ciLintPath); }); + + describe('Reset Runners Cache', () => { + beforeEach(() => { + const mockData = { + newPipelinePath: 'foo', + ciLintPath: 'foo', + resetCachePath: 'foo', + }; + + component = mountComponent(NavControlsComponent, mockData); + }); + + it('should render button for resetting runner caches', () => { + expect(component.$el.querySelector('.js-clear-cache').textContent.trim()).toContain('Clear Runner Caches'); + }); + + it('should emit postAction event when reset runner cache button is clicked', () => { + spyOn(component, '$emit'); + + component.$el.querySelector('.js-clear-cache').click(); + + expect(component.$emit).toHaveBeenCalledWith('resetRunnersCache', 'foo'); + }); + }); }); diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js index 84fd0329f08..7e242eb45e1 100644 --- a/spec/javascripts/pipelines/pipelines_spec.js +++ b/spec/javascripts/pipelines/pipelines_spec.js @@ -95,16 +95,16 @@ describe('Pipelines', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); - it('renders Run Pipeline button', () => { + it('renders Run Pipeline link', () => { expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath); }); - it('renders CI Lint button', () => { + it('renders CI Lint link', () => { expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath); }); it('renders Clear Runner Cache button', () => { - expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath); + expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches'); }); it('renders pipelines table', () => { @@ -139,16 +139,16 @@ describe('Pipelines', () => { expect(vm.$el.querySelector('.js-pipelines-tab-all').textContent.trim()).toContain('All'); }); - it('renders Run Pipeline button', () => { + it('renders Run Pipeline link', () => { expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath); }); - it('renders CI Lint button', () => { + it('renders CI Lint link', () => { expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath); }); it('renders Clear Runner Cache button', () => { - expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath); + expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches'); }); it('renders tab empty state', () => { @@ -218,7 +218,7 @@ describe('Pipelines', () => { it('renders buttons', () => { expect(vm.$el.querySelector('.js-run-pipeline').getAttribute('href')).toEqual(paths.newPipelinePath); expect(vm.$el.querySelector('.js-ci-lint').getAttribute('href')).toEqual(paths.ciLintPath); - expect(vm.$el.querySelector('.js-clear-cache').getAttribute('href')).toEqual(paths.resetCachePath); + expect(vm.$el.querySelector('.js-clear-cache').textContent.trim()).toEqual('Clear Runner Caches'); }); it('renders error state', () => { diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js index dda83645c92..1b65f767f96 100644 --- a/spec/javascripts/project_select_combo_button_spec.js +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import ProjectSelectComboButton from '~/project_select_combo_button'; const fixturePath = 'static/project_select_combo_button.html.raw'; diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js index 8731ce35d81..84515d2bf97 100644 --- a/spec/javascripts/projects/project_new_spec.js +++ b/spec/javascripts/projects/project_new_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import projectNew from '~/projects/project_new'; describe('New Project', () => { diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 35bb630bf5d..80770a61011 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */ +import $ from 'jquery'; import MockAdapter from 'axios-mock-adapter'; import '~/commons/bootstrap'; import axios from '~/lib/utils/axios_utils'; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 206f95abc1a..40115792652 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, max-len */ +import $ from 'jquery'; import '~/gl_dropdown'; import SearchAutocomplete from '~/search_autocomplete'; import '~/lib/utils/common_utils'; diff --git a/spec/javascripts/search_spec.js b/spec/javascripts/search_spec.js index 38e94d45e55..522851c584b 100644 --- a/spec/javascripts/search_spec.js +++ b/spec/javascripts/search_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Api from '~/api'; import Search from '~/pages/search/show/search'; diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index 5d6a885d4cc..faaf710cf6f 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import initCopyAsGFM from '~/behaviors/copy_as_gfm'; import ShortcutsIssuable from '~/shortcuts_issuable'; diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js index a2a609edef9..ee92295ef5e 100644 --- a/spec/javascripts/shortcuts_spec.js +++ b/spec/javascripts/shortcuts_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Shortcuts from '~/shortcuts'; describe('Shortcuts', () => { diff --git a/spec/javascripts/sidebar/assignee_title_spec.js b/spec/javascripts/sidebar/assignee_title_spec.js index ac93f918ce4..509edba2036 100644 --- a/spec/javascripts/sidebar/assignee_title_spec.js +++ b/spec/javascripts/sidebar/assignee_title_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import AssigneeTitle from '~/sidebar/components/assignees/assignee_title'; +import AssigneeTitle from '~/sidebar/components/assignees/assignee_title.vue'; describe('AssigneeTitle component', () => { let component; diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js index 0da5d91e376..d8e636cbdf0 100644 --- a/spec/javascripts/sidebar/sidebar_move_issue_spec.js +++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import Vue from 'vue'; import SidebarMediator from '~/sidebar/sidebar_mediator'; diff --git a/spec/javascripts/smart_interval_spec.js b/spec/javascripts/smart_interval_spec.js index 7265e1b6cb5..a54219d58c2 100644 --- a/spec/javascripts/smart_interval_spec.js +++ b/spec/javascripts/smart_interval_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import _ from 'underscore'; import SmartInterval from '~/smart_interval'; diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index 763a15e710b..0d1fa680e00 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes */ +import $ from 'jquery'; import syntaxHighlight from '~/syntax_highlight'; describe('Syntax Highlighter', function() { diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index 35871dddf89..898bbb3819b 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import * as urlUtils from '~/lib/utils/url_utility'; import Todos from '~/pages/dashboard/todos/index/todos'; import '~/lib/utils/common_utils'; diff --git a/spec/javascripts/toggle_buttons_spec.js b/spec/javascripts/toggle_buttons_spec.js index 205e396d682..17d0b94ebe0 100644 --- a/spec/javascripts/toggle_buttons_spec.js +++ b/spec/javascripts/toggle_buttons_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import setupToggleButtons from '~/toggle_buttons'; import getSetTimeoutPromise from './helpers/set_timeout_promise_helper'; diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 4d15bcc4956..39c47a5c06d 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FAuthenticate from '~/u2f/authenticate'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index dbe89c2923c..136b4cad737 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import U2FRegister from '~/u2f/register'; import 'vendor/u2f'; import MockU2FDevice from './mock_u2f_device'; diff --git a/spec/javascripts/version_check_image_spec.js b/spec/javascripts/version_check_image_spec.js index 9637bd0414a..5f963e8c11e 100644 --- a/spec/javascripts/version_check_image_spec.js +++ b/spec/javascripts/version_check_image_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import VersionCheckImage from '~/version_check_image'; import ClassSpecHelper from './helpers/class_spec_helper'; diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js index 07ed7f7f532..31710551399 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js @@ -1,5 +1,5 @@ import Vue from 'vue'; -import memoryUsageComponent from '~/vue_merge_request_widget/components/mr_widget_memory_usage'; +import MemoryUsage from '~/vue_merge_request_widget/components/memory_usage.vue'; import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; const url = '/root/acets-review-apps/environments/15/deployments/1/metrics'; @@ -34,7 +34,7 @@ const metricsMockData = { }; const createComponent = () => { - const Component = Vue.extend(memoryUsageComponent); + const Component = Vue.extend(MemoryUsage); return new Component({ el: document.createElement('div'), @@ -67,21 +67,9 @@ describe('MemoryUsage', () => { el = vm.$el; }); - describe('props', () => { - it('should have props with defaults', () => { - const { metricsUrl } = memoryUsageComponent.props; - const MetricsUrlTypeClass = metricsUrl.type; - - Vue.nextTick(() => { - expect(new MetricsUrlTypeClass() instanceof String).toBeTruthy(); - expect(metricsUrl.required).toBeTruthy(); - }); - }); - }); - describe('data', () => { it('should have default data', () => { - const data = memoryUsageComponent.data(); + const data = MemoryUsage.data(); expect(Array.isArray(data.memoryMetrics)).toBeTruthy(); expect(data.memoryMetrics.length).toBe(0); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js index dd907ad9015..d47815a5b5a 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js @@ -1,5 +1,6 @@ import Vue from 'vue'; import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue'; +import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; import eventHub from '~/vue_merge_request_widget/event_hub'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; @@ -25,12 +26,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { targetBranchPath, targetBranch, }, - service: { - cancelAutomaticMerge() {}, - mergeResource: { - save() {}, - }, - }, + service: new MRWidgetService({}), }); }); @@ -90,18 +86,16 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { describe('removeSourceBranch', () => { it('should set flag and call service then request main component to update the widget', (done) => { - spyOn(vm.service.mergeResource, 'save').and.returnValue(new Promise((resolve) => { - resolve({ - data: { - status: 'merge_when_pipeline_succeeds', - }, - }); + spyOn(vm.service, 'merge').and.returnValue(Promise.resolve({ + data: { + status: 'merge_when_pipeline_succeeds', + }, })); vm.removeSourceBranch(); setTimeout(() => { expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested'); - expect(vm.service.mergeResource.save).toHaveBeenCalledWith({ + expect(vm.service.merge).toHaveBeenCalledWith({ sha, merge_when_pipeline_succeeds: true, should_remove_source_branch: true, 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 073f26cc78f..58f683fb3e6 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 @@ -517,13 +517,9 @@ describe('MRWidgetReadyToMerge', () => { describe('Remove source branch checkbox', () => { describe('when user can merge but cannot delete branch', () => { - it('isRemoveSourceBranchButtonDisabled should be true', () => { - expect(vm.isRemoveSourceBranchButtonDisabled).toBe(true); - }); - it('should be disabled in the rendered output', () => { const checkboxElement = vm.$el.querySelector('#remove-source-branch-input'); - expect(checkboxElement.getAttribute('disabled')).toBe('disabled'); + expect(checkboxElement).toBeNull(); }); }); @@ -540,7 +536,7 @@ describe('MRWidgetReadyToMerge', () => { it('should be enabled in rendered output', () => { const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input'); - expect(checkboxElement.getAttribute('disabled')).toBeNull(); + expect(checkboxElement).not.toBeNull(); }); }); }); @@ -549,12 +545,12 @@ describe('MRWidgetReadyToMerge', () => { describe('when allowed to merge', () => { beforeEach(() => { vm = createComponent({ - mr: { isMergeAllowed: true }, + mr: { isMergeAllowed: true, canRemoveSourceBranch: true }, }); }); it('shows remove source branch checkbox', () => { - expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).toBeDefined(); + expect(vm.$el.querySelector('.js-remove-source-branch-checkbox')).not.toBeNull(); }); it('shows modify commit message button', () => { diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js index ebe151ac3b1..3e310980ffa 100644 --- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js @@ -81,6 +81,29 @@ describe('mrWidgetOptions', () => { }); }); + describe('shouldRenderSourceBranchRemovalStatus', () => { + it('should return true when cannot remove source branch and branch will be removed', () => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = true; + + expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(true); + }); + + it('should return false when can remove source branch and branch will be removed', () => { + vm.mr.canRemoveSourceBranch = true; + vm.mr.shouldRemoveSourceBranch = true; + + expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false); + }); + + it('should return false when cannot remove source branch and branch will not be removed', () => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = false; + + expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false); + }); + }); + describe('shouldRenderDeployments', () => { it('should return false for the initial data', () => { expect(vm.shouldRenderDeployments).toBeFalsy(); @@ -379,4 +402,22 @@ describe('mrWidgetOptions', () => { }); }); }); + + describe('rendering source branch removal status', () => { + it('renders when user cannot remove branch and branch should be removed', (done) => { + vm.mr.canRemoveSourceBranch = false; + vm.mr.shouldRemoveSourceBranch = true; + + vm.$nextTick(() => { + const tooltip = vm.$el.querySelector('.fa-question-circle'); + + expect(vm.$el.textContent).toContain('Removes source branch'); + expect(tooltip.getAttribute('data-original-title')).toBe( + 'A user with write access to the source branch selected this option', + ); + + done(); + }); + }); + }); }); diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js index 2805d9a7003..85cb1b90fc6 100644 --- a/spec/javascripts/vue_shared/components/gl_modal_spec.js +++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import GlModal from '~/vue_shared/components/gl_modal.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; diff --git a/spec/javascripts/vue_shared/components/markdown/field_spec.js b/spec/javascripts/vue_shared/components/markdown/field_spec.js index 5f980bbf36c..69034975422 100644 --- a/spec/javascripts/vue_shared/components/markdown/field_spec.js +++ b/spec/javascripts/vue_shared/components/markdown/field_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import fieldComponent from '~/vue_shared/components/markdown/field.vue'; diff --git a/spec/javascripts/vue_shared/components/memory_graph_spec.js b/spec/javascripts/vue_shared/components/memory_graph_spec.js index d46a3f2328e..73a69df019e 100644 --- a/spec/javascripts/vue_shared/components/memory_graph_spec.js +++ b/spec/javascripts/vue_shared/components/memory_graph_spec.js @@ -1,12 +1,12 @@ import Vue from 'vue'; -import memoryGraphComponent from '~/vue_shared/components/memory_graph'; +import MemoryGraph from '~/vue_shared/components/memory_graph.vue'; import { mockMetrics, mockMedian, mockMedianIndex } from './mock_data'; const defaultHeight = '25'; const defaultWidth = '100'; const createComponent = () => { - const Component = Vue.extend(memoryGraphComponent); + const Component = Vue.extend(MemoryGraph); return new Component({ el: document.createElement('div'), @@ -32,29 +32,9 @@ describe('MemoryGraph', () => { el = vm.$el; }); - describe('props', () => { - it('should have props with defaults', (done) => { - const { metrics, deploymentTime, width, height } = memoryGraphComponent.props; - - Vue.nextTick(() => { - const typeClassMatcher = (propItem, expectedType) => { - const PropItemTypeClass = propItem.type; - expect(new PropItemTypeClass() instanceof expectedType).toBeTruthy(); - expect(propItem.required).toBeTruthy(); - }; - - typeClassMatcher(metrics, Array); - typeClassMatcher(deploymentTime, Number); - typeClassMatcher(width, String); - typeClassMatcher(height, String); - done(); - }); - }); - }); - describe('data', () => { it('should have default data', () => { - const data = memoryGraphComponent.data(); + const data = MemoryGraph.data(); const dataValidator = (dataItem, expectedType, defaultVal) => { expect(typeof dataItem).toBe(expectedType); expect(dataItem).toBe(defaultVal); diff --git a/spec/javascripts/vue_shared/components/modal_spec.js b/spec/javascripts/vue_shared/components/modal_spec.js index 8412df74f98..d01a94c25e5 100644 --- a/spec/javascripts/vue_shared/components/modal_spec.js +++ b/spec/javascripts/vue_shared/components/modal_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import modal from '~/vue_shared/components/modal.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js index 67056793a20..8daaf018396 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/base_spec.js @@ -37,6 +37,32 @@ describe('BaseComponent', () => { vmNonEditable.$destroy(); }); }); + + describe('createLabelTitle', () => { + it('returns `Create project label` when `isProject` prop is true', () => { + expect(vm.createLabelTitle).toBe('Create project label'); + }); + + it('return `Create group label` when `isProject` prop is false', () => { + const mockConfigGroup = Object.assign({}, mockConfig, { isProject: false }); + const vmGroup = createComponent(mockConfigGroup); + expect(vmGroup.createLabelTitle).toBe('Create group label'); + vmGroup.$destroy(); + }); + }); + + describe('manageLabelsTitle', () => { + it('returns `Manage project labels` when `isProject` prop is true', () => { + expect(vm.manageLabelsTitle).toBe('Manage project labels'); + }); + + it('return `Manage group labels` when `isProject` prop is false', () => { + const mockConfigGroup = Object.assign({}, mockConfig, { isProject: false }); + const vmGroup = createComponent(mockConfigGroup); + expect(vmGroup.manageLabelsTitle).toBe('Manage group labels'); + vmGroup.$destroy(); + }); + }); }); describe('methods', () => { diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js index f07aefb2f87..5cb4bb6fea6 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_create_label_spec.js @@ -6,10 +6,12 @@ import { mockSuggestedColors } from './mock_data'; import mountComponent from '../../../../helpers/vue_mount_component_helper'; -const createComponent = () => { +const createComponent = (headerTitle) => { const Component = Vue.extend(dropdownCreateLabelComponent); - return mountComponent(Component); + return mountComponent(Component, { + headerTitle, + }); }; describe('DropdownCreateLabelComponent', () => { @@ -41,11 +43,19 @@ describe('DropdownCreateLabelComponent', () => { expect(backButtonEl.querySelector('.fa-arrow-left')).not.toBe(null); }); - it('renders component header element', () => { + it('renders component header element as `Create new label` when `headerTitle` prop is not provided', () => { const headerEl = vm.$el.querySelector('.dropdown-title'); expect(headerEl.innerText.trim()).toContain('Create new label'); }); + it('renders component header element with value of `headerTitle` prop', () => { + const headerTitle = 'Create project label'; + const vmWithHeaderTitle = createComponent(headerTitle); + const headerEl = vmWithHeaderTitle.$el.querySelector('.dropdown-title'); + expect(headerEl.innerText.trim()).toContain(headerTitle); + vmWithHeaderTitle.$destroy(); + }); + it('renders `Close` button on component header', () => { const closeButtonEl = vm.$el.querySelector('.dropdown-title button.dropdown-title-button.dropdown-menu-close'); expect(closeButtonEl).not.toBe(null); diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js index 809e0327b1c..0f4fa716f8a 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_footer_spec.js @@ -6,15 +6,23 @@ import { mockConfig } from './mock_data'; import mountComponent from '../../../../helpers/vue_mount_component_helper'; -const createComponent = (labelsWebUrl = mockConfig.labelsWebUrl) => { +const createComponent = ( + labelsWebUrl = mockConfig.labelsWebUrl, + createLabelTitle, + manageLabelsTitle, +) => { const Component = Vue.extend(dropdownFooterComponent); return mountComponent(Component, { labelsWebUrl, + createLabelTitle, + manageLabelsTitle, }); }; describe('DropdownFooterComponent', () => { + const createLabelTitle = 'Create project label'; + const manageLabelsTitle = 'Manage project labels'; let vm; beforeEach(() => { @@ -26,17 +34,35 @@ describe('DropdownFooterComponent', () => { }); describe('template', () => { - it('renders `Create new label` link element', () => { + it('renders link element with `Create new label` when `createLabelTitle` prop is not provided', () => { const createLabelEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-toggle-page'); expect(createLabelEl).not.toBeNull(); expect(createLabelEl.innerText.trim()).toBe('Create new label'); }); - it('renders `Manage labels` link element', () => { + it('renders link element with value of `createLabelTitle` prop', () => { + const vmWithCreateLabelTitle = createComponent(mockConfig.labelsWebUrl, createLabelTitle); + const createLabelEl = vmWithCreateLabelTitle.$el.querySelector('.dropdown-footer-list .dropdown-toggle-page'); + expect(createLabelEl.innerText.trim()).toBe(createLabelTitle); + vmWithCreateLabelTitle.$destroy(); + }); + + it('renders link element with `Manage labels` when `manageLabelsTitle` prop is not provided', () => { const manageLabelsEl = vm.$el.querySelector('.dropdown-footer-list .dropdown-external-link'); expect(manageLabelsEl).not.toBeNull(); expect(manageLabelsEl.getAttribute('href')).toBe(vm.labelsWebUrl); expect(manageLabelsEl.innerText.trim()).toBe('Manage labels'); }); + + it('renders link element with value of `manageLabelsTitle` prop', () => { + const vmWithManageLabelsTitle = createComponent( + mockConfig.labelsWebUrl, + createLabelTitle, + manageLabelsTitle, + ); + const manageLabelsEl = vmWithManageLabelsTitle.$el.querySelector('.dropdown-footer-list .dropdown-external-link'); + expect(manageLabelsEl.innerText.trim()).toBe(manageLabelsTitle); + vmWithManageLabelsTitle.$destroy(); + }); }); }); diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js index e9008c29b22..3fcb91b6f5e 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/mock_data.js @@ -34,6 +34,7 @@ export const mockSuggestedColors = [ export const mockConfig = { showCreate: true, + isProject: true, abilityName: 'issue', context: { labels: mockLabels, diff --git a/spec/javascripts/vue_shared/directives/tooltip_spec.js b/spec/javascripts/vue_shared/directives/tooltip_spec.js index b1b3071527b..4a644913e44 100644 --- a/spec/javascripts/vue_shared/directives/tooltip_spec.js +++ b/spec/javascripts/vue_shared/directives/tooltip_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Vue from 'vue'; import tooltip from '~/vue_shared/directives/tooltip'; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index 8edba1f47a3..7fe3bd92049 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -1,3 +1,4 @@ +import $ from 'jquery'; import Mousetrap from 'mousetrap'; import Dropzone from 'dropzone'; import ZenMode from '~/zen_mode'; diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb index 4dab58b26a0..ff295068ba9 100644 --- a/spec/lib/constraints/group_url_constrainer_spec.rb +++ b/spec/lib/constraints/group_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe GroupUrlConstrainer do +describe Constraints::GroupUrlConstrainer do let!(:group) { create(:group, path: 'gitlab') } describe '#matches?' do diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb index 92331eb2e5d..c96e7ab8495 100644 --- a/spec/lib/constraints/project_url_constrainer_spec.rb +++ b/spec/lib/constraints/project_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe ProjectUrlConstrainer do +describe Constraints::ProjectUrlConstrainer do let!(:project) { create(:project) } let!(:namespace) { project.namespace } diff --git a/spec/lib/constraints/user_url_constrainer_spec.rb b/spec/lib/constraints/user_url_constrainer_spec.rb index cb3b4ff1391..e2c85bb27bb 100644 --- a/spec/lib/constraints/user_url_constrainer_spec.rb +++ b/spec/lib/constraints/user_url_constrainer_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe UserUrlConstrainer do +describe Constraints::UserUrlConstrainer do let!(:user) { create(:user, username: 'dz') } describe '#matches?' do diff --git a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb index 21a791f5695..c43ed72038e 100644 --- a/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb +++ b/spec/lib/gitlab/background_migration/add_merge_request_diff_commits_count_spec.rb @@ -37,6 +37,18 @@ describe Gitlab::BackgroundMigration::AddMergeRequestDiffCommitsCount, :migratio expect(diff.reload.commits_count).to eq(0) end + it 'skips diffs that have commits_count already set' do + timestamp = 2.days.ago + diff = merge_request_diffs_table.create!( + merge_request_id: merge_request.id, + commits_count: 0, + updated_at: timestamp) + + subject.perform(diff.id, diff.id) + + expect(diff.reload.updated_at).to be_within(1.second).of(timestamp) + end + it 'migrates multiple diffs to the correct values' do diffs = Array.new(3).map.with_index { |_, i| create_diff!(i, commits: 3) } diff --git a/spec/lib/gitlab/conflict/file_collection_spec.rb b/spec/lib/gitlab/conflict/file_collection_spec.rb index 5944ce8049a..c93912db411 100644 --- a/spec/lib/gitlab/conflict/file_collection_spec.rb +++ b/spec/lib/gitlab/conflict/file_collection_spec.rb @@ -10,6 +10,38 @@ describe Gitlab::Conflict::FileCollection do end end + describe '#cache' do + it 'specifies a custom namespace with the merge request commit ids' do + our_commit = merge_request.source_branch_head.raw + their_commit = merge_request.target_branch_head.raw + custom_namespace = "#{our_commit.id}:#{their_commit.id}" + + expect(file_collection.send(:cache).namespace).to include(custom_namespace) + end + end + + describe '#can_be_resolved_in_ui?' do + it 'returns true if conflicts for this collection can be resolved in the UI' do + expect(file_collection.can_be_resolved_in_ui?).to be true + end + + it "returns false if conflicts for this collection can't be resolved in the UI" do + expect(file_collection).to receive(:files).and_raise(Gitlab::Git::Conflict::Resolver::ConflictSideMissing) + + expect(file_collection.can_be_resolved_in_ui?).to be false + end + + it 'caches the result' do + expect(file_collection).to receive(:files).twice.and_call_original + + expect(file_collection.can_be_resolved_in_ui?).to be true + + expect(file_collection).not_to receive(:files) + + expect(file_collection.can_be_resolved_in_ui?).to be true + end + end + describe '#default_commit_message' do it 'matches the format of the git CLI commit message' do expect(file_collection.default_commit_message).to eq(<<EOM.chomp) diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb index 6193e177668..aed7d8d81ce 100644 --- a/spec/lib/gitlab/exclusive_lease_spec.rb +++ b/spec/lib/gitlab/exclusive_lease_spec.rb @@ -88,4 +88,16 @@ describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do expect(lease.ttl).to be_nil end end + + describe '.reset_all!' do + it 'removes all existing lease keys from redis' do + uuid = described_class.new(unique_key, timeout: 3600).try_obtain + + expect(described_class.get_uuid(unique_key)).to eq(uuid) + + described_class.reset_all! + + expect(described_class.get_uuid(unique_key)).to be_falsey + end + end end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index c46bb8edebf..57905a74e92 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -108,14 +108,26 @@ describe Gitlab::ProjectSearchResults do context 'when the search returns non-ASCII data' do context 'with UTF-8' do - let(:results) { project.repository.search_files_by_content("файл", 'master') } + let(:results) { project.repository.search_files_by_content('файл', 'master') } it 'returns results as UTF-8' do expect(subject.filename).to eq('encoding/russian.rb') expect(subject.basename).to eq('encoding/russian') expect(subject.ref).to eq('master') expect(subject.startline).to eq(1) - expect(subject.data).to eq("Хороший файл") + expect(subject.data).to eq('Хороший файл') + end + end + + context 'with UTF-8 in the filename' do + let(:results) { project.repository.search_files_by_content('webhook', 'master') } + + it 'returns results as UTF-8' do + expect(subject.filename).to eq('encoding/テスト.txt') + expect(subject.basename).to eq('encoding/テスト') + expect(subject.ref).to eq('master') + expect(subject.startline).to eq(3) + expect(subject.data).to include('WebHookの確認') end end diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb new file mode 100644 index 00000000000..85971f2a7ef --- /dev/null +++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe Gitlab::RepositoryCacheAdapter do + let(:project) { create(:project, :repository) } + let(:repository) { project.repository } + let(:cache) { repository.send(:cache) } + + describe '#cache_method_output', :use_clean_rails_memory_store_caching do + let(:fallback) { 10 } + + context 'with a non-existing repository' do + let(:project) { create(:project) } # No repository + + subject do + repository.cache_method_output(:cats, fallback: fallback) do + repository.cats_call_stub + end + end + + it 'returns the fallback value' do + expect(subject).to eq(fallback) + end + + it 'avoids calling the original method' do + expect(repository).not_to receive(:cats_call_stub) + + subject + end + end + + context 'with a method throwing a non-existing-repository error' do + subject do + repository.cache_method_output(:cats, fallback: fallback) do + raise Gitlab::Git::Repository::NoRepository + end + end + + it 'returns the fallback value' do + expect(subject).to eq(fallback) + end + + it 'does not cache the data' do + subject + + expect(repository.instance_variable_defined?(:@cats)).to eq(false) + expect(cache.exist?(:cats)).to eq(false) + end + end + + context 'with an existing repository' do + it 'caches the output' do + object = double + + expect(object).to receive(:number).once.and_return(10) + + 2.times do + val = repository.cache_method_output(:cats) { object.number } + + expect(val).to eq(10) + end + + expect(repository.send(:cache).exist?(:cats)).to eq(true) + expect(repository.instance_variable_get(:@cats)).to eq(10) + end + end + end + + describe '#expire_method_caches' do + it 'expires the caches of the given methods' do + expect(cache).to receive(:expire).with(:readme) + expect(cache).to receive(:expire).with(:gitignore) + + repository.expire_method_caches(%i(readme gitignore)) + end + end +end diff --git a/spec/lib/gitlab/repository_cache_spec.rb b/spec/lib/gitlab/repository_cache_spec.rb new file mode 100644 index 00000000000..fc259cf1208 --- /dev/null +++ b/spec/lib/gitlab/repository_cache_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe Gitlab::RepositoryCache do + let(:backend) { double('backend').as_null_object } + let(:project) { create(:project) } + let(:repository) { project.repository } + let(:namespace) { "#{repository.full_path}:#{project.id}" } + let(:cache) { described_class.new(repository, backend: backend) } + + describe '#cache_key' do + subject { cache.cache_key(:foo) } + + it 'includes the namespace' do + expect(subject).to eq "foo:#{namespace}" + end + + context 'with a given namespace' do + let(:extra_namespace) { 'my:data' } + let(:cache) do + described_class.new(repository, extra_namespace: extra_namespace, + backend: backend) + end + + it 'includes the full namespace' do + expect(subject).to eq "foo:#{namespace}:#{extra_namespace}" + end + end + end + + describe '#expire' do + it 'expires the given key from the cache' do + cache.expire(:foo) + expect(backend).to have_received(:delete).with("foo:#{namespace}") + end + end + + describe '#fetch' do + it 'fetches the given key from the cache' do + cache.fetch(:bar) + expect(backend).to have_received(:fetch).with("bar:#{namespace}") + end + + it 'accepts a block' do + p = -> {} + + cache.fetch(:baz, &p) + expect(backend).to have_received(:fetch).with("baz:#{namespace}", &p) + end + end +end diff --git a/spec/lib/gitlab/verify/job_artifacts_spec.rb b/spec/lib/gitlab/verify/job_artifacts_spec.rb new file mode 100644 index 00000000000..ec490bdfde2 --- /dev/null +++ b/spec/lib/gitlab/verify/job_artifacts_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe Gitlab::Verify::JobArtifacts do + include GitlabVerifyHelpers + + it_behaves_like 'Gitlab::Verify::BatchVerifier subclass' do + let!(:objects) { create_list(:ci_job_artifact, 3, :archive) } + end + + describe '#run_batches' do + let(:failures) { collect_failures } + let(:failure) { failures[artifact] } + + let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) } + + it 'passes artifacts with the correct file' do + expect(failures).to eq({}) + end + + it 'fails artifacts with a missing file' do + FileUtils.rm_f(artifact.file.path) + + expect(failures.keys).to contain_exactly(artifact) + expect(failure).to be_a(Errno::ENOENT) + expect(failure.to_s).to include(artifact.file.path) + end + + it 'fails artifacts with a mismatched checksum' do + File.truncate(artifact.file.path, 0) + + expect(failures.keys).to contain_exactly(artifact) + expect(failure.to_s).to include('Checksum mismatch') + end + end +end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index e638ad7a2c9..3c8206031cf 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -64,4 +64,108 @@ describe Mattermost::Team do end end end + + describe '#create' do + subject { described_class.new(nil).create(name: "devteam", display_name: "Dev Team", type: "O") } + + context 'for a new team' do + let(:response) do + { + "id" => "cuojfcetjty7tb4pxe47pwpndo", + "create_at" => 1517688728701, + "update_at" => 1517688728701, + "delete_at" => 0, + "display_name" => "Dev Team", + "name" => "devteam", + "description" => "", + "email" => "admin@example.com", + "type" => "O", + "company_name" => "", + "allowed_domains" => "", + "invite_id" => "7mp9d3ayaj833ymmkfnid8js6w", + "allow_open_invite" => false + } + end + + before do + stub_request(:post, "http://mattermost.example.com/api/v3/teams/create") + .to_return( + status: 200, + body: response.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'returns the new team' do + is_expected.to eq(response) + end + end + + context 'for existing team' do + before do + stub_request(:post, 'http://mattermost.example.com/api/v3/teams/create') + .to_return( + status: 400, + headers: { 'Content-Type' => 'application/json' }, + body: { + id: "store.sql_team.save.domain_exists.app_error", + message: "A team with that name already exists", + detailed_error: "", + request_id: "1hsb5bxs97r8bdggayy7n9gxaw", + status_code: 400 + }.to_json + ) + end + + it 'raises an error with message' do + expect { subject }.to raise_error(Mattermost::Error, 'A team with that name already exists') + end + end + end + + describe '#delete' do + subject { described_class.new(nil).destroy(team_id: "cuojfcetjty7tb4pxe47pwpndo") } + + context 'for an existing team' do + let(:response) do + { + "status" => "OK" + } + end + + before do + stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo") + .to_return( + status: 200, + body: response.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'returns team status' do + is_expected.to eq(response) + end + end + + context 'for an unknown team' do + before do + stub_request(:delete, "http://mattermost.example.com/api/v4/teams/cuojfcetjty7tb4pxe47pwpndo") + .to_return( + status: 404, + body: { + id: "store.sql_team.get.find.app_error", + message: "We couldn't find the existing team", + detailed_error: "", + request_id: "my114ab5nbnui8c9pes4kz8mza", + status_code: 404 + }.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'raises an error with message' do + expect { subject }.to raise_error(Mattermost::Error, "We couldn't find the existing team") + end + end + end end diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb deleted file mode 100644 index 8b0c7254b5e..00000000000 --- a/spec/lib/repository_cache_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -describe RepositoryCache do - let(:project) { create(:project) } - let(:backend) { double('backend').as_null_object } - let(:cache) { described_class.new('example', project.id, backend) } - - describe '#cache_key' do - it 'includes the namespace' do - expect(cache.cache_key(:foo)).to eq "foo:example:#{project.id}" - end - end - - describe '#expire' do - it 'expires the given key from the cache' do - cache.expire(:foo) - expect(backend).to have_received(:delete).with("foo:example:#{project.id}") - end - end - - describe '#fetch' do - it 'fetches the given key from the cache' do - cache.fetch(:bar) - expect(backend).to have_received(:fetch).with("bar:example:#{project.id}") - end - - it 'accepts a block' do - p = -> {} - - cache.fetch(:baz, &p) - expect(backend).to have_received(:fetch).with("baz:example:#{project.id}", &p) - end - end -end diff --git a/spec/migrations/reschedule_commits_count_for_merge_request_diff_spec.rb b/spec/migrations/reschedule_commits_count_for_merge_request_diff_spec.rb new file mode 100644 index 00000000000..26489ef58bd --- /dev/null +++ b/spec/migrations/reschedule_commits_count_for_merge_request_diff_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20180309121820_reschedule_commits_count_for_merge_request_diff') + +describe RescheduleCommitsCountForMergeRequestDiff, :migration, :sidekiq do + let(:merge_request_diffs) { table(:merge_request_diffs) } + let(:merge_requests) { table(:merge_requests) } + let(:projects) { table(:projects) } + let(:namespaces) { table(:namespaces) } + + before do + stub_const("#{described_class.name}::BATCH_SIZE", 1) + + namespaces.create!(id: 1, name: 'gitlab', path: 'gitlab') + + projects.create!(id: 1, namespace_id: 1) + + merge_requests.create!(id: 1, target_project_id: 1, source_project_id: 1, target_branch: 'feature', source_branch: 'master') + + merge_request_diffs.create!(id: 1, merge_request_id: 1) + merge_request_diffs.create!(id: 2, merge_request_id: 1) + merge_request_diffs.create!(id: 3, merge_request_id: 1, commits_count: 0) + merge_request_diffs.create!(id: 4, merge_request_id: 1) + end + + it 'correctly schedules background migrations' do + Sidekiq::Testing.fake! do + Timecop.freeze do + migrate! + + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 2, 2) + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, 4, 4) + expect(BackgroundMigrationWorker.jobs.size).to eq 3 + end + end + end +end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 579069ffa14..5bc972bca14 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1447,7 +1447,6 @@ describe Repository do it 'expires the caches for an empty repository' do allow(repository).to receive(:empty?).and_return(true) - expect(cache).to receive(:expire).with(:empty?) expect(cache).to receive(:expire).with(:has_visible_content?) repository.expire_emptiness_caches @@ -1456,7 +1455,6 @@ describe Repository do it 'does not expire the cache for a non-empty repository' do allow(repository).to receive(:empty?).and_return(false) - expect(cache).not_to receive(:expire).with(:empty?) expect(cache).not_to receive(:expire).with(:has_visible_content?) repository.expire_emptiness_caches @@ -2171,15 +2169,6 @@ describe Repository do end end - describe '#expire_method_caches' do - it 'expires the caches of the given methods' do - expect_any_instance_of(RepositoryCache).to receive(:expire).with(:readme) - expect_any_instance_of(RepositoryCache).to receive(:expire).with(:gitignore) - - repository.expire_method_caches(%i(readme gitignore)) - end - end - describe '#expire_all_method_caches' do it 'expires the caches of all methods' do expect(repository).to receive(:expire_method_caches) @@ -2325,66 +2314,6 @@ describe Repository do end end - describe '#cache_method_output', :use_clean_rails_memory_store_caching do - let(:fallback) { 10 } - - context 'with a non-existing repository' do - let(:project) { create(:project) } # No repository - - subject do - repository.cache_method_output(:cats, fallback: fallback) do - repository.cats_call_stub - end - end - - it 'returns the fallback value' do - expect(subject).to eq(fallback) - end - - it 'avoids calling the original method' do - expect(repository).not_to receive(:cats_call_stub) - - subject - end - end - - context 'with a method throwing a non-existing-repository error' do - subject do - repository.cache_method_output(:cats, fallback: fallback) do - raise Gitlab::Git::Repository::NoRepository - end - end - - it 'returns the fallback value' do - expect(subject).to eq(fallback) - end - - it 'does not cache the data' do - subject - - expect(repository.instance_variable_defined?(:@cats)).to eq(false) - expect(repository.send(:cache).exist?(:cats)).to eq(false) - end - end - - context 'with an existing repository' do - it 'caches the output' do - object = double - - expect(object).to receive(:number).once.and_return(10) - - 2.times do - val = repository.cache_method_output(:cats) { object.number } - - expect(val).to eq(10) - end - - expect(repository.send(:cache).exist?(:cats)).to eq(true) - expect(repository.instance_variable_get(:@cats)).to eq(10) - end - end - end - describe '#refresh_method_caches' do it 'refreshes the caches of the given types' do expect(repository).to receive(:expire_method_caches) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 00b5226d874..5680eb24985 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -27,7 +27,6 @@ describe User do it { is_expected.to have_many(:keys).dependent(:destroy) } it { is_expected.to have_many(:deploy_keys).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) } - it { is_expected.to have_many(:recent_events).class_name('Event') } it { is_expected.to have_many(:issues).dependent(:destroy) } it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:merge_requests).dependent(:destroy) } diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 56d025f0176..9345671a1a7 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -9,7 +9,7 @@ require 'spec_helper' # user_calendar_activities GET /u/:username/calendar_activities(.:format) describe UsersController, "routing" do it "to #show" do - allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true) + allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true) expect(get("/User")).to route_to('users#show', username: 'User') end @@ -210,7 +210,7 @@ describe Profiles::KeysController, "routing" do # get all the ssh-keys of a user it "to #get_keys" do - allow_any_instance_of(UserUrlConstrainer).to receive(:matches?).and_return(true) + allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true) expect(get("/foo.keys")).to route_to('profiles/keys#get_keys', username: 'foo') end diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index ad5a289290c..d454ac0bda5 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -132,6 +132,15 @@ describe Projects::UpdateService do expect(result).to eq({ status: :success }) expect(project.wiki_repository_exists?).to be false end + + it 'handles empty project feature attributes' do + project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED) + + result = update_project(project, user, { name: 'test1' }) + + expect(result).to eq({ status: :success }) + expect(project.wiki_repository_exists?).to be false + end end context 'when enabling a wiki' do diff --git a/spec/tasks/gitlab/artifacts/check_rake_spec.rb b/spec/tasks/gitlab/artifacts/check_rake_spec.rb new file mode 100644 index 00000000000..d495b08aca0 --- /dev/null +++ b/spec/tasks/gitlab/artifacts/check_rake_spec.rb @@ -0,0 +1,34 @@ +require 'rake_helper' + +describe 'gitlab:artifacts rake tasks' do + describe 'check' do + let!(:artifact) { create(:ci_job_artifact, :archive, :correct_checksum) } + + before do + Rake.application.rake_require('tasks/gitlab/artifacts/check') + stub_env('VERBOSE' => 'true') + end + + it 'outputs the integrity check for each batch' do + expect { run_rake_task('gitlab:artifacts:check') }.to output(/Failures: 0/).to_stdout + end + + it 'errors out about missing files on the file system' do + FileUtils.rm_f(artifact.file.path) + + expect { run_rake_task('gitlab:artifacts:check') }.to output(/No such file.*#{Regexp.quote(artifact.file.path)}/).to_stdout + end + + it 'errors out about invalid checksum' do + artifact.update_column(:file_sha256, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855') + + expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum mismatch/).to_stdout + end + + it 'errors out about missing checksum' do + artifact.update_column(:file_sha256, nil) + + expect { run_rake_task('gitlab:artifacts:check') }.to output(/Checksum missing/).to_stdout + end + end +end |
