eyes_selenium 3.15.39 → 3.15.40

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/applitools/selenium/browser_types.rb +1 -0
  3. data/lib/applitools/selenium/browsers_info.rb +24 -23
  4. data/lib/applitools/selenium/concerns/selenium_eyes.rb +154 -0
  5. data/lib/applitools/selenium/configuration.rb +5 -4
  6. data/lib/applitools/selenium/css_parser/find_embedded_resources.rb +4 -1
  7. data/lib/applitools/selenium/css_translate_position_provider.rb +1 -1
  8. data/lib/applitools/selenium/devices.rb +1 -0
  9. data/lib/applitools/selenium/dom_capture/dom_capture.rb +9 -8
  10. data/lib/applitools/selenium/dom_capture/dom_capture_script.rb +3 -1
  11. data/lib/applitools/selenium/external_css_resources.rb +7 -3
  12. data/lib/applitools/selenium/eyes.rb +2 -3
  13. data/lib/applitools/selenium/full_page_capture_algorithm.rb +5 -1
  14. data/lib/applitools/selenium/orientations.rb +1 -0
  15. data/lib/applitools/selenium/render_browser_info_fluent.rb +3 -1
  16. data/lib/applitools/selenium/render_resources.rb +12 -5
  17. data/lib/applitools/selenium/rgrid_dom.rb +4 -8
  18. data/lib/applitools/selenium/scripts/get_element_xpath.rb +3 -1
  19. data/lib/applitools/selenium/scripts/process_page_and_poll.rb +154 -72
  20. data/lib/applitools/selenium/scripts/process_page_and_serialize.rb +3 -1
  21. data/lib/applitools/selenium/selenium_eyes.rb +66 -221
  22. data/lib/applitools/selenium/stitch_modes.rb +2 -1
  23. data/lib/applitools/selenium/target.rb +31 -14
  24. data/lib/applitools/selenium/test_list.rb +16 -10
  25. data/lib/applitools/selenium/visual_grid/chrome_emulation_info.rb +2 -1
  26. data/lib/applitools/selenium/visual_grid/emulation_base_info.rb +2 -1
  27. data/lib/applitools/selenium/visual_grid/eyes_connector.rb +13 -7
  28. data/lib/applitools/selenium/visual_grid/render_browser_info.rb +2 -1
  29. data/lib/applitools/selenium/visual_grid/render_info.rb +2 -1
  30. data/lib/applitools/selenium/visual_grid/render_request.rb +4 -3
  31. data/lib/applitools/selenium/visual_grid/render_requests.rb +2 -1
  32. data/lib/applitools/selenium/visual_grid/render_task.rb +71 -46
  33. data/lib/applitools/selenium/visual_grid/resource_cache.rb +4 -3
  34. data/lib/applitools/selenium/visual_grid/running_test.rb +26 -4
  35. data/lib/applitools/selenium/visual_grid/thread_pool.rb +3 -2
  36. data/lib/applitools/selenium/visual_grid/vg_match_window_data.rb +9 -3
  37. data/lib/applitools/selenium/visual_grid/vg_region.rb +2 -1
  38. data/lib/applitools/selenium/visual_grid/vg_resource.rb +8 -7
  39. data/lib/applitools/selenium/visual_grid/vg_task.rb +2 -1
  40. data/lib/applitools/selenium/visual_grid/visual_grid_eyes.rb +114 -168
  41. data/lib/applitools/selenium/visual_grid/visual_grid_runner.rb +38 -11
  42. data/lib/applitools/selenium/visual_grid/web_element_region.rb +3 -1
  43. data/lib/applitools/version.rb +1 -1
  44. data/lib/eyes_selenium.rb +1 -1
  45. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aab8529dcb077f8221beb47146b533b99972fed1bb8564526ce3e3080ccadab4
4
- data.tar.gz: c019144e8b13f7c3f7217dac08d96fbc91e935e028502406c0e76f1518e8facc
3
+ metadata.gz: dbee900cd3702aacc958add560a4ac3ecd307021f08926babf1b6269d0b5bacf
4
+ data.tar.gz: 9faadc80999564bfddae87dbb445239e9f8db6c9297f7eefc8e232e149aa00ba
5
5
  SHA512:
