Class: Unobtainium::Drivers::Phantom Private

Inherits:
Selenium
  • Object
show all
Extended by:
Support::Identifiers, Support::PortScanner, Support::Utility
Defined in:
lib/unobtainium/drivers/phantom.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Driver implementation using the selenium-webdriver gem to connect to PhantomJS.

Constant Summary collapse

LABELS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Recognized labels for matching the driver

{
  phantomjs: %i[headless phantom],
}.freeze
PORT_RANGES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Port scanning ranges (can also be arrays or single port numbers.

[
  9134,
  8080,
  8000..8079,
  8081..10000,
  1025..7999,
  10001..65535,
].freeze
CONNECT_TIMEOUT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Timeout for waiting for connecting to PhantomJS server, in seconds

60

Constants included from Support::PortScanner

Support::PortScanner::MAX_RETRIES, Support::PortScanner::RETRY_DELAY

Constants inherited from Selenium

Selenium::CHROMIUM_EXECUTABLES

Class Method Summary collapse

Methods included from Support::Identifiers

identifier

Methods included from Support::PortScanner

port_open?, scan

Methods included from Support::Utility

normalize_label

Methods inherited from Selenium

matches?

Class Method Details

.create(_, options) ⇒ Object

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.

Create and return a driver instance



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/unobtainium/drivers/phantom.rb', line 125

def create(_, options)
  # :nocov:

  # Extract PhantomJS options
  host = options['phantomjs.host']
  port = options['phantomjs.port'] || options['phantomjs.generated_port']
  opts = options.dup
  opts.delete('phantomjs')

  # Start PhantomJS server, if it isn't already running
  conn_str = "#{host}:#{port}"
  runner = ::Unobtainium::Runtime.instance.store_with_if(conn_str) do
    ::Unobtainium::Support::Runner.new(conn_str,
                                       Phantomjs.path,
                                       "--webdriver=#{conn_str}")
  end
  runner.start

  # Wait for the server to open a port.
  timeout = CONNECT_TIMEOUT
  while timeout > 0 and not port_open?(host, port)
    sleep 1
    timeout -= 1
  end
  if timeout <= 0
    runner.kill
    out = runner.stdout.read
    err = runner.stderr.read
    runner.reset

    raise "Timeout waiting to connect to PhantomJS!\n"\
      "STDOUT: #{out}\n"\
      "STDERR: #{err}"
  end

  # Run Selenium against server
  driver = ::Selenium::WebDriver.for(:remote, opts)
  return driver

  # :nocov:
end

.ensure_preconditions(_, _) ⇒ Object

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.

Ensure that the driver’s preconditions are fulfilled.



53
54
55
56
57
58
59
60
61
62
# File 'lib/unobtainium/drivers/phantom.rb', line 53

def ensure_preconditions(_, _)
  super
  begin
    require 'phantomjs'
  rescue LoadError => err
    raise LoadError, "#{err.message}: you need to add "\
          "'phantomjs' to your Gemfile to use this driver!",
          err.backtrace
  end
end

.resolve_options(label, options) ⇒ Object

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.

Mostly provides webdriver-specific options for PhantomJS



66
67
68
69
70
71
72
73
74
75
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/unobtainium/drivers/phantom.rb', line 66

def resolve_options(label, options)
  label, options = super

  options = ::Collapsium::UberHash.new(options)

  # If a URL is already provided, we should respect this.
  merge_url(options)

  # Provide defaults for webdriver host and port.
  merge_defaults(options)

  # At this point, the :phantomjs field is canonical in that it will
  # be used to generate a :port and :url if necessary. That means we
  # can use it to create a stable ID, too.
  # This also implies that the :url field is pointless and should not
  # be part of the ID; it will be generated again later on.
  options.delete(:url)

  # We need to figure out what we have to do based on detecting whether
  # a port or some other option changed (or nothing did!)
  fix_ports(label, options)

  # We find a free port here, so there's a possibility it'll get used
  # before we run the server in #create. However, for the purpose of
  # resolving options that's necessary. So we'll just live with this
  # until it becomes a problem.
  if options['phantomjs.generated_port'].nil?
    if options['phantomjs.port'].nil?
      ports = scan(options['phantomjs.host'], *PORT_RANGES,
                   for: :available, amount: :first)
      if ports.empty?
        raise "Could not find an available port for the PhantomJS server!"
      end
      options['phantomjs.generated_port'] = ports[0]
    else
      options['phantomjs.generated_port'] = options['phantomjs.port']
    end
  end

  # Now we can't just use new_id because we might have found a new
  # port in the meantime. We'll have to generate yet another ID, and
  # use that.
  # Now before calculating this new ID, we'll run the options through
  # the super method again. This is to ensure that all keys have the
  # expected class *before* we perform this calculation.
  new_id = identifier('driver', label, options)
  options['unobtainium_instance_id'] = new_id

  # Now we can generate the :url field for Selenium's benefit; it's
  # just a copy of the canonical options.
  options[:url] = "#{options['phantomjs.scheme']}://"\
      "#{options['phantomjs.host']}:"\
      "#{options['phantomjs.generated_port']}"

  return label, options
end