require 'spec/runner/formatter/html_formatter'
require 'win32/screenshot'
require 'rmagick'
require 'pathname'
require 'fileutils'
module WatirSplash
# Custom RSpec formatter for WatirSplash
# * saves screenshot of the browser upon test failure
# * saves html of the browser upon test failure
# * saves javascript error dialog upon test failure
# * saves all files generated/downloaded during the test and shows them in the report
class HtmlFormatter < ::Spec::Runner::Formatter::HtmlFormatter
# currently used browser object
# needed for saving of screenshots and html
attr_writer :browser
def initialize(options, output) # :nodoc:
raise "output has to be a file path!" unless output.is_a?(String)
@output_dir = File.expand_path(File.dirname(output))
archive_results
puts "Results will be saved into the directory #{@output_dir}"
@files_dir = File.join(@output_dir, "files")
FileUtils.mkdir_p(@files_dir)
@files_saved_during_example = []
super
end
def example_group_started(example_group) # :nodoc:
@files_saved_during_example.clear
super
end
def example_started(example) # :nodoc:
@files_saved_during_example.clear
example.description << " (#{Time.now.strftime("%H:%M %d.%m")})"
super
end
def extra_failure_content(failure) # :nodoc:
if @browser.exists?
save_javascript_error
save_html
save_screenshot
end
content = []
content << ""
@files_saved_during_example.each {|f| content << link_for(f)}
content << ""
super + content.join($/)
end
def link_for(file) # :nodoc:
return unless File.exists?(file[:path])
description = file[:desc] ? file[:desc] : File.extname(file[:path]).upcase[1..-1]
path = Pathname.new(file[:path])
"#{description} "
end
def save_html # :nodoc:
begin
html = @browser.html
file_name = file_path("browser.html")
File.open(file_name, 'w') {|f| f.puts html}
rescue => e
$stderr.puts "saving of html failed: #{e.message}"
end
file_name
end
def save_screenshot(description="Screenshot", hwnd=nil) # :nodoc:
begin
hwnd ||= @browser.hwnd
@browser.bring_to_front
Win32::Screenshot.hwnd(hwnd) do |width, height, blob|
file_name = file_path("screenshot.png", description)
img = Magick::ImageList.new
img.from_blob(blob)
img.write(file_name)
end
rescue => e
$stderr.puts "saving of screenshot failed: #{e.message}"
end
file_name
end
def save_javascript_error # :nodoc:
file_name = nil
begin
if @browser.is_a?(Watir::IE) && @browser.status =~ /Error on page/
autoit = Watir::autoit
autoit.AutoItSetOption("MouseCoordMode", 0)
autoit.ControlClick("[TITLE:#{@browser.title}]", "", "[CLASS:msctls_statusbar32]", "left", 2)
popup_title = "[REGEXPTITLE:^(Windows )?Internet Explorer$]"
autoit.WinWait(popup_title, "", 10)
file_name = save_screenshot("JS_Error", autoit.WinGetHandle(popup_title).hex)
autoit.WinClose(popup_title)
end
rescue => e
$stderr.puts "saving of javascript error failed: #{e.message}"
end
file_name
end
# Generates unique file name and path for each example.
#
# All file names generated with this method will be shown
# on the report.
def file_path(file_name, description=nil)
extension = File.extname(file_name)
basename = File.basename(file_name, extension)
file_path = File.join(@files_dir, "#{basename}_#{Time.now.strftime("%H%M%S")}_#{example_group_number}_#{example_number}#{extension}")
@files_saved_during_example.unshift(:desc => description, :path => file_path)
file_path
end
private
def archive_results
if File.exists?(@output_dir)
archive_dir = File.join(@output_dir, "../archive")
FileUtils.mkdir_p(archive_dir) unless File.exists?(archive_dir)
FileUtils.mv @output_dir, File.join(archive_dir, "#{File.basename(@output_dir)}_#{File.mtime(@output_dir).strftime("%y%m%d_%H%M%S")}")
end
end
end
end