6
- metadata.gz: 99b0b16d5160a1ccbff7915afedaf15b62965ca8a58980e73e198f3e1aa5986d4277dcf423cfaf14da1c61329e831f768af2e15c79fb202a47771da4b4169ad1
7
- data.tar.gz: baf60a724aaf8819182a61b726cfbef865e49fe745fbb3c58a9ec589148f95d04aacb6e87b8534bcfcfe84be50a15eed8e8c1c4893b79811b88427b2f33c9255
6
+ metadata.gz: 89996f378e3540d53126e2392d18158eff4deec019a9a18d3030e65abb67b9265a29d220057ac15f56589bd88c903a8bc6685bccd73909a04ac6d1db190c16d6
7
+ data.tar.gz: 2513697371bdd3f4ee2dac36933b64cd7ae01730b28d1e7032f5a3c0e97a566279c01d731ce1891f82901685c6aa7a2dbfc269fa1a2345a205d6cf1fcec8a197
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module BrowserTypes
2
3
  extend self
3
4
  CHROME = :chrome
@@ -1,25 +1,26 @@
1
- module Applitools
2
- module Selenium
3
- class BrowsersInfo < Set
1
+ # frozen_string_literal: true
4
2
 
5
- def add(obj)
6
- return super if obj.is_a? Applitools::Selenium::RenderBrowserInfo
7
- raise(
8
- Applitools::EyesIllegalArgument,
9
- "It is expected the value to be an Applitools::Selenium::RenderBrowserInfo instance," \
10
- " but got #{obj.class} instead"
11
- )
12
- end
3
+ module Applitools
4
+ module Selenium
5
+ class BrowsersInfo < Set
6
+ def add(obj)
7
+ return super if obj.is_a? Applitools::Selenium::RenderBrowserInfo
8
+ raise(
9
+ Applitools::EyesIllegalArgument,
10
+ 'It is expected the value to be an Applitools::Selenium::RenderBrowserInfo instance,' \
11
+ " but got #{obj.class} instead"
12
+ )
13
+ end
13
14
 
