Class: Browsery::Connector
- Inherits:
-
Object
- Object
- Browsery::Connector
- Defined in:
- lib/browsery/connector.rb
Overview
A connector provides a thin layer that combines configuration files and access to the WebDriver. It’s a thin layer in that, other than #initialize, it is a drop-in replacement for WebDriver calls.
For example, if you usually access a method as ‘@driver.find_element`, you can still access them as the same method under `@connector.find_element`.
Defined Under Namespace
Classes: Config
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
Class Method Summary collapse
-
.browser_name ⇒ Object
Equivalent to @driver.browser.
-
.finalize!(force = false) ⇒ Object
Finalize connectors in the pool that are no longer used, and then clear the pool if it should be empty.
-
.get(connector_id, env_id) ⇒ Connector
Given a connector profile and an environment profile, this method will instantiate a connector object with the correct WebDriver instance and settings.
-
.get_default ⇒ Connector
Retrieve the default connector for the current environment.
-
.load(path, selector) ⇒ Hash
Load profile from a specific path using the selector(s) specified.
-
.resolve(cfg, overrides) ⇒ Hash
Resolve a set of profile overrides.
Instance Method Summary collapse
-
#finalize! ⇒ Object
Perform cleanup on the connector and driver.
-
#initialize(config) ⇒ Connector
constructor
private
Initialize a new connector with a set of configuration files.
-
#method_missing(name, *args, &block) ⇒ Object
Forward any other method call to the configuration container; if that fails, forward it to the WebDriver.
-
#reset! ⇒ Boolean
Resets the current session by deleting all cookies and clearing all local and session storage.
-
#respond_to?(name) ⇒ Boolean
Forward unhandled message checks to the configuration and driver.
-
#url_for(path) ⇒ URI
Compose a URL from the provided
path
and the environment profile.
Constructor Details
#initialize(config) ⇒ Connector
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Initialize a new connector with a set of configuration files.
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/browsery/connector.rb', line 176 def initialize(config) @config = config # Load and configure the WebDriver, if necessary if concon = config.connector driver_config = { } driver = concon[:driver] raise ArgumentError, "Connector driver must not be empty" if driver.nil? # Handle hub-related options, like hub URLs (for remote execution) if hub = concon[:hub] builder = URI.parse(hub[:url]) builder.user = hub[:user] if hub.has_key?(:user) builder.password = hub[:pass] if hub.has_key?(:pass) Browsery.logger.debug("Connector(##{self.object_id}): targeting remote #{builder.to_s}") driver_config[:url] = builder.to_s end # Handle driver-related timeouts if timeouts = concon[:timeouts] client = Selenium::WebDriver::Remote::Http::Default.new client.timeout = timeouts[:driver] driver_config[:http_client] = client end # Handle archetypal capability lists if archetype = concon[:archetype] Browsery.logger.debug("Connector(##{self.object_id}): using #{archetype.inspect} as capabilities archetype") caps = Selenium::WebDriver::Remote::Capabilities.send(archetype) if caps_set = concon[:capabilities] caps.merge!(caps_set) end driver_config[:desired_capabilities] = caps end # Load Firefox profile if specified - applicable only when using the firefoxdriver if profile = concon[:profile] driver_config[:profile] = profile end # Initialize the driver and declare explicit browser timeouts Browsery.logger.debug("Connector(##{self.object_id}): using WebDriver(#{driver.inspect}, #{driver_config.inspect})") @driver = Selenium::WebDriver.for(driver.to_sym, driver_config) # Resize browser window for local browser with 'resolution' if concon[:resolution] width = concon[:resolution].split(/x/)[0].to_i height = concon[:resolution].split(/x/)[1].to_i @driver.manage.window.resize_to(width, height) end # setTimeout is undefined for safari driver so skip these steps for it unless @driver.browser == :safari if timeouts = concon[:timeouts] @driver.manage.timeouts.implicit_wait = timeouts[:implicit_wait] if timeouts[:implicit_wait] @driver.manage.timeouts.page_load = timeouts[:page_load] if timeouts[:page_load] @driver.manage.timeouts.script_timeout = timeouts[:script_timeout] if timeouts[:script_timeout] end end end end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
Forward any other method call to the configuration container; if that fails, forward it to the WebDriver. The WebDriver will take care of any method resolution errors.
245 246 247 248 249 250 251 252 |
# File 'lib/browsery/connector.rb', line 245 def method_missing(name, *args, &block) if @config.respond_to?(name) @config.send(name, *args, *block) else Browsery.logger.debug("Connector(##{self.object_id})->#{name}(#{args.map { |a| a.inspect }.join(', ')})") @driver.send(name, *args, &block) end end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
164 165 166 |
# File 'lib/browsery/connector.rb', line 164 def config @config end |
Class Method Details
.browser_name ⇒ Object
Equivalent to @driver.browser
121 122 123 |
# File 'lib/browsery/connector.rb', line 121 def self.browser_name Thread.current[:active_connector].browser end |
.finalize!(force = false) ⇒ Object
Finalize connectors in the pool that are no longer used, and then clear the pool if it should be empty.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/browsery/connector.rb', line 48 def self.finalize!(force = false) return if Browsery.settings.reuse_driver? && !force if Thread.current[:active_connector] self.finalization_queue << Thread.current[:active_connector] Thread.current[:active_connector] = nil end return unless Browsery.settings.auto_finalize? while self.finalization_queue.size > 0 connector = self.finalization_queue.pop begin connector.finalize! rescue => e Browsery.logger.error("Could not finalize Connector(##{connector.object_id}): #{e.}") end end end |
.get(connector_id, env_id) ⇒ Connector
Given a connector profile and an environment profile, this method will instantiate a connector object with the correct WebDriver instance and settings.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/browsery/connector.rb', line 76 def self.get(connector_id, env_id) # Ensure arguments are at least provided raise ArgumentError, "A connector must be provided" if connector_id.blank? raise ArgumentError, "An environment must be provided" if env_id.blank? # Find the connector and environment profiles connector_cfg = self.load(Browsery.root.join('config/browsery', 'connectors'), connector_id) env_cfg = self.load(Browsery.root.join('config/browsery', 'environments'), env_id) cfg = Config.new(connector_cfg, env_cfg) if Thread.current[:active_connector] && !Browsery.settings.reuse_driver? self.finalization_queue << Thread.current[:active_connector] Thread.current[:active_connector] = nil end # If the current thread already has an active connector, and the connector # is of the same type requested, reuse it after calling `reset!` active_connector = Thread.current[:active_connector] if active_connector.present? if active_connector.config == cfg active_connector.reset! else self.finalization_queue << active_connector active_connector = nil end end # Reuse or instantiate Thread.current[:active_connector] = active_connector || Connector.new(cfg) end |
.get_default ⇒ Connector
Retrieve the default connector for the current environment.
111 112 113 114 115 116 117 118 |
# File 'lib/browsery/connector.rb', line 111 def self.get_default connector = Browsery.settings.connector env = Browsery.settings.env Browsery.logger.debug("Retrieving connector with settings (#{connector}, #{env})") # Get a connector instance and use it in the new page object self.get(connector, env) end |
.load(path, selector) ⇒ Hash
Load profile from a specific path using the selector(s) specified.
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/browsery/connector.rb', line 131 def self.load(path, selector) overrides = selector.to_s.split(/:/) name = overrides.shift filepath = path.join("#{name}.yml") raise ArgumentError, "Cannot load profile #{name.inspect} because #{filepath.inspect} does not exist" unless filepath.exist? cfg = YAML.load(ERB.new(File.read(filepath)).result) cfg = self.resolve(cfg, overrides) cfg.freeze end |
.resolve(cfg, overrides) ⇒ Hash
Resolve a set of profile overrides.
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/browsery/connector.rb', line 148 def self.resolve(cfg, overrides) cfg = cfg.dup.with_indifferent_access if = cfg.delete(:overrides) # Evaluate each override in turn, allowing each override to--well, # override--anything coming before it overrides.each do |override| if tree = [override] cfg.deep_merge!(tree) end end end cfg end |
Instance Method Details
#finalize! ⇒ Object
Perform cleanup on the connector and driver.
167 168 169 170 |
# File 'lib/browsery/connector.rb', line 167 def finalize! @driver.quit true end |
#reset! ⇒ Boolean
Resets the current session by deleting all cookies and clearing all local and session storage. Local and session storage are only cleared if the underlying driver supports it, and even then, only if the storage supports atomic clearing.
260 261 262 263 264 265 |
# File 'lib/browsery/connector.rb', line 260 def reset! @driver.manage. @driver.try(:local_storage).try(:clear) @driver.try(:session_storage).try(:clear) true end |
#respond_to?(name) ⇒ Boolean
Forward unhandled message checks to the configuration and driver.
271 272 273 |
# File 'lib/browsery/connector.rb', line 271 def respond_to?(name) super || @config.respond_to?(name) || @driver.respond_to?(name) end |
#url_for(path) ⇒ URI
Compose a URL from the provided path
and the environment profile. The latter contains things like the hostname, port, SSL settings.
280 281 282 283 284 |
# File 'lib/browsery/connector.rb', line 280 def url_for(path) root = @config.env[:root] raise ArgumentError, "The 'root' attribute is missing from the environment profile" unless root URI.join(root, path) end |