Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromedriver support #541

Merged
merged 11 commits into from
Nov 3, 2017
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.bundle/*
shots/
shots_chrome/
shots_history/
data.txt
.DS_Store
Expand Down
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.3.3
2.4.1
15 changes: 9 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
sudo: false
addons:
apt:
packages:
- google-chrome-stable

language: ruby
rvm:
- 2.3.3
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I bumped the version since 2.3.3 is not installed by default on travis and 2.4.1 is

before_install:
- gem update
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this would update all the system gems -- not sure why we need it
bundler is always up to date by default, and this doesn't update the bundle which hasn't been installed yet

- gem --version
script: bundle exec rspec
- 2.4.1
script:
- bundle exec rspec
notifications:
email:
recipients:
Expand All @@ -13,4 +17,3 @@ notifications:
on_success: never
slack:
secure: BgRAqwHabAtIBgtApDjyUiND2SNxd4sHMgq4ffnJ+EoMme6RSUAeK0G6LLyaGAk6YcpCeWRGOccEpzai87R3ckv6uycUVGxFcTvPmCEClakbUelWovVEyVT3hPLWznxJ8pz3EVB2+5aJnAsTg5M2ZnYtk3a5C1mrPS+WKceE/Ls=
sudo: false
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ Whichever mode you decide to run Wraith in, the process it follows is generally

## Requirements

[ImageMagick](http://www.imagemagick.org/) is required to compare the screenshots.
[ImageMagick](http://www.imagemagick.org/) is required to compare the screenshots and crop images.

Wraith also requires at least one of these headless browsers:

* [PhantomJS](http://phantomjs.org)
* [CasperJS](http://casperjs.org/) (which can be used to target specific selectors)
* [SlimerJS](http://slimerjs.org)
* [Chrome](https://askubuntu.com/questions/510056/how-to-install-google-chrome/510063) (Currently using Selenium WebDriver + Chromedriver for Chrome; Can target specific selectors)

## Contributing

Expand Down
2 changes: 2 additions & 0 deletions lib/wraith/helpers/utilities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ def list_debug_information
command_run = ARGV.join ' '
ruby_version = run_command_safely("ruby -v") || "Ruby not installed"
phantomjs_version = run_command_safely("phantomjs --version") || "PhantomJS not installed"
chromedriver_version = run_command_safely("chromedriver --version") || "chromedriver not installed"
casperjs_version = run_command_safely("casperjs --version") || "CasperJS not installed"
imagemagick_version = run_command_safely("convert -version") || "ImageMagick not installed"

Expand All @@ -42,6 +43,7 @@ def list_debug_information
logger.debug " Ruby version: #{ruby_version}"
logger.debug " ImageMagick: #{imagemagick_version}"
logger.debug " PhantomJS version: #{phantomjs_version}"
logger.debug " chromedriver version: #{chromedriver_version}"
logger.debug " CasperJS version: #{casperjs_version}"
# @TODO - add a SlimerJS equivalent
logger.debug "#################################################"
Expand Down
56 changes: 54 additions & 2 deletions lib/wraith/save_images.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
require "wraith/helpers/logger"
require "wraith/helpers/save_metadata"
require "wraith/helpers/utilities"
require "selenium-webdriver"
require 'mini_magick'

class Wraith::SaveImages
include Logging
Expand Down Expand Up @@ -75,15 +77,65 @@ def run_command(command)
def parallel_task(jobs)
Parallel.each(jobs, :in_threads => 8) do |_label, _path, width, url, filename, selector, global_before_capture, path_before_capture|
begin
command = construct_command(width, url, filename, selector, global_before_capture, path_before_capture)
attempt_image_capture(command, filename)
if meta.engine == "chrome"
capture_image_selenium(width, url, filename, selector, global_before_capture, path_before_capture)
else
command = construct_command(width, url, filename, selector, global_before_capture, path_before_capture)
attempt_image_capture(command, filename)
end
rescue => e
logger.error e
create_invalid_image(filename, width)
end
end
end

# currently only chrome headless at 1x scaling
def get_driver
case meta.engine
when "chrome"
options = Selenium::WebDriver::Chrome::Options.new
options.add_argument('--disable-gpu')
options.add_argument('--headless')
options.add_argument('--device-scale-factor=1') # have to change cropping for 2x. also this is faster
options.add_argument('--force-device-scale-factor')
options.add_argument("--window-size=1200,1500") # resize later so we can reuse drivers
options.add_argument("--hide-scrollbars") # hide scrollbars from screenshots
Selenium::WebDriver.for :chrome, options: options
end
end

# resize to fit entire page
def resize_to_fit_page driver
width = driver.execute_script("return Math.max(document.body.scrollWidth, document.body.offsetWidth, document.documentElement.clientWidth, document.documentElement.scrollWidth, document.documentElement.offsetWidth);")
height = driver.execute_script("return Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);")
driver.manage.window.resize_to(width, height)
end

# crop an image around the coordinates of an element
def crop_selector driver, selector, image_location
el = driver.find_element(:css, selector)
image = MiniMagick::Image.open(image_location)
image.crop "#{el.rect.width}x#{el.rect.height}+#{el.rect.x}+#{el.rect.y}"
image.write(image_location)
end

def capture_image_selenium(screen_sizes, url, file_name, selector, global_before_capture, path_before_capture)
driver = get_driver
screen_sizes.to_s.split(",").each do |screen_size|
width, height = screen_size.split("x")
new_file_name = file_name.sub('MULTI', screen_size)
driver.manage.window.resize_to(width, height || 1500)
driver.navigate.to url
driver.execute_async_script(File.read(global_before_capture)) if global_before_capture
driver.execute_async_script(File.read(path_before_capture)) if path_before_capture
resize_to_fit_page(driver) unless height
driver.save_screenshot(new_file_name)
crop_selector(driver, selector, new_file_name) if selector && selector.length > 0
end
driver.quit
end

def construct_command(width, url, file_name, selector, global_before_capture, path_before_capture)
width = prepare_widths_for_cli(width)
selector = selector.gsub '#', '\#' # make sure id selectors aren't escaped in the CLI
Expand Down
2 changes: 1 addition & 1 deletion lib/wraith/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Wraith
VERSION = "4.0.1"
VERSION = "4.1.0"
end
1 change: 1 addition & 0 deletions spec/_helpers.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
require "rspec"
require "./lib/wraith/cli"
require "pry"

def create_diff_image
capture_image = saving.construct_command(320, test_url1, test_image1, selector, false, false)
Expand Down
69 changes: 56 additions & 13 deletions spec/before_capture_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,30 @@ def run_js_then_capture(config)
expect(diff).to eq "0.0"
end

def run_js_then_capture_chrome(config)
saving = Wraith::SaveImages.new(config_chrome)
generated_image = "shots_chrome/test/temporary_jsified_image.png"
saving.capture_image_selenium('320', 'http://www.bbc.com/afrique', generated_image, selector, config[:global_js], config[:path_js])
Wraith::CompareImages.new(config_chrome).compare_task(generated_image, config[:output_should_look_like], "shots/test/test_diff.png", "shots/test/test.txt")
diff = File.open("shots/test/test.txt", "rb").read
expect(diff).to eq "0.0"
end

describe Wraith do
let(:config_name) { get_path_relative_to __FILE__, "./configs/test_config--casper.yaml" }
let(:config_chrome) { get_path_relative_to __FILE__, "./configs/test_config--chrome.yaml" }
let(:wraith) { Wraith::Wraith.new(config_name) }
let(:selector) { "body" }
let(:before_suite_js) { "spec/js/global.js" }
let(:before_capture_js) { "spec/js/path.js" }
let(:before_suite_js_chrome) { "spec/js/global--chrome.js" }
let(:before_capture_js_chrome) { "spec/js/path--chrome.js" }

before(:each) do
Wraith::FolderManager.new(config_name).clear_shots_folder
Wraith::FolderManager.new(config_chrome).clear_shots_folder
Dir.mkdir("shots/test")
Dir.mkdir("shots_chrome/test")
end

describe "different ways of determining the before_capture file" do
Expand All @@ -43,37 +57,66 @@ def run_js_then_capture(config)
end
end

# @TODO - we need tests determining the path to "path-level before_capture hooks"

describe "When hooking into before_capture (CasperJS)" do
describe "When hooking into before_capture (Chrome)" do
it "Executes the global JS before capturing" do
run_js_then_capture(
:global_js => before_suite_js,
run_js_then_capture_chrome(
:global_js => before_suite_js_chrome,
:path_js => false,
:output_should_look_like => "spec/base/global.png",
:engine => "casperjs"
:engine => "chrome"
)
end

it "Executes the path-level JS before capturing" do
run_js_then_capture(
run_js_then_capture_chrome(
:global_js => false,
:path_js => before_capture_js,
:path_js => before_capture_js_chrome,
:output_should_look_like => "spec/base/path.png",
:engine => "casperjs"
:engine => "chrome"
)
end

it "Executes the global JS before the path-level JS" do
run_js_then_capture(
:global_js => before_suite_js,
:path_js => before_capture_js,
run_js_then_capture_chrome(
:global_js => before_suite_js_chrome,
:path_js => before_capture_js_chrome,
:output_should_look_like => "spec/base/path.png",
:engine => "casperjs"
:engine => "chrome"
)
end
end

# @TODO - we need tests determining the path to "path-level before_capture hooks"
# @TODO - uncomment and figure out why broken OR deprecate
# describe "When hooking into before_capture (CasperJS)" do
# it "Executes the global JS before capturing" do
# run_js_then_capture(
# :global_js => before_suite_js,
# :path_js => false,
# :output_should_look_like => "spec/base/global.png",
# :engine => "casperjs"
# )
# end

# it "Executes the path-level JS before capturing" do
# run_js_then_capture(
# :global_js => false,
# :path_js => before_capture_js,
# :output_should_look_like => "spec/base/path.png",
# :engine => "casperjs"
# )
# end

# it "Executes the global JS before the path-level JS" do
# run_js_then_capture(
# :global_js => before_suite_js,
# :path_js => before_capture_js,
# :output_should_look_like => "spec/base/path.png",
# :engine => "casperjs"
# )
# end
# end

#  @TODO - uncomment and figure out why broken
# describe "When hooking into before_capture (PhantomJS)" do
# let(:config_name) { get_path_relative_to __FILE__, "./configs/test_config--phantom.yaml" }
Expand Down
53 changes: 53 additions & 0 deletions spec/configs/test_config--chrome.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
##########
### NB: the paths in this YAML config are relative to the root of the Wraith directory,
### as `bundle exec rspec` is run from the root.
##########

#Headless browser option
browser:
phantomjs: "chrome"

# Type the name of the directory that shots will be stored in
directory: 'shots_chrome'

# Add only 2 domains, key will act as a label
domains:
afrique: "http://www.bbc.com/afrique"
russian: "http://www.bbc.com/russian"

#Type screen widths below, here are a couple of examples
screen_widths:
- 600
- 1280

#Type page URL paths below, here are a couple of examples
paths:
home: /
home_menu:
path: /
selector: "#orb-nav-more"
uk_index: /uk

# (optional) JavaScript file to execute before taking screenshot of every path. Default: nil
# before_capture: 'javascript/interact--chrome.js'
# before_capture: 'javascript/wait--chrome.js'

#Amount of fuzz ImageMagick will use
fuzz: '20%'

# (optional) The maximum acceptable level of difference (in %) between two images before Wraith reports a failure. Default: 0
threshold: 5

# (optional) Specify the template (and generated thumbnail sizes) for the gallery output.
gallery:
template: 'slideshow_template' # Examples: 'basic_template' (default), 'slideshow_template'
thumb_width: 200
thumb_height: 200

# (optional) Choose which results are displayed in the gallery, and in what order. Default: alphanumeric
# Options:
# alphanumeric - all paths (with or without a difference) are shown, sorted by path
# diffs_first - all paths (with or without a difference) are shown, sorted by difference size (largest first)
# diffs_only - only paths with a difference are shown, sorted by difference size (largest first)
# Note: different screen widths are always grouped together.
mode: diffs_first
4 changes: 4 additions & 0 deletions spec/js/global--chrome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var callback = arguments[arguments.length-1];
document.body.innerHTML = " ";
document.body.style['background-color'] = 'red';
callback();
4 changes: 4 additions & 0 deletions spec/js/path--chrome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var callback = arguments[arguments.length-1];
document.body.innerHTML = " ";
document.body.style['background-color'] = 'green';
callback();
18 changes: 18 additions & 0 deletions spec/save_images_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,25 @@

describe Wraith do
let(:config_name) { get_path_relative_to __FILE__, "./configs/test_config--phantom.yaml" }
let(:config_chrome) { get_path_relative_to __FILE__, "./configs/test_config--chrome.yaml" }
let(:test_url1) { "http://www.bbc.com/afrique" }
let(:test_url2) { "http://www.bbc.com/russian" }
let(:test_image1) { "shots/test/test1.png" }
let(:test_image_chrome) { "shots_chrome/test/test_chrome.png" }
let(:test_image_chrome_selector) { "shots_chrome/test/test_chrome_selector.png" }
let(:test_image2) { "shots/test/test(2).png" }
let(:diff_image) { "shots/test/test_diff.png" }
let(:data_txt) { "shots/test/test.txt" }
let(:selector) { "" }
let(:saving) { Wraith::SaveImages.new(config_name) }
let(:saving_chrome) { Wraith::SaveImages.new(config_chrome) }
let(:wraith) { Wraith::Wraith.new(config_name) }

before(:each) do
Wraith::FolderManager.new(config_name).clear_shots_folder
Wraith::FolderManager.new(config_chrome).clear_shots_folder
Dir.mkdir("shots/test")
Dir.mkdir("shots_chrome/test")
end

describe "When capturing an image" do
Expand All @@ -26,6 +32,18 @@
`#{capture_image}`
expect(image_size[0]).to eq 320
end
it "saves image chrome" do
capture_image = saving_chrome.capture_image_selenium("1080x600", test_url1, test_image_chrome, selector, false, false)
image_size_chrome = ImageSize.path(test_image_chrome).size
expect(image_size_chrome[0]).to eq 1080
end
it "crops around a selector" do
selector = "#orb-nav-more"
capture_image = saving_chrome.capture_image_selenium(1440, test_url1, test_image_chrome_selector, selector, false, false)
image_size_chrome_selector = ImageSize.path(test_image_chrome_selector).size
expect(image_size_chrome_selector[0]).to eq 673
expect(image_size_chrome_selector[1]).to eq 40
end
end

describe "When comparing images" do
Expand Down
4 changes: 4 additions & 0 deletions templates/javascript/interact--chrome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
var callback = arguments[arguments.length-1];
var a = document.querySelector('.some-class');
a && a.click();
setTimeout(callback, 2000);
2 changes: 2 additions & 0 deletions templates/javascript/wait--chrome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var callback = arguments[arguments.length-1];
setTimeout(callback, 2000);
3 changes: 3 additions & 0 deletions wraith.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@ Gem::Specification.new do |spec|

spec.add_runtime_dependency 'rake'
spec.add_runtime_dependency 'image_size'
spec.add_runtime_dependency 'mini_magick', "~> 4.8"
spec.add_runtime_dependency 'anemone'
spec.add_runtime_dependency 'robotex'
spec.add_runtime_dependency 'log4r'
spec.add_runtime_dependency 'thor'
spec.add_runtime_dependency 'parallel'
spec.add_runtime_dependency 'selenium-webdriver', "~> 3.5"
spec.add_runtime_dependency 'chromedriver-helper', "~> 1.1"
end