14
- def each(viewport_size = nil)
15
- return super() unless empty?
16
- return unless viewport_size
17
- default = Applitools::Selenium::RenderBrowserInfo.new.tap do |bi|
18
- bi.viewport_size = viewport_size
19
- bi.browser_type = BrowserTypes::CHROME
20
- end
21
- yield(default)
22
- end
23
- end
24
- end
25
- end
15
+ def each(viewport_size = nil)
16
+ return super() unless empty?
17
+ return unless viewport_size
18
+ default = Applitools::Selenium::RenderBrowserInfo.new.tap do |bi|
19
+ bi.viewport_size = viewport_size
20
+ bi.browser_type = BrowserTypes::CHROME
21
+ end
22
+ yield(default)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Applitools
4
+ module Selenium
5
+ module Concerns
6
+ module SeleniumEyes
7
+ USE_DEFAULT_MATCH_TIMEOUT = -1
8
+
9
+ # Validates the contents of an iframe and matches it with the expected output.
10
+ #
11
+ # @param [Hash] options The specific parameters of the desired screenshot.
12
+ # @option options [Array] :target_frames The frames to check.
13
+ def check_in_frame(options)
14
+ Applitools::ArgumentGuard.is_a? options, 'options', Hash
15
+
16
+ frames = options.delete :target_frames
17
+
18
+ Applitools::ArgumentGuard.is_a? frames, 'target_frames: []', Array
19
+
20
+ return yield if block_given? && frames.empty?
21
+
22
+ original_frame_chain = driver.frame_chain
23
+
24
+ logger.info 'Switching to target frame according to frames path...'
25
+ driver.switch_to.frames(frames_path: frames)
26
+ frame_chain_to_reset = driver.frame_chain
27
+ logger.info 'Done!'
28
+
29
+ ensure_frame_visible
30
+
31
+ yield if block_given?
32
+
33
+ reset_frames_scroll_position(frame_chain_to_reset)
34
+
35
+ logger.info 'Switching back into top level frame...'
36
+ driver.switch_to.default_content
37
+ return unless original_frame_chain
38
+ logger.info 'Switching back into original frame...'
39
+ driver.switch_to.frames frame_chain: original_frame_chain
40
+ end
41
+
42
+ # Takes a snapshot of the application under test and matches it with the expected output.
43
+ #
44
+ # @param [String] tag An optional tag to be assosiated with the snapshot.
45
+ # @param [Fixnum] match_timeout The amount of time to retry matching (seconds)
46
+ # def check_window(tag = nil, match_timeout = USE_DEFAULT_MATCH_TIMEOUT)
47
+ def check_window(*args)
48
+ tag = args.select { |a| a.is_a?(String) || a.is_a?(Symbol) }.first
49
+ match_timeout = args.select { |a| a.is_a?(Integer) }.first
50
+ fully = args.select { |a| a.is_a?(TrueClass) || a.is_a?(FalseClass) }.first
51
+ target = Applitools::Selenium::Target.window.tap do |t|
52
+ t.timeout(match_timeout || USE_DEFAULT_MATCH_TIMEOUT)
53
+ if is_a?(Applitools::Selenium::VisualGridEyes)
54
+ t.fully(true)
55
+ else
56
+ t.fully(force_full_page_screenshot)
57
+ end
58
+ t.fully(fully) unless fully.nil?
59
+ end
60
+ check(tag, target)
61
+ end
62
+
63
+ # Takes a snapshot of the application under test and matches a region of
64
+ # a specific element with the expected region output.
65
+ #
66
+ # @param [Applitools::Selenium::Element] element Represents a region to check.
67
+ # @param [Symbol] how a finder, such :css or :id. Selects a finder will be used to find an element
68
+ # See Selenium::Webdriver::Element#find_element documentation for full list of possible finders.
69
+ # @param [String] what The value will be passed to a specified finder. If finder is :css it must be a css selector.
70
+ # @param [Hash] options
71
+ # @option options [String] :tag An optional tag to be associated with the snapshot.
72
+ # @option options [Fixnum] :match_timeout The amount of time to retry matching. (Seconds)
73
+ # @option options [Boolean] :stitch_content If set to true, will try to get full content of the element
74
+ # (including hidden content due overflow settings) by scrolling the element,
75
+ # taking and stitching partial screenshots.
76
+ # @example Check region by element
77
+ # check_region(element, tag: 'Check a region by element', match_timeout: 3, stitch_content: false)
78
+ # @example Check region by css selector
79
+ # check_region(:css, '.form-row .input#e_mail', tag: 'Check a region by element', match_timeout: 3,
80
+ # stitch_content: false)
81
+ # @!parse def check_region(element, how=nil, what=nil, options = {}); end
82
+ def check_region(*args)
83
+ options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil }.merge! Applitools::Utils.extract_options!(args)
84
+ target = Applitools::Selenium::Target.new.region(*args).timeout(options[:match_timeout])
85
+ target.fully if options[:stitch_content]
86
+ check(options[:tag], target)
87
+ end
88
+
89
+ # Validates the contents of an iframe and matches it with the expected output.
90
+ #
91
+ # @param [Hash] options The specific parameters of the desired screenshot.
92
+ # @option options [Fixnum] :timeout The amount of time to retry matching. (Seconds)
93
+ # @option options [String] :tag An optional tag to be associated with the snapshot.
94
+ # @option options [String] :frame Frame element or frame name or frame id.
95
+ # @option options [String] :name_or_id The name or id of the target frame (deprecated. use :frame instead).
96
+ # @option options [String] :frame_element The frame element (deprecated. use :frame instead).
97
+ # @return [Applitools::MatchResult] The match results.
98
+
99
+ def check_frame(options = {})
100
+ options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil }.merge!(options)
101
+ frame = options[:frame] || options[:frame_element] || options[:name_or_id]
102
+ target = Applitools::Selenium::Target.frame(frame).timeout(options[:timeout]).fully
103
+ check(options[:tag], target)
104
+ end
105
+
106
+ # Validates the contents of a region in an iframe and matches it with the expected output.
107
+ #
108
+ # @param [Hash] options The specific parameters of the desired screenshot.
109
+ # @option options [String] :name_or_id The name or id of the target frame (deprecated. use :frame instead).
110
+ # @option options [String] :frame_element The frame element (deprecated. use :frame instead).
111
+ # @option options [String] :frame Frame element or frame name or frame id.
112
+ # @option options [String] :tag An optional tag to be associated with the snapshot.
113
+ # @option options [Symbol] :by By which identifier to find the region (e.g :css, :id).
114
+ # @option options [Fixnum] :timeout The amount of time to retry matching. (Seconds)
115
+ # @option options [Boolean] :stitch_content Whether to stitch the content or not.
116
+ # @return [Applitools::MatchResult] The match results.
117
+ def check_region_in_frame(options = {})
118
+ options = { timeout: USE_DEFAULT_MATCH_TIMEOUT, tag: nil, stitch_content: false }.merge!(options)
119
+ Applitools::ArgumentGuard.not_nil options[:by], 'options[:by]'
120
+ Applitools::ArgumentGuard.is_a? options[:by], 'options[:by]', Array
121
+
122
+ how_what = options.delete(:by)
123
+ frame = options[:frame] || options[:frame_element] || options[:name_or_id]
124
+
125
+ target = Applitools::Selenium::Target.new.timeout(options[:timeout])
126
+ target.frame(frame) if frame
127
+ target.fully if options[:stitch_content]
128
+ target.region(*how_what)
129
+
130
+ check(options[:tag], target)
131
+ end
132
+
133
+ # Use this method to perform seamless testing with selenium through eyes driver.
134
+ # It yields a block and passes to it an Applitools::Selenium::Driver instance, which wraps standard driver.
135
+ # Using Selenium methods inside the 'test' block will send the messages to Selenium
136
+ # after creating the Eyes triggers for them. Options are similar to {open}
137
+ # @yieldparam driver [Applitools::Selenium::Driver] Gives a driver to a block, which translates calls to a native
138
+ # Selemium::Driver instance
139
+ # @example
140
+ # eyes.test(app_name: 'my app', test_name: 'my test') do |driver|
141
+ # driver.get "http://www.google.com"
142
+ # driver.check_window("initial")
143
+ # end
144
+ def test(options = {}, &_block)
145
+ open(options)
146
+ yield(driver)
147
+ close
148
+ ensure
149
+ abort_if_not_closed
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'applitools/selenium/stitch_modes'
2
4
  require 'applitools/selenium/browsers_info'
