Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 160 additions & 0 deletions test/support/driver_contract_tests.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,165 @@ module DriverContractTests
assert_not File.exist?(comp.reporter.annotated_base_image_path)
assert_not File.exist?(comp.reporter.annotated_image_path)
end

# Method presence / signature --------------------------------------------
# Pins the current de-facto driver interface so a v2 refactor (inheritance
# -> mixin, class renames) has a regression net. See dissent #4 in the v2
# architecture design: method NAMES are intentionally out of scope here.

test "[contract] driver implements the shared driver interface" do
driver = make_comparison(:a, :a).driver

%i[
load_images add_black_box find_difference_region crop from_file
save_image_to resize_image_to draw_rectangles same_pixels?
same_dimension? height_for width_for image_area_size dimension supports?
].each do |method_name|
assert_respond_to driver, method_name, "driver should implement ##{method_name}"
end
end

test "[contract] #find_difference_region, #same_pixels?, and #same_dimension? each take a single comparison argument" do
driver = make_comparison(:a, :a).driver

assert_equal 1, driver.method(:find_difference_region).arity
assert_equal 1, driver.method(:same_pixels?).arity
assert_equal 1, driver.method(:same_dimension?).arity
end

test "[contract] #load_images takes exactly the old and new file paths" do
driver = make_comparison(:a, :a).driver
assert_equal 2, driver.method(:load_images).arity
end

# load_images -------------------------------------------------------------

test "[contract] #load_images loads both images from disk in (old, new) order" do
driver = make_comparison(:a, :a).driver

old_image, new_image = driver.load_images(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "b.png")

assert_not_nil old_image
assert_not_nil new_image
assert_equal driver.dimension(old_image), driver.dimension(new_image)
end
Comment on lines +72 to +80

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (testing): The #load_images contract test claims to verify (old, new) ordering but only asserts that both returned images are non-nil and have equal dimensions. Because fixtures a.png and b.png share dimensions, an implementation that returns the images in reverse order passes this test silently.

Triggers: When a driver regresses by swapping the old and new images returned from load_images.

Suggested fix: Assert the returned image contents against the corresponding fixture, not just their dimensions.


# find_difference_region result shape --------------------------------------

test "[contract] different? exposes a Difference with a region, meta hash, and the comparison" do
comp = make_comparison(:a, :c)
assert comp.different?

difference = comp.difference
assert_kind_of Capybara::Screenshot::Diff::Difference, difference
assert_not_nil difference.region
assert_kind_of Hash, difference.meta
assert_equal comp.driver, difference.comparison.driver
end

# Dimension handling --------------------------------------------------------

test "[contract] #same_dimension? returns true when images share dimensions" do
driver = make_comparison(:a, :a).driver
old_image, new_image = driver.load_images(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "b.png")
comparison = Capybara::Screenshot::Diff::Comparison.new(new_image, old_image, {}, driver)

assert driver.same_dimension?(comparison)
end

test "[contract] #same_dimension? returns false when images differ in dimensions" do
driver = make_comparison(:a, :a).driver
old_image, new_image = driver.load_images(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "a_cropped.png")
comparison = Capybara::Screenshot::Diff::Comparison.new(new_image, old_image, {}, driver)

assert_not driver.same_dimension?(comparison)
end

test "[contract] #width_for, #height_for, #dimension, and #image_area_size agree with each other" do
driver = make_comparison(:a, :a).driver
image = driver.from_file(TEST_IMAGES_DIR / "a.png")

assert_equal [driver.width_for(image), driver.height_for(image)], driver.dimension(image)
assert_equal driver.width_for(image) * driver.height_for(image), driver.image_area_size(image)
end

# Same-image fast paths -------------------------------------------------

test "[contract] #same_pixels? returns true for pixel-identical images and false otherwise" do
driver = make_comparison(:a, :a).driver

old_image, new_image = driver.load_images(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "a.png")
same_comparison = Capybara::Screenshot::Diff::Comparison.new(new_image, old_image, {}, driver)
assert driver.same_pixels?(same_comparison)

other_old_image, other_new_image = driver.load_images(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "c.png")
different_comparison = Capybara::Screenshot::Diff::Comparison.new(other_new_image, other_old_image, {}, driver)
assert_not driver.same_pixels?(different_comparison)
end

# Option handling -----------------------------------------------------------
# tolerance/color_distance_limit/skip_area are supported identically by both
# drivers today; thresholds below are chosen with headroom on both drivers'
# actual measurements for the a/b and a/d fixture pairs.

test "[contract] tolerance option treats small differences as equal" do
comp = make_comparison(:a, :b, tolerance: 0.5)
assert_not comp.different?
end

test "[contract] tolerance option still flags differences exceeding the ratio" do
comp = make_comparison(:a, :b, tolerance: 0.001)
assert comp.different?
end

test "[contract] color_distance_limit option treats close colors as equal" do
comp = make_comparison(:a, :b, color_distance_limit: 255)
assert_not comp.different?
end

test "[contract] color_distance_limit option still flags colors beyond the limit" do
comp = make_comparison(:a, :b, color_distance_limit: 1)
assert comp.different?
end

test "[contract] skip_area option excludes covered regions from comparison" do
comp = make_comparison(
:a,
:d,
skip_area: [
Region.from_edge_coordinates(9, 0, 11, 80),
Region.from_edge_coordinates(79, 79, 80, 80)
]
)
assert_not comp.different?
end

test "[contract] skip_area option still detects differences outside the skipped regions" do
comp = make_comparison(
:a,
:d,
skip_area: [
Region.from_edge_coordinates(79, 79, 80, 80),
Region.from_edge_coordinates(78, 78, 80, 80)
]
)
assert comp.different?
end

# Error behavior on missing files --------------------------------------------

test "[contract] raises ArgumentError when the base (original) image is missing" do
error = assert_raises(ArgumentError) do
Capybara::Screenshot::Diff::ImageCompare.new(TEST_IMAGES_DIR / "a.png", TEST_IMAGES_DIR / "does_not_exist.png")
end
assert_match(/no original \(base\) screenshot/, error.message)
end

test "[contract] raises ArgumentError when the new image is missing" do
error = assert_raises(ArgumentError) do
Capybara::Screenshot::Diff::ImageCompare.new(TEST_IMAGES_DIR / "does_not_exist.png", TEST_IMAGES_DIR / "a.png")
end
assert_match(/no new screenshot/, error.message)
end
end
end
Loading