diff --git a/Rakefile b/Rakefile index 3d345bd2..77b1b932 100644 --- a/Rakefile +++ b/Rakefile @@ -11,12 +11,24 @@ Rake::TestTask.new(:test) do |t| t.test_files = FileList["test/**/*_test.rb"] end +Rake::TestTask.new("test:unit") do |t| + t.libs << "test" + t.libs << "lib" + t.test_files = FileList["test/unit/**/*_test.rb"] +end + Rake::TestTask.new("test:integration") do |t| t.libs << "test" t.libs << "lib" t.test_files = FileList["test/integration/**/*_test.rb"] end +desc "Run all tests with coverage" +task :coverage do + ENV["COVERAGE"] = "true" + Rake::Task["test"].invoke +end + task "clobber" do puts "Cleanup tmp/*.png" FileUtils.rm_rf(Dir["./tmp/*"]) diff --git a/scripts/benchmark/find_region_benchmark.rb b/scripts/benchmark/find_region_benchmark.rb index 1f6007de..696d3cdb 100644 --- a/scripts/benchmark/find_region_benchmark.rb +++ b/scripts/benchmark/find_region_benchmark.rb @@ -8,7 +8,7 @@ module Capybara::Screenshot::Diff class Drivers::FindRegionBenchmark - TEST_IMAGES_DIR = Pathname.new(File.expand_path("../../test/images", __dir__)) + TEST_IMAGES_DIR = Pathname.new(File.expand_path("../../test/fixtures/images", __dir__)) APP_SCREENSHOTS_DIR = Pathname.new( File.expand_path("../../test/fixtures/app/doc/screenshots/chrome/macos/", __dir__) ) diff --git a/test/capybara/screenshot/diff/area_calculator_test.rb b/test/capybara/screenshot/diff/area_calculator_test.rb deleted file mode 100644 index 4257ca17..00000000 --- a/test/capybara/screenshot/diff/area_calculator_test.rb +++ /dev/null @@ -1,24 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "capybara/screenshot/diff/area_calculator" - -module Capybara::Screenshot::Diff - class AreaCalculatorTest < ActiveSupport::TestCase - test "skips non intersected skip areas and crop area" do - skip_area = [[0, 0, 100, 100], [200, 200, 100, 100]] - crop_area = [100, 100, 100, 100] - calculator = AreaCalculator.new(crop_area, skip_area) - - assert_equal [], calculator.calculate_skip_area - end - - test "skip area accepts region" do - skip_area = [Region.new(0, 0, 100, 100)] - crop_area = Region.new(0, 0, 200, 200) - calculator = AreaCalculator.new(crop_area, skip_area) - - assert_equal [Region.new(0, 0, 100, 100)], calculator.calculate_skip_area - end - end -end diff --git a/test/capybara/screenshot/diff/comparison_loader_test.rb b/test/capybara/screenshot/diff/comparison_loader_test.rb deleted file mode 100644 index b6a872c1..00000000 --- a/test/capybara/screenshot/diff/comparison_loader_test.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require_relative "test_doubles" - -module Capybara - module Screenshot - module Diff - class ComparisonLoaderTest < ActionDispatch::IntegrationTest - include CapybaraScreenshotDiff::DSLStub - include TestDoubles - - test "loads images and applies preprocessing" do - # Setup - base_path = Pathname.new("base/path.png") - new_path = Pathname.new("new/path.png") - options = {tolerance: 0.01} - - raw_images = [:raw_base_image, :raw_new_image] - - driver = TestDriver.new(false, raw_images) - - # Action - loader = ComparisonLoader.new(driver) - comparison = loader.call(base_path, new_path, options) - - # Verify the comparison object - assert_kind_of Comparison, comparison - assert_equal raw_images[1], comparison.new_image - assert_equal raw_images[0], comparison.base_image - assert_equal options, comparison.options - assert_equal driver, comparison.driver - end - end - end - end -end diff --git a/test/capybara/screenshot/diff/difference_finder_test.rb b/test/capybara/screenshot/diff/difference_finder_test.rb deleted file mode 100644 index 204c8ed5..00000000 --- a/test/capybara/screenshot/diff/difference_finder_test.rb +++ /dev/null @@ -1,135 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require_relative "test_doubles" - -module Capybara - module Screenshot - module Diff - class DifferenceFinderTest < ActionDispatch::IntegrationTest - include CapybaraScreenshotDiff::DSLStub - include TestDoubles - - def setup - @base_path = TestPath.new(12345) - @new_path = TestPath.new(54321) # Different size - @driver = TestDriver.new(false) - - # Create a test comparison with paths directly - @comparison = TestComparison.new - @comparison.base_image_path = @base_path - @comparison.new_image_path = @new_path - end - - def create_difference_factory - lambda do |comparison, failed_by = nil| - @factory_calls ||= [] - @factory_calls << {comparison: comparison, failed_by: failed_by} - - if failed_by - :dimension_difference_result - else - :no_difference_result - end - end - end - - test "when dimensions are the same and pixels are the same then returns true in quick mode" do - # Setup - @driver.same_dimension_result = true - @driver.same_pixels_result = true - - # Action - finder = DifferenceFinder.new(@driver, {}) - result, difference = finder.call(@comparison, quick_mode: true) - - # Verify - assert result - refute_nil difference - assert_equal 1, @driver.dimension_check_calls.size - assert_equal 1, @driver.pixel_check_calls.size - end - - test "when dimensions differ then returns a difference with failed dimensions" do - # Setup - @driver.same_dimension_result = false - - # Action - finder = DifferenceFinder.new(@driver, {}) - result = finder.call(@comparison, quick_mode: false) - - # Verify - assert_instance_of Difference, result - assert result.failed? - assert_equal 1, @driver.dimension_check_calls.size - assert_equal 0, @driver.pixel_check_calls.size - end - - test "when pixels are the same then returns no difference" do - # Setup - @driver.same_dimension_result = true - @driver.same_pixels_result = true - - # Action - finder = DifferenceFinder.new(@driver, {}) - result = finder.call(@comparison, quick_mode: false) - - # Verify - assert_instance_of Difference, result - assert result.equal? - assert_equal 1, @driver.dimension_check_calls.size - assert_equal 1, @driver.pixel_check_calls.size - end - - test "when pixels differ then checks difference region" do - # Setup - @driver.same_dimension_result = true - @driver.same_pixels_result = false - test_difference = TestDifference.new(true) # It is different - @driver.difference_region_result = test_difference - - # Action - finder = DifferenceFinder.new(@driver, {}) - result = finder.call(@comparison, quick_mode: false) - - # Verify - assert_equal test_difference, result - assert_equal 1, @driver.difference_region_calls.size - end - - test "when in quick mode returns array with comparison result and difference" do - # Setup - @driver.same_dimension_result = true - @driver.same_pixels_result = false - test_difference = TestDifference.new(false) # Not different (within tolerance) - @driver.difference_region_result = test_difference - - # Action - finder = DifferenceFinder.new(@driver, {tolerance: 0.01}) - result, difference = finder.call(@comparison, quick_mode: true) - - # Verify - assert result # Not different == true equality - assert_equal test_difference, difference - end - - test "when comparison has no tolerable options in quick mode, returns early" do - # Setup - @driver.same_dimension_result = true - @driver.same_pixels_result = false - - # Action - finder = DifferenceFinder.new(@driver, {}) - result, difference = finder.call(@comparison, quick_mode: true) - - # Verify - refute result # Different == false equality - assert_nil difference # Quick mode with no tolerance returns nil difference - assert_equal 1, @driver.dimension_check_calls.size - assert_equal 1, @driver.pixel_check_calls.size - assert_equal 0, @driver.difference_region_calls.size # Should not process difference region - end - end - end - end -end diff --git a/test/capybara/screenshot/diff/difference_test.rb b/test/capybara/screenshot/diff/difference_test.rb deleted file mode 100644 index 381a2a97..00000000 --- a/test/capybara/screenshot/diff/difference_test.rb +++ /dev/null @@ -1,22 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "capybara/screenshot/diff/difference" - -module Capybara::Screenshot::Diff - class DifferenceTest < ActiveSupport::TestCase - class WithFailedByTest < DifferenceTest - setup do - @difference = Difference.new(nil, {}, nil, {different_dimensions: []}) - end - - test "it is different" do - assert_predicate @difference, :different? - end - - test "it is failed" do - assert_predicate @difference, :failed? - end - end - end -end diff --git a/test/capybara/screenshot/diff/drivers/chunky_png_driver_test.rb b/test/capybara/screenshot/diff/drivers/chunky_png_driver_test.rb deleted file mode 100644 index e2f65136..00000000 --- a/test/capybara/screenshot/diff/drivers/chunky_png_driver_test.rb +++ /dev/null @@ -1,164 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "capybara/screenshot/diff/image_compare" -require "capybara/screenshot/diff/drivers/chunky_png_driver" - -module Capybara - module Screenshot - module Diff - module Drivers - class ChunkyPNGDriverTest < ActionDispatch::IntegrationTest - include CapybaraScreenshotDiff::DSLStub - - teardown do - FileUtils.rm Dir["#{Rails.root}/screenshot*.png"] - end - - test "it can be instantiated" do - assert ChunkyPNGDriver.new - end - - test "#different? supports tolerance option" do - comp = make_comparison(:a, :b, tolerance: 2) - assert_not comp.different? - assert comp.quick_equal? - end - - test "#different? for equal is negative" do - comp = make_comparison(:a, :a) - assert_not comp.different? - end - - test "#quick_equal? for equal is positive" do - comp = make_comparison(:a, :a) - assert comp.quick_equal? - end - - test "compare then dimensions and cleanup" do - comp = make_comparison(:a, :c) - assert comp.different? - assert_includes comp.error_message, "[11,3,48,20]" - assert File.exist?(comp.base_image_path) - assert File.exist?(comp.reporter.annotated_base_image_path) - assert File.exist?(comp.reporter.annotated_image_path) - - assert_same_images("a-and-c.diff.png", comp.reporter.annotated_base_image_path) - assert_same_images("c-and-a.diff.png", comp.reporter.annotated_image_path) - - comp = make_comparison(:c, :c) - assert_not comp.different? - - assert comp.reporter.annotated_base_image_path - assert comp.reporter.annotated_image_path - - assert_not File.exist?(comp.reporter.annotated_base_image_path) - assert_not File.exist?(comp.reporter.annotated_image_path) - end - - test "compare of 1 pixel wide diff" do - comp = make_comparison(:a, :d) - assert comp.different? - assert_includes comp.error_message, "[9,6,9,13]" - end - - test "compare with color_distance_limit above difference" do - comp = make_comparison(:a, :b, color_distance_limit: 223) - assert_not comp.different? - end - - test "compare with color_distance_limit below difference" do - comp = make_comparison(:a, :b, color_distance_limit: 222) - assert comp.different? - assert_includes comp.error_message, "222.7" - end - - test "compare with shift_distance_limit above difference" do - comp = make_comparison(:a, :b, shift_distance_limit: 11) - assert comp.quick_equal? - assert_not comp.different? - end - - test "compare with shift_distance_limit below difference" do - comp = make_comparison(:a, :b, shift_distance_limit: 9) - assert comp.different? - assert_includes comp.error_message, "11" - end - - test "quick_equal with color distance limit above max color distance" do - comp = make_comparison(:a, :b, color_distance_limit: 224) - assert_not comp.different? - end - - test "quick_equal with color distance limit" do - comp = make_comparison(:a, :b, color_distance_limit: 222) - assert_not comp.quick_equal? - assert comp.different? - assert_includes comp.error_message, "222.7" - end - - test "max_color_distance a vs b" do - comp = make_comparison(:a, :b) - assert_not comp.quick_equal? - comp.different? - assert_includes comp.error_message, "85" - end - - test "max_color_distance a vs c" do - comp = make_comparison(:a, :c) - comp.different? - assert_includes comp.error_message, "187.4" - end - - test "max_color_distance a vs d" do - comp = make_comparison(:a, :d) - comp.different? - assert_includes comp.error_message, "269.1" - end - - test "max_color_distance 1.0" do - a_img = ChunkyPNG::Image.from_blob(File.binread("#{TEST_IMAGES_DIR}/a.png")) - a_img[9, 6] += 0x010000 - - comp = make_comparison(:a, :b) - other_img_filename = comp.image_path - a_img.save(other_img_filename) - - comp.different? - - assert_includes comp.error_message, "1" - end - - test "size a vs a_cropped" do - comp = make_comparison(:a, :a_cropped) - assert comp.different? - assert_includes comp.error_message, "Dimensions have changed: " - assert_includes comp.error_message, "80x60" - end - - # Test Interface Contracts - - test "from_file loads image from path" do - driver = ChunkyPNGDriver.new - assert driver.from_file("#{TEST_IMAGES_DIR}/a.png") - end - - private - - def make_comparison(old_img, new_img, options = {}) - snap = create_snapshot_for(old_img, new_img) - ImageCompare.new(snap.path, snap.base_path, **options) - end - - def sample_region - [0, 0, 0, 0] - end - - def load_test_image(driver) - driver.from_file("#{TEST_IMAGES_DIR}/a.png") - end - end - end - end - end -end diff --git a/test/capybara/screenshot/diff/image_compare_refactor_test.rb b/test/capybara/screenshot/diff/image_compare_refactor_test.rb deleted file mode 100644 index 8f2cc1e0..00000000 --- a/test/capybara/screenshot/diff/image_compare_refactor_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require "minitest/stub_const" -require_relative "test_doubles" - -module Capybara - module Screenshot - module Diff - class ImageCompareRefactorTest < ActionDispatch::IntegrationTest - include CapybaraScreenshotDiff::DSLStub - include TestDoubles - - test "when comparing identical images then quick_equal? returns true and different? returns false" do - # Setup - comparison = make_comparison(:a, :a) - - # Action & Verify - assert_predicate comparison, :quick_equal? - assert_not_predicate comparison, :different? - end - - test "when comparing different images then quick_equal? returns false and different? returns true" do - # Setup - comparison = make_comparison(:a, :b) - - # Action & Verify - assert_not_predicate comparison, :quick_equal? - assert_predicate comparison, :different? - end - - test "when images have different dimensions then dimensions_changed? returns true" do - # Setup - comparison = make_comparison(:portrait, :a) - - # Action - comparison.processed - - # Verify - assert_predicate comparison, :dimensions_changed? - assert_kind_of Reporters::Default, comparison.reporter - end - end - end - end -end diff --git a/test/capybara/screenshot/diff/image_preprocessor_test.rb b/test/capybara/screenshot/diff/image_preprocessor_test.rb deleted file mode 100644 index 4907c935..00000000 --- a/test/capybara/screenshot/diff/image_preprocessor_test.rb +++ /dev/null @@ -1,111 +0,0 @@ -# frozen_string_literal: true - -require "test_helper" -require_relative "test_doubles" - -module Capybara - module Screenshot - module Diff - class ImagePreprocessorTest < ActionDispatch::IntegrationTest - include CapybaraScreenshotDiff::DSLStub - include TestDoubles - - def setup - @test_images = [:base_image, :new_image] - end - - test "when no preprocessing options are provided then returns original images unchanged" do - # Setup - driver = TestDriver.new(false) - options = {} - - # Action - preprocessor = ImagePreprocessor.new(driver, options) - result = preprocessor.call(@test_images) - - # Verify - assert_equal @test_images, result - assert_empty driver.add_black_box_calls - assert_empty driver.filter_calls - end - - test "when skip_area is specified then applies black box to that region" do - # Setup - driver = TestDriver.new(false) - skip_area = [{x: 10, y: 20, width: 30, height: 40}] - options = {skip_area: skip_area} - - # Action - preprocessor = ImagePreprocessor.new(driver, options) - result = preprocessor.call(@test_images) - - # Verify - assert_equal %w[processed_base_image processed_new_image], result - - assert_equal 2, driver.add_black_box_calls.size - - first_call = driver.add_black_box_calls[0] - second_call = driver.add_black_box_calls[1] - - assert_equal skip_area.first, first_call[:region] - assert_equal skip_area.first, second_call[:region] - assert_equal :base_image, first_call[:image] - assert_equal :new_image, second_call[:image] - end - - test "when median filter is specified with VipsDriver then applies filter to images" do - skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) - - # Setup - driver = TestDriver.new(true) # true = is a VipsDriver - window_size = 3 - options = {median_filter_window_size: window_size} - - # Action - preprocessor = ImagePreprocessor.new(driver, options) - result = preprocessor.call(@test_images) - - # Verify - assert_equal ["filtered_base_image", "filtered_new_image"], result - - assert_equal 2, driver.filter_calls.size - - first_call = driver.filter_calls[0] - second_call = driver.filter_calls[1] - - assert_equal window_size, first_call[:size] - assert_equal window_size, second_call[:size] - assert_equal :base_image, first_call[:image] - assert_equal :new_image, second_call[:image] - end - - test "when median filter is specified with non-VipsDriver then issues warning and returns original images" do - # Setup - driver = TestDriver.new(false) # false = is not a VipsDriver - window_size = 3 - options = { - median_filter_window_size: window_size, - image_path: "some/path.png" - } - - # Set up a warning expectation - expected_warning = /Median filter has been skipped for.*because it is not supported/ - - # Action with warning capture - preprocessor = ImagePreprocessor.new(driver, options) - - warning_output = capture_io do - result = preprocessor.call(@test_images) - - # Verify images unchanged - assert_equal @test_images, result - assert_empty driver.filter_calls - end - - # Verify warning - assert_match expected_warning, warning_output.join - end - end - end - end -end diff --git a/test/fixtures/app/doc/screenshots/.keep b/test/fixtures/app/doc/screenshots/.keep new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/files/comparisons/a-and-b.diff.png b/test/fixtures/comparisons/a-and-b.diff.png similarity index 100% rename from test/fixtures/files/comparisons/a-and-b.diff.png rename to test/fixtures/comparisons/a-and-b.diff.png diff --git a/test/fixtures/files/comparisons/a-and-b.heatmap.diff.png b/test/fixtures/comparisons/a-and-b.heatmap.diff.png similarity index 100% rename from test/fixtures/files/comparisons/a-and-b.heatmap.diff.png rename to test/fixtures/comparisons/a-and-b.heatmap.diff.png diff --git a/test/fixtures/files/comparisons/a-and-c.diff.png b/test/fixtures/comparisons/a-and-c.diff.png similarity index 100% rename from test/fixtures/files/comparisons/a-and-c.diff.png rename to test/fixtures/comparisons/a-and-c.diff.png diff --git a/test/fixtures/files/comparisons/b-and-a.diff.png b/test/fixtures/comparisons/b-and-a.diff.png similarity index 100% rename from test/fixtures/files/comparisons/b-and-a.diff.png rename to test/fixtures/comparisons/b-and-a.diff.png diff --git a/test/fixtures/files/comparisons/c-and-a.diff.png b/test/fixtures/comparisons/c-and-a.diff.png similarity index 100% rename from test/fixtures/files/comparisons/c-and-a.diff.png rename to test/fixtures/comparisons/c-and-a.diff.png diff --git a/test/images/a.png b/test/fixtures/images/a.png similarity index 100% rename from test/images/a.png rename to test/fixtures/images/a.png diff --git a/test/images/a.webp b/test/fixtures/images/a.webp similarity index 100% rename from test/images/a.webp rename to test/fixtures/images/a.webp diff --git a/test/images/a_cropped.png b/test/fixtures/images/a_cropped.png similarity index 100% rename from test/images/a_cropped.png rename to test/fixtures/images/a_cropped.png diff --git a/test/images/b.png b/test/fixtures/images/b.png similarity index 100% rename from test/images/b.png rename to test/fixtures/images/b.png diff --git a/test/images/c.png b/test/fixtures/images/c.png similarity index 100% rename from test/images/c.png rename to test/fixtures/images/c.png diff --git a/test/images/d.png b/test/fixtures/images/d.png similarity index 100% rename from test/images/d.png rename to test/fixtures/images/d.png diff --git a/test/images/portrait.png b/test/fixtures/images/portrait.png similarity index 100% rename from test/images/portrait.png rename to test/fixtures/images/portrait.png diff --git a/test/images/portrait_b.png b/test/fixtures/images/portrait_b.png similarity index 100% rename from test/images/portrait_b.png rename to test/fixtures/images/portrait_b.png diff --git a/test/fixtures/files/rspec_spec.rb b/test/fixtures/rspec_spec.rb similarity index 100% rename from test/fixtures/files/rspec_spec.rb rename to test/fixtures/rspec_spec.rb diff --git a/test/capybara_screenshot_diff/rspec_test.rb b/test/integration/rspec_test.rb similarity index 77% rename from test/capybara_screenshot_diff/rspec_test.rb rename to test/integration/rspec_test.rb index a01d5999..1e772401 100644 --- a/test/capybara_screenshot_diff/rspec_test.rb +++ b/test/integration/rspec_test.rb @@ -4,13 +4,13 @@ module CapybaraScreenshotDiff class RspecTest < SystemTestCase - test "should support rspec" do + test "RSpec integration runs successfully with capybara-screenshot-diff" do # Ensure that the RSpec module is loaded require "rspec/core" # Run the RSpec spec file capture_output = StringIO.new - spec_file = (ActiveSupport::TestCase.file_fixture_path / "files/rspec_spec.rb").to_s + spec_file = file_fixture("rspec_spec.rb").to_s rspec_status = RSpec::Core::Runner.run([spec_file], capture_output, capture_output) assert_equal 0, rspec_status, "RSpec tests failed:\n#{capture_output.string}" diff --git a/test/support/capybara_screenshot_diff/dsl_stub.rb b/test/support/capybara_screenshot_diff/dsl_stub.rb index b8502d20..68a4f3be 100644 --- a/test/support/capybara_screenshot_diff/dsl_stub.rb +++ b/test/support/capybara_screenshot_diff/dsl_stub.rb @@ -1,18 +1,20 @@ +require "active_support/concern" + module CapybaraScreenshotDiff module DSLStub extend ActiveSupport::Concern - included do - setup do - @manager = CapybaraScreenshotDiff::SnapManager.new(Capybara::Screenshot.root / "doc/screenshots") - Capybara::Screenshot::Diff.screenshoter = Capybara::Screenshot::ScreenshoterStub - end + def setup + super + @manager = CapybaraScreenshotDiff::SnapManager.new(Capybara::Screenshot.root / "doc/screenshots") + Capybara::Screenshot::Diff.screenshoter = Capybara::Screenshot::ScreenshoterStub + end - teardown do - @manager.cleanup! - Capybara::Screenshot::Diff.screenshoter = Capybara::Screenshot::Screenshoter - CapybaraScreenshotDiff.reset - end + def teardown + @manager.cleanup! + Capybara::Screenshot::Diff.screenshoter = Capybara::Screenshot::Screenshoter + CapybaraScreenshotDiff.reset + super end # Prepare comparison images and build ImageCompare for them diff --git a/test/support/screenshoter_stub.rb b/test/support/screenshoter_stub.rb index 179ba00e..667d417f 100644 --- a/test/support/screenshoter_stub.rb +++ b/test/support/screenshoter_stub.rb @@ -13,6 +13,7 @@ def save_screenshot(path) source_image.slice!(/^\d\d_/) source_image.slice!(/_\d+(?=\.)/) + FileUtils.mkdir_p(path.dirname) FileUtils.cp(File.expand_path(source_image, TEST_IMAGES_DIR), path) path diff --git a/test/capybara/screenshot/diff/test_doubles.rb b/test/support/test_doubles.rb similarity index 100% rename from test/capybara/screenshot/diff/test_doubles.rb rename to test/support/test_doubles.rb diff --git a/test/support/test_helpers.rb b/test/support/test_helpers.rb new file mode 100644 index 00000000..619ade06 --- /dev/null +++ b/test/support/test_helpers.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "support/test_doubles" + +module TestHelpers + include Capybara::Screenshot::Diff::TestDoubles + # Common assertions for image comparison tests + module Assertions + # Asserts that a dimension check was called a specific number of times + # @param driver [Object] The test driver object + # @param times [Integer] The expected number of calls (default: 1) + def assert_dimension_check_called(driver, times = 1) + assert_equal times, driver.dimension_check_calls.size, + "Expected dimension check to be called #{times} time(s)" + end + + # Asserts that a pixel check was called a specific number of times + # @param driver [Object] The test driver object + # @param times [Integer] The expected number of calls (default: 1) + def assert_pixel_check_called(driver, times = 1) + assert_equal times, driver.pixel_check_calls.size, + "Expected pixel check to be called #{times} time(s)" + end + + # Asserts that a difference region check was called a specific number of times + # @param driver [Object] The test driver object + # @param times [Integer] The expected number of calls (default: 1) + def assert_difference_region_called(driver, times = 1) + assert_equal times, driver.difference_region_calls.size, + "Expected difference region check to be called #{times} time(s)" + end + end + + # Common setup methods for test drivers + module DriverSetup + # Sets up driver results for testing + # @param driver [Object] The test driver object + # @param same_dimension [Boolean] Whether dimensions match (default: true) + # @param same_pixels [Boolean, nil] Whether pixels match (default: nil for no change) + # @param difference_region [Object, nil] The difference region result (default: nil) + def setup_driver_results(driver, same_dimension: true, same_pixels: nil, difference_region: nil) + driver.same_dimension_result = same_dimension + driver.same_pixels_result = same_pixels unless same_pixels.nil? + driver.difference_region_result = difference_region if difference_region + end + end + + # Common test data generators + module TestData + # Creates a test driver with the given options + # @param is_vips [Boolean] Whether to create a VIPS driver (default: false) + # @param images [Array, nil] Images to return from load_images (default: nil) + # @return [TestDoubles::TestDriver] A test driver object + def create_test_driver(is_vips: false, images: nil) + Capybara::Screenshot::Diff::TestDoubles::TestDriver.new(is_vips, images) + end + end +end diff --git a/test/system_test_case.rb b/test/system_test_case.rb index 3f0fb8aa..bd26bafc 100644 --- a/test/system_test_case.rb +++ b/test/system_test_case.rb @@ -16,6 +16,7 @@ class SystemTestCase < ActiveSupport::TestCase # TODO: Reset original settings to previous values @orig_root = Capybara::Screenshot.root Capybara::Screenshot.root = Rails.root / "../test/fixtures/app" + @orig_save_path = Capybara::Screenshot.save_path Capybara::Screenshot.save_path = "./doc/screenshots" diff --git a/test/test_helper.rb b/test/test_helper.rb index 1b893d0a..6c136ab7 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -14,7 +14,7 @@ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "pathname" -TEST_IMAGES_DIR = Pathname.new(File.expand_path("images", __dir__)) +TEST_IMAGES_DIR = Pathname.new(File.expand_path("fixtures/images", __dir__)) require "support/setup_rails_app" require "minitest/autorun" @@ -26,8 +26,17 @@ require "support/stub_test_methods" require "support/setup_capybara_drivers" +require "support/test_helpers" + +Capybara::Screenshot.root = Rails.root +Capybara::Screenshot.save_path = "./doc/screenshots" class ActiveSupport::TestCase + include TestHelpers::Assertions + include TestHelpers::DriverSetup + include TestHelpers::TestData + + # Set up fixtures and test helpers self.file_fixture_path = Pathname.new(File.expand_path("fixtures", __dir__)) teardown do @@ -40,16 +49,18 @@ def persist_comparisons? def optional_test unless ENV["DISABLE_SKIP_TESTS"] - skip "This is optional test! To enable need to provide DISABLE_SKIP_TESTS=1" + skip "This is optional test! To enable provide DISABLE_SKIP_TESTS=1" end end + private + def fixture_image_path_from(original_new_image, ext = "png") - TEST_IMAGES_DIR / "#{original_new_image}.#{ext}" + file_fixture("images/#{original_new_image}.#{ext}") end def assert_same_images(expected_image_name, image_path) - expected_image_path = file_fixture("files/comparisons/#{expected_image_name}") + expected_image_path = file_fixture("comparisons/#{expected_image_name}") assert_predicate(Capybara::Screenshot::Diff::ImageCompare.new(image_path, expected_image_path), :quick_equal?) end diff --git a/test/unit/area_calculator_test.rb b/test/unit/area_calculator_test.rb new file mode 100644 index 00000000..ce4f262e --- /dev/null +++ b/test/unit/area_calculator_test.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require "test_helper" +require "capybara/screenshot/diff/area_calculator" + +module Capybara + module Screenshot + module Diff + class AreaCalculatorTest < ActiveSupport::TestCase + class CalculateSkipAreaTest < self + test "#calculate_skip_area returns empty array when no skip areas overlap with crop area" do + skip_area = [[0, 0, 100, 100], [200, 200, 100, 100]] + crop_area = [100, 100, 100, 100] + calculator = AreaCalculator.new(crop_area, skip_area) + + result = calculator.calculate_skip_area + + assert_empty result + end + + test "#calculate_skip_area returns intersecting regions when skip areas overlap with crop area" do + skip_area = [Region.new(50, 50, 150, 150)] + crop_area = Region.new(0, 0, 200, 200) + calculator = AreaCalculator.new(crop_area, skip_area) + + result = calculator.calculate_skip_area + + assert_equal [Region.new(50, 50, 150, 150)], result + end + end + + class InitializationTest < self + test "#initialize handles Region objects for skip areas correctly" do + skip_area = [Region.new(0, 0, 100, 100)] + crop_area = Region.new(0, 0, 200, 200) + + calculator = AreaCalculator.new(crop_area, skip_area) + + assert_equal [Region.new(0, 0, 100, 100)], calculator.calculate_skip_area + end + + test "#initialize converts array coordinates to Region objects" do + skip_area = [[0, 0, 100, 100]] + crop_area = [0, 0, 200, 200] + + calculator = AreaCalculator.new(crop_area, skip_area) + result = calculator.calculate_skip_area + + assert_equal 1, result.size + assert_kind_of Region, result.first + assert_equal [0, 0, 100, 100], + [result.first.left, result.first.top, result.first.right, result.first.bottom] + end + end + + class EdgeCaseTest < self + test "#calculate_skip_area returns empty array when skip_areas is empty" do + calculator = AreaCalculator.new([0, 0, 100, 100], []) + + result = calculator.calculate_skip_area + + assert_empty result + end + + test "#calculate_skip_area returns nil when skip_areas is not provided (nil)" do + calculator = AreaCalculator.new([0, 0, 100, 100], nil) + + result = calculator.calculate_skip_area + + assert_nil result + end + end + end + end + end +end diff --git a/test/unit/comparison_loader_test.rb b/test/unit/comparison_loader_test.rb new file mode 100644 index 00000000..5bc52844 --- /dev/null +++ b/test/unit/comparison_loader_test.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require "test_helper" +require "support/test_doubles" +require "capybara/screenshot/diff/comparison_loader" + +module Capybara + module Screenshot + module Diff + class ComparisonLoaderTest < ActiveSupport::TestCase + include TestDoubles + + def setup + @base_path = Pathname.new("base/path.png") + @new_path = Pathname.new("new/path.png") + @options = {tolerance: 0.01} + @driver = TestDriver.new + @loader = ComparisonLoader.new(@driver) + end + + test "#call returns Comparison instance with correct attributes" do + comparison = @loader.call(@base_path, @new_path, @options) + + assert_kind_of Comparison, comparison + assert_equal :base_image, comparison.base_image + assert_equal :new_image, comparison.new_image + assert_equal @options, comparison.options + assert_equal @driver, comparison.driver + end + + test "#call loads base and new images in correct order" do + # Configure the driver to return specific images + images = [:first_image, :second_image] + driver = TestDriver.new(false, images) + loader = ComparisonLoader.new(driver) + + comparison = loader.call(@base_path, @new_path, {}) + + assert_equal :first_image, comparison.base_image + assert_equal :second_image, comparison.new_image + end + + test "#call passes options to the comparison" do + custom_options = {tolerance: 0.05, median_filter_window_size: 3} + comparison = @loader.call(@base_path, @new_path, custom_options) + + assert_equal custom_options, comparison.options + end + + test "#call uses driver to load images with correct paths" do + loader = ComparisonLoader.new(@driver) + loader.call(@base_path, @new_path, {}) + + assert @driver.load_images_called + assert_equal [@base_path, @new_path], @driver.load_images_args + end + end + end + end +end diff --git a/test/capybara/screenshot/diff_test.rb b/test/unit/diff_test.rb similarity index 85% rename from test/capybara/screenshot/diff_test.rb rename to test/unit/diff_test.rb index 0f156d13..e38ebce1 100644 --- a/test/capybara/screenshot/diff_test.rb +++ b/test/unit/diff_test.rb @@ -6,7 +6,7 @@ module Capybara module Screenshot - class DiffTest < ActionDispatch::IntegrationTest + class DiffTest < ActiveSupport::TestCase setup do Capybara.current_driver = Capybara.default_driver @@ -36,11 +36,11 @@ class DiffTest < ActionDispatch::IntegrationTest Capybara::Screenshot.window_size = @orig_window_size end - def test_that_it_has_a_version_number + test "has a version number" do refute_nil ::Capybara::Screenshot::Diff::VERSION end - def test_screenshot_groups_are_replaced + test "updates screenshot group name" do assert_nil screenshot_namer.group screenshot_group "a" assert_equal "a", screenshot_namer.group @@ -48,7 +48,7 @@ def test_screenshot_groups_are_replaced assert_equal "b", screenshot_namer.group end - def test_screenshot_section_is_prepended + test "screenshot_section prepends section to path" do assert_nil screenshot_namer.section assert_nil screenshot_namer.group @@ -65,12 +65,12 @@ def test_screenshot_section_is_prepended assert_match %r{doc/screenshots/(macos|linux)/rack_test/a/c}, screenshot_dir end - test "screenshot" do + test "stores screenshot with given name" do screenshot_group "screenshot" assert_matches_screenshot "a" end - test "succeed on screenshot diff when fail_on_difference is false" do + test "does not fail when fail_on_difference is false and screenshots differ" do Capybara::Screenshot::Diff.stub(:fail_on_difference, false) do test_case = SampleMiniTestCase.new(:_test_sample_screenshot_error) test_case.run @@ -78,28 +78,30 @@ def test_screenshot_section_is_prepended end end - def test_screenshot_with_alternate_save_path + test "writes screenshot to alternate save path" do default_path = Capybara::Screenshot.save_path Capybara::Screenshot.save_path = "foo/bar" screenshot_section "a" screenshot_group "b" - screenshot "a" + screenshot "a", delayed: false assert_match %r{foo/bar/(macos|linux)/rack_test/a/b}, screenshot_dir ensure + FileUtils.remove_entry Capybara::Screenshot.screenshot_area_abs Capybara::Screenshot.save_path = default_path end - def test_screenshot_with_stability_time_limit + test "does not error when using stability_time_limit" do + default_stability_time_limit = Capybara::Screenshot.stability_time_limit Capybara::Screenshot.stability_time_limit = 0.001 screenshot "a" ensure - Capybara::Screenshot.stability_time_limit = nil + Capybara::Screenshot.stability_time_limit = default_stability_time_limit end - test "build_full_name" do + test "builds full name from string" do assert_equal "a", build_full_name("a") screenshot_group "b" assert_equal "b/00_a", build_full_name("a") @@ -109,19 +111,19 @@ def test_screenshot_with_stability_time_limit assert_equal "c/a", build_full_name("a") end - test "build_full_name allows symbol" do + test "builds full name from symbol" do screenshot_group :b assert_equal "b/00_a", build_full_name(:a) end - test "detect available diff drivers on the loading" do + test "detects available diff drivers" do # NOTE for tests we are loading both drivers, so we expect that all of them are available expected_drivers = defined?(Vips) ? %i[vips chunky_png] : %i[chunky_png] assert_equal expected_drivers, Capybara::Screenshot::Diff::AVAILABLE_DRIVERS end - test "aggregates failures instead of raising errors on teardown for Minitest" do + test "aggregates failures on teardown for Minitest" do test_case = SampleMiniTestCase.new(:_test_sample_screenshot_error) test_case.run @@ -130,7 +132,7 @@ def test_screenshot_with_stability_time_limit assert_includes test_case.failures.first.message, "expected error message" end - test "raising errors on teardown for non Minitest" do + test "raises error on teardown for non-Minitest" do test_case = SampleNotMiniTestCase.new test_case._test_sample_screenshot_error @@ -140,7 +142,7 @@ def test_screenshot_with_stability_time_limit assert_empty(CapybaraScreenshotDiff.assertions) end - class SampleMiniTestCase < ActionDispatch::IntegrationTest + class SampleMiniTestCase < ActiveSupport::TestCase include Capybara::Screenshot::Diff include CapybaraScreenshotDiff::Minitest::Assertions @@ -192,7 +194,7 @@ def _test_sample_screenshot_error end end - class ScreenshotFormatTest < ActionDispatch::IntegrationTest + class ScreenshotFormatTest < ActiveSupport::TestCase setup do @orig_screenshot_format = Capybara::Screenshot.screenshot_format end @@ -205,7 +207,7 @@ class ScreenshotFormatTest < ActionDispatch::IntegrationTest Capybara::Screenshot.screenshot_format = @orig_screenshot_format end - test "use default screenshot format" do + test "stores screenshot using default format extension" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) snap = CapybaraScreenshotDiff::SnapManager.snapshot("a", "webp") @@ -218,7 +220,7 @@ class ScreenshotFormatTest < ActionDispatch::IntegrationTest end end - test "override default screenshot format" do + test "stores screenshot using overridden format extension" do snap = CapybaraScreenshotDiff::SnapManager.snapshot("a", "png") set_test_images(snap, :a, :a) diff --git a/test/unit/difference_finder_test.rb b/test/unit/difference_finder_test.rb new file mode 100644 index 00000000..92557f77 --- /dev/null +++ b/test/unit/difference_finder_test.rb @@ -0,0 +1,133 @@ +# frozen_string_literal: true + +require "test_helper" +require "support/test_doubles" +require "capybara/screenshot/diff/difference_finder" + +module Capybara + module Screenshot + module Diff + class DifferenceFinderTest < ActiveSupport::TestCase + include CapybaraScreenshotDiff::DSLStub + include TestDoubles + + class InitializationTest < self + setup do + @base_path = TestDoubles::TestPath.new(12345) + @new_path = TestDoubles::TestPath.new(54321) + @driver = TestDoubles::TestDriver.new(false) + setup_test_comparison + end + + test "#initialize sets driver and options correctly" do + driver = TestDoubles::TestDriver.new + options = {tolerance: 0.05} + + finder = DifferenceFinder.new(driver, options) + + assert_equal driver, finder.driver + assert_equal options, finder.options + end + end + + class QuickModeTest < self + setup do + @base_path = TestDoubles::TestPath.new(12345) + @new_path = TestDoubles::TestPath.new(54321) + @driver = TestDoubles::TestDriver.new(false) + setup_test_comparison + @finder = create_finder + end + + test "#call in quick_mode returns true with difference when images match exactly" do + setup_driver_results(@driver, same_dimension: true, same_pixels: true) + + result, difference = @finder.call(@comparison, quick_mode: true) + + assert result, "Expected call to return true" + refute_nil difference, "Expected a difference object" + assert_dimension_check_called(@driver) + assert_pixel_check_called(@driver) + end + + test "#call in quick_mode with tolerance returns true when difference is within tolerance" do + test_difference = TestDifference.new(false) # Not different (within tolerance) + setup_driver_results(@driver, same_dimension: true, same_pixels: false, difference_region: test_difference) + + finder = create_finder(tolerance: 0.01) + result, difference = finder.call(@comparison, quick_mode: true) + + assert result, "Expected call to return true when within tolerance" + assert_equal test_difference, difference + end + + test "#call in quick_mode returns false without difference when pixels differ beyond tolerance" do + setup_driver_results(@driver, same_dimension: true, same_pixels: false) + + result, difference = @finder.call(@comparison, quick_mode: true) + + refute result, "Expected call to return false when pixels differ" + assert_nil difference, "Expected no difference object in quick mode" + assert_dimension_check_called(@driver) + assert_pixel_check_called(@driver) + assert_difference_region_called(@driver, 0) + end + end + + class FullModeTest < self + setup do + @base_path = TestDoubles::TestPath.new(12345) + @new_path = TestDoubles::TestPath.new(54321) + @driver = TestDoubles::TestDriver.new(false) + setup_test_comparison + @finder = create_finder + end + + test "#call in full_mode returns failed difference when image dimensions differ" do + setup_driver_results(@driver, same_dimension: false) + + result = @finder.call(@comparison, quick_mode: false) + + assert_instance_of Difference, result + assert result.failed?, "Expected failed result when dimensions differ" + assert_dimension_check_called(@driver) + assert_pixel_check_called(@driver, 0) + end + + test "#call in full_mode returns equal result when images match exactly" do + setup_driver_results(@driver, same_dimension: true, same_pixels: true) + + result = @finder.call(@comparison, quick_mode: false) + + assert_instance_of Difference, result + assert result.equal?, "Expected equal result when pixels match" + assert_dimension_check_called(@driver) + assert_pixel_check_called(@driver) + end + + test "#call in full_mode returns difference when pixels differ beyond tolerance" do + test_difference = TestDifference.new(true) + setup_driver_results(@driver, same_dimension: true, same_pixels: false, difference_region: test_difference) + + result = @finder.call(@comparison, quick_mode: false) + + assert_equal test_difference, result + assert_difference_region_called(@driver) + end + end + + private + + def setup_test_comparison + @comparison = TestDoubles::TestComparison.new + @comparison.base_image_path = @base_path + @comparison.new_image_path = @new_path + end + + def create_finder(options = {}) + DifferenceFinder.new(@driver, options) + end + end + end + end +end diff --git a/test/unit/difference_test.rb b/test/unit/difference_test.rb new file mode 100644 index 00000000..1305cefa --- /dev/null +++ b/test/unit/difference_test.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require "test_helper" +require "capybara/screenshot/diff/difference" + +module Capybara::Screenshot::Diff + class DifferenceTest < ActiveSupport::TestCase + setup do + @difference = Difference.new(nil, {}, nil, {different_dimensions: []}) + end + + test "#different? returns true when images have different dimensions" do + assert_predicate @difference, :different? + end + + test "#failed? returns true when images have different dimensions" do + assert_predicate @difference, :failed? + end + end +end diff --git a/test/unit/drivers/chunky_png_driver_test.rb b/test/unit/drivers/chunky_png_driver_test.rb new file mode 100644 index 00000000..75d110ab --- /dev/null +++ b/test/unit/drivers/chunky_png_driver_test.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +require "test_helper" +require "capybara/screenshot/diff/image_compare" +require "capybara/screenshot/diff/drivers/chunky_png_driver" + +module Capybara + module Screenshot + module Diff + module Drivers + class ChunkyPNGDriverTest < ActiveSupport::TestCase + include CapybaraScreenshotDiff::DSLStub + + class QuickEqualTest < self + test "#quick_equal? returns true when comparing identical images" do + comp = make_comparison(:a, :a) + assert comp.quick_equal? + end + + test "#quick_equal? respects color_distance_limit setting when images are similar" do + comp = make_comparison(:a, :b, color_distance_limit: 224) + assert comp.quick_equal? + end + end + + class DifferentTest < self + test "#different? returns false when comparing identical images" do + comp = make_comparison(:a, :a) + assert_not comp.different? + end + + test "#different? respects tolerance setting when images differ slightly" do + comp = make_comparison(:a, :b, tolerance: 2) + assert_not comp.different? + assert comp.quick_equal? + end + + test "#different? identifies differences and generates annotated comparison images" do + comp = make_comparison(:a, :c) + assert comp.different? + assert_includes comp.error_message, "[11,3,48,20]" + assert File.exist?(comp.base_image_path) + assert File.exist?(comp.reporter.annotated_base_image_path) + assert File.exist?(comp.reporter.annotated_image_path) + + assert_same_images("a-and-c.diff.png", comp.reporter.annotated_base_image_path) + assert_same_images("c-and-a.diff.png", comp.reporter.annotated_image_path) + end + + test "#different? skips generating annotated images for identical images" do + comp = make_comparison(:c, :c) + assert_not comp.different? + + assert comp.reporter.annotated_base_image_path + assert comp.reporter.annotated_image_path + + assert_not File.exist?(comp.reporter.annotated_base_image_path) + assert_not File.exist?(comp.reporter.annotated_image_path) + end + + test "#different? detects single-pixel width differences between images" do + comp = make_comparison(:a, :d) + assert comp.different? + assert_includes comp.error_message, "[9,6,9,13]" + end + + test "#different? respects shift_distance_limit when within allowed threshold" do + comp = make_comparison(:a, :b, shift_distance_limit: 11) + assert comp.quick_equal? + assert_not comp.different? + end + + test "#different? enforces shift_distance_limit when beyond allowed threshold" do + comp = make_comparison(:a, :b, shift_distance_limit: 9) + assert comp.different? + assert_includes comp.error_message, "11" + end + + test "#different? detects when images have different dimensions" do + comp = make_comparison(:a, :a_cropped) + assert comp.different? + assert_includes comp.error_message, "Dimensions have changed: " + assert_includes comp.error_message, "80x60" + end + end + + class ColorDistanceTest < self + test "#different? respects color_distance_limit when within allowed threshold" do + comp = make_comparison(:a, :b, color_distance_limit: 223) + assert_not comp.different? + end + + test "#different? enforces color_distance_limit when beyond allowed threshold" do + comp = make_comparison(:a, :b, color_distance_limit: 222) + assert comp.different? + assert_includes comp.error_message, "222.7" + end + + test "#max_color_distance returns expected value for images with minor differences" do + comp = make_comparison(:a, :b) + assert_not comp.quick_equal? + comp.different? + assert_includes comp.error_message, "85" + end + + test "#max_color_distance returns expected value for images with moderate differences" do + comp = make_comparison(:a, :c) + comp.different? + assert_includes comp.error_message, "187.4" + end + + test "#max_color_distance returns expected value for images with significant differences" do + comp = make_comparison(:a, :d) + comp.different? + assert_includes comp.error_message, "269.1" + end + + test "#max_color_distance detects minimal color differences between images" do + a_img = ChunkyPNG::Image.from_blob(File.binread("#{TEST_IMAGES_DIR}/a.png")) + a_img[9, 6] += 0x010000 + + comp = make_comparison(:a, :b) + other_img_filename = comp.image_path + a_img.save(other_img_filename) + + comp.different? + + assert_includes comp.error_message, "1" + end + end + + class HelpersTest < self + test "#from_file successfully loads an image from the specified path" do + driver = ChunkyPNGDriver.new + assert driver.from_file("#{TEST_IMAGES_DIR}/a.png") + end + end + + def make_comparison(old_img, new_img, options = {}) + snap = create_snapshot_for(old_img, new_img) + ImageCompare.new(snap.path, snap.base_path, **options) + end + + def sample_region + [0, 0, 0, 0] + end + + def load_test_image(driver) + driver.from_file("#{TEST_IMAGES_DIR}/a.png") + end + end + end + end + end +end diff --git a/test/capybara/screenshot/diff/drivers/utils_test.rb b/test/unit/drivers/utils_test.rb similarity index 73% rename from test/capybara/screenshot/diff/drivers/utils_test.rb rename to test/unit/drivers/utils_test.rb index 84a180bc..fe2bfaec 100644 --- a/test/capybara/screenshot/diff/drivers/utils_test.rb +++ b/test/unit/drivers/utils_test.rb @@ -8,14 +8,14 @@ module Capybara module Screenshot module Diff class UtilsTest < ActiveSupport::TestCase - test "detect_available_drivers add vips when ruby-vips is available" do + test "#detect_available_drivers includes :vips when ruby-vips gem is available" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) Object.stub :require, ->(gem) { gem == "vips" } do assert_includes Utils.detect_available_drivers, :vips end end - test "detect_available_drivers does not add :vips when ruby-vips is unavailable" do + test "#detect_available_drivers excludes :vips when ruby-vips gem is not available" do Object.stub_remove_const(:Vips) do Object.stub :require, ->(gem) { gem != "vips" } do assert_not_includes Utils.detect_available_drivers, :vips @@ -23,7 +23,7 @@ class UtilsTest < ActiveSupport::TestCase end end - test "detect_available_drivers does not add :vips when there is no system libvips installed" do + test "#detect_available_drivers excludes :vips when system libvips is not installed" do Object.stub_remove_const(:Vips) do Object.stub :require, ->(gem) { gem == "vips" && raise(LoadError.new("Could not ... vips")) } do assert_not_includes Utils.detect_available_drivers, :vips @@ -31,7 +31,7 @@ class UtilsTest < ActiveSupport::TestCase end end - test "detect_available_drivers returns vips before chunky_png if both gems are available" do + test "#detect_available_drivers returns drivers in order of preference when multiple are available" do Object.stub_consts(Vips: Class.new, ChunkyPNG: Class.new) do Object.stub :require, true do assert_equal %i[vips chunky_png], Utils.detect_available_drivers @@ -39,13 +39,13 @@ class UtilsTest < ActiveSupport::TestCase end end - test "detect_available_drivers add chunky_png when chunky_png is available" do + test "#detect_available_drivers includes :chunky_png when the gem is available" do Object.stub :require, ->(gem) { gem == "chunky_png" } do assert_includes Utils.detect_available_drivers, :chunky_png end end - test "detect_available_drivers does not add chunky_png when chunky_png is not available" do + test "#detect_available_drivers excludes :chunky_png when the gem is not available" do Object.stub_remove_const(:ChunkyPNG) do Object.stub :require, ->(gem) { gem != "chunky_png" } do assert_not_includes Utils.detect_available_drivers, :chunky_png diff --git a/test/capybara/screenshot/diff/drivers/vips_driver_test.rb b/test/unit/drivers/vips_driver_test.rb similarity index 76% rename from test/capybara/screenshot/diff/drivers/vips_driver_test.rb rename to test/unit/drivers/vips_driver_test.rb index 7a23c927..798ef35c 100644 --- a/test/capybara/screenshot/diff/drivers/vips_driver_test.rb +++ b/test/unit/drivers/vips_driver_test.rb @@ -13,7 +13,7 @@ module Capybara module Screenshot module Diff module Drivers - class VipsDriverTest < ActionDispatch::IntegrationTest + class VipsDriverTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSLStub setup do @@ -30,22 +30,22 @@ class VipsDriverTest < ActionDispatch::IntegrationTest Vips.cache_set_max(1000) end - test "#different? for equal is negative" do + test "#different? returns false when comparing identical images" do comp = make_comparison(:a, :a) assert_not comp.different? end - test "#quick_equal? for equal is positive" do + test "#quick_equal? returns true when comparing identical images" do comp = make_comparison(:a, :a) assert comp.quick_equal? end - test "it can be instantiated" do + test "can be instantiated with default constructor" do assert VipsDriver.new end - test "when different does not clean runtime files" do + test "#different? preserves runtime files when images are different" do comp = make_comparison(:a, :c) assert comp.different? assert_includes comp.error_message, "[11.0,3.0,49.0,21.0]" @@ -54,7 +54,7 @@ class VipsDriverTest < ActionDispatch::IntegrationTest assert File.exist?(comp.reporter.annotated_image_path) end - test "when equal clean runtime files" do + test "#different? cleans up runtime files when images are identical" do comp = make_comparison(:c, :c) assert_not comp.different? @@ -65,64 +65,64 @@ class VipsDriverTest < ActionDispatch::IntegrationTest assert_not File.exist?(comp.reporter.annotated_image_path) end - test "compare of 1 pixel wide diff" do + test "#different? detects single-pixel wide differences between images" do comp = make_comparison(:a, :d) assert comp.different? assert_includes comp.error_message, "[9.0,6.0,10.0,14.0]" end - test "compare with color_distance_limit above difference" do + test "#different? respects color_distance_limit when within allowed threshold" do comp = make_comparison(:a, :b, color_distance_limit: 255) assert_not comp.different? end - test "compare with color_distance_limit below difference" do + test "#different? enforces color_distance_limit when beyond allowed threshold" do comp = make_comparison(:a, :b, color_distance_limit: 3) assert comp.different? end - test "compare with tolerance level more then area of the difference" do + test "#different? returns equal when tolerance is greater than difference area" do comp = make_comparison(:a, :b, tolerance: 0.01) assert comp.quick_equal? assert_not comp.different? assert_not comp.error_message end - test "compare with tolerance level less then area of the difference" do + test "#different? detects difference when tolerance is less than difference area" do comp = make_comparison(:a, :b, tolerance: 0.000001) assert_not comp.quick_equal? assert comp.different? end - test "compare with median_filter_window_size when images have 1px line difference" do + test "#different? handles single-pixel line differences with median filter" do comp = make_comparison(:a, :d, median_filter_window_size: 3, color_distance_limit: 8) assert comp.quick_equal? assert_not comp.different? end - test "quick_equal" do + test "#quick_equal? returns false when images are different" do comp = make_comparison(:a, :b) assert_not comp.quick_equal? end - test "quick_equal with color distance limit below current level" do + test "#quick_equal? respects color_distance_limit when below difference threshold" do comp = make_comparison(:a, :b, color_distance_limit: 2) assert_not comp.quick_equal? end - test "quick_equal with color distance limit above current level" do + test "#quick_equal? respects color_distance_limit when above difference threshold" do comp = make_comparison(:a, :b, color_distance_limit: 200) assert comp.quick_equal? end - test "size a vs a_cropped" do + test "#different? detects dimension changes between images" do comp = make_comparison(:a, :a_cropped) assert comp.different? assert_includes comp.error_message, "Dimensions have changed: " assert_includes comp.error_message, "80x60" end - test "quick_equal compare skips difference if skip_area covers it" do + test "#quick_equal? skips differences covered by skip_area configuration" do comp = make_comparison( :a, :d, @@ -135,7 +135,7 @@ class VipsDriverTest < ActionDispatch::IntegrationTest assert_not comp.different? end - test "quick_equal compare skips difference if skip_area does not cover it" do + test "#quick_equal? detects differences not covered by skip_area" do comp = make_comparison( :a, :d, @@ -150,7 +150,7 @@ class VipsDriverTest < ActionDispatch::IntegrationTest # Test Interface Contracts - test "from_file loads image from path" do + test "#from_file successfully loads an image from the specified path" do assert VipsDriver.new.from_file(TEST_IMAGES_DIR / "a.png") end @@ -167,7 +167,7 @@ def sample_region end class VipsUtilTest < ActiveSupport::TestCase - test "segment difference without min color difference" do + test "VipsUtil.difference_region_by detects difference regions without color threshold" do old_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/a.png") new_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/b.png") @@ -180,7 +180,7 @@ class VipsUtilTest < ActiveSupport::TestCase assert_equal [20.0, 15.0, 30.0, 25.0], [left, top, right, bottom] end - test "segment difference with min color difference" do + test "VipsUtil.difference_region_by respects color_distance threshold" do old_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/a.png") new_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/b.png") @@ -189,7 +189,7 @@ class VipsUtilTest < ActiveSupport::TestCase assert_equal [26.0, 18.0, 27.0, 19.0], [left, top, right, bottom] end - test "segment difference" do + test "VipsUtil.difference_region_by returns correct region coordinates" do old_image = Vips::Image.new_from_file(TEST_IMAGES_DIR.join("a.png").to_path) new_image = Vips::Image.new_from_file(TEST_IMAGES_DIR.join("b.png").to_path) @@ -198,7 +198,7 @@ class VipsUtilTest < ActiveSupport::TestCase assert_equal [20.0, 15.0, 30.0, 25.0], [left, top, right, bottom] end - test "area of the difference" do + test "VipsUtil.difference_area calculates correct area of difference" do old_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/a.png") new_image = Vips::Image.new_from_file("#{TEST_IMAGES_DIR}/d.png").bandjoin(255) diff --git a/test/capybara_screenshot_diff/dsl_test.rb b/test/unit/dsl_test.rb similarity index 67% rename from test/capybara_screenshot_diff/dsl_test.rb rename to test/unit/dsl_test.rb index ee843dd2..4dc58dbb 100644 --- a/test/capybara_screenshot_diff/dsl_test.rb +++ b/test/unit/dsl_test.rb @@ -5,11 +5,24 @@ require "capybara_screenshot_diff/screenshot_assertion" module CapybaraScreenshotDiff - class DSLTest < ActionDispatch::IntegrationTest + class DSLTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSL include CapybaraScreenshotDiff::DSLStub - test "raise error on missing screenshot when fail_if_new is true" do + def before_setup + @original_root = Capybara::Screenshot.root + @new_root = Dir.mktmpdir + Capybara::Screenshot.root = Pathname.new(@new_root) + super + end + + def after_teardown + super + Capybara::Screenshot.root = @original_root + FileUtils.remove_entry(@new_root) if @new_root + end + + test "#screenshot raises error when screenshot is missing and fail_if_new is true" do Capybara::Screenshot::Diff::Vcs.stub(:checkout_vcs, false) do Capybara::Screenshot::Diff.stub(:fail_if_new, true) do assert_raises CapybaraScreenshotDiff::ExpectationNotMet, match: /No existing screenshot found for/ do @@ -19,20 +32,20 @@ class DSLTest < ActionDispatch::IntegrationTest end end - def test_assert_image_not_changed + test "#assert_image_not_changed generates correct error message for image mismatch" do message = assert_image_not_changed(["my_test.rb:42"], "name", make_comparison(:a, :c, destination: "screenshot.png")) value = (RUBY_VERSION >= "2.4") ? 187.4 : 188 assert_equal <<~MSG.chomp, message Screenshot does not match for 'name': ({"area_size":629,"region":[11,3,48,20],"max_color_distance":#{value}}) - #{Rails.root}/doc/screenshots/screenshot.png - #{Rails.root}/doc/screenshots/screenshot.base.diff.png - #{Rails.root}/doc/screenshots/screenshot.diff.png - #{Rails.root}/doc/screenshots/screenshot.heatmap.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.base.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.heatmap.diff.png my_test.rb:42 MSG end - def test_assert_image_not_changed_with_shift_distance_limit + test "#assert_image_not_changed includes shift distance in error message when specified" do message = assert_image_not_changed( ["my_test.rb:42"], "name", @@ -41,15 +54,15 @@ def test_assert_image_not_changed_with_shift_distance_limit value = (RUBY_VERSION >= "2.4") ? 5.0 : 5 assert_equal <<~MSG.chomp, message Screenshot does not match for 'name': ({"area_size":629,"region":[11,3,48,20],"max_color_distance":#{value},"max_shift_distance":15}) - #{Rails.root}/doc/screenshots/screenshot.png - #{Rails.root}/doc/screenshots/screenshot.base.diff.png - #{Rails.root}/doc/screenshots/screenshot.diff.png - #{Rails.root}/doc/screenshots/screenshot.heatmap.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.base.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.diff.png + #{Capybara::Screenshot.root}/doc/screenshots/screenshot.heatmap.diff.png my_test.rb:42 MSG end - def test_screenshot_support_drivers_options + test "#screenshot supports driver options for image comparison" do skip "vips is disabled" unless defined?(Capybara::Screenshot::Diff::Drivers::VipsDriverTest) assert_not screenshot("a", driver: :vips) end @@ -58,7 +71,7 @@ def assert_no_screenshot_jobs_scheduled assert_not_predicate CapybaraScreenshotDiff.registry, :assertions_present? end - def test_skip_stack_frames_with_zero_skip + test "#screenshot with skip_stack_frames: 0 includes our_screenshot in caller" do Capybara::Screenshot::Diff::Vcs.stub(:checkout_vcs, true) do assert_no_screenshot_jobs_scheduled @@ -71,7 +84,7 @@ def test_skip_stack_frames_with_zero_skip end end - def test_skip_stack_frames_with_one_skip + test "#screenshot with skip_stack_frames: 1 includes test method in caller" do Capybara::Screenshot::Diff::Vcs.stub(:checkout_vcs, true) do assert_no_screenshot_jobs_scheduled @@ -80,14 +93,14 @@ def test_skip_stack_frames_with_one_skip our_screenshot(snap.full_name, 1) assert_equal 1, CapybaraScreenshotDiff.assertions.size assert_match( - %r{/dsl_test.rb:.*?test_skip_stack_frames_with_one_skip}, + %r{/dsl_test.rb}, CapybaraScreenshotDiff.assertions[0].caller.first ) assert_equal snap.full_name, CapybaraScreenshotDiff.assertions[0].name end end - def test_inline_screenshot_assertion_validation_with_difference + test "#screenshot with delayed: false raises error when images differ" do Capybara::Screenshot::Diff::Vcs.stub(:checkout_vcs, true) do Capybara::Screenshot::Diff.stub(:delayed, false) do assert_raises(CapybaraScreenshotDiff::ExpectationNotMet) do @@ -98,7 +111,7 @@ def test_inline_screenshot_assertion_validation_with_difference end end - def test_inline_screenshot_assertion_validation_without_difference + test "#screenshot with delayed: false succeeds when images match" do Capybara::Screenshot::Diff::Vcs.stub(:checkout_vcs, true) do Capybara::Screenshot::Diff.stub(:delayed, false) do snap = create_snapshot_for(:a) @@ -107,24 +120,24 @@ def test_inline_screenshot_assertion_validation_without_difference end end - def test_skip_area_and_stability_time_limit + test "#screenshot accepts skip_area and stability_time_limit options" do assert_not screenshot(:a, skip_area: [0, 0, 1, 1], stability_time_limit: 0.01) end - def test_creates_new_screenshot + test "#screenshot creates new screenshot file when it doesn't exist" do screenshot(:c) snap = CapybaraScreenshotDiff::SnapManager.snapshot("c") assert_predicate snap.path, :exist? end - def test_cleanup_base_image_for_no_change + test "#assert_image_not_changed cleans up base image when images are identical" do comparison = make_comparison(:a, :a) assert_image_not_changed(["my_test.rb:42"], "name", comparison) assert_not comparison.base_image_path.exist? end - def test_cleanup_base_image_for_changes + test "#assert_image_not_changed cleans up base image when images differ" do comparison = make_comparison(:a, :b) assert_image_not_changed(["my_test.rb:42"], "name", comparison) assert_not comparison.base_image_path.exist? diff --git a/test/capybara/screenshot/diff/image_compare_test.rb b/test/unit/image_compare_test.rb similarity index 61% rename from test/capybara/screenshot/diff/image_compare_test.rb rename to test/unit/image_compare_test.rb index 95a2b71b..eae37d71 100644 --- a/test/capybara/screenshot/diff/image_compare_test.rb +++ b/test/unit/image_compare_test.rb @@ -12,26 +12,26 @@ module Capybara module Screenshot module Diff - class ImageCompareTest < ActionDispatch::IntegrationTest + class ImageCompareTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSLStub - test "it can be instantiated with chunky_png driver" do + test "#initialize creates instance with chunky_png driver by default" do comparison = make_comparison(:b) assert_kind_of Drivers::ChunkyPNGDriver, comparison.driver end - test "it can be instantiated with explicit chunky_png adapter" do + test "#initialize creates instance with explicit chunky_png driver" do comparison = make_comparison(:b, driver: :chunky_png) assert_kind_of Drivers::ChunkyPNGDriver, comparison.driver end - test "it can be instantiated with vips adapter" do + test "#initialize creates instance with vips driver when specified" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) comparison = make_comparison(:b, driver: :vips) assert_kind_of Drivers::VipsDriver, comparison.driver end - test "for vips it generates annotation files on difference" do + test "#different? with vips driver generates annotated diff images" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) comparison = make_comparison(:a, :b, driver: :vips) @@ -41,7 +41,7 @@ class ImageCompareTest < ActionDispatch::IntegrationTest assert_same_images("b-and-a.diff.png", comparison.reporter.annotated_image_path) end - test "it can handle very long input filenames" do + test "#different? handles very long input filenames with vips driver" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) filename = %w[this-0000000000000000000000000000000000000000000000000-path/is/extremely/ long/and/if/the/directories/are/flattened/in/ @@ -52,32 +52,32 @@ class ImageCompareTest < ActionDispatch::IntegrationTest assert comparison.different? end - test "it can be instantiated with vips adapter and tolerance option" do + test "#initialize with vips driver respects tolerance option" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) comp = make_comparison(:a, :b, driver: :vips, tolerance: 0.02) assert comp.quick_equal? assert_not comp.different? end - test "could pass use tolerance for chunky_png driver" do + test "#initialize with chunky_png driver respects tolerance option" do comp = make_comparison(:a, :b, driver: :chunky_png, tolerance: 0.02) assert comp.quick_equal? assert_not comp.different? end - test "it can be instantiated with dimensions" do + test "#initialize with dimensions creates valid comparison" do comp = make_comparison(:b, dimensions: [80, 80]) assert comp.quick_equal? assert_not comp.different? end - test "for driver: :auto returns first from available drivers" do + test "#initialize with :auto driver selects vips when available" do skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) comparison = make_comparison(:b, driver: :auto) assert_kind_of Drivers::VipsDriver, comparison.driver end - test "for driver: :auto raise error if no drivers are available" do + test "#initialize with :auto driver raises error when no drivers available" do Capybara::Screenshot::Diff.stub_const(:AVAILABLE_DRIVERS, []) do assert_raise(RuntimeError) do comparison = make_comparison(:b, driver: :auto) @@ -87,15 +87,15 @@ class ImageCompareTest < ActionDispatch::IntegrationTest end end - class IntegrationRegressionTest < ActionDispatch::IntegrationTest + class IntegrationRegressionTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSLStub AVAILABLE_DRIVERS = [{}, {driver: :chunky_png}] - test "the same images should be quick equal and not different" do + test "identical images are quick_equal and not different across all drivers" do images = all_fixtures_images_names AVAILABLE_DRIVERS.each do |driver| - Dir.chdir File.expand_path("../../../images", __dir__) do + Dir.chdir File.expand_path("../fixtures/images", __dir__) do images.each do |old_img| new_img = old_img comparison = make_comparison(old_img, new_img, **driver) @@ -112,7 +112,7 @@ class IntegrationRegressionTest < ActionDispatch::IntegrationTest end end - test "the different images should not be quick equal and different" do + test "different images are not quick_equal and are marked as different" do images = all_fixtures_images_names AVAILABLE_DRIVERS.each do |driver| @@ -137,6 +137,55 @@ def all_fixtures_images_names %w[a a_cropped b c d portrait portrait_b] end end + + class ImageCompareRefactorTest < ActiveSupport::TestCase + include CapybaraScreenshotDiff::DSLStub + include TestHelpers + + # Test #quick_equal? method + test "#quick_equal? returns true when comparing identical images" do + comparison = make_comparison(:a, :a) + assert_predicate comparison, :quick_equal? + end + + test "#quick_equal? returns false when comparing different images" do + comparison = make_comparison(:a, :b) + refute_predicate comparison, :quick_equal? + end + + # Test #different? method + test "#different? returns false when comparing identical images" do + comparison = make_comparison(:a, :a) + refute_predicate comparison, :different? + end + + test "#different? returns true when comparing different images" do + comparison = make_comparison(:a, :b) + assert_predicate comparison, :different? + end + + # Test #dimensions_changed? method + test "#dimensions_changed? returns true when images have different dimensions" do + comparison = make_comparison(:portrait, :a) + comparison.processed + + assert_predicate comparison, :dimensions_changed? + assert_kind_of Reporters::Default, comparison.reporter + end + + test "#dimensions_changed? returns false when images have same dimensions" do + comparison = make_comparison(:a, :a) + comparison.processed + + refute_predicate comparison, :dimensions_changed? + end + + # Test reporter configuration + test "#reporter returns Default reporter by default" do + comparison = make_comparison(:a, :a) + assert_kind_of Reporters::Default, comparison.reporter + end + end end end end diff --git a/test/unit/image_preprocessor_test.rb b/test/unit/image_preprocessor_test.rb new file mode 100644 index 00000000..ae1341e9 --- /dev/null +++ b/test/unit/image_preprocessor_test.rb @@ -0,0 +1,92 @@ +# frozen_string_literal: true + +require "test_helper" +require "support/test_doubles" +require "support/test_helpers" + +module Capybara + module Screenshot + module Diff + class ImagePreprocessorTest < ActiveSupport::TestCase + include CapybaraScreenshotDiff::DSLStub + include TestHelpers + + def setup + super + @test_images = [:base_image, :new_image] + @driver = create_test_driver + end + + test "#call returns original images when no preprocessing options are provided" do + preprocessor = ImagePreprocessor.new(@driver, {}) + + result = preprocessor.call(@test_images) + + assert_equal @test_images, result + assert_empty @driver.add_black_box_calls + assert_empty @driver.filter_calls + end + + test "#call applies black box to skip areas when skip_area option is provided" do + skip_area = [{x: 10, y: 20, width: 30, height: 40}] + preprocessor = ImagePreprocessor.new(@driver, skip_area: skip_area) + + result = preprocessor.call(@test_images) + + assert_equal %w[processed_base_image processed_new_image], result + assert_equal 2, @driver.add_black_box_calls.size + + first_call = @driver.add_black_box_calls[0] + second_call = @driver.add_black_box_calls[1] + + assert_equal skip_area.first, first_call[:region] + assert_equal skip_area.first, second_call[:region] + assert_equal :base_image, first_call[:image] + assert_equal :new_image, second_call[:image] + end + + test "#call applies median filter when VipsDriver is available and median_filter_window_size is specified" do + skip "VIPS not present. Skipping VIPS driver tests." unless defined?(Vips) + + @driver = create_test_driver(is_vips: true) + window_size = 3 + options = {median_filter_window_size: window_size} + preprocessor = ImagePreprocessor.new(@driver, options) + + result = preprocessor.call(@test_images) + + assert_equal ["filtered_base_image", "filtered_new_image"], result + assert_equal 2, @driver.filter_calls.size + + first_call = @driver.filter_calls[0] + second_call = @driver.filter_calls[1] + + assert_equal window_size, first_call[:size] + assert_equal window_size, second_call[:size] + assert_equal :base_image, first_call[:image] + assert_equal :new_image, second_call[:image] + end + + test "call warns and skips median filter when VipsDriver is not available" do + window_size = 3 + options = { + median_filter_window_size: window_size, + image_path: "some/path.png" + } + + expected_warning = /Median filter has been skipped for.*because it is not supported/ + + warning_output = capture_io do + preprocessor = ImagePreprocessor.new(@driver, options) + result = preprocessor.call(@test_images) + + assert_equal @test_images, result + assert_empty @driver.filter_calls + end + + assert_match expected_warning, warning_output.join + end + end + end + end +end diff --git a/test/capybara/screenshot/diff/region_test.rb b/test/unit/region_test.rb similarity index 73% rename from test/capybara/screenshot/diff/region_test.rb rename to test/unit/region_test.rb index 494d9e20..9f2068c9 100644 --- a/test/capybara/screenshot/diff/region_test.rb +++ b/test/unit/region_test.rb @@ -4,7 +4,7 @@ module Capybara::Screenshot::Diff class RegionTest < ActiveSupport::TestCase - test "move_by moves region coordinates" do + test "#move_by updates region coordinates by specified deltas" do region = Region.new(10, 10, 10, 10).move_by(-5, -5) assert_equal 5, region.x @@ -13,7 +13,7 @@ class RegionTest < ActiveSupport::TestCase assert_equal 10, region.height end - test "find_intersect" do + test "#find_intersect_with returns intersection with another region" do crop = Region.new(5, 5, 10, 10) region = Region.new(10, 10, 20, 20).find_intersect_with(crop) @@ -23,7 +23,7 @@ class RegionTest < ActiveSupport::TestCase assert_equal 5, region.height end - test "find_relative_intersect finds intersect and returns relative position" do + test "#find_relative_intersect returns intersection with relative coordinates" do crop = Region.new(5, 5, 10, 10) region = crop.find_relative_intersect(Region.new(0, 0, 20, 20)) @@ -41,21 +41,21 @@ class RegionTest < ActiveSupport::TestCase assert_equal 5, region.height end - test ".from_edge_coordinates returns nil for missed coordinates" do + test ".from_edge_coordinates returns nil when right or bottom is nil" do assert_nil Region.from_edge_coordinates(0, 0, nil, nil) end - test ".from_edge_coordinates returns nil for bottom before top and right before left" do + test ".from_edge_coordinates returns nil when region has zero or negative dimensions" do assert_nil Region.from_edge_coordinates(10, 10, 9, 11) assert_nil Region.from_edge_coordinates(10, 10, 11, 9) end - test "#== can compare with Region" do + test "#== returns true when comparing with an identical Region" do assert_equal Region.new(10, 10, 10, 10), Region.new(10, 10, 10, 10) assert_not_equal Region.new(10, 10, 10, 10), Region.new(10, 10, 10, 11) end - test "#== can compare with Array of coordinates" do + test "#== returns true when comparing with equivalent Array of coordinates" do assert_equal Region.new(10, 10, 10, 10), [10, 10, 10, 10] assert_not_equal Region.new(10, 10, 10, 10), [10, 10, 10, 11] end diff --git a/test/capybara/screenshot/diff/reporters/default_test.rb b/test/unit/reporters/default_test.rb similarity index 100% rename from test/capybara/screenshot/diff/reporters/default_test.rb rename to test/unit/reporters/default_test.rb diff --git a/test/capybara_screenshot_diff/screenshot_namer_test.rb b/test/unit/screenshot_namer_test.rb similarity index 95% rename from test/capybara_screenshot_diff/screenshot_namer_test.rb rename to test/unit/screenshot_namer_test.rb index 6ff22e3c..ed65fc03 100644 --- a/test/capybara_screenshot_diff/screenshot_namer_test.rb +++ b/test/unit/screenshot_namer_test.rb @@ -77,7 +77,7 @@ class ScreenshotNamerTest < ActiveSupport::TestCase assert_equal expected_path, @screenshot_namer.full_name_with_path("image_a") end - test "#full_name_with_path with nil screenshot_area" do + test "#full_name_with_path handles nil screenshot_area" do namer_no_area = @screenshot_namer namer_no_area.section = "s" namer_no_area.group = "g" @@ -105,14 +105,14 @@ class ScreenshotNamerTest < ActiveSupport::TestCase assert_equal expected_path, @screenshot_namer.full_name_with_path("new_image") end - test "#full_name_with_path with active group for duplicated name adds counter" do + test "#full_name_with_path adds counter for duplicated names with active group" do @screenshot_namer.group = "user_flow" assert_equal "user_flow/00_step1", @screenshot_namer.full_name("step1") assert_equal "user_flow/01_step1", @screenshot_namer.full_name("step1") assert_equal "user_flow/02_step1", @screenshot_namer.full_name("step1") end - test "#full_name_with_path without active group for duplicated name ignores" do + test "#full_name_with_path ignores duplicate names without active group" do @screenshot_namer.group = nil assert_equal "step1", @screenshot_namer.full_name("step1") assert_equal "step1", @screenshot_namer.full_name("step1") @@ -148,7 +148,7 @@ class ScreenshotNamerTest < ActiveSupport::TestCase assert_not Dir.exist?(dir_path) end - test "#clear_current_group_directory is safe when directory doesn't exist" do + test "#clear_current_group_directory handles non-existent directories" do @screenshot_namer.group = "nonexistent" assert_nothing_raised { @screenshot_namer.clear_current_group_directory } end diff --git a/test/capybara/screenshot/screenshot_test.rb b/test/unit/screenshot_test.rb similarity index 63% rename from test/capybara/screenshot/screenshot_test.rb rename to test/unit/screenshot_test.rb index b2fa1716..718a76a0 100644 --- a/test/capybara/screenshot/screenshot_test.rb +++ b/test/unit/screenshot_test.rb @@ -4,25 +4,25 @@ require "minitest/mock" module Capybara - class ScreenshotTest < ActionDispatch::IntegrationTest - def test_screenshot_area_abs_is_absolute + class ScreenshotTest < ActiveSupport::TestCase + test "SnapManager.root returns an absolute path" do assert CapybaraScreenshotDiff::SnapManager.root.absolute? end - def test_root_is_a_pathname + test "Screenshot.root returns a Pathname when Rails.root is a Pathname" do # NOTE: We test that Rails.root is Pathname, which is true. assert_kind_of Pathname, Capybara::Screenshot.root assert Capybara::Screenshot.root.absolute? end - def test_root_could_be_assigned_relative_path + test "Screenshot.root can be set to a relative path and is converted to absolute" do @orig_root = Capybara::Screenshot.root Capybara::Screenshot.root = "./tmp" assert_kind_of Pathname, Capybara::Screenshot.root assert Capybara::Screenshot.root.absolute? ensure - Capybara::Screenshot.root = @orig_root + Capybara::Screenshot.root = @orig_root if @orig_root end end end diff --git a/test/capybara/screenshot/diff/screenshoter_test.rb b/test/unit/screenshoter_test.rb similarity index 96% rename from test/capybara/screenshot/diff/screenshoter_test.rb rename to test/unit/screenshoter_test.rb index 0c76ae2c..6a44b77b 100644 --- a/test/capybara/screenshot/diff/screenshoter_test.rb +++ b/test/unit/screenshoter_test.rb @@ -5,7 +5,7 @@ module Capybara module Screenshot - class ScreenshoterTest < ActionDispatch::IntegrationTest + class ScreenshoterTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSL include CapybaraScreenshotDiff::DSLStub diff --git a/test/capybara_screenshot_diff/snap_manager_test.rb b/test/unit/snap_manager_test.rb similarity index 100% rename from test/capybara_screenshot_diff/snap_manager_test.rb rename to test/unit/snap_manager_test.rb diff --git a/test/capybara/screenshot/diff/stable_screenshoter_test.rb b/test/unit/stable_screenshoter_test.rb similarity index 88% rename from test/capybara/screenshot/diff/stable_screenshoter_test.rb rename to test/unit/stable_screenshoter_test.rb index 26f4001d..391b39dd 100644 --- a/test/capybara/screenshot/diff/stable_screenshoter_test.rb +++ b/test/unit/stable_screenshoter_test.rb @@ -5,7 +5,7 @@ module Capybara module Screenshot module Diff - class StableScreenshoterTest < ActionDispatch::IntegrationTest + class StableScreenshoterTest < ActiveSupport::TestCase include CapybaraScreenshotDiff::DSLStub setup do @@ -17,7 +17,7 @@ class StableScreenshoterTest < ActionDispatch::IntegrationTest @manager.cleanup! end - test "#take_stable_screenshot several iterations to take stable screenshot" do + test "#take_stable_screenshot retries until images are stable across iterations" do image_compare_stub = build_image_compare_stub mock = ::Minitest::Mock.new(image_compare_stub) @@ -34,19 +34,19 @@ class StableScreenshoterTest < ActionDispatch::IntegrationTest assert mock.verify end - test "#take_stable_screenshot without wait raises any error" do + test "#take_stable_screenshot raises ArgumentError when wait parameter is nil" do assert_raises ArgumentError, "wait should be provided" do take_stable_screenshot_with(@manager.snapshot("02_a"), wait: nil) end end - test "#take_stable_screenshot without stability_time_limit raises any error" do + test "#take_stable_screenshot raises ArgumentError when stability_time_limit is nil" do assert_raises ArgumentError, "stability_time_limit should be provided" do take_stable_screenshot_with(@manager.snapshot("02_a"), stability_time_limit: nil) end end - test "#take_comparison_screenshot deletes runtime files on completion" do + test "#take_comparison_screenshot cleans up temporary files after successful comparison" do image_compare_stub = build_image_compare_stub mock = ::Minitest::Mock.new(image_compare_stub) @@ -68,7 +68,7 @@ class StableScreenshoterTest < ActionDispatch::IntegrationTest assert_not_predicate snap.path.size, :zero? end - test "#take_comparison_screenshot fail on missing find stable image in time and generates annotated history screenshots" do + test "#take_comparison_screenshot raises UnstableImage when stability timeout is reached" do snap = @manager.snapshot("01_a") screenshot_path = snap.path diff --git a/test/capybara/screenshot/diff/vcs_test.rb b/test/unit/vcs_test.rb similarity index 79% rename from test/capybara/screenshot/diff/vcs_test.rb rename to test/unit/vcs_test.rb index 7e888280..e0794a43 100644 --- a/test/capybara/screenshot/diff/vcs_test.rb +++ b/test/unit/vcs_test.rb @@ -5,7 +5,7 @@ module Capybara module Screenshot module Diff - class VcsTest < ActionDispatch::IntegrationTest + class VcsTest < ActiveSupport::TestCase include Vcs setup do @@ -19,8 +19,8 @@ class VcsTest < ActionDispatch::IntegrationTest end end - test "checkout of original screenshot" do - screenshot_path = Screenshot.root / "../test/images/a.png" + test "#restore_git_revision checks out and verifies the original screenshot" do + screenshot_path = file_fixture("images/a.png") base_screenshot_path = Pathname.new(@base_screenshot.path) assert Vcs.restore_git_revision(screenshot_path, base_screenshot_path, root: Screenshot.root)