3
5
 
4
6
  module Applitools
5
7
  module Selenium
6
8
  class Configuration < Applitools::EyesBaseConfiguration
7
-
8
9
  DEFAULT_CONFIG = proc do
9
10
  {
10
11
  force_full_page_screenshot: false,
@@ -69,7 +70,7 @@ module Applitools
69
70
  new_config = self.class.new
70
71
  config_keys.each do |k|
71
72
  new_config.send(
72
- "#{k}=", case value = self.send(k)
73
+ "#{k}=", case value = send(k)
73
74
  when Symbol, FalseClass, TrueClass, Integer, Float
74
75
  value
75
76
  else
@@ -84,10 +85,10 @@ module Applitools
84
85
  user_defined_vp = super
85
86
  user_defined_vp = nil if user_defined_vp.respond_to?(:square) && user_defined_vp.square == 0
86
87
  return user_defined_vp if user_defined_vp
87
- from_browsers_info = browsers_info.select {|bi| bi.viewport_size.square > 0 }.first
88
+ from_browsers_info = browsers_info.select { |bi| bi.viewport_size.square > 0 }.first
88
89
  return from_browsers_info.viewport_size if from_browsers_info
89
90
  nil
90
91
  end
91
92
  end
92
93
  end
93
- end
94
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'crass'
2
4
 
3
5
  module Applitools
@@ -35,7 +37,8 @@ module Applitools
35
37
  url = node[:tokens].select { |t| t[:node] == :function && t[:value] == 'url' }.first
36
38
  url_index = node[:tokens].index(url)
37
39
  url_string_node = url_index && node[:tokens][url_index + 1]
38
- url_string_node && url_string_node[:node] == :string && !url_string_node[:value].empty? && url_string_node[:value]
40
+ url_string_node &&
41
+ url_string_node[:node] == :string && !url_string_node[:value].empty? && url_string_node[:value]
39
42
  end
40
43
 
41
44
  def fetch_urls(nodes)
@@ -38,7 +38,7 @@ module Applitools::Selenium
38
38
  #
39
39
  # @param [Applitools::Location] value The location.
40
40
  def restore_state(value)
41
- Applitools::Utils::EyesSeleniumUtils.set_current_transforms(executor, "translate(10px, 0px)")
41
+ Applitools::Utils::EyesSeleniumUtils.set_current_transforms(executor, 'translate(10px, 0px)')
42
42
 
43
43
  transforms = value.values.compact.map(&:to_s).select { |el| !el.empty? }
44
44
  Applitools::Utils::EyesSeleniumUtils.set_transforms(executor, value)
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: false
1
2
  module Devices
2
3
  extend self
3
4
  IPhone4 = 'iPhone 4'.freeze
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Applitools
2
4
  module Selenium
3
5
  module DomCapture
4
6
  extend self
5
- DOM_EXTRACTION_TIMEOUT = 300 #seconds
7
+ DOM_EXTRACTION_TIMEOUT = 300 # seconds
6
8
  def full_window_dom(driver, server_connector, logger, position_provider = nil)
7
9
  return get_dom(driver, server_connector, logger) unless position_provider
8
10
  scroll_top_and_return_back(position_provider) do
@@ -18,7 +20,6 @@ module Applitools
18
20
  driver.switch_to.frames(frame_chain: original_frame_chain)
19
21
  end
20
22
  # CSS processing
21
-
22
23
  dom
23
24
  end
24
25
 
@@ -35,7 +36,7 @@ module Applitools
35
36
  raise Applitools::EyesError, "DOM extraction error: #{script_response['error']}" if script_response['error']
36
37
  sleep(0.2)
37
38
  end
38
- response_lines = script_response['value'].split /\r?\n/
39
+ response_lines = script_response['value'].split(/\r?\n/)
39
40
  separators = Oj.load(response_lines.shift)
40
41
  missing_css_list = []
41
42
  missing_frame_list = []
@@ -52,7 +53,6 @@ module Applitools
52
53
  end
53
54
  logger.info "Missing CSS: #{missing_css_list.count}"
54
55
  logger.info "Missing frames: #{missing_frame_list.count}"
55
- #fetch_css_files(missing_css_list)
56
56
 
57
57
  frame_data = recurse_frames(driver, server_connector, logger, missing_frame_list)
58
58
  result = replace(separators['iframeStartToken'], separators['iframeEndToken'], data.first, frame_data)
@@ -79,9 +79,10 @@ module Applitools
79
79
 
80
80
  css = missing_css_response.body
81
81
 
82
- found_and_missing_css = Applitools::Selenium::CssParser::FindEmbeddedResources.new(css).imported_css.map do |found_url|
83
- base_url(url).merge(found_url).to_s
84
- end
82
+ found_and_missing_css =
83
+ Applitools::Selenium::CssParser::FindEmbeddedResources.new(css).imported_css.map do |found_url|
84
+ base_url(url).merge(found_url).to_s
85
+ end
85
86
  fetch_css_files(found_and_missing_css, server_connector).each do |_k, v|
86
87
  css += v
87
88
  end
@@ -139,7 +140,7 @@ module Applitools
139
140
 
140
141
  def base_url(url)
141
142
  uri = URI.parse(url)
142
- uri.query = uri.fragment = nil;
143
+ uri.query = uri.fragment = nil
143
144
  uri.path = ''
144
145
  uri
145
146
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Applitools
2
4
  module Selenium
3
5
  module DomCapture
@@ -459,4 +461,4 @@ function __captureDomAndPoll() {
459
461
  SCRIPT
460
462
  end
461
463
  end
462
- end
464
+ end
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  require 'css_parser'
2
3
 
3
4
  module Applitools
4
5
  module Selenium
5
6
  class ExternalCssResources
6
7
  include CssParser
7
- def initialize(url, base_url = nil)
8
+ def initialize(url, _base_url = nil)
8
9
  @parser = CssParser::Parser.new(absolute_paths: true)
9
10
  @parser.load_uri!(url)
10
11
  @parser.compact!
@@ -20,9 +21,12 @@ module Applitools
20
21
 
21
22
  def images
22
23
  result = []
23
- @parser.each_rule_set { |s| s.expand_background_shorthand!; result.push(s) unless s.get_value('background-image').empty? }
24
+ @parser.each_rule_set do |s|
25
+ s.expand_background_shorthand!
26
+ result.push(s) unless s.get_value('background-image').empty?
27
+ end
24
28
  result
25
29
  end
26
30
  end
27
31
  end
28
- end
32
+ end
@@ -1,7 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module Applitools
2
3
  module Selenium
3
4
  class Eyes < SimpleDelegator
4
-
5
5
  def initialize(*args)
6
6
  options = Applitools::Utils.extract_options!(args)
7
7
  server_url = options.delete(:server_url)
@@ -13,7 +13,6 @@ module Applitools
13
13
  super Applitools::Selenium::SeleniumEyes.new(server_url, runner: runner || Applitools::ClassicRunner.new)
14
14
  end
15
15
  end
16
-
17
16
  end
18
17
  end
19
- end
18
+ end
@@ -116,7 +116,11 @@ module Applitools::Selenium
116
116
  logger.info 'Done! Adding initial screenshot..'
117
117
  logger.info "Initial part:(0,0) [#{image.width} x #{image.height}]"
118
118
 
119
- image.crop!(0,0,stitched_image.width < image.width ? stitched_image.width : image.width, stitched_image.height < image.height ? stitched_image.height : image.height)
119
+ image.crop!(
120
+ 0, 0,
121
+ stitched_image.width < image.width ? stitched_image.width : image.width,
122
+ stitched_image.height < image.height ? stitched_image.height : image.height
123
+ )
120
124
 
121
125
  stitched_image.replace! image, 0, 0
122
126
  logger.info 'Done!'
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Orientations
2
3
  PORTRAIT = 'portrait'
3
4
  LANDSCAPE = 'landscape'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Applitools
2
4
  module Selenium
3
5
  class RenderBrowserInfoFluent
@@ -42,4 +44,4 @@ module Applitools
42
44
  end
43
45
  end
44
46
  end
45
- end
47
+ end
@@ -1,14 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Applitools
2
4
  module Selenium
3
5
  class RenderResources < Hash
4
6
  class ResourceMissingInCache < EyesError; end
5
7
  def []=(key, value)
6
- raise Applitools::EyesIllegalArgument, "Expected key to be an instance of URI (but got #{key.class}) - #{key}" unless
7
- key.is_a? URI
8
- raise Applitools::EyesIllegalArgument, "Expected value to be an instance of Applitools::Selenium::VGResource" \
9
- " (but got #{value.class}) - #{key}:#{value}" unless value.is_a? Applitools::Selenium::VGResource
8
+ unless key.is_a? URI
9
+ raise Applitools::EyesIllegalArgument, "Expected key to be an instance of URI (but got #{key.class}) - #{key}"
10
+ end
11
+ unless value.is_a? Applitools::Selenium::VGResource
12
+ raise(
13
+ Applitools::EyesIllegalArgument, 'Expected value to be an instance of Applitools::Selenium::VGResource' \
14
+ " (but got #{value.class}) - #{key}:#{value}"
15
+ )
16
+ end
10
17
  super
11
18
  end
12
19
  end
13
20
  end
14
- end
21
+ end