eyes_selenium 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/appium_eyes_example.rb +41 -31
- data/eyes_selenium.gemspec +3 -2
- data/lib/eyes_selenium/eyes/agent_connector.rb +0 -2
- data/lib/eyes_selenium/eyes/driver.rb +89 -9
- data/lib/eyes_selenium/eyes/eyes.rb +45 -15
- data/lib/eyes_selenium/eyes/match_window_task.rb +2 -1
- data/lib/eyes_selenium/eyes/viewport_size.rb +11 -3
- data/lib/eyes_selenium/utils.rb +1 -0
- data/lib/eyes_selenium/utils/image_delta_compressor.rb +5 -5
- data/lib/eyes_selenium/utils/image_utils.rb +76 -0
- data/lib/eyes_selenium/version.rb +1 -1
- data/test_script.rb +2 -2
- metadata +19 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ebc04f208fa510c98a5260826fb118d86291185
|
4
|
+
data.tar.gz: d5226529324ab94f2cca6a96b059851b11102384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6038fb5f5d17c9eb8a9d80d984c4160ddbac031e81d442e50cb8223124d45199192b56bcf80dedd5573d2d94c8157424a123bd7f32140165e6eea7ec69be87d8
|
7
|
+
data.tar.gz: df5fba1575662b834bf311a14a5f21a97a69612204e8957867c86cdf10edd0c6b989216ffb229a60d8b7c5e99737517f6ec8f8d8e67664fe033fbf86779b96ad
|
data/appium_eyes_example.rb
CHANGED
@@ -1,47 +1,57 @@
|
|
1
1
|
require 'eyes_selenium'
|
2
|
+
require 'openssl'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
##
|
4
|
+
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
5
|
+
##
|
6
6
|
# Based on Appium example: https://github.com/appium/appium/blob/master/sample-code/examples/ruby/
|
7
7
|
|
8
|
-
desired_capabilities = {
|
9
|
-
"device" => "Android",
|
10
|
-
"version" => "4.2",
|
11
|
-
"app" => "http://appium.s3.amazonaws.com/NotesList.apk",
|
12
|
-
"app-package" => "com.example.android.notepad",
|
13
|
-
"app-activity" => ".NotesList"
|
14
|
-
}
|
15
8
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
def android_caps
|
10
|
+
{
|
11
|
+
deviceName: 'Samsung Galaxy S4 Emulator',
|
12
|
+
platformName: 'Android',
|
13
|
+
platformVersion: 4.4,
|
14
|
+
app: '/Users/daniel/test/NotesList.apk',
|
15
|
+
appPackage: 'com.example.android.notepad',
|
16
|
+
appActivity: '.NotesList',
|
17
|
+
# orientation: 'landscape',
|
18
|
+
newCommandTimeout: 300
|
19
|
+
}
|
20
|
+
end
|
21
|
+
def ios_caps
|
22
|
+
{
|
23
|
+
deviceName: 'iPhone 6',
|
24
|
+
platformName: 'ios',
|
25
|
+
platformVersion: 8.3,
|
26
|
+
app: '/Users/daniel/Library/Developer/Xcode/DerivedData/HelloXcode-cldusyhxlaclfkbirmthhbgpchqv/Build/Products/Debug-iphonesimulator/HelloXcode.app',
|
27
|
+
orientation: 'landscape',
|
28
|
+
newCommandTimeout: 300
|
29
|
+
}
|
21
30
|
end
|
22
31
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
-
|
32
|
+
def appium_opts
|
33
|
+
{
|
34
|
+
server_url: 'http://127.0.0.1:4723/wd/hub',
|
35
|
+
}
|
27
36
|
end
|
28
37
|
|
29
|
-
|
38
|
+
|
39
|
+
@eyes = Applitools::Eyes.new(server_url: 'https://localhost.applitools.com')
|
40
|
+
@eyes.log_handler = Logger.new(STDOUT)
|
41
|
+
@eyes.api_key = ENV['APPLITOOLS_API_KEY']
|
30
42
|
begin
|
31
|
-
@driver =
|
32
|
-
@driver =
|
43
|
+
@driver = Appium::Driver.new({caps: android_caps, appium_lib: appium_opts})
|
44
|
+
# @driver = Appium::Driver.new({caps: ios_caps, appium_lib: appium_opts})
|
45
|
+
@driver.start_driver
|
46
|
+
# @driver.driver.rotate :landscape
|
47
|
+
puts "Screen size: #{@driver.driver.manage.window.size}"
|
48
|
+
puts "orientation: #{@driver.driver.orientation}"
|
49
|
+
puts @driver.caps
|
50
|
+
@eyes.open(app_name: 'Selenium Israel', test_name: 'Appium Notepad', driver: @driver)
|
33
51
|
@eyes.check_window("No notes")
|
34
52
|
|
35
|
-
create_note "I didn't expect a kind of Spanish Inquisition!"
|
36
|
-
create_note "Nobody expects the Spanish Inquisition!"
|
37
|
-
@eyes.check_window("Two notes")
|
38
|
-
|
39
|
-
clear_note_by_text "I didn't expect a kind of Spanish Inquisition!"
|
40
|
-
@eyes.check_window("One note")
|
41
|
-
|
42
53
|
@eyes.close
|
43
54
|
ensure
|
44
|
-
sleep 5
|
45
55
|
@eyes.abort_if_not_closed
|
46
|
-
@driver.
|
56
|
+
@driver.driver_quit
|
47
57
|
end
|
data/eyes_selenium.gemspec
CHANGED
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "selenium-webdriver", [">= 2.
|
22
|
-
spec.add_dependency "
|
21
|
+
spec.add_dependency "selenium-webdriver", [">= 2.45.0"]
|
22
|
+
spec.add_dependency "appium_lib", [">= 6.0.0"]
|
23
|
+
spec.add_dependency "httparty"
|
23
24
|
spec.add_dependency "oily_png", [">= 1.1.0"]
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.3"
|
@@ -35,10 +35,8 @@ class Applitools::AgentConnector
|
|
35
35
|
def start_session(session_start_info)
|
36
36
|
self.class.headers 'Content-Type' => 'application/json'
|
37
37
|
res = self.class.post(@endpoint_uri, query: {apiKey: api_key}, body: { startInfo: session_start_info.to_hash }.to_json)
|
38
|
-
EyesLogger.debug "Got response! #{res}"
|
39
38
|
status_code = res.response.message
|
40
39
|
parsed_res = res.parsed_response
|
41
|
-
EyesLogger.debug "Parsed response #{parsed_res}"
|
42
40
|
Applitools::Session.new(parsed_res['id'], parsed_res['url'], status_code == 'Created' )
|
43
41
|
end
|
44
42
|
|
@@ -1,7 +1,35 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'selenium-webdriver'
|
3
|
+
require 'appium_lib'
|
4
|
+
|
3
5
|
class Applitools::Driver
|
4
6
|
|
7
|
+
# Prepares an image for being sent to the Eyes server (e.g., handling rotation, scaling etc.).
|
8
|
+
#
|
9
|
+
# +driver+:: +Applitools::Driver+ The driver which produced the screenshot.
|
10
|
+
# +image+:: +ChunkyPNG::Canvas+ The image to normalize.
|
11
|
+
#
|
12
|
+
# Returns:
|
13
|
+
# +Integer+ The rotation of the screenshot we get from the webdriver (degrees).
|
14
|
+
def self.normalize_image!(driver, image, rotation=0)
|
15
|
+
EyesLogger.debug "#{__method__}()"
|
16
|
+
# Handling rotation
|
17
|
+
num_quadrants = 0
|
18
|
+
if rotation != 0
|
19
|
+
if rotation % 90 != 0
|
20
|
+
raise Applitools::EyesError.new "Currently only quadrant rotations are supported. Current rotation: #{rotation}"
|
21
|
+
end
|
22
|
+
num_quadrants = (rotation / 90).to_i
|
23
|
+
elsif driver.mobile_device? && driver.landscape_orientation? && image.height > image.width
|
24
|
+
# For Android, we need to rotate images to the right, and for iOS to the left.
|
25
|
+
num_quadrants = driver.android? ? 1 : -1
|
26
|
+
end
|
27
|
+
if num_quadrants != 0
|
28
|
+
Applitools::Utils::ImageUtils.quadrant_rotate!(image, num_quadrants)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
5
33
|
include Selenium::WebDriver::DriverExtensions::HasInputDevices
|
6
34
|
|
7
35
|
attr_reader :remote_server_url, :remote_session_id, :screenshot_taker, :eyes
|
@@ -9,7 +37,7 @@ class Applitools::Driver
|
|
9
37
|
|
10
38
|
DRIVER_METHODS = [
|
11
39
|
:title, :execute_script, :execute_async_script, :quit, :close, :get,
|
12
|
-
:post, :page_source, :window_handles, :window_handle, :switch_to,
|
40
|
+
:post, :page_source, :window_handles, :window_handle, :switch_to,
|
13
41
|
:navigate, :manage, :capabilities
|
14
42
|
]
|
15
43
|
|
@@ -17,8 +45,9 @@ class Applitools::Driver
|
|
17
45
|
#
|
18
46
|
def initialize(eyes, options)
|
19
47
|
@driver = options[:driver]
|
48
|
+
@is_mobile_device = options.fetch(:is_mobile_device, false)
|
20
49
|
@eyes = eyes
|
21
|
-
# FIXME fix getting "remote address url" or remove "Screenshot taker"
|
50
|
+
# FIXME fix getting "remote address url" or remove "Screenshot taker" altogether.
|
22
51
|
# @remote_server_url = address_of_remote_server
|
23
52
|
@remote_server_url = 'MOCK_URL'
|
24
53
|
@remote_session_id = remote_session_id
|
@@ -29,7 +58,7 @@ class Applitools::Driver
|
|
29
58
|
else
|
30
59
|
@screenshot_taker = Applitools::ScreenshotTaker.new(@remote_server_url, @remote_session_id)
|
31
60
|
end
|
32
|
-
rescue => e
|
61
|
+
rescue => e
|
33
62
|
raise Applitools::EyesError.new "Can't take screenshots (#{e.message})"
|
34
63
|
end
|
35
64
|
end
|
@@ -40,14 +69,64 @@ class Applitools::Driver
|
|
40
69
|
end
|
41
70
|
end
|
42
71
|
|
43
|
-
|
44
|
-
|
72
|
+
# Returns:
|
73
|
+
# +String+ The platform name or +nil+ if it is undefined.
|
74
|
+
def platform_name
|
75
|
+
driver.capabilities['platformName']
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns:
|
79
|
+
# +String+ The platform version or +nil+ if it is undefined.
|
80
|
+
def platform_version
|
81
|
+
version = driver.capabilities['platformVersion']
|
82
|
+
version.nil? ? nil : version.to_s
|
83
|
+
end
|
45
84
|
|
46
|
-
|
47
|
-
|
85
|
+
# Returns:
|
86
|
+
# +true+ if the driver is an Android driver.
|
87
|
+
def android?
|
88
|
+
platform_name.to_s.upcase == 'ANDROID'
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns:
|
92
|
+
# +true+ if the driver is an iOS driver.
|
93
|
+
def ios?
|
94
|
+
platform_name.to_s.upcase == 'IOS'
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns:
|
98
|
+
# +true+ if the driver orientation is landscape.
|
99
|
+
def landscape_orientation?
|
100
|
+
driver.orientation.to_s.upcase == 'LANDSCAPE'
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns:
|
104
|
+
# +true+ if the platform running the test is a mobile platform. +false+ otherwise.
|
105
|
+
def mobile_device?
|
106
|
+
# We CAN'T check if the device is an +Appium::Driver+ since it is not a RemoteWebDriver. Because of that we use a
|
107
|
+
# flag we got as an option in the constructor.
|
108
|
+
@is_mobile_device
|
109
|
+
end
|
110
|
+
|
111
|
+
def screenshot_as(output_type)
|
112
|
+
# TODO Check if screenshot_taker is still required
|
113
|
+
if screenshot_taker
|
114
|
+
if output_type.downcase.to_sym != :base64
|
115
|
+
raise Applitools::EyesError.new("#{output_type} output type not supported for screenshot")
|
116
|
+
end
|
117
|
+
screenshot64 = screenshot_taker.screenshot
|
118
|
+
else
|
119
|
+
screenshot = driver.screenshot_as(output_type)
|
120
|
+
# We only support additional processing of the output (such as rotation) for Base64 type of screenshots.
|
121
|
+
if output_type.downcase.to_sym != :base64
|
122
|
+
return screenshot
|
123
|
+
end
|
124
|
+
screenshot64 = screenshot
|
48
125
|
end
|
49
|
-
|
50
|
-
|
126
|
+
screenshot = Applitools::Utils::ImageUtils.png_image_from_base64(screenshot64)
|
127
|
+
Applitools::Driver.normalize_image!(self, screenshot)
|
128
|
+
Applitools::Utils::ImageUtils.base64_from_png_image(screenshot)
|
129
|
+
end
|
51
130
|
|
52
131
|
def mouse
|
53
132
|
Applitools::EyesMouse.new(self, driver.mouse)
|
@@ -103,6 +182,7 @@ class Applitools::Driver
|
|
103
182
|
execute_script 'return navigator.userAgent'
|
104
183
|
rescue => e
|
105
184
|
EyesLogger.info "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
|
185
|
+
return nil
|
106
186
|
end
|
107
187
|
|
108
188
|
private
|
@@ -91,6 +91,8 @@ class Applitools::Eyes
|
|
91
91
|
|
92
92
|
if driver.is_a?(Selenium::WebDriver::Driver)
|
93
93
|
@driver = Applitools::Driver.new(self, {driver: driver})
|
94
|
+
elsif driver.is_a?(Appium::Driver)
|
95
|
+
@driver = Applitools::Driver.new(self, {driver: driver.driver, is_mobile_device: true})
|
94
96
|
else
|
95
97
|
unless driver.is_a?(Applitools::Driver)
|
96
98
|
raise Applitools::EyesError.new("Driver is not a Selenium::WebDriver::Driver (#{driver.class.name})")
|
@@ -250,32 +252,60 @@ class Applitools::Eyes
|
|
250
252
|
params.fetch(:driver, nil)
|
251
253
|
end
|
252
254
|
|
253
|
-
def mobile_os
|
254
|
-
caps = driver.capabilities
|
255
|
-
device = caps['device'] ? caps['device'] : caps[:platform]
|
256
|
-
if device && device!=''
|
257
|
-
major_version = caps[:version] ? caps[:version].split('.')[0] : ''
|
258
|
-
major_version = (major_version != nil) && (major_version != '') && (major_version != '0') ? major_version : nil
|
259
|
-
major_version.nil? ? ('%s' % device) : ('%s %s' % [device, major_version])
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
255
|
def inferred_environment
|
264
256
|
user_agent = driver.user_agent
|
265
257
|
if user_agent
|
266
|
-
|
258
|
+
"useragent:#{user_agent}"
|
267
259
|
else
|
268
|
-
|
269
|
-
|
270
|
-
|
260
|
+
nil
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Application environment is the environment (e.g., the host OS) which runs the application under test.
|
265
|
+
#
|
266
|
+
# Returns:
|
267
|
+
# +Applitools::Environment+ The application environment.
|
268
|
+
def app_environment
|
269
|
+
os = host_os
|
270
|
+
if os.nil?
|
271
|
+
EyesLogger.info 'No OS set, checking for mobile OS...'
|
272
|
+
if driver.mobile_device?
|
273
|
+
platform_name = nil
|
274
|
+
EyesLogger.info 'Mobile device detected! Checking device type..'
|
275
|
+
if driver.android?
|
276
|
+
EyesLogger.info 'Android detected.'
|
277
|
+
platform_name = 'Android'
|
278
|
+
elsif driver.ios?
|
279
|
+
EyesLogger.info 'iOS detected.'
|
280
|
+
platform_name = 'iOS'
|
281
|
+
else
|
282
|
+
EyesLogger.info 'Unknown device type.'
|
283
|
+
end
|
284
|
+
# We only set the OS if we identified the device type.
|
285
|
+
unless platform_name.nil?
|
286
|
+
platform_version = driver.platform_version
|
287
|
+
if platform_version.nil?
|
288
|
+
os = platform_name
|
289
|
+
else
|
290
|
+
# Notice that Ruby's +split+ function's +limit+ is the number of elements, whereas in Python it is the
|
291
|
+
# maximum splits performed (which is why they are set differently).
|
292
|
+
major_version = platform_version.split('.', 2)[0]
|
293
|
+
os = "#{platform_name} #{major_version}"
|
294
|
+
end
|
295
|
+
EyesLogger.info "Setting OS: #{os}"
|
296
|
+
end
|
297
|
+
else
|
298
|
+
EyesLogger.info 'No mobile OS detected.'
|
271
299
|
end
|
272
300
|
end
|
301
|
+
# Create and return the environment object.
|
302
|
+
Applitools::Environment.new(os, host_app, viewport_size, inferred_environment)
|
273
303
|
end
|
274
304
|
|
275
305
|
def start_session
|
276
306
|
assign_viewport_size
|
277
307
|
self.batch ||= Applitools::BatchInfo.new
|
278
|
-
app_env =
|
308
|
+
app_env = app_environment
|
279
309
|
self.session_start_info = Applitools::StartInfo.new(
|
280
310
|
full_agent_id, app_name, test_name, batch, baseline_name, app_env, match_level, nil, branch_name, parent_branch_name
|
281
311
|
)
|
@@ -94,8 +94,9 @@ class Applitools::MatchWindowTask
|
|
94
94
|
title = eyes.title
|
95
95
|
EyesLogger.debug 'Getting screenshot...'
|
96
96
|
screenshot64 = driver.screenshot_as(:base64)
|
97
|
+
# We need a reference to the raw bytes of the PNG, which is why we didn't
|
98
|
+
# use +Applitools::Utils::ImageUtils.image_from_base64+.
|
97
99
|
EyesLogger.debug 'Done! Decoding base64...'
|
98
|
-
# 'encoded', as in 'png'.
|
99
100
|
current_screenshot_encoded = Base64.decode64(screenshot64)
|
100
101
|
EyesLogger.debug 'Done! Creating image object from PNG...'
|
101
102
|
@current_screenshot = ChunkyPNG::Image.from_blob(current_screenshot_encoded)
|
@@ -48,11 +48,19 @@ class Applitools::ViewportSize
|
|
48
48
|
width = extract_viewport_width
|
49
49
|
height = extract_viewport_height
|
50
50
|
rescue => e
|
51
|
-
EyesLogger.info "
|
51
|
+
EyesLogger.info "#{__method__}(): Failed to extract viewport size using Javascript: (#{e.message})"
|
52
52
|
end
|
53
53
|
if width.nil? || height.nil?
|
54
|
-
EyesLogger.info
|
54
|
+
EyesLogger.info "#{__method__}(): Using window size as viewport size."
|
55
55
|
width, height = *browser_size.values
|
56
|
+
width, height = width.ceil, height.ceil
|
57
|
+
begin
|
58
|
+
if driver.landscape_orientation? && height > width
|
59
|
+
width, height = height, width
|
60
|
+
end
|
61
|
+
rescue NameError
|
62
|
+
# Ignored. This error will occur for web based drivers, since they don't have the "orientation" attribute.
|
63
|
+
end
|
56
64
|
end
|
57
65
|
Applitools::Dimension.new(width,height)
|
58
66
|
end
|
@@ -64,7 +72,7 @@ class Applitools::ViewportSize
|
|
64
72
|
self.dimension = Struct.new(:width, :height).new(dimension[:width], dimension[:height])
|
65
73
|
elsif !dimension.respond_to?(:width) || !dimension.respond_to?(:height)
|
66
74
|
raise ArgumentError, "expected #{dimension.inspect}:#{dimension.class}" +
|
67
|
-
|
75
|
+
' to respond to #width and #height, or be a hash with these keys.'
|
68
76
|
end
|
69
77
|
self.browser_size = dimension
|
70
78
|
verify_size(:browser_size)
|
data/lib/eyes_selenium/utils.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
=begin
|
2
2
|
Applitools SDK class.
|
3
3
|
|
4
|
-
Provides image compression based on image sequences and deflate
|
4
|
+
Provides image compression based on image sequences and deflate.
|
5
5
|
=end
|
6
6
|
require 'oily_png'
|
7
|
-
require 'base64'
|
8
7
|
|
9
8
|
class Applitools::Utils::ImageDeltaCompressor
|
10
9
|
|
11
10
|
# Compresses the target image based on the source image.
|
11
|
+
#
|
12
12
|
# +target+:: +ChunkyPNG::Canvas+ The image to compress based on the source image.
|
13
13
|
# +target_encoded+:: +Array+ The uncompressed image as binary string.
|
14
14
|
# +source+:: +ChunkyPNG::Canvas+ The source image used as a base for compressing the target image.
|
15
15
|
# +block_size+:: +Integer+ The width/height of each block.
|
16
|
-
#
|
16
|
+
#
|
17
17
|
# Returns +String+ The binary result (either the compressed image, or the uncompressed image if the compression
|
18
|
-
# is greater in length)
|
18
|
+
# is greater in length).
|
19
19
|
def self.compress_by_raw_blocks(target, target_encoded, source, block_size = 10)
|
20
20
|
# If we can't compress for any reason, return the target image as is.
|
21
21
|
if source.nil? || (source.height != target.height) || (source.width != target.width)
|
@@ -84,7 +84,7 @@ class Applitools::Utils::ImageDeltaCompressor
|
|
84
84
|
### PRIVATE
|
85
85
|
private
|
86
86
|
|
87
|
-
@@PREAMBLE =
|
87
|
+
@@PREAMBLE = 'applitools'
|
88
88
|
@@FORMAT_RAW_BLOCKS = 3
|
89
89
|
|
90
90
|
Dimension = Struct.new(:width, :height)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
=begin
|
2
|
+
Applitools SDK class.
|
3
|
+
|
4
|
+
Provides images manipulation functionality.
|
5
|
+
=end
|
6
|
+
require 'oily_png'
|
7
|
+
require 'base64'
|
8
|
+
|
9
|
+
module Applitools::Utils::ImageUtils
|
10
|
+
|
11
|
+
# Creates an image object from the PNG bytes.
|
12
|
+
# +png_bytes+:: +String+ A binary string of the PNG bytes of the image.
|
13
|
+
#
|
14
|
+
# Returns:
|
15
|
+
# +ChunkyPNG::Canvas+ An image object.
|
16
|
+
def self.png_image_from_bytes(png_bytes)
|
17
|
+
EyesLogger.debug "#{__method__}()"
|
18
|
+
image = ChunkyPNG::Image.from_blob(png_bytes)
|
19
|
+
EyesLogger.debug 'Done!'
|
20
|
+
return image
|
21
|
+
end
|
22
|
+
|
23
|
+
# Creates an image instance from a base64 representation of its PNG encoding.
|
24
|
+
#
|
25
|
+
# +png_bytes64+:: +String+ The Base64 representation of a PNG image.
|
26
|
+
#
|
27
|
+
# Returns:
|
28
|
+
# +ChunkyPNG::Canvas+ An image object.
|
29
|
+
def self.png_image_from_base64(png_bytes64)
|
30
|
+
EyesLogger.debug "#{__method__}()"
|
31
|
+
png_bytes = Base64.decode64(png_bytes64)
|
32
|
+
EyesLogger.debug 'Done!'
|
33
|
+
return png_image_from_bytes(png_bytes)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get the raw PNG bytes of an image.
|
37
|
+
#
|
38
|
+
# +ChunkyPNG::Canvas+ The image object for which to get the PNG bytes.
|
39
|
+
#
|
40
|
+
# Returns:
|
41
|
+
# +String+ The PNG bytes of the image.
|
42
|
+
def self.bytes_from_png_image(image)
|
43
|
+
EyesLogger.debug "#{__method__}()"
|
44
|
+
png_bytes = image.to_blob
|
45
|
+
EyesLogger.debug 'Done!'
|
46
|
+
return png_bytes
|
47
|
+
end
|
48
|
+
|
49
|
+
# Get the Base64 representation of the raw PNG bytes of an image.
|
50
|
+
#
|
51
|
+
# +ChunkyPNG::Canvas+ The image object for which to get the PNG bytes.
|
52
|
+
#
|
53
|
+
# Returns:
|
54
|
+
# +String+ the Base64 representation of the raw PNG bytes of an image.
|
55
|
+
def self.base64_from_png_image(image)
|
56
|
+
EyesLogger.debug "#{__method__}()"
|
57
|
+
png_bytes = bytes_from_png_image(image)
|
58
|
+
EyesLogger.debug 'Encoding as base64...'
|
59
|
+
image64 = Base64.encode64(png_bytes)
|
60
|
+
EyesLogger.debug 'Done!'
|
61
|
+
return image64
|
62
|
+
end
|
63
|
+
|
64
|
+
# Rotates a matrix 90 deg clockwise or counter clockwise (depending whether num_quadrants is positive or negative,
|
65
|
+
# respectively).
|
66
|
+
#
|
67
|
+
# +image+:: +ChunkyPNG::Canvas+ The image to rotate.
|
68
|
+
# +num_quadrants+:: +Integer+ The number of rotations to perform. Positive values are used for clockwise rotation
|
69
|
+
# and negative values are used for counter-clockwise rotation.
|
70
|
+
#
|
71
|
+
def self.quadrant_rotate!(image, num_quadrants)
|
72
|
+
rotate_method = num_quadrants > 0 ? image.method('rotate_right!'.to_sym) : image.method('rotate_left!'.to_sym)
|
73
|
+
(0..(num_quadrants.abs-1)).each { rotate_method.call }
|
74
|
+
return image
|
75
|
+
end
|
76
|
+
end
|
data/test_script.rb
CHANGED
@@ -14,8 +14,8 @@ begin
|
|
14
14
|
eyes.test(app_name: 'Ruby SDK', test_name: 'Applitools website test', viewport_size: {width: 1024, height: 768}, driver: my_webdriver) do |driver|
|
15
15
|
driver.get 'http://www.applitools.com'
|
16
16
|
eyes.check_window('initial')
|
17
|
-
eyes.check_region(:css, '
|
18
|
-
driver.find_element(:css, '
|
17
|
+
eyes.check_region(:css, '.pricing', 'Pricing button')
|
18
|
+
driver.find_element(:css, '.pricing a').click
|
19
19
|
eyes.check_window('pricing page')
|
20
20
|
end
|
21
21
|
ensure
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eyes_selenium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Applitools team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.45.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.45.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: appium_lib
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 6.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 6.0.0
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: httparty
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +178,7 @@ files:
|
|
164
178
|
- lib/eyes_selenium/eyes_logger.rb
|
165
179
|
- lib/eyes_selenium/utils.rb
|
166
180
|
- lib/eyes_selenium/utils/image_delta_compressor.rb
|
181
|
+
- lib/eyes_selenium/utils/image_utils.rb
|
167
182
|
- lib/eyes_selenium/version.rb
|
168
183
|
- spec/find_spec.rb
|
169
184
|
- test_script.rb
|