diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-16 09:09:08 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-16 09:09:08 +0300 |
commit | 80f5d0d15f8d7ced767651978fb016072003f376 (patch) | |
tree | 8ddbe65b30cf5f2d2b6543bac7f7508ba259b9ec /spec | |
parent | 2a3313dc5ec97ba732681fe034de900215807ac3 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
7 files changed, 139 insertions, 34 deletions
diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index ab6242784fe..f96717970bf 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -23,7 +23,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do milestone: create(:milestone, project: project, due_date: '2013-12-11'), created_at: 1.minute.ago, updated_at: 1.minute.ago) - @fix.metrics.update_column(:merged_at, 10.seconds.ago) + @fix.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.seconds.ago) @markdown = create(:merge_request, title: 'markdown', @@ -34,7 +34,7 @@ RSpec.describe 'Merge requests > User lists merge requests' do milestone: create(:milestone, project: project, due_date: '2013-12-12'), created_at: 2.minutes.ago, updated_at: 2.minutes.ago) - @markdown.metrics.update_column(:merged_at, 50.seconds.ago) + @markdown.metrics.update!(merged_at: 10.minutes.ago, latest_closed_at: 10.seconds.ago) @merge_test = create(:merge_request, title: 'merge-test', @@ -42,7 +42,15 @@ RSpec.describe 'Merge requests > User lists merge requests' do source_branch: 'merge-test', created_at: 3.minutes.ago, updated_at: 10.seconds.ago) - @merge_test.metrics.update_column(:merged_at, 10.seconds.ago) + @merge_test.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.seconds.ago) + + @feature = create(:merge_request, + title: 'feature', + source_project: project, + source_branch: 'feautre', + created_at: 2.minutes.ago, + updated_at: 1.minute.ago) + @feature.metrics.update!(merged_at: 10.seconds.ago, latest_closed_at: 10.minutes.ago) end context 'merge request reviewers' do @@ -71,9 +79,10 @@ RSpec.describe 'Merge requests > User lists merge requests' do expect(current_path).to eq(project_merge_requests_path(project)) expect(page).to have_content 'merge-test' + expect(page).to have_content 'feature' expect(page).not_to have_content 'fix' expect(page).not_to have_content 'markdown' - expect(count_merge_requests).to eq(1) + expect(count_merge_requests).to eq(2) end it 'filters on a specific assignee' do @@ -90,28 +99,35 @@ RSpec.describe 'Merge requests > User lists merge requests' do expect(first_merge_request).to include('fix') expect(last_merge_request).to include('merge-test') - expect(count_merge_requests).to eq(3) + expect(count_merge_requests).to eq(4) end it 'sorts by last updated' do visit_merge_requests(project, sort: sort_value_recently_updated) expect(first_merge_request).to include('merge-test') - expect(count_merge_requests).to eq(3) + expect(count_merge_requests).to eq(4) end it 'sorts by milestone' do visit_merge_requests(project, sort: sort_value_milestone) expect(first_merge_request).to include('fix') - expect(count_merge_requests).to eq(3) + expect(count_merge_requests).to eq(4) end it 'sorts by merged at' do visit_merge_requests(project, sort: sort_value_merged_date) expect(first_merge_request).to include('markdown') - expect(count_merge_requests).to eq(3) + expect(count_merge_requests).to eq(4) + end + + it 'sorts by closed at' do + visit_merge_requests(project, sort: sort_value_closed_date) + + expect(first_merge_request).to include('feature') + expect(count_merge_requests).to eq(4) end it 'filters on one label and sorts by due date' do diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js index 74f579e77ed..d3e1bfef561 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js @@ -86,7 +86,7 @@ describe('AuthorToken', () => { }); describe('methods', () => { - describe('fetchAuthorBySearchTerm', () => { + describe('fetchAuthors', () => { beforeEach(() => { wrapper = createComponent(); }); @@ -155,7 +155,7 @@ describe('AuthorToken', () => { expect(baseTokenEl.exists()).toBe(true); expect(baseTokenEl.props()).toMatchObject({ suggestions: mockAuthors, - fnActiveTokenValue: wrapper.vm.getActiveAuthor, + getActiveTokenValue: wrapper.vm.getActiveAuthor, }); }); diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js index cd6ffd679d0..c746cb7749a 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js @@ -53,7 +53,6 @@ const mockProps = { suggestionsLoading: false, defaultSuggestions: DEFAULT_LABELS, recentSuggestionsStorageKey: mockStorageKey, - fnCurrentTokenValue: jest.fn(), }; function createComponent({ @@ -99,31 +98,20 @@ describe('BaseToken', () => { }); describe('computed', () => { - describe('currentTokenValue', () => { - it('calls `fnCurrentTokenValue` when it is provided', () => { - // We're disabling lint to trigger computed prop execution for this test. - // eslint-disable-next-line no-unused-vars - const { currentTokenValue } = wrapper.vm; - - expect(wrapper.vm.fnCurrentTokenValue).toHaveBeenCalledWith(`"${mockRegularLabel.title}"`); - }); - }); - describe('activeTokenValue', () => { - it('calls `fnActiveTokenValue` when it is provided', async () => { - const mockFnActiveTokenValue = jest.fn(); + it('calls `getActiveTokenValue` when it is provided', async () => { + const mockGetActiveTokenValue = jest.fn(); wrapper.setProps({ - fnActiveTokenValue: mockFnActiveTokenValue, - fnCurrentTokenValue: undefined, + getActiveTokenValue: mockGetActiveTokenValue, }); await wrapper.vm.$nextTick(); - expect(mockFnActiveTokenValue).toHaveBeenCalledTimes(1); - expect(mockFnActiveTokenValue).toHaveBeenCalledWith( + expect(mockGetActiveTokenValue).toHaveBeenCalledTimes(1); + expect(mockGetActiveTokenValue).toHaveBeenCalledWith( mockLabels, - `"${mockRegularLabel.title.toLowerCase()}"`, + `"${mockRegularLabel.title}"`, ); }); }); diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js index ec9458f64d2..e5ffbd41afa 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js @@ -98,11 +98,11 @@ describe('LabelToken', () => { }); }); - describe('fetchLabelBySearchTerm', () => { + describe('fetchLabels', () => { it('calls `config.fetchLabels` with provided searchTerm param', () => { jest.spyOn(wrapper.vm.config, 'fetchLabels'); - wrapper.vm.fetchLabelBySearchTerm('foo'); + wrapper.vm.fetchLabels('foo'); expect(wrapper.vm.config.fetchLabels).toHaveBeenCalledWith('foo'); }); @@ -110,7 +110,7 @@ describe('LabelToken', () => { it('sets response to `labels` when request is succesful', () => { jest.spyOn(wrapper.vm.config, 'fetchLabels').mockResolvedValue(mockLabels); - wrapper.vm.fetchLabelBySearchTerm('foo'); + wrapper.vm.fetchLabels('foo'); return waitForPromises().then(() => { expect(wrapper.vm.labels).toEqual(mockLabels); @@ -120,7 +120,7 @@ describe('LabelToken', () => { it('calls `createFlash` with flash error message when request fails', () => { jest.spyOn(wrapper.vm.config, 'fetchLabels').mockRejectedValue({}); - wrapper.vm.fetchLabelBySearchTerm('foo'); + wrapper.vm.fetchLabels('foo'); return waitForPromises().then(() => { expect(createFlash).toHaveBeenCalledWith({ @@ -132,7 +132,7 @@ describe('LabelToken', () => { it('sets `loading` to false when request completes', () => { jest.spyOn(wrapper.vm.config, 'fetchLabels').mockRejectedValue({}); - wrapper.vm.fetchLabelBySearchTerm('foo'); + wrapper.vm.fetchLabels('foo'); return waitForPromises().then(() => { expect(wrapper.vm.loading).toBe(false); @@ -160,7 +160,7 @@ describe('LabelToken', () => { expect(baseTokenEl.exists()).toBe(true); expect(baseTokenEl.props()).toMatchObject({ suggestions: mockLabels, - fnActiveTokenValue: wrapper.vm.getActiveLabel, + getActiveTokenValue: wrapper.vm.getActiveLabel, }); }); diff --git a/spec/graphql/resolvers/merge_requests_resolver_spec.rb b/spec/graphql/resolvers/merge_requests_resolver_spec.rb index aec6c6c6708..64ee0d4f9cc 100644 --- a/spec/graphql/resolvers/merge_requests_resolver_spec.rb +++ b/spec/graphql/resolvers/merge_requests_resolver_spec.rb @@ -303,6 +303,29 @@ RSpec.describe Resolvers::MergeRequestsResolver do expect { resolve_mr(project, sort: :merged_at_desc, labels: %w[a b]) }.not_to raise_error end end + + context 'when sorting by closed at' do + before do + merge_request_1.metrics.update!(latest_closed_at: 10.days.ago) + merge_request_3.metrics.update!(latest_closed_at: 5.days.ago) + end + + it 'sorts merge requests ascending' do + expect(resolve_mr(project, sort: :closed_at_asc)) + .to match_array(mrs) + .and be_sorted(->(mr) { [closed_at(mr), -mr.id] }) + end + + it 'sorts merge requests descending' do + expect(resolve_mr(project, sort: :closed_at_desc)) + .to match_array(mrs) + .and be_sorted(->(mr) { [-closed_at(mr), -mr.id] }) + end + + def closed_at(mr) + nils_last(mr.metrics.latest_closed_at) + end + end end end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index edd543854cb..4a8a2909891 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -80,6 +80,24 @@ RSpec.describe MergeRequest, factory_default: :keep do end end + describe '.order_closed_at_asc' do + let_it_be(:older_mr) { create(:merge_request, :closed_last_month) } + let_it_be(:newer_mr) { create(:merge_request, :closed_last_month) } + + it 'returns MRs ordered by closed_at ascending' do + expect(described_class.order_closed_at_asc).to eq([older_mr, newer_mr]) + end + end + + describe '.order_closed_at_desc' do + let_it_be(:older_mr) { create(:merge_request, :closed_last_month) } + let_it_be(:newer_mr) { create(:merge_request, :closed_last_month) } + + it 'returns MRs ordered by closed_at descending' do + expect(described_class.order_closed_at_desc).to eq([newer_mr, older_mr]) + end + end + describe '.with_jira_issue_keys' do let_it_be(:mr_with_jira_title) { create(:merge_request, :unique_branches, title: 'Fix TEST-123') } let_it_be(:mr_with_jira_description) { create(:merge_request, :unique_branches, description: 'this closes TEST-321') } @@ -577,6 +595,26 @@ RSpec.describe MergeRequest, factory_default: :keep do expect(merge_requests).to eq([newer_mr, older_mr]) end end + + context 'closed_at' do + let_it_be(:older_mr) { create(:merge_request, :closed_last_month) } + let_it_be(:newer_mr) { create(:merge_request, :closed_last_month) } + + it 'sorts asc' do + merge_requests = described_class.sort_by_attribute(:closed_at_asc) + expect(merge_requests).to eq([older_mr, newer_mr]) + end + + it 'sorts desc' do + merge_requests = described_class.sort_by_attribute(:closed_at_desc) + expect(merge_requests).to eq([newer_mr, older_mr]) + end + + it 'sorts asc when its closed_at' do + merge_requests = described_class.sort_by_attribute(:closed_at) + expect(merge_requests).to eq([older_mr, newer_mr]) + end + end end describe 'time to merge calculations' do diff --git a/spec/requests/api/graphql/project/merge_requests_spec.rb b/spec/requests/api/graphql/project/merge_requests_spec.rb index 7fc1ef05fa7..1b0405be09c 100644 --- a/spec/requests/api/graphql/project/merge_requests_spec.rb +++ b/spec/requests/api/graphql/project/merge_requests_spec.rb @@ -422,6 +422,46 @@ RSpec.describe 'getting merge request listings nested in a project' do end end end + + context 'when sorting by closed_at DESC' do + let(:sort_param) { :CLOSED_AT_DESC } + let(:expected_results) do + [ + merge_request_b, + merge_request_d, + merge_request_c, + merge_request_e, + merge_request_a + ].map { |mr| global_id_of(mr) } + end + + before do + five_days_ago = 5.days.ago + + merge_request_d.metrics.update!(latest_closed_at: five_days_ago) + + # same merged_at, the second order column will decide (merge_request.id) + merge_request_c.metrics.update!(latest_closed_at: five_days_ago) + + merge_request_b.metrics.update!(latest_closed_at: 1.day.ago) + end + + it_behaves_like 'sorted paginated query' do + let(:first_param) { 2 } + end + + context 'when last parameter is given' do + let(:params) { graphql_args(sort: sort_param, last: 2) } + let(:page_info) { nil } + + it 'takes the last 2 records' do + query = pagination_query(params) + post_graphql(query, current_user: current_user) + + expect(results.map { |item| item["id"] }).to eq(expected_results.last(2)) + end + end + end end context 'when only the count is requested' do |