eyes_selenium 1.25.0 → 1.26.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 +8 -8
- data/lib/eyes_selenium/eyes/agent_connector.rb +1 -1
- data/lib/eyes_selenium/eyes/driver.rb +1 -1
- data/lib/eyes_selenium/eyes/eyes.rb +32 -18
- data/lib/eyes_selenium/eyes/match_window_task.rb +59 -33
- data/lib/eyes_selenium/eyes/mouse_trigger.rb +2 -2
- data/lib/eyes_selenium/eyes/region.rb +5 -0
- data/lib/eyes_selenium/version.rb +1 -1
- data/test_script.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ODUwYjE0ZmI1ODE3ZjNiZTFlODMwOGNlNGRjODJlMmUyOTBmMzQzZg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NmI0YjkyYWRhMmQ5NTMxY2NkZWNhZDc1YTc0ZDJiNjBlMDk5NWM1NA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OThkYjg4YTZkZDhhMTRhODE2MTk2Y2VlOGM2Zjk3NTk3NDYxOTA1N2MwODZj
|
10
|
+
OWZkN2QwMDIwMzcyYmU5MGQ1YjgwMThjMzg5ZGU4ZDI1MGE2ZGVhY2QxYTFk
|
11
|
+
YjEzMmQ2NDcyZWUzNjIzMzI2ODUxOTNmZjAxOTA4MTg1ZDkwNTk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YzcwZDA5MzZhOTRkYWUxYmRmNmQ5ZDdjMThiNTU0YmM3ODVkYWQxMGZmZGUz
|
14
|
+
MmVmZTczODhmOTExZTU1YzEyOTQ5NDliOTg4ZWUzZDBkZTM3YzM5YThiNWVk
|
15
|
+
YmFlY2M4OWNjOWQ1ZDY3NzM5MTgxZTA0MTg1MDkwY2Y5ZWUwMzA=
|
@@ -15,7 +15,7 @@ class Applitools::AgentConnector
|
|
15
15
|
|
16
16
|
def match_window(session, data)
|
17
17
|
self.class.headers 'Content-Type' => 'application/octet-stream'
|
18
|
-
json_data = data.to_hash.to_json.encode('
|
18
|
+
json_data = data.to_hash.to_json.encode('BINARY') # Notice that this does not include the screenshot
|
19
19
|
body = [json_data.length].pack('L>') + json_data + data.screenshot
|
20
20
|
|
21
21
|
res = self.class.post(uri + "/#{session.id}",basic_auth: auth, body: body)
|
@@ -74,7 +74,7 @@ class Applitools::Driver
|
|
74
74
|
def user_agent
|
75
75
|
execute_script 'return navigator.userAgent'
|
76
76
|
rescue => e
|
77
|
-
|
77
|
+
EyesLogger.info "getUserAgent(): Failed to obtain user-agent string (#{e.message})"
|
78
78
|
end
|
79
79
|
|
80
80
|
private
|
@@ -100,25 +100,16 @@ class Applitools::Eyes
|
|
100
100
|
user_inputs.clear
|
101
101
|
end
|
102
102
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
103
|
+
def check_region(how, what, tag=nil)
|
104
|
+
element_to_check = driver.find_element(how, what)
|
105
|
+
location = element_to_check.location
|
106
|
+
size = element_to_check.size
|
107
|
+
region = Applitools::Region.new(location.x, location.y, size.width, size.height)
|
108
|
+
check_region_(region, tag)
|
109
|
+
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
self.should_match_window_run_once_on_timeout = true
|
114
|
-
unless session.new_session?
|
115
|
-
EyesLogger.info %( "mismatch #{ tag ? '' : "(#{tag})" } )
|
116
|
-
if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
|
117
|
-
raise Applitools::TestFailedError.new("Mismatch found in '#{session_start_info.scenario_id_or_name}'"\
|
118
|
-
" of '#{session_start_info.app_id_or_name}'")
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
111
|
+
def check_window(tag=nil)
|
112
|
+
check_region_(Applitools::Region::EMPTY, tag)
|
122
113
|
end
|
123
114
|
|
124
115
|
def close
|
@@ -238,4 +229,27 @@ class Applitools::Eyes
|
|
238
229
|
@viewport_size = Applitools::ViewportSize.new(driver).extract_viewport_from_browser!
|
239
230
|
end
|
240
231
|
end
|
232
|
+
|
233
|
+
def check_region_(region, tag=nil)
|
234
|
+
return if disabled?
|
235
|
+
raise Applitools::EyesError.new('region cannot be nil!') if region.nil?
|
236
|
+
raise Applitools::EyesError.new('Eyes not open') if !open?
|
237
|
+
|
238
|
+
unless session
|
239
|
+
start_session
|
240
|
+
self.match_window_task = Applitools::MatchWindowTask.new(self, agent_connector, session, driver, match_timeout)
|
241
|
+
end
|
242
|
+
|
243
|
+
as_expected = match_window_task.match_window(region, tag, should_match_window_run_once_on_timeout)
|
244
|
+
unless as_expected
|
245
|
+
self.should_match_window_run_once_on_timeout = true
|
246
|
+
unless session.new_session?
|
247
|
+
EyesLogger.info %( "mismatch #{ tag ? '' : "(#{tag})" } )
|
248
|
+
if failure_reports.to_i == Applitools::FailureReports::IMMEDIATE
|
249
|
+
raise Applitools::TestFailedError.new("Mismatch found in '#{session_start_info.scenario_id_or_name}'"\
|
250
|
+
" of '#{session_start_info.app_id_or_name}'")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
241
255
|
end
|
@@ -7,7 +7,7 @@ class Applitools::MatchWindowTask
|
|
7
7
|
MATCH_INTERVAL = 0.5
|
8
8
|
AppOutput = Struct.new(:title, :screenshot64)
|
9
9
|
|
10
|
-
attr_reader :eyes, :agent_connector, :session, :driver, :max_window_load_time
|
10
|
+
attr_reader :eyes, :agent_connector, :session, :driver, :max_window_load_time, :last_checked_window ,:last_screenshot_bounds
|
11
11
|
|
12
12
|
public
|
13
13
|
## max_load_time: maximum wait time for check window, in seconds
|
@@ -18,65 +18,94 @@ class Applitools::MatchWindowTask
|
|
18
18
|
@driver = driver
|
19
19
|
@max_window_load_time = max_window_load_time
|
20
20
|
@last_checked_window = nil # +ChunkyPNG::Canvas+
|
21
|
+
@last_screenshot_bounds = Applitools::Region::EMPTY # +Applitools::Region+
|
21
22
|
@current_screenshot = nil # +ChunkyPNG::Canvas+
|
22
23
|
end
|
23
24
|
|
24
|
-
def match_window(tag,run_once_after_wait=false)
|
25
|
+
def match_window(region, tag,run_once_after_wait=false)
|
25
26
|
res = if max_window_load_time.zero?
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
27
|
+
run(region, tag)
|
28
|
+
elsif run_once_after_wait
|
29
|
+
run(region, tag, max_window_load_time)
|
30
|
+
else
|
31
|
+
run_with_intervals(region, tag, max_window_load_time)
|
32
|
+
end
|
33
|
+
@last_checked_window = @current_screenshot
|
34
|
+
@last_screenshot_bounds = region.empty? ? Applitools::Region.new(0, 0, last_checked_window.width, last_checked_window.height) : region
|
32
35
|
#noinspection RubyUnnecessaryReturnStatement
|
33
36
|
driver.eyes.clear_user_inputs and return res
|
34
37
|
end
|
35
38
|
|
36
|
-
def run(tag, wait_before_run=nil)
|
39
|
+
def run(region, tag, wait_before_run=nil)
|
37
40
|
sleep(wait_before_run) if wait_before_run
|
38
|
-
match(tag)
|
41
|
+
match(region, tag)
|
39
42
|
end
|
40
43
|
|
41
|
-
def run_with_intervals(tag, total_run_time)
|
44
|
+
def run_with_intervals(region, tag, total_run_time)
|
42
45
|
start = Time.now
|
43
46
|
match_retry = total_run_time
|
44
47
|
while match_retry > 0
|
45
48
|
sleep(MATCH_INTERVAL)
|
46
|
-
return true if match(tag, true)
|
49
|
+
return true if match(region, tag, true)
|
47
50
|
match_retry -= (Time.now - start)
|
48
51
|
end
|
49
52
|
## lets try one more time if we still don't have a match
|
50
|
-
match(tag)
|
53
|
+
match(region, tag)
|
51
54
|
end
|
52
55
|
|
53
56
|
private
|
54
57
|
|
55
|
-
def prep_match_data(tag, ignore_mismatch)
|
58
|
+
def prep_match_data(region, tag, ignore_mismatch)
|
56
59
|
title = eyes.title
|
60
|
+
# 'encoded', as in 'png'.
|
57
61
|
current_screenshot_encoded = Base64.decode64(driver.screenshot_as(:base64))
|
58
62
|
@current_screenshot = ChunkyPNG::Image.from_blob(current_screenshot_encoded)
|
63
|
+
# If a region was defined, we refer to the sub-image defined by the region.
|
64
|
+
unless region.empty?
|
65
|
+
@current_screenshot.crop!(region.left, region.top, region.width, region.height)
|
66
|
+
current_screenshot_encoded = @current_screenshot.to_blob.force_encoding('BINARY')
|
67
|
+
end
|
59
68
|
compressed_screenshot = Applitools::Utils::ImageDeltaCompressor.compress_by_raw_blocks(@current_screenshot,
|
60
69
|
current_screenshot_encoded,
|
61
|
-
|
70
|
+
last_checked_window)
|
62
71
|
app_output = AppOutput.new(title, nil)
|
63
72
|
user_inputs = []
|
64
|
-
if
|
65
|
-
user_inputs = driver.eyes.user_inputs
|
66
|
-
else
|
73
|
+
if !last_checked_window.nil?
|
67
74
|
driver.eyes.user_inputs.each do |trigger|
|
68
|
-
if trigger.is_a?
|
75
|
+
if trigger.is_a?(Applitools::MouseTrigger)
|
76
|
+
updated_trigger = nil
|
69
77
|
trigger_left = trigger.control.left + trigger.location.x
|
70
78
|
trigger_top = trigger.control.top + trigger.location.y
|
71
|
-
if trigger_left
|
72
|
-
|
79
|
+
if last_screenshot_bounds.contains?(trigger_left, trigger_top)
|
80
|
+
trigger.control.intersect(last_screenshot_bounds)
|
81
|
+
if trigger.control.empty?
|
82
|
+
trigger_left = trigger_left - last_screenshot_bounds.left
|
83
|
+
trigger_top = trigger_top -last_screenshot_bounds.top
|
84
|
+
updated_trigger = Applitools::MouseTrigger.new(trigger.mouse_action, trigger.control, Selenium::WebDriver::Point.new(trigger_left, trigger_top))
|
85
|
+
else
|
86
|
+
trigger_left = trigger_left - trigger.control.left
|
87
|
+
trigger_top = trigger_top - trigger.control.top
|
88
|
+
control_left = trigger.control.left - last_screenshot_bounds.left
|
89
|
+
control_top = trigger.control.top - last_screenshot_bounds.top
|
90
|
+
updated_control = Applitools::Region.new(control_left, control_top, trigger.control.width, trigger.control.height)
|
91
|
+
updated_trigger = Applitools::MouseTrigger.new(trigger.mouse_action, updated_control, Selenium::WebDriver::Point.new(trigger_left, trigger_top))
|
92
|
+
end
|
93
|
+
user_inputs << updated_trigger
|
73
94
|
else
|
74
95
|
EyesLogger.info "Trigger ignored: #{trigger} (out of bounds)"
|
75
96
|
end
|
76
|
-
elsif trigger.is_a?
|
77
|
-
|
78
|
-
|
79
|
-
|
97
|
+
elsif trigger.is_a?(Applitools::TextTrigger)
|
98
|
+
unless trigger.control.empty?
|
99
|
+
trigger.control.intersect(last_screenshot_bounds)
|
100
|
+
unless trigger.control.empty?
|
101
|
+
control_left = trigger.control.left - last_screenshot_bounds.left
|
102
|
+
control_top = trigger.control.top - last_screenshot_bounds.top
|
103
|
+
updated_control = Applitools::Region.new(control_left, control_top, trigger.control.width, trigger.control.height)
|
104
|
+
updated_trigger = Applitools::TextTrigger.new(trigger.text, updated_control)
|
105
|
+
user_inputs << updated_trigger
|
106
|
+
else
|
107
|
+
EyesLogger.info "Trigger ignored: #{trigger} (control out of bounds)"
|
108
|
+
end
|
80
109
|
else
|
81
110
|
EyesLogger.info "Trigger ignored: #{trigger} (out of bounds)"
|
82
111
|
end
|
@@ -84,17 +113,14 @@ class Applitools::MatchWindowTask
|
|
84
113
|
EyesLogger.info "Trigger ignored: #{trigger} (Unrecognized trigger)"
|
85
114
|
end
|
86
115
|
end
|
116
|
+
else
|
117
|
+
EyesLogger.info 'Triggers ignored: no previous window checked'
|
87
118
|
end
|
88
119
|
Applitools::MatchWindowData.new(app_output, user_inputs, tag, ignore_mismatch, compressed_screenshot)
|
89
120
|
end
|
90
121
|
|
91
|
-
def match(tag, ignore_mismatch=false)
|
92
|
-
data = prep_match_data(tag, ignore_mismatch)
|
93
|
-
|
94
|
-
# If the server stored this image, it will be used as a base for our next screenshot compression
|
95
|
-
unless ignore_mismatch
|
96
|
-
@last_checked_window = @current_screenshot
|
97
|
-
end
|
98
|
-
as_expected
|
122
|
+
def match(region, tag, ignore_mismatch=false)
|
123
|
+
data = prep_match_data(region, tag, ignore_mismatch)
|
124
|
+
agent_connector.match_window(session, data)
|
99
125
|
end
|
100
126
|
end
|
@@ -5,14 +5,14 @@ class Applitools::MouseTrigger
|
|
5
5
|
attr_reader :mouse_action, :control, :location
|
6
6
|
|
7
7
|
def initialize(mouse_action, control, location)
|
8
|
-
@mouse_action =
|
8
|
+
@mouse_action = mouse_action
|
9
9
|
@control = control
|
10
10
|
@location = location
|
11
11
|
end
|
12
12
|
|
13
13
|
def to_hash
|
14
14
|
{
|
15
|
-
"$type" => "Applitools.Models.MouseTrigger, Core", mouseAction: mouse_action,
|
15
|
+
"$type" => "Applitools.Models.MouseTrigger, Core", mouseAction: MOUSE_ACTION[mouse_action],
|
16
16
|
control: control.to_hash, location: Hash[location.each_pair.to_a]
|
17
17
|
}
|
18
18
|
end
|
@@ -49,6 +49,11 @@ class Applitools::Region
|
|
49
49
|
self.height = i_bottom - i_top
|
50
50
|
end
|
51
51
|
|
52
|
+
def contains?(other_left, other_top)
|
53
|
+
other_left >= left && other_left <= right && \
|
54
|
+
other_top >= top && other_top <= bottom
|
55
|
+
end
|
56
|
+
|
52
57
|
def middle_offset
|
53
58
|
mid_x = width / 2
|
54
59
|
mid_y = height / 2
|
data/test_script.rb
CHANGED
@@ -14,6 +14,7 @@ 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, 'li.pricing', 'Pricing button')
|
17
18
|
driver.find_element(:css, "li.pricing a").click
|
18
19
|
eyes.check_window("pricing page")
|
19
20
|
el = driver.find_elements(:css, ".footer-row a").first
|
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: 1.
|
4
|
+
version: 1.26.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: 2014-01-
|
11
|
+
date: 2014-01-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: selenium-webdriver
|