diff options
author | Michael Kozono <mkozono@gmail.com> | 2019-08-13 01:02:28 +0300 |
---|---|---|
committer | Michael Kozono <mkozono@gmail.com> | 2019-08-13 01:02:28 +0300 |
commit | 4254f5dc0ea4c226690d0d9abd20d1c9822fefcb (patch) | |
tree | 3cd94454d455b99ae3dd192633fc0942441c46d6 /spec | |
parent | 4ce6d2b9db680b7c8563ee65fe25ee4d38a329e9 (diff) | |
parent | 2f8709fb53137c2f53409f2400cd85083b06d6f6 (diff) |
Merge branch 'ce-12547-load-search-counts-async' into 'master'
Load search result counts asynchronously (CE)
See merge request gitlab-org/gitlab-ce!31663
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/search_controller_spec.rb | 202 | ||||
-rw-r--r-- | spec/features/search/user_searches_for_users_spec.rb | 4 | ||||
-rw-r--r-- | spec/features/search/user_uses_header_search_field_spec.rb | 17 | ||||
-rw-r--r-- | spec/frontend/pages/search/show/__snapshots__/refresh_counts_spec.js.snap | 7 | ||||
-rw-r--r-- | spec/frontend/pages/search/show/refresh_counts_spec.js | 35 | ||||
-rw-r--r-- | spec/helpers/search_helper_spec.rb | 44 | ||||
-rw-r--r-- | spec/lib/gitlab/project_search_results_spec.rb | 22 | ||||
-rw-r--r-- | spec/lib/gitlab/search_results_spec.rb | 37 | ||||
-rw-r--r-- | spec/lib/gitlab/snippet_search_results_spec.rb | 18 |
9 files changed, 294 insertions, 92 deletions
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 5a5c0a1f6ac..3e0d53a6573 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -11,151 +11,173 @@ describe SearchController do sign_in(user) end - context 'uses the right partials depending on scope' do - using RSpec::Parameterized::TableSyntax - render_views - - set(:project) { create(:project, :public, :repository, :wiki_repo) } - + shared_examples_for 'when the user cannot read cross project' do |action, params| before do - expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original + allow(Ability).to receive(:allowed?).and_call_original + allow(Ability).to receive(:allowed?) + .with(user, :read_cross_project, :global) { false } end - subject { get(:show, params: { project_id: project.id, scope: scope, search: 'merge' }) } + it 'blocks access without a project_id' do + get action, params: params - where(:partial, :scope) do - '_blob' | :blobs - '_wiki_blob' | :wiki_blobs - '_commit' | :commits + expect(response).to have_gitlab_http_status(403) end - with_them do - it do - project_wiki = create(:project_wiki, project: project, user: user) - create(:wiki_page, wiki: project_wiki, attrs: { title: 'merge', content: 'merge' }) + it 'allows access with a project_id' do + get action, params: params.merge(project_id: create(:project, :public).id) - expect(subject).to render_template("search/results/#{partial}") - end + expect(response).to have_gitlab_http_status(200) end end - context 'global search' do - render_views - - it 'omits pipeline status from load' do - project = create(:project, :public) - expect(Gitlab::Cache::Ci::ProjectPipelineStatus).not_to receive(:load_in_batch_for_projects) - - get :show, params: { scope: 'projects', search: project.name } + shared_examples_for 'with external authorization service enabled' do |action, params| + let(:project) { create(:project, namespace: user.namespace) } + let(:note) { create(:note_on_issue, project: project) } - expect(assigns[:search_objects].first).to eq project + before do + enable_external_authorization_service_check end - end - - it 'finds issue comments' do - project = create(:project, :public) - note = create(:note_on_issue, project: project) - get :show, params: { project_id: project.id, scope: 'notes', search: note.note } + it 'renders a 403 when no project is given' do + get action, params: params - expect(assigns[:search_objects].first).to eq note - end - - context 'when the user cannot read cross project' do - before do - allow(Ability).to receive(:allowed?).and_call_original - allow(Ability).to receive(:allowed?) - .with(user, :read_cross_project, :global) { false } + expect(response).to have_gitlab_http_status(403) end - it 'still allows accessing the search page' do - get :show + it 'renders a 200 when a project was set' do + get action, params: params.merge(project_id: project.id) expect(response).to have_gitlab_http_status(200) end + end - it 'still blocks searches without a project_id' do - get :show, params: { search: 'hello' } + describe 'GET #show' do + it_behaves_like 'when the user cannot read cross project', :show, { search: 'hello' } do + it 'still allows accessing the search page' do + get :show - expect(response).to have_gitlab_http_status(403) + expect(response).to have_gitlab_http_status(200) + end end - it 'allows searches with a project_id' do - get :show, params: { search: 'hello', project_id: create(:project, :public).id } + it_behaves_like 'with external authorization service enabled', :show, { search: 'hello' } - expect(response).to have_gitlab_http_status(200) - end - end + context 'uses the right partials depending on scope' do + using RSpec::Parameterized::TableSyntax + render_views + + set(:project) { create(:project, :public, :repository, :wiki_repo) } - context 'on restricted projects' do - context 'when signed out' do before do - sign_out(user) + expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original end - it "doesn't expose comments on issues" do - project = create(:project, :public, :issues_private) - note = create(:note_on_issue, project: project) + subject { get(:show, params: { project_id: project.id, scope: scope, search: 'merge' }) } - get :show, params: { project_id: project.id, scope: 'notes', search: note.note } + where(:partial, :scope) do + '_blob' | :blobs + '_wiki_blob' | :wiki_blobs + '_commit' | :commits + end - expect(assigns[:search_objects].count).to eq(0) + with_them do + it do + project_wiki = create(:project_wiki, project: project, user: user) + create(:wiki_page, wiki: project_wiki, attrs: { title: 'merge', content: 'merge' }) + + expect(subject).to render_template("search/results/#{partial}") + end end end - it "doesn't expose comments on merge_requests" do - project = create(:project, :public, :merge_requests_private) - note = create(:note_on_merge_request, project: project) + context 'global search' do + render_views - get :show, params: { project_id: project.id, scope: 'notes', search: note.note } + it 'omits pipeline status from load' do + project = create(:project, :public) + expect(Gitlab::Cache::Ci::ProjectPipelineStatus).not_to receive(:load_in_batch_for_projects) + + get :show, params: { scope: 'projects', search: project.name } - expect(assigns[:search_objects].count).to eq(0) + expect(assigns[:search_objects].first).to eq project + end end - it "doesn't expose comments on snippets" do - project = create(:project, :public, :snippets_private) - note = create(:note_on_project_snippet, project: project) + it 'finds issue comments' do + project = create(:project, :public) + note = create(:note_on_issue, project: project) get :show, params: { project_id: project.id, scope: 'notes', search: note.note } - expect(assigns[:search_objects].count).to eq(0) + expect(assigns[:search_objects].first).to eq note end - end - context 'with external authorization service enabled' do - let(:project) { create(:project, namespace: user.namespace) } - let(:note) { create(:note_on_issue, project: project) } + context 'on restricted projects' do + context 'when signed out' do + before do + sign_out(user) + end - before do - enable_external_authorization_service_check - end + it "doesn't expose comments on issues" do + project = create(:project, :public, :issues_private) + note = create(:note_on_issue, project: project) - describe 'GET #show' do - it 'renders a 403 when no project is given' do - get :show, params: { scope: 'notes', search: note.note } + get :show, params: { project_id: project.id, scope: 'notes', search: note.note } - expect(response).to have_gitlab_http_status(403) + expect(assigns[:search_objects].count).to eq(0) + end end - it 'renders a 200 when a project was set' do + it "doesn't expose comments on merge_requests" do + project = create(:project, :public, :merge_requests_private) + note = create(:note_on_merge_request, project: project) + get :show, params: { project_id: project.id, scope: 'notes', search: note.note } - expect(response).to have_gitlab_http_status(200) + expect(assigns[:search_objects].count).to eq(0) end - end - describe 'GET #autocomplete' do - it 'renders a 403 when no project is given' do - get :autocomplete, params: { term: 'hello' } + it "doesn't expose comments on snippets" do + project = create(:project, :public, :snippets_private) + note = create(:note_on_project_snippet, project: project) - expect(response).to have_gitlab_http_status(403) + get :show, params: { project_id: project.id, scope: 'notes', search: note.note } + + expect(assigns[:search_objects].count).to eq(0) end + end + end - it 'renders a 200 when a project was set' do - get :autocomplete, params: { project_id: project.id, term: 'hello' } + describe 'GET #count' do + it_behaves_like 'when the user cannot read cross project', :count, { search: 'hello', scope: 'projects' } + it_behaves_like 'with external authorization service enabled', :count, { search: 'hello', scope: 'projects' } - expect(response).to have_gitlab_http_status(200) - end + it 'returns the result count for the given term and scope' do + create(:project, :public, name: 'hello world') + create(:project, :public, name: 'foo bar') + + get :count, params: { search: 'hello', scope: 'projects' } + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to eq({ 'count' => '1' }) + end + + it 'raises an error if search term is missing' do + expect do + get :count, params: { scope: 'projects' } + end.to raise_error(ActionController::ParameterMissing) end + + it 'raises an error if search scope is missing' do + expect do + get :count, params: { search: 'hello' } + end.to raise_error(ActionController::ParameterMissing) + end + end + + describe 'GET #autocomplete' do + it_behaves_like 'when the user cannot read cross project', :autocomplete, { term: 'hello' } + it_behaves_like 'with external authorization service enabled', :autocomplete, { term: 'hello' } end end diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb index 2517a843c62..e10c1afc0b8 100644 --- a/spec/features/search/user_searches_for_users_spec.rb +++ b/spec/features/search/user_searches_for_users_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe 'User searches for users' do context 'when on the dashboard' do - it 'finds the user' do + it 'finds the user', :js do create(:user, username: 'gob_bluth', name: 'Gob Bluth') sign_in(create(:user)) @@ -12,7 +12,7 @@ describe 'User searches for users' do visit dashboard_projects_path fill_in 'search', with: 'gob' - click_button 'Go' + find('#search').send_keys(:enter) expect(page).to have_content('Users 1') diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb index c781048d06d..5006631cc14 100644 --- a/spec/features/search/user_uses_header_search_field_spec.rb +++ b/spec/features/search/user_uses_header_search_field_spec.rb @@ -96,6 +96,23 @@ describe 'User uses header search field', :js do let(:url) { root_path } let(:scope_name) { 'All GitLab' } end + + context 'when searching through the search field' do + before do + create(:issue, project: project, title: 'project issue') + + fill_in('search', with: 'project') + find('#search').send_keys(:enter) + end + + it 'displays result counts for all categories' do + expect(page).to have_content('Projects 1') + expect(page).to have_content('Issues 1') + expect(page).to have_content('Merge requests 0') + expect(page).to have_content('Milestones 0') + expect(page).to have_content('Users 0') + end + end end context 'when user is in a project scope' do diff --git a/spec/frontend/pages/search/show/__snapshots__/refresh_counts_spec.js.snap b/spec/frontend/pages/search/show/__snapshots__/refresh_counts_spec.js.snap new file mode 100644 index 00000000000..ce456d6c899 --- /dev/null +++ b/spec/frontend/pages/search/show/__snapshots__/refresh_counts_spec.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`pages/search/show/refresh_counts fetches and displays search counts 1`] = ` +"<div class=\\"badge\\">22</div> +<div class=\\"badge js-search-count\\" data-url=\\"http://test.host/search/count?search=lorem+ipsum&project_id=3&scope=issues\\">4</div> +<div class=\\"badge js-search-count\\" data-url=\\"http://test.host/search/count?search=lorem+ipsum&project_id=3&scope=merge_requests\\">5</div>" +`; diff --git a/spec/frontend/pages/search/show/refresh_counts_spec.js b/spec/frontend/pages/search/show/refresh_counts_spec.js new file mode 100644 index 00000000000..ead268b3971 --- /dev/null +++ b/spec/frontend/pages/search/show/refresh_counts_spec.js @@ -0,0 +1,35 @@ +import MockAdapter from 'axios-mock-adapter'; +import { TEST_HOST } from 'helpers/test_constants'; +import axios from '~/lib/utils/axios_utils'; +import refreshCounts from '~/pages/search/show/refresh_counts'; + +const URL = `${TEST_HOST}/search/count?search=lorem+ipsum&project_id=3`; +const urlWithScope = scope => `${URL}&scope=${scope}`; +const counts = [{ scope: 'issues', count: 4 }, { scope: 'merge_requests', count: 5 }]; +const fixture = `<div class="badge">22</div> +<div class="badge js-search-count hidden" data-url="${urlWithScope('issues')}"></div> +<div class="badge js-search-count hidden" data-url="${urlWithScope('merge_requests')}"></div>`; + +describe('pages/search/show/refresh_counts', () => { + let mock; + + beforeEach(() => { + mock = new MockAdapter(axios); + setFixtures(fixture); + }); + + afterEach(() => { + mock.restore(); + }); + + it('fetches and displays search counts', () => { + counts.forEach(({ scope, count }) => { + mock.onGet(urlWithScope(scope)).reply(200, { count }); + }); + + // assert before act behavior + return refreshCounts().then(() => { + expect(document.body.innerHTML).toMatchSnapshot(); + }); + }); +}); diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index c69493b579f..2ab72679ee7 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -177,4 +177,48 @@ describe SearchHelper do end end end + + describe 'search_filter_link' do + it 'renders a search filter link for the current scope' do + @scope = 'projects' + @search_results = double + + expect(@search_results).to receive(:formatted_count).with('projects').and_return('23') + + link = search_filter_link('projects', 'Projects') + + expect(link).to have_css('li.active') + expect(link).to have_link('Projects', href: search_path(scope: 'projects')) + expect(link).to have_css('span.badge.badge-pill:not(.js-search-count):not(.hidden):not([data-url])', text: '23') + end + + it 'renders a search filter link for another scope' do + link = search_filter_link('projects', 'Projects') + count_path = search_count_path(scope: 'projects') + + expect(link).to have_css('li:not([class="active"])') + expect(link).to have_link('Projects', href: search_path(scope: 'projects')) + expect(link).to have_css("span.badge.badge-pill.js-search-count.hidden[data-url='#{count_path}']", text: '') + end + + it 'merges in the current search params and given params' do + expect(self).to receive(:params).and_return( + ActionController::Parameters.new( + search: 'hello', + scope: 'ignored', + other_param: 'ignored' + ) + ) + + link = search_filter_link('projects', 'Projects', search: { project_id: 23 }) + + expect(link).to have_link('Projects', href: search_path(scope: 'projects', search: 'hello', project_id: 23)) + end + + it 'assigns given data attributes on the list container' do + link = search_filter_link('projects', 'Projects', data: { foo: 'bar' }) + + expect(link).to have_css('li[data-foo="bar"]') + end + end end diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index 4a41d5cf51e..c7462500c82 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -22,6 +22,28 @@ describe Gitlab::ProjectSearchResults do it { expect(results.query).to eq('hello world') } end + describe '#formatted_count' do + using RSpec::Parameterized::TableSyntax + + let(:results) { described_class.new(user, project, query) } + + where(:scope, :count_method, :expected) do + 'blobs' | :blobs_count | '1234' + 'notes' | :limited_notes_count | '1000+' + 'wiki_blobs' | :wiki_blobs_count | '1234' + 'commits' | :commits_count | '1234' + 'projects' | :limited_projects_count | '1000+' + 'unknown' | nil | nil + end + + with_them do + it 'returns the expected formatted count' do + expect(results).to receive(count_method).and_return(1234) if count_method + expect(results.formatted_count(scope)).to eq(expected) + end + end + end + shared_examples 'general blob search' do |entity_type, blob_kind| let(:query) { 'files' } subject(:results) { described_class.new(user, project, query).objects(blob_type) } diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index 3d27156b356..c287da19343 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -29,6 +29,43 @@ describe Gitlab::SearchResults do end end + describe '#formatted_count' do + using RSpec::Parameterized::TableSyntax + + where(:scope, :count_method, :expected) do + 'projects' | :limited_projects_count | '1000+' + 'issues' | :limited_issues_count | '1000+' + 'merge_requests' | :limited_merge_requests_count | '1000+' + 'milestones' | :limited_milestones_count | '1000+' + 'users' | :limited_users_count | '1000+' + 'unknown' | nil | nil + end + + with_them do + it 'returns the expected formatted count' do + expect(results).to receive(count_method).and_return(1234) if count_method + expect(results.formatted_count(scope)).to eq(expected) + end + end + end + + describe '#formatted_limited_count' do + using RSpec::Parameterized::TableSyntax + + where(:count, :expected) do + 23 | '23' + 1000 | '1000' + 1001 | '1000+' + 1234 | '1000+' + end + + with_them do + it 'returns the expected formatted limited count' do + expect(results.formatted_limited_count(count)).to eq(expected) + end + end + end + context "when count_limit is lower than total amount" do before do allow(results).to receive(:count_limit).and_return(1) diff --git a/spec/lib/gitlab/snippet_search_results_spec.rb b/spec/lib/gitlab/snippet_search_results_spec.rb index b661a894c0c..35df38f052b 100644 --- a/spec/lib/gitlab/snippet_search_results_spec.rb +++ b/spec/lib/gitlab/snippet_search_results_spec.rb @@ -16,4 +16,22 @@ describe Gitlab::SnippetSearchResults do expect(results.snippet_blobs_count).to eq(1) end end + + describe '#formatted_count' do + using RSpec::Parameterized::TableSyntax + + where(:scope, :count_method, :expected) do + 'snippet_titles' | :snippet_titles_count | '1234' + 'snippet_blobs' | :snippet_blobs_count | '1234' + 'projects' | :limited_projects_count | '1000+' + 'unknown' | nil | nil + end + + with_them do + it 'returns the expected formatted count' do + expect(results).to receive(count_method).and_return(1234) if count_method + expect(results.formatted_count(scope)).to eq(expected) + end + end + end end |