diff options
Diffstat (limited to 'spec/tooling')
-rw-r--r-- | spec/tooling/danger/specs_spec.rb | 33 | ||||
-rw-r--r-- | spec/tooling/danger/user_types_spec.rb | 56 | ||||
-rw-r--r-- | spec/tooling/lib/tooling/view_to_js_mappings_spec.rb | 356 | ||||
-rw-r--r-- | spec/tooling/quality/test_level_spec.rb | 36 |
4 files changed, 389 insertions, 92 deletions
diff --git a/spec/tooling/danger/specs_spec.rb b/spec/tooling/danger/specs_spec.rb index dcc1f592062..422923827a8 100644 --- a/spec/tooling/danger/specs_spec.rb +++ b/spec/tooling/danger/specs_spec.rb @@ -245,15 +245,16 @@ RSpec.describe Tooling::Danger::Specs, feature_category: :tooling do " let_it_be(:user) { create(:user) }", " end", " describe 'GET \"time_summary\"' do", - " end" - ] - end - - let(:matching_lines) do - [ - "+ RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController, feature_category: :planning_analytics do", - "+RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do", - "+ RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do" + " end", + " \n", + "RSpec.describe Projects :aggregate_failures,", + " feature_category: planning_analytics do", + " \n", + "RSpec.describe Epics :aggregate_failures,", + " ee: true do", + "\n", + "RSpec.describe Issues :aggregate_failures,", + " feature_category: :team_planning do" ] end @@ -264,14 +265,24 @@ RSpec.describe Tooling::Danger::Specs, feature_category: :tooling do "+ let_it_be(:user) { create(:user) }", "- end", "+ describe 'GET \"time_summary\"' do", - "+ RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do" + "+ RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do", + "+RSpec.describe Projects :aggregate_failures,", + "+ feature_category: planning_analytics do", + "+RSpec.describe Epics :aggregate_failures,", + "+ ee: true do", + "+RSpec.describe Issues :aggregate_failures," ] end + before do + allow(specs.helper).to receive(:changed_lines).with(filename).and_return(changed_lines) + end + it 'adds suggestions at the correct lines', :aggregate_failures do [ { suggested_line: "RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do", number: 5 }, - { suggested_line: " RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do", number: 10 } + { suggested_line: " RSpec.describe Projects::Analytics::CycleAnalytics::SummaryController do", number: 10 }, + { suggested_line: "RSpec.describe Epics :aggregate_failures,", number: 19 } ].each do |test_case| comment = format(template, suggested_line: test_case[:suggested_line]) diff --git a/spec/tooling/danger/user_types_spec.rb b/spec/tooling/danger/user_types_spec.rb deleted file mode 100644 index 53556601212..00000000000 --- a/spec/tooling/danger/user_types_spec.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -require 'gitlab-dangerfiles' -require 'gitlab/dangerfiles/spec_helper' -require_relative '../../../tooling/danger/user_types' - -RSpec.describe Tooling::Danger::UserTypes, feature_category: :subscription_cost_management do - include_context 'with dangerfile' - - let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) } - let(:user_types) { fake_danger.new(helper: fake_helper) } - - describe 'changed files' do - subject(:bot_user_types_change_warning) { user_types.bot_user_types_change_warning } - - before do - allow(fake_helper).to receive(:modified_files).and_return(modified_files) - allow(fake_helper).to receive(:changed_lines).and_return(changed_lines) - end - - context 'when has_user_type.rb file is not impacted' do - let(:modified_files) { ['app/models/concerns/importable.rb'] } - let(:changed_lines) { ['+ANY_CHANGES'] } - - it "doesn't add any warnings" do - expect(user_types).not_to receive(:warn) - - bot_user_types_change_warning - end - end - - context 'when the has_user_type.rb file is impacted' do - let(:modified_files) { ['app/models/concerns/has_user_type.rb'] } - - context 'with BOT_USER_TYPES changes' do - let(:changed_lines) { ['+BOT_USER_TYPES'] } - - it 'adds warning' do - expect(user_types).to receive(:warn).with(described_class::BOT_USER_TYPES_CHANGED_WARNING) - - bot_user_types_change_warning - end - end - - context 'without BOT_USER_TYPES changes' do - let(:changed_lines) { ['+OTHER_CHANGES'] } - - it "doesn't add any warnings" do - expect(user_types).not_to receive(:warn) - - bot_user_types_change_warning - end - end - end - end -end diff --git a/spec/tooling/lib/tooling/view_to_js_mappings_spec.rb b/spec/tooling/lib/tooling/view_to_js_mappings_spec.rb new file mode 100644 index 00000000000..b09df2a9200 --- /dev/null +++ b/spec/tooling/lib/tooling/view_to_js_mappings_spec.rb @@ -0,0 +1,356 @@ +# frozen_string_literal: true + +require 'tempfile' +require_relative '../../../../tooling/lib/tooling/view_to_js_mappings' + +RSpec.describe Tooling::ViewToJsMappings, feature_category: :tooling do + # We set temporary folders, and those readers give access to those folder paths + attr_accessor :view_base_folder, :js_base_folder + + around do |example| + Dir.mktmpdir do |tmp_js_base_folder| + Dir.mktmpdir do |tmp_views_base_folder| + self.js_base_folder = tmp_js_base_folder + self.view_base_folder = tmp_views_base_folder + + example.run + end + end + end + + describe '#execute' do + let(:instance) do + described_class.new( + view_base_folder: view_base_folder, + js_base_folder: js_base_folder + ) + end + + let(:changed_files) { %W[#{view_base_folder}/index.html] } + + subject { instance.execute(changed_files) } + + context 'when no view files have been changed' do + before do + allow(instance).to receive(:view_files).and_return([]) + end + + it 'returns nothing' do + expect(subject).to match_array([]) + end + end + + context 'when some view files have been changed' do + before do + File.write("#{view_base_folder}/index.html", index_html_content) + end + + context 'when they do not contain the HTML attribute value we search for' do + let(:index_html_content) do + <<~FILE + Beginning of file + End of file + FILE + end + + it 'returns nothing' do + expect(subject).to match_array([]) + end + end + + context 'when they contain the HTML attribute value we search for' do + let(:index_html_content) do + <<~FILE + Beginning of file + + <a id="js-some-id">A link</a> + + End of file + FILE + end + + context 'when no matching JS files are found' do + it 'returns nothing' do + expect(subject).to match_array([]) + end + end + + context 'when some matching JS files are found' do + let(:index_js_content) do + <<~FILE + Beginning of file + + const isMainAwardsBlock = votesBlock.closest('#js-some-id.some_class').length; + + End of file + FILE + end + + before do + File.write("#{js_base_folder}/index.js", index_js_content) + end + + it 'returns the matching JS files' do + expect(subject).to match_array(["#{js_base_folder}/index.js"]) + end + end + end + end + + context 'when rails partials are included in the file' do + before do + File.write("#{view_base_folder}/index.html", index_html_content) + File.write("#{view_base_folder}/_my-partial.html.haml", partial_file_content) + File.write("#{js_base_folder}/index.js", index_js_content) + end + + let(:index_html_content) do + <<~FILE + Beginning of file + + = render 'my-partial' + + End of file + FILE + end + + let(:partial_file_content) do + <<~FILE + Beginning of file + + <a class="js-some-class">A link with class</a> + + End of file + FILE + end + + let(:index_js_content) do + <<~FILE + Beginning of file + + const isMainAwardsBlock = votesBlock.closest('.js-some-class').length; + + End of file + FILE + end + + it 'scans those partials for the HTML attribute value' do + expect(subject).to match_array(["#{js_base_folder}/index.js"]) + end + end + end + + describe '#view_files' do + subject { described_class.new(view_base_folder: view_base_folder).view_files(changed_files) } + + before do + File.write("#{js_base_folder}/index.js", "index.js") + File.write("#{view_base_folder}/index.html", "index.html") + end + + context 'when no files were changed' do + let(:changed_files) { [] } + + it 'returns an empty array' do + expect(subject).to match_array([]) + end + end + + context 'when no view files were changed' do + let(:changed_files) { ["#{js_base_folder}/index.js"] } + + it 'returns an empty array' do + expect(subject).to match_array([]) + end + end + + context 'when view files were changed' do + let(:changed_files) { ["#{js_base_folder}/index.js", "#{view_base_folder}/index.html"] } + + it 'returns the path to the view files' do + expect(subject).to match_array(["#{view_base_folder}/index.html"]) + end + end + + context 'when view files are deleted' do + let(:changed_files) { ["#{js_base_folder}/index.js", "#{view_base_folder}/deleted.html"] } + + it 'returns an empty array' do + expect(subject).to match_array([]) + end + end + end + + describe '#folders_for_available_editions' do + let(:base_folder_path) { 'app/views' } + + subject { described_class.new.folders_for_available_editions(base_folder_path) } + + context 'when FOSS' do + before do + allow(GitlabEdition).to receive(:ee?).and_return(false) + allow(GitlabEdition).to receive(:jh?).and_return(false) + end + + it 'returns the correct paths' do + expect(subject).to match_array([base_folder_path]) + end + end + + context 'when EE' do + before do + allow(GitlabEdition).to receive(:ee?).and_return(true) + allow(GitlabEdition).to receive(:jh?).and_return(false) + end + + it 'returns the correct paths' do + expect(subject).to eq([base_folder_path, "ee/#{base_folder_path}"]) + end + end + + context 'when JiHu' do + before do + allow(GitlabEdition).to receive(:ee?).and_return(true) + allow(GitlabEdition).to receive(:jh?).and_return(true) + end + + it 'returns the correct paths' do + expect(subject).to eq([base_folder_path, "ee/#{base_folder_path}", "jh/#{base_folder_path}"]) + end + end + end + + describe '#find_partials' do + subject { described_class.new(view_base_folder: view_base_folder).find_partials(file_path) } + + let(:file_path) { "#{view_base_folder}/my_html_file.html" } + + before do + File.write(file_path, file_content) + end + + context 'when the file includes a partial' do + context 'when the partial is in the same folder as the view file' do + before do + File.write("#{view_base_folder}/_my-partial.html.haml", 'Hello from partial') + end + + let(:file_content) do + <<~FILE + Beginning of file + + = render "my-partial" + + End of file + FILE + end + + it "returns the partial file path" do + expect(subject).to match_array(["#{view_base_folder}/_my-partial.html.haml"]) + end + end + + context 'when the partial is in a subfolder' do + before do + FileUtils.mkdir_p("#{view_base_folder}/subfolder") + + (1..12).each do |i| + FileUtils.touch "#{view_base_folder}/subfolder/_my-partial#{i}.html.haml" + end + end + + let(:file_content) do + <<~FILE + Beginning of file + + = render("subfolder/my-partial1") + = render "subfolder/my-partial2" + = render(partial: "subfolder/my-partial3") + = render partial: "subfolder/my-partial4" + = render(partial:"subfolder/my-partial5", path: 'else') + = render partial:"subfolder/my-partial6" + = render_if_exist("subfolder/my-partial7", path: 'else') + = render_if_exist "subfolder/my-partial8" + = render_if_exist(partial: "subfolder/my-partial9", path: 'else') + = render_if_exist partial: "subfolder/my-partial10" + = render_if_exist(partial:"subfolder/my-partial11", path: 'else') + = render_if_exist partial:"subfolder/my-partial12" + + End of file + FILE + end + + it "returns the partials file path" do + expect(subject).to match_array([ + "#{view_base_folder}/subfolder/_my-partial1.html.haml", + "#{view_base_folder}/subfolder/_my-partial2.html.haml", + "#{view_base_folder}/subfolder/_my-partial3.html.haml", + "#{view_base_folder}/subfolder/_my-partial4.html.haml", + "#{view_base_folder}/subfolder/_my-partial5.html.haml", + "#{view_base_folder}/subfolder/_my-partial6.html.haml", + "#{view_base_folder}/subfolder/_my-partial7.html.haml", + "#{view_base_folder}/subfolder/_my-partial8.html.haml", + "#{view_base_folder}/subfolder/_my-partial9.html.haml", + "#{view_base_folder}/subfolder/_my-partial10.html.haml", + "#{view_base_folder}/subfolder/_my-partial11.html.haml", + "#{view_base_folder}/subfolder/_my-partial12.html.haml" + ]) + end + end + + context 'when the file does not include a partial' do + let(:file_content) do + <<~FILE + Beginning of file + End of file + FILE + end + + it 'returns an empty array' do + expect(subject).to match_array([]) + end + end + end + end + + describe '#find_pattern_in_file' do + let(:subject) { described_class.new.find_pattern_in_file(file.path, /pattern/) } + let(:file) { Tempfile.new('find_pattern_in_file') } + + before do + file.write(file_content) + file.close + end + + context 'when the file contains the pattern' do + let(:file_content) do + <<~FILE + Beginning of file + + pattern + pattern + pattern + + End of file + FILE + end + + it 'returns the pattern once' do + expect(subject).to match_array(%w[pattern]) + end + end + + context 'when the file does not contain the pattern' do + let(:file_content) do + <<~FILE + Beginning of file + End of file + FILE + end + + it 'returns an empty array' do + expect(subject).to match_array([]) + end + end + end +end diff --git a/spec/tooling/quality/test_level_spec.rb b/spec/tooling/quality/test_level_spec.rb index 3f46b3e79f4..aac7d19c079 100644 --- a/spec/tooling/quality/test_level_spec.rb +++ b/spec/tooling/quality/test_level_spec.rb @@ -4,9 +4,9 @@ require 'fast_spec_helper' require_relative '../../../tooling/quality/test_level' -RSpec.describe Quality::TestLevel do +RSpec.describe Quality::TestLevel, feature_category: :tooling do describe 'TEST_LEVEL_FOLDERS constant' do - it 'all directories it refers to exists', :aggregate_failures do + it 'ensures all directories it refers to exists', :aggregate_failures do ee_only_directories = %w[ lib/ee/gitlab/background_migration elastic @@ -53,7 +53,7 @@ RSpec.describe Quality::TestLevel do context 'when level is migration' do it 'returns a pattern' do expect(subject.pattern(:migration)) - .to eq("spec/{migrations,lib/gitlab/background_migration,lib/ee/gitlab/background_migration}{,/**/}*_spec.rb") + .to eq("spec/{migrations}{,/**/}*_spec.rb") end end @@ -128,7 +128,7 @@ RSpec.describe Quality::TestLevel do context 'when level is migration' do it 'returns a regexp' do expect(subject.regexp(:migration)) - .to eq(%r{spec/(migrations|lib/gitlab/background_migration|lib/ee/gitlab/background_migration)/}) + .to eq(%r{spec/(migrations)/}) end end @@ -196,7 +196,7 @@ RSpec.describe Quality::TestLevel do end it 'returns the correct level for a background migration test' do - expect(subject.level_for('spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb')).to eq(:migration) + expect(subject.level_for('spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb')).to eq(:background_migration) end it 'returns the correct level for an EE file without passing a prefix' do @@ -208,7 +208,7 @@ RSpec.describe Quality::TestLevel do end it 'returns the correct level for a EE-namespaced background migration test' do - expect(described_class.new('ee/').level_for('ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb')).to eq(:migration) + expect(described_class.new('ee/').level_for('ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb')).to eq(:background_migration) end it 'returns the correct level for an integration test' do @@ -228,27 +228,13 @@ RSpec.describe Quality::TestLevel do .to raise_error(described_class::UnknownTestLevelError, %r{Test level for spec/unknown/foo_spec.rb couldn't be set. Please rename the file properly or change the test level detection regexes in .+/tooling/quality/test_level.rb.}) end - end - describe '#background_migration?' do - it 'returns false for a unit test' do - expect(subject.background_migration?('spec/models/abuse_report_spec.rb')).to be(false) - end + it 'ensures all spec/ folders are covered by a test level' do + Dir['{,ee/}spec/**/*/'].each do |path| + next if path =~ %r{\A(ee/)?spec/(benchmarks|docs_screenshots|fixtures|frontend_integration|support)/} - it 'returns true for a migration test' do - expect(subject.background_migration?('spec/migrations/add_default_and_free_plans_spec.rb')).to be(false) - end - - it 'returns true for a background migration test' do - expect(subject.background_migration?('spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb')).to be(true) - end - - it 'returns true for a geo migration test' do - expect(described_class.new('ee/').background_migration?('ee/spec/migrations/geo/migrate_ci_job_artifacts_to_separate_registry_spec.rb')).to be(false) - end - - it 'returns true for a EE-namespaced background migration test' do - expect(described_class.new('ee/').background_migration?('ee/spec/lib/ee/gitlab/background_migration/prune_orphaned_geo_events_spec.rb')).to be(true) + expect { subject.level_for(path) }.not_to raise_error + end end end end |