NAME
Selenium::Client - Module for communicating with WC3 standard selenium servers
VERSION
version 1.02
CONSTRUCTOR
new(%options) = Selenium::Client
Either connects to a driver at the specified host and port, or spawns one locally.
Spawns a server on a random port in the event the host is "localhost" (or 127.0.0.1) and nothing is reachable on the provided port.
Returns a Selenium::Client object with all WC3 methods exposed.
To view all available methods and their documentation, the catalog() method is provided.
Remote Server options:
version
ENUM (stable,draft,unstable) - WC3 Spec to use.-
Default: stable
host
STRING - hostname of your server.-
Default: localhost
prefix
STRING - any prefix needed to communicate with the server, such as /wd, /hub, /wd/hub, or /grid-
Default: ''
port
INTEGER - Port which the server is listening on.-
Default: 4444 Note: when spawning, this will be ignored and a random port chosen instead.
scheme
ENUM (http,https) - HTTP scheme to use-
Default: http
nofetch
BOOL - Do not check for a newer copy of the WC3 specifications on startup if we already have them available.-
Default: 1
client_dir
STRING - Where to store specs and other files downloaded when spawning servers.-
Default: ~/.selenium
debug
BOOLEAN - Whether to print out various debugging output.-
Default: false
auto_close
BOOLEAN - Automatically close spawned selenium servers and sessions.-
Only turn this off when you are debugging.
Default: true
post_callbacks
ARRAY[CODE] - Executed after each request to the selenium server.-
Callbacks are passed $self, an HTTP::Tiny response hashref and the request hashref. Use this to implement custom error handlers, testing harness modifications etc.
Return a truthy value to immediately exit the request subroutine after all cbs are executed. Truthy values (if any are returned) are returned in order encountered.
When using remote servers, you should take extra care that they automatically clean up after themselves. We cannot guarantee the state of said servers after interacting with them.
Spawn Options:
driver
STRING - Plug-in module used to spawn drivers when needed.-
Included are 'Auto', 'SeleniumHQ::Jar', 'Gecko', 'Chrome', 'Edge' Default: Auto
The 'Auto' Driver will pick whichever direct driver looks like it will work for your chosen browser. If we can't find one, we'll fall back to SeleniumHQ::Jar.
browser
STRING - desired browser. Used by the 'Auto' Driver.-
Default: Blank
headless
BOOL - Whether to run the browser headless. Ignored by 'Safari' Driver.-
Default: True
driver_version
STRING - Version of your driver software you wish to download and run.-
Blank and Partial versions will return the latest sub-version available. Only relevant to Drivers which auto-download (currently only SeleniumHQ::Jar).
Default: Blank
Driver modules should be in the Selenium::Driver namespace. They may implement additional parameters which can be passed into the options hash.
METHODS
Most of the methods are dynamic based on the selenium spec
This means that the Selenium::Client class can directly call all selenium methods. We provide a variety of subclasses as sugar around this:
Selenium::Session
Selenium::Capabilities
Selenium::Element
Which will simplify correctly passing arguments in the case of sessions and elements. However, this does not change the fact that you still must take great care. We do no validation whatsoever of the inputs, and the selenium server likes to hang when you give it an invalid input. So take great care and understand this is what "script hung and died" means -- you passed the function an unrecognized argument.
This is because Selenium::Specification cannot (yet!) parse the inputs and outputs for each endpoint at this time. As such we can't just filter against the relevant prototype.
In any case, all subs will look like this, for example:
$client->Method( key => value, key1 => value1, ...) = (@return_per_key)
The options passed in are basically JSON serialized and passed directly as a POST body (or included into the relevant URL). We return a list of items which are a hashref per item in the result (some of them blessed). For example, NewSession will return a Selenium::Capabilities and Selenium::Session object. The order in which they are returned will be ordered alphabetically.
Passing Capabilities to NewSession()
By default, we will pass a set of capabilities that satisfy the options passed to new().
If you want *other* capabilities, pass them directly to NewSession as documented in the WC3 spec.
However, this will ignore what you passed to new(). Caveat emptor.
For the general list of options supported by each browser, see here:
Firefox
- https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities/firefoxOptionsChrome
- https://sites.google.com/a/chromium.org/chromedriver/capabilitiesEdge
- https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-optionsSafari
- https://developer.apple.com/documentation/webkit/about_webdriver_for_safari
catalog(BOOL verbose=0) = HASHREF
Returns the entire method catalog. Prints out every method and a link to the relevant documentation if verbose is true.
SUBCLASSES
Selenium::Capabilities
Returned as first element from NewSession(). Query this object for various things about the server capabilities.
Selenium::Session
Returned as second element of NewSession(). Has a destructor which will automatically clean itself up when we go out of scope. Alternatively, when the driver object goes out of scope, all sessions it spawned will be destroyed.
You can call Selenium methods on this object which require a sessionid without passing it explicitly.
Selenium::Element
Returned from find element calls.
You can call Selenium methods on this object which require a sessionid and elementid without passing them explicitly.
STUPID SELENIUM TRICKS
There are a variety of quirks with Selenium drivers that you just have to put up with, don't log bugs on these behaviors.
alerts
If you have an alert() open on the page, all calls to the selenium server will 500 until you dismiss or accept it.
Also be aware that chrome will re-fire alerts when you do a forward() or back() event, unlike firefox.
tag names
Safari returns ALLCAPS names for tags. amazing
properties and attributes
Many valid properties/attributes will never be accessible via GetProperty() or GetAttribute().
For example, getting the "for" value of a <label> element is flat-out impossible using either GetProperty or GetAttribute. There are many other such cases, the most common being "non-standard" properties such as aria-* or things used by JS templating engines. You are better off using JS shims to do any element inspection.
Similarly the IsElementSelected() method is quite unreliable. We can work around this however by just using the CSS :checked pseudoselector when looking for elements, as that actually works.
It is this for these reasons that you should consider abandoning Selenium for something that can actually do this correctly such as Playwright.
windows
When closing windows, be aware you will be NOT be shot back to the last window you had focused before switching to the current one. You have to manually switch back to an existing one.
Opening _blank targeted links *does not* automatically switch to the new window. The procedure for handling links of such a sort to do this is as follows:
# Get current handle
my $handle = $session->GetWindowHandle();
# Assuming the element is an href with target=_blank ...
$element->ClickElement();
# Get all handles and filter for the ones that we aren't currently using
my @handles = $session->GetWindowHandles();
my @new_handles = grep { $handle != $_ } @handles;
# Use pop() as it will always be returned in the order windows are opened
$session->SwitchToWindow( handle => pop(@new_handles) );
Different browser drivers also handle window handles differently. Chrome in particular demands you stringify handles returned from the driver. It also seems to be a lot less cooperative than firefox when setting the WindowRect.
arguments
If you make a request of the server with arguments it does not understand it will hang for 30s, so set a SIGALRM handler if you insist on doing so.
MSWin32 issues
The default version of the Java JRE from java.com is quite simply ancient on windows, and SeleniumHQ develops against JDK 11 and better. So make sure your JDK bin dir is in your PATH before the JRE path (or don't install an ancient JRE lol)
If you don't, you'll probably get insta-explosions due to their usage of new language features. Kind of like how you'll die if you use a perl without signatures with this module :)
Also, due to perl pseudo-forks hanging forever if anything is ever waiting on read() in windows, we don't fork to spawn binaries. Instead we use start
to open a new cmd.exe window, which will show up in your task tray. Don't close this or your test will fail for obvious reasons.
AUTHOR
George S. Baugh <george@troglodyne.net>
AUTHOR
George S. Baugh <george@troglodyne.net>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2021 by George S. Baugh.
This is free software, licensed under:
The MIT (X11) License