Add code to save the HTML of the page being screenshotted during the take_screenshot method

that is enabled by a new environment variable - RAILS_SYSTEM_TESTING_SCREENSHOT_HTML=1

Add the ability to call `take_screenshot` more than once in a single test by prefixing the name of
the image file with a counter that is incremented on every `take_screenshot` call.  This allows a
developer to see their pages in sequence when trying to debug test errors.  This does not affect
the failure case where the prefix remains 'failures'
This commit is contained in:
Tom Fakes 2019-06-23 19:41:30 -07:00
parent f6db8b8d82
commit c699a877ca
3 changed files with 110 additions and 30 deletions

@ -1,3 +1,12 @@
* Allow system test screen shots to be taken more than once in
a test by prefixing the file name with an incrementing counter.
Add an environment variable `RAILS_SYSTEM_TESTING_SCREENSHOT_HTML` to
enable saving of HTML during a screenshot in addition to the image.
This uses the same image name, with the extension replaced with `.html`
*Tom Fakes*
* Keep part when scope option has value.
When a route was defined within an optional scope, if that route didn't

@ -9,10 +9,16 @@ module ScreenshotHelper
#
# +take_screenshot+ can be used at any point in your system tests to take
# a screenshot of the current state. This can be useful for debugging or
# automating visual testing.
# automating visual testing. You can take multiple screenshots per test
# to investigate changes at different points during your test. These will be
# named with a sequential prefix (or 'failed' for failing tests)
#
# The screenshot will be displayed in your console, if supported.
#
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT_HTML+ environment variable to
# save the HTML from the page that is being screenhoted so you can investigate the
# elements on the page at the time of the screenshot
#
# You can set the +RAILS_SYSTEM_TESTING_SCREENSHOT+ environment variable to
# control the output. Possible values are:
# * [+simple+ (default)] Only displays the screenshot path.
@ -22,6 +28,8 @@ module ScreenshotHelper
# * [+artifact+] Display the screenshot in the terminal, using the terminal
# artifact format (https://buildkite.github.io/terminal-to-html/inline-images/).
def take_screenshot
increment_unique
save_html if save_html?
save_image
puts display_image
end
@ -38,17 +46,48 @@ def take_failed_screenshot
end
private
attr_accessor :_screenshot_counter
def save_html?
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] == "1"
end
def increment_unique
@_screenshot_counter ||= 0
@_screenshot_counter += 1
end
def unique
failed? ? "failures" : (_screenshot_counter || 0).to_s
end
def image_name
name = method_name[0...225]
failed? ? "failures_#{name}" : name
name = "#{unique}_#{method_name}"
name[0...225]
end
def image_path
@image_path ||= absolute_image_path.to_s
absolute_image_path.to_s
end
def html_path
absolute_html_path.to_s
end
def absolute_path
Rails.root.join("tmp/screenshots/#{image_name}")
end
def absolute_image_path
Rails.root.join("tmp/screenshots/#{image_name}.png")
"#{absolute_path}.png"
end
def absolute_html_path
"#{absolute_path}.html"
end
def save_html
page.save_page(absolute_html_path)
end
def save_image
@ -66,7 +105,8 @@ def output_type
end
def display_image
message = +"[Screenshot]: #{image_path}\n"
message = +"[Screenshot Image]: #{image_path}\n"
message << +"[Screenshot HTML]: #{html_path}\n" if save_html?
case output_type
when "artifact"

@ -6,60 +6,93 @@
require "selenium/webdriver"
class ScreenshotHelperTest < ActiveSupport::TestCase
def setup
@new_test = DrivenBySeleniumWithChrome.new("x")
@new_test.send("_screenshot_counter=", nil)
end
test "image path is saved in tmp directory" do
new_test = DrivenBySeleniumWithChrome.new("x")
Rails.stub :root, Pathname.getwd do
assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
end
end
test "image path unique counter is changed when incremented" do
@new_test.send(:increment_unique)
Rails.stub :root, Pathname.getwd do
assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
end
end
# To allow multiple screenshots in same test
test "image path unique counter generates different path in same test" do
Rails.stub :root, Pathname.getwd do
@new_test.send(:increment_unique)
assert_equal Rails.root.join("tmp/screenshots/1_x.png").to_s, @new_test.send(:image_path)
@new_test.send(:increment_unique)
assert_equal Rails.root.join("tmp/screenshots/2_x.png").to_s, @new_test.send(:image_path)
end
end
test "image path includes failures text if test did not pass" do
new_test = DrivenBySeleniumWithChrome.new("x")
Rails.stub :root, Pathname.getwd do
new_test.stub :passed?, false do
assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, new_test.send(:image_path)
@new_test.stub :passed?, false do
assert_equal Rails.root.join("tmp/screenshots/failures_x.png").to_s, @new_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/failures_x.html").to_s, @new_test.send(:html_path)
end
end
end
test "image path does not include failures text if test skipped" do
new_test = DrivenBySeleniumWithChrome.new("x")
Rails.stub :root, Pathname.getwd do
new_test.stub :passed?, false do
new_test.stub :skipped?, true do
assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
@new_test.stub :passed?, false do
@new_test.stub :skipped?, true do
assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/0_x.html").to_s, @new_test.send(:html_path)
end
end
end
end
test "image name truncates names over 225 characters" do
new_test = DrivenBySeleniumWithChrome.new("x" * 400)
test "image name truncates names over 225 characters including counter" do
long_test = DrivenBySeleniumWithChrome.new("x" * 400)
Rails.stub :root, Pathname.getwd do
assert_equal Rails.root.join("tmp/screenshots/#{"x" * 225}.png").to_s, new_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.png").to_s, long_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/0_#{"x" * 223}.html").to_s, long_test.send(:html_path)
end
end
test "defaults to simple output for the screenshot" do
new_test = DrivenBySeleniumWithChrome.new("x")
assert_equal "simple", new_test.send(:output_type)
assert_equal "simple", @new_test.send(:output_type)
end
test "display_image return html path when RAILS_SYSTEM_TESTING_SCREENSHOT_HTML environment" do
original_html_setting = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"]
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = "1"
assert @new_test.send(:save_html?)
Rails.stub :root, Pathname.getwd do
@new_test.stub :passed?, false do
assert_match %r|\[Screenshot HTML\].+?tmp/screenshots/failures_x\.html|, @new_test.send(:display_image)
end
end
ensure
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT_HTML"] = original_html_setting
end
test "display_image return artifact format when specify RAILS_SYSTEM_TESTING_SCREENSHOT environment" do
original_output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"]
ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = "artifact"
new_test = DrivenBySeleniumWithChrome.new("x")
assert_equal "artifact", new_test.send(:output_type)
assert_equal "artifact", @new_test.send(:output_type)
Rails.stub :root, Pathname.getwd do
new_test.stub :passed?, false do
assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, new_test.send(:display_image)
@new_test.stub :passed?, false do
assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, @new_test.send(:display_image)
end
end
ensure
@ -67,10 +100,8 @@ class ScreenshotHelperTest < ActiveSupport::TestCase
end
test "image path returns the absolute path from root" do
new_test = DrivenBySeleniumWithChrome.new("x")
Rails.stub :root, Pathname.getwd.join("..") do
assert_equal Rails.root.join("tmp/screenshots/x.png").to_s, new_test.send(:image_path)
assert_equal Rails.root.join("tmp/screenshots/0_x.png").to_s, @new_test.send(:image_path)
end
end
end