diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-02 12:18:33 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-05-02 12:18:33 +0300 |
commit | 74da249f7e22c20e144ba3c044c6bdeb5df86cd4 (patch) | |
tree | 0db7396e87d999b13cc61dff61e4f323e0a4a5d2 /spec | |
parent | e14edb3ce5fd3162d3cf10b88f58333066109f53 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r-- | spec/benchmarks/banzai_benchmark.rb | 24 | ||||
-rw-r--r-- | spec/factories/merge_requests_diff_llm_summary.rb | 10 | ||||
-rw-r--r-- | spec/frontend/boards/components/board_list_header_spec.js | 70 | ||||
-rw-r--r-- | spec/frontend/boards/mock_data.js | 8 | ||||
-rw-r--r-- | spec/frontend/lib/utils/datetime/date_format_utility_spec.js | 15 | ||||
-rw-r--r-- | spec/models/merge_request/diff_llm_summary_spec.rb | 17 | ||||
-rw-r--r-- | spec/requests/api/environments_spec.rb | 50 | ||||
-rw-r--r-- | spec/rubocop/cop/gettext/static_identifier_spec.rb | 174 | ||||
-rw-r--r-- | spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb | 48 |
9 files changed, 339 insertions, 77 deletions
diff --git a/spec/benchmarks/banzai_benchmark.rb b/spec/benchmarks/banzai_benchmark.rb index 7a60825c1e6..45f45bcc8dd 100644 --- a/spec/benchmarks/banzai_benchmark.rb +++ b/spec/benchmarks/banzai_benchmark.rb @@ -16,8 +16,15 @@ require 'benchmark/ips' # or # rake benchmark:banzai # +# A specific filter can also be benchmarked by using the `FILTER` +# environment variable. +# +# BENCHMARK=1 FILTER=MathFilter rspec spec/benchmarks/banzai_benchmark.rb --tag specific_filter +# or +# FILTER=MathFilter rake benchmark:banzai +# # rubocop: disable RSpec/TopLevelDescribePath -RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do +RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures, feature_category: :team_planning do include MarkupHelper let_it_be(:feature) { MarkdownFeature.new } @@ -83,9 +90,15 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do benchmark_pipeline_filters(:plain_markdown) end - it 'benchmarks specified filters in the FullPipeline' do - filter_klass_list = [Banzai::Filter::MathFilter] - benchmark_pipeline_filters(:full, filter_klass_list) + it 'benchmarks specified filters in the FullPipeline', :specific_filter do + begin + filter = ENV['FILTER'] || 'MarkdownFilter' + filter_klass = "Banzai::Filter::#{filter}".constantize + rescue NameError + raise 'Incorrect filter specified. Correct example: FILTER=MathFilter' + end + + benchmark_pipeline_filters(:full, [filter_klass]) end end @@ -114,7 +127,8 @@ RSpec.describe 'GitLab Markdown Benchmark', :aggregate_failures do pipeline = Banzai::Pipeline[pipeline_type] filter_source = build_filter_text(pipeline, markdown_text) - puts "\n--> Benchmarking #{pipeline.name.demodulize} filters\n" + filter_msg = filter_klass_list ? filter_klass_list.first.name.demodulize : 'all filters' + puts "\n--> Benchmarking #{filter_msg} for #{pipeline.name.demodulize}\n" Benchmark.ips do |x| x.config(time: 10, warmup: 2) diff --git a/spec/factories/merge_requests_diff_llm_summary.rb b/spec/factories/merge_requests_diff_llm_summary.rb new file mode 100644 index 00000000000..c72ce97efcb --- /dev/null +++ b/spec/factories/merge_requests_diff_llm_summary.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :merge_request_diff_llm_summary, class: 'MergeRequest::DiffLlmSummary' do + association :user, factory: :user + association :merge_request_diff, factory: :merge_request_diff + provider { 0 } + content { 'test' } + end +end diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js index 0f91d2315cf..d4489b3c535 100644 --- a/spec/frontend/boards/components/board_list_header_spec.js +++ b/spec/frontend/boards/components/board_list_header_spec.js @@ -4,8 +4,13 @@ import VueApollo from 'vue-apollo'; import Vuex from 'vuex'; import createMockApollo from 'helpers/mock_apollo_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { boardListQueryResponse, mockLabelList } from 'jest/boards/mock_data'; +import { + boardListQueryResponse, + mockLabelList, + updateBoardListResponse, +} from 'jest/boards/mock_data'; import BoardListHeader from '~/boards/components/board_list_header.vue'; +import updateBoardListMutation from '~/boards/graphql/board_list_update.mutation.graphql'; import { ListType } from '~/boards/constants'; import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql'; @@ -19,6 +24,8 @@ describe('Board List Header Component', () => { const updateListSpy = jest.fn(); const toggleListCollapsedSpy = jest.fn(); + const mockClientToggleListCollapsedResolver = jest.fn(); + const updateListHandler = jest.fn().mockResolvedValue(updateBoardListResponse); afterEach(() => { fakeApollo = null; @@ -34,7 +41,7 @@ describe('Board List Header Component', () => { listQueryHandler = jest.fn().mockResolvedValue(boardListQueryResponse()), injectedProps = {}, } = {}) => { - const boardId = '1'; + const boardId = 'gid://gitlab/Board/1'; const listMock = { ...mockLabelList, @@ -58,8 +65,17 @@ describe('Board List Header Component', () => { state: {}, actions: { updateList: updateListSpy, toggleListCollapsed: toggleListCollapsedSpy }, }); - - fakeApollo = createMockApollo([[listQuery, listQueryHandler]]); + fakeApollo = createMockApollo( + [ + [listQuery, listQueryHandler], + [updateBoardListMutation, updateListHandler], + ], + { + Mutation: { + clientToggleListCollapsed: mockClientToggleListCollapsedResolver, + }, + }, + ); wrapper = shallowMountExtended(BoardListHeader, { apolloProvider: fakeApollo, @@ -67,9 +83,9 @@ describe('Board List Header Component', () => { propsData: { list: listMock, filterParams: {}, + boardId, }, provide: { - boardId, weightFeatureAvailable: false, currentUserId, isEpicBoard: false, @@ -191,7 +207,9 @@ describe('Board List Header Component', () => { await nextTick(); expect(updateListSpy).not.toHaveBeenCalled(); - expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.collapsed`)).toBe(String(isCollapsed())); + expect(localStorage.getItem(`${wrapper.vm.uniqueKey}.collapsed`)).toBe( + String(!isCollapsed()), + ); }); }); @@ -214,4 +232,44 @@ describe('Board List Header Component', () => { expect(findTitle().classes()).toContain('gl-cursor-grab'); }); }); + + describe('Apollo boards', () => { + beforeEach(async () => { + createComponent({ listType: ListType.label, injectedProps: { isApolloBoard: true } }); + await nextTick(); + }); + + it('set active board item on client when clicking on card', async () => { + findCaret().vm.$emit('click'); + await nextTick(); + + expect(mockClientToggleListCollapsedResolver).toHaveBeenCalledWith( + {}, + { + list: mockLabelList, + collapsed: true, + }, + expect.anything(), + expect.anything(), + ); + }); + + it('does not call update list mutation when user is not logged in', async () => { + createComponent({ currentUserId: null, injectedProps: { isApolloBoard: true } }); + + findCaret().vm.$emit('click'); + await nextTick(); + + expect(updateListHandler).not.toHaveBeenCalled(); + }); + + it('calls update list mutation when user is logged in', async () => { + createComponent({ currentUserId: 1, injectedProps: { isApolloBoard: true } }); + + findCaret().vm.$emit('click'); + await nextTick(); + + expect(updateListHandler).toHaveBeenCalledWith({ listId: mockLabelList.id, collapsed: true }); + }); + }); }); diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js index 832e24d477b..d9baf88c624 100644 --- a/spec/frontend/boards/mock_data.js +++ b/spec/frontend/boards/mock_data.js @@ -989,4 +989,12 @@ export const updateEpicTitleResponse = { }, }; +export const updateBoardListResponse = { + data: { + updateBoardList: { + list: mockList, + }, + }, +}; + export const DEFAULT_COLOR = '#1068bf'; diff --git a/spec/frontend/lib/utils/datetime/date_format_utility_spec.js b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js index a83b0ed9fbe..6b515e9f96a 100644 --- a/spec/frontend/lib/utils/datetime/date_format_utility_spec.js +++ b/spec/frontend/lib/utils/datetime/date_format_utility_spec.js @@ -136,11 +136,16 @@ describe('formatTimeAsSummary', () => { describe('durationTimeFormatted', () => { it.each` - duration | expectedOutput - ${87} | ${'00:01:27'} - ${141} | ${'00:02:21'} - ${12} | ${'00:00:12'} - ${60} | ${'00:01:00'} + duration | expectedOutput + ${0} | ${'00:00:00'} + ${12} | ${'00:00:12'} + ${60} | ${'00:01:00'} + ${60 + 27} | ${'00:01:27'} + ${120 + 21} | ${'00:02:21'} + ${4 * 60 * 60 + 25 * 60 + 37} | ${'04:25:37'} + ${35 * 60 * 60 + 3 * 60 + 7} | ${'35:03:07'} + ${-60} | ${'-00:01:00'} + ${-(35 * 60 * 60 + 3 * 60 + 7)} | ${'-35:03:07'} `('returns $expectedOutput when provided $duration', ({ duration, expectedOutput }) => { expect(utils.durationTimeFormatted(duration)).toBe(expectedOutput); }); diff --git a/spec/models/merge_request/diff_llm_summary_spec.rb b/spec/models/merge_request/diff_llm_summary_spec.rb new file mode 100644 index 00000000000..a94adae9fa5 --- /dev/null +++ b/spec/models/merge_request/diff_llm_summary_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::MergeRequest::DiffLlmSummary, feature_category: :code_review_workflow do + let_it_be_with_reload(:project) { create(:project, :repository) } + + subject(:merge_request_diff_llm_summary) { build(:merge_request_diff_llm_summary) } + + describe 'associations' do + it { is_expected.to belong_to(:merge_request_diff) } + it { is_expected.to belong_to(:user).optional } + it { is_expected.to validate_presence_of(:content) } + it { is_expected.to validate_length_of(:content).is_at_most(2056) } + it { is_expected.to validate_presence_of(:provider) } + end +end diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index 6164555ad19..eb1e02de4f1 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -229,17 +229,24 @@ RSpec.describe API::Environments, feature_category: :continuous_delivery do end describe 'PUT /projects/:id/environments/:environment_id' do - it 'returns a 200 if name and external_url are changed' do + it 'returns a 200 if external_url is changed' do url = 'https://mepmep.whatever.ninja' put api("/projects/#{project.id}/environments/#{environment.id}", user), - params: { name: 'Mepmep', external_url: url } + params: { external_url: url } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('public_api/v4/environment') - expect(json_response['name']).to eq('Mepmep') expect(json_response['external_url']).to eq(url) end + it 'returns a 400 if name is changed' do + put api("/projects/#{project.id}/environments/#{environment.id}", user), + params: { name: 'Mepmep' } + + expect(response).to have_gitlab_http_status(:bad_request) + expect(json_response['message']).to eq(described_class::ENVIRONMENT_NAME_UPDATE_ERROR) + end + it 'returns a 200 if tier is changed' do put api("/projects/#{project.id}/environments/#{environment.id}", user), params: { tier: 'production' } @@ -258,21 +265,38 @@ RSpec.describe API::Environments, feature_category: :continuous_delivery do expect(json_response["error"]).to eq("slug is automatically generated and cannot be changed") end - it "won't update the external_url if only the name is passed" do - url = environment.external_url - put api("/projects/#{project.id}/environments/#{environment.id}", user), - params: { name: 'Mepmep' } - - expect(response).to have_gitlab_http_status(:ok) - expect(json_response['name']).to eq('Mepmep') - expect(json_response['external_url']).to eq(url) - end - it 'returns a 404 if the environment does not exist' do put api("/projects/#{project.id}/environments/#{non_existing_record_id}", user) expect(response).to have_gitlab_http_status(:not_found) end + + context 'when disallow_environment_name_update feature flag is disabled' do + before do + stub_feature_flags(disallow_environment_name_update: false) + end + + it 'returns a 200 if name and external_url are changed' do + url = 'https://mepmep.whatever.ninja' + put api("/projects/#{project.id}/environments/#{environment.id}", user), + params: { name: 'Mepmep', external_url: url } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('public_api/v4/environment') + expect(json_response['name']).to eq('Mepmep') + expect(json_response['external_url']).to eq(url) + end + + it "won't update the external_url if only the name is passed" do + url = environment.external_url + put api("/projects/#{project.id}/environments/#{environment.id}", user), + params: { name: 'Mepmep' } + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['name']).to eq('Mepmep') + expect(json_response['external_url']).to eq(url) + end + end end describe 'DELETE /projects/:id/environments/:environment_id' do diff --git a/spec/rubocop/cop/gettext/static_identifier_spec.rb b/spec/rubocop/cop/gettext/static_identifier_spec.rb new file mode 100644 index 00000000000..a0c15d8ad48 --- /dev/null +++ b/spec/rubocop/cop/gettext/static_identifier_spec.rb @@ -0,0 +1,174 @@ +# frozen_string_literal: true + +require 'rubocop_spec_helper' +require 'rspec-parameterized' + +require_relative '../../../../rubocop/cop/gettext/static_identifier' + +RSpec.describe RuboCop::Cop::Gettext::StaticIdentifier, feature_category: :internationalization do + describe '#_()' do + it 'does not flag correct use' do + expect_no_offenses(<<~'RUBY') + _('Hello') + _('Hello #{name}') + + _('Hello %{name}') % { name: name } + format(_('Hello %{name}') % { name: name }) + + _('Hello' \ + 'Multiline') + _('Hello' \ + 'Multiline %{name}') % { name: name } + + var = "Hello" + _(var) + _(method_name) + list.each { |item| _(item) } + _(CONST) + RUBY + end + + it 'flags incorrect use' do + expect_offense(<<~'RUBY') + _('Hello' + ' concat') + ^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `_(...)`. + _('Hello'.concat(' concat')) + ^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `_(...)`. + _("Hello #{name}") + ^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `_(...)`. + _('Hello %{name}' % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `_(...)`. + _(format('Hello %{name}') % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `_(...)`. + RUBY + end + end + + describe '#N_()' do + it 'does not flag correct use' do + expect_no_offenses(<<~'RUBY') + N_('Hello') + N_('Hello #{name}') + N_('Hello %{name}') % { name: name } + format(_('Hello %{name}') % { name: name }) + + N_('Hello' \ + 'Multiline') + + var = "Hello" + N_(var) + N_(method_name) + list.each { |item| N_(item) } + N_(CONST) + RUBY + end + + it 'flags incorrect use' do + expect_offense(<<~'RUBY') + N_('Hello' + ' concat') + ^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `N_(...)`. + N_("Hello #{name}") + ^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `N_(...)`. + N_('Hello %{name}' % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `N_(...)`. + N_('Hello' \ + ^^^^^^^^^ Ensure to pass static strings to translation method `N_(...)`. + 'Multiline %{name}' % { name: name }) + N_(format('Hello %{name}') % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `N_(...)`. + RUBY + end + end + + describe '#s_()' do + it 'does not flag correct use' do + expect_no_offenses(<<~'RUBY') + s_('World|Hello') + s_('World|Hello #{name}') + s_('World|Hello %{name}') % { name: name } + format(s_('World|Hello %{name}') % { name: name }) + + s_('World|Hello' \ + 'Multiline') + + var = "Hello" + s_(var) + s_(method_name) + list.each { |item| s_(item) } + s_(CONST) + RUBY + end + + it 'flags incorrect use' do + expect_offense(<<~'RUBY') + s_("World|Hello #{name}") + ^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `s_(...)`. + s_('World|Hello' + ' concat') + ^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `s_(...)`. + s_('World|Hello %{name}' % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `s_(...)`. + s_('World|Hello' \ + ^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `s_(...)`. + 'Multiline %{name}' % { name: name }) + s_(format('World|Hello %{name}') % { name: name }) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `s_(...)`. + RUBY + end + end + + describe '#n_()' do + it 'does not flag correct use' do + expect_no_offenses(<<~'RUBY') + n_('Hello', 'Hellos', 2) + n_('Hello', 'Hellos', count) + + n_('Hello' ' concat', 'Hellos', 2) + n_('Hello', 'Hello' 's', 2) + + n_('Hello %{name}', 'Hellos %{name}', 2) % { name: name } + format(n_('Hello %{name}', 'Hellos %{name}', count) % { name: name }) + + n_('Hello', 'Hellos' \ + 'Multiline', 2) + + n_('Hello' \ + 'Multiline', 'Hellos', 2) + + n_('Hello' \ + 'Multiline %{name}', 'Hellos %{name}', 2) % { name: name } + + var = "Hello" + n_(var, var, 1) + n_(method_name, method_name, count) + list.each { |item| n_(item, item, 2) } + n_(CONST, CONST, 2) + RUBY + end + + it 'flags incorrect use' do + expect_offense(<<~'RUBY') + n_('Hello' + ' concat', 'Hellos', 2) + ^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + n_('Hello', 'Hello' + 's', 2) + ^^^^^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + n_("Hello #{name}", "Hellos", 2) + ^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + n_('Hello %{name}' % { name: name }, 'Hellos', 2) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + n_('Hello' \ + ^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + 'Multiline %{name}' % { name: name }, 'Hellos %{name}', 2) + n_('Hello', format('Hellos %{name}') % { name: name }, count) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Ensure to pass static strings to translation method `n_(...)`. + RUBY + end + end + + describe 'edge cases' do + it 'does not flag' do + expect_no_offenses(<<~RUBY) + n_(s_('World|Hello'), s_('World|Hellos'), 2) + RUBY + end + end +end diff --git a/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb b/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb deleted file mode 100644 index b687e91601c..00000000000 --- a/spec/rubocop/cop/ruby_interpolation_in_translation_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -# frozen_string_literal: true - -require 'rubocop_spec_helper' - -require_relative '../../../rubocop/cop/ruby_interpolation_in_translation' - -# Disabling interpolation check as we deliberately want to have #{} in strings. -# rubocop:disable Lint/InterpolationCheck -RSpec.describe RuboCop::Cop::RubyInterpolationInTranslation do - let(:msg) { "Don't use ruby interpolation \#{} inside translated strings, instead use %{}" } - - it 'does not add an offense for a regular messages' do - expect_no_offenses('_("Hello world")') - end - - it 'adds the correct offense when using interpolation in a string' do - expect_offense(<<~CODE) - _("Hello \#{world}") - ^^^^^ #{msg} - ^^^^^^^^ #{msg} - CODE - end - - it 'detects when using a ruby interpolation in the first argument of a pluralized string' do - expect_offense(<<~CODE) - n_("Hello \#{world}", "Hello world") - ^^^^^ #{msg} - ^^^^^^^^ #{msg} - CODE - end - - it 'detects when using a ruby interpolation in the second argument of a pluralized string' do - expect_offense(<<~CODE) - n_("Hello world", "Hello \#{world}") - ^^^^^ #{msg} - ^^^^^^^^ #{msg} - CODE - end - - it 'detects when using interpolation in a namespaced translation' do - expect_offense(<<~CODE) - s_("Hello|\#{world}") - ^^^^^ #{msg} - ^^^^^^^^ #{msg} - CODE - end -end -# rubocop:enable Lint/InterpolationCheck |