|
@@ -2,32 +2,43 @@ package Selenium::Firefox;
|
|
|
|
|
|
|
|
# ABSTRACT: Use FirefoxDriver without a Selenium server
|
|
# ABSTRACT: Use FirefoxDriver without a Selenium server
|
|
|
use Moo;
|
|
use Moo;
|
|
|
-use Selenium::CanStartBinary::FindBinary qw/coerce_firefox_binary/;
|
|
|
|
|
|
|
+use Selenium::Firefox::Binary qw/firefox_path/;
|
|
|
|
|
+use Selenium::CanStartBinary::FindBinary qw/coerce_simple_binary coerce_firefox_binary/;
|
|
|
extends 'Selenium::Remote::Driver';
|
|
extends 'Selenium::Remote::Driver';
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
|
|
+ # these two are the same, and will only work with Firefox 48 and
|
|
|
|
|
+ # greater
|
|
|
my $driver = Selenium::Firefox->new;
|
|
my $driver = Selenium::Firefox->new;
|
|
|
my $driver = Selenium::Firefox->new( marionette_enabled => 1 );
|
|
my $driver = Selenium::Firefox->new( marionette_enabled => 1 );
|
|
|
|
|
+ # execute your test as usual
|
|
|
|
|
+ $driver->shutdown_binary;
|
|
|
|
|
+
|
|
|
|
|
+ # For Firefox 47 and older, disable marionette:
|
|
|
|
|
+ my $driver = Selenium::Firefox->new( marionette_enabled => 0 );
|
|
|
|
|
+ $driver->shutdown_binary;
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
This class allows you to use the FirefoxDriver without needing the JRE
|
|
This class allows you to use the FirefoxDriver without needing the JRE
|
|
|
-or a selenium server running. When you refrain from passing the
|
|
|
|
|
-C<remote_server_addr> and C<port> arguments, we will search for the
|
|
|
|
|
-Firefox executable in your $PATH. We'll try to start the binary
|
|
|
|
|
-connect to it, shutting it down at the end of the test.
|
|
|
|
|
|
|
+or a selenium server running. Unlike starting up an instance of
|
|
|
|
|
+S::R::D, do not pass the C<remote_server_addr> and C<port> arguments,
|
|
|
|
|
+and we will search for the Firefox executable in your $PATH. We'll try
|
|
|
|
|
+to start the binary, connect to it, and shut it down at the end of the
|
|
|
|
|
+test.
|
|
|
|
|
|
|
|
If the Firefox application is not found in the expected places, we'll
|
|
If the Firefox application is not found in the expected places, we'll
|
|
|
fall back to the default L<Selenium::Remote::Driver> behavior of
|
|
fall back to the default L<Selenium::Remote::Driver> behavior of
|
|
|
assuming defaults of 127.0.0.1:4444 after waiting a few seconds.
|
|
assuming defaults of 127.0.0.1:4444 after waiting a few seconds.
|
|
|
|
|
|
|
|
-If you specify a remote server address, or a port, we'll assume you
|
|
|
|
|
-know what you're doing and take no additional behavior.
|
|
|
|
|
|
|
+If you specify a remote server address, or a port, our assumption is
|
|
|
|
|
+that you are doing standard S::R::D behavior and we will not attempt
|
|
|
|
|
+any binary startup.
|
|
|
|
|
|
|
|
If you're curious whether your Selenium::Firefox instance is using a
|
|
If you're curious whether your Selenium::Firefox instance is using a
|
|
|
separate Firefox binary, or through the selenium server, you can check
|
|
separate Firefox binary, or through the selenium server, you can check
|
|
|
-the C<binary_mode> attr after instantiation.
|
|
|
|
|
|
|
+the value of the C<binary_mode> attr after instantiation.
|
|
|
|
|
|
|
|
=cut
|
|
=cut
|
|
|
|
|
|
|
@@ -38,17 +49,23 @@ has '+browser_name' => (
|
|
|
|
|
|
|
|
=attr binary
|
|
=attr binary
|
|
|
|
|
|
|
|
-Optional: specify the path to your binary. If you don't specify
|
|
|
|
|
-anything, we'll try to find it on our own in the default installation
|
|
|
|
|
-paths for Firefox. If your Firefox is elsewhere, we probably won't be
|
|
|
|
|
-able to find it, so you may be well served by specifying it yourself.
|
|
|
|
|
|
|
+Optional: specify the path to the C<geckodriver> binary - this is NOT
|
|
|
|
|
+the path to the Firefox browser. To specify the path to your Firefox
|
|
|
|
|
+browser binary, see the L</firefox_binary> attr.
|
|
|
|
|
+
|
|
|
|
|
+For Firefox 48 and greater, this is the path to your C<geckodriver>
|
|
|
|
|
+executable. If you don't specify anything, we'll search for
|
|
|
|
|
+C<geckodriver> in your $PATH.
|
|
|
|
|
+
|
|
|
|
|
+For Firefox 47 and older, this attribute does not apply, because the
|
|
|
|
|
+older FF browsers do not use the separate driver binary startup.
|
|
|
|
|
|
|
|
=cut
|
|
=cut
|
|
|
|
|
|
|
|
has 'binary' => (
|
|
has 'binary' => (
|
|
|
is => 'lazy',
|
|
is => 'lazy',
|
|
|
- coerce => \&coerce_firefox_binary,
|
|
|
|
|
- default => sub { 'firefox' },
|
|
|
|
|
|
|
+ coerce => \&coerce_simple_binary,
|
|
|
|
|
+ default => sub { 'geckodriver' },
|
|
|
predicate => 1
|
|
predicate => 1
|
|
|
);
|
|
);
|
|
|
|
|
|
|
@@ -71,22 +88,54 @@ has 'binary_port' => (
|
|
|
default => sub { 9090 }
|
|
default => sub { 9090 }
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+=attr firefox_profile
|
|
|
|
|
+
|
|
|
|
|
+Optional: Pass in an instance of L<Selenium::Firefox::Profile>
|
|
|
|
|
+pre-configured as you please. The preferences you specify will be
|
|
|
|
|
+merged with the ones necessary for setting up webdriver, and as a
|
|
|
|
|
+result some options may be overwritten or ignored.
|
|
|
|
|
+
|
|
|
|
|
+ my $profile = Selenium::Firefox::Profile->new;
|
|
|
|
|
+ my $firefox = Selenium::Firefox->new(
|
|
|
|
|
+ firefox_profile => $profile
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+=cut
|
|
|
|
|
+
|
|
|
has '_binary_args' => (
|
|
has '_binary_args' => (
|
|
|
is => 'lazy',
|
|
is => 'lazy',
|
|
|
builder => sub {
|
|
builder => sub {
|
|
|
my ($self) = @_;
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
- my $args = ' -no-remote';
|
|
|
|
|
- if( $self->marionette_enabled ) {
|
|
|
|
|
- $args .= ' -marionette';
|
|
|
|
|
|
|
+ if ( $self->marionette_enabled ) {
|
|
|
|
|
+ my $args = ' --port ' . $self->port;
|
|
|
|
|
+ $args .= ' --marionette-port ' . $self->marionette_binary_port;
|
|
|
|
|
+
|
|
|
|
|
+ if ( $self->has_firefox_binary ) {
|
|
|
|
|
+ $args .= ' --binary "' . $self->firefox_binary . '"';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $args;
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ return ' -no-remote';
|
|
|
}
|
|
}
|
|
|
- return $args;
|
|
|
|
|
}
|
|
}
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
has '+wd_context_prefix' => (
|
|
has '+wd_context_prefix' => (
|
|
|
is => 'ro',
|
|
is => 'ro',
|
|
|
- default => sub { '/hub' }
|
|
|
|
|
|
|
+ default => sub {
|
|
|
|
|
+ my ($self) = @_;
|
|
|
|
|
+
|
|
|
|
|
+ if ($self->marionette_enabled) {
|
|
|
|
|
+ return '';
|
|
|
|
|
+ }
|
|
|
|
|
+ else {
|
|
|
|
|
+ return '/hub';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
=attr marionette_binary_port
|
|
=attr marionette_binary_port
|
|
@@ -97,15 +146,15 @@ there's no a priori guarantee that this will be an open port, this is
|
|
|
_not_ necessarily the port that we end up using - if the port here is
|
|
_not_ necessarily the port that we end up using - if the port here is
|
|
|
already bound, we'll search above it until we find an open one.
|
|
already bound, we'll search above it until we find an open one.
|
|
|
|
|
|
|
|
-See L<Selenium::CanStartBinary/port> for more details, and
|
|
|
|
|
-L<Selenium::Remote::Driver/port> after instantiation to see what the
|
|
|
|
|
-actual port turned out to be.
|
|
|
|
|
-
|
|
|
|
|
Selenium::Firefox->new(
|
|
Selenium::Firefox->new(
|
|
|
marionette_enabled => 1,
|
|
marionette_enabled => 1,
|
|
|
marionette_binary_port => 12345,
|
|
marionette_binary_port => 12345,
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+Attempting to specify a C<marionette_binary_port> in conjunction with
|
|
|
|
|
+setting C<marionette_enabled> does not make sense and will most likely
|
|
|
|
|
+not do anything useful.
|
|
|
|
|
+
|
|
|
=cut
|
|
=cut
|
|
|
|
|
|
|
|
has 'marionette_binary_port' => (
|
|
has 'marionette_binary_port' => (
|
|
@@ -115,34 +164,46 @@ has 'marionette_binary_port' => (
|
|
|
|
|
|
|
|
=attr marionette_enabled
|
|
=attr marionette_enabled
|
|
|
|
|
|
|
|
-Optional: specify whether L<marionette|https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette>
|
|
|
|
|
-should be enabled or not. If you enable the marionette_enabled flag,
|
|
|
|
|
-Firefox is launched with marionette server listening to
|
|
|
|
|
-C<marionette_binary_port>.
|
|
|
|
|
|
|
+Optional: specify whether
|
|
|
|
|
+L<marionette|https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette>
|
|
|
|
|
+should be enabled or not. By default, marionette is enabled, which
|
|
|
|
|
+assumes you are running with Firefox 48 or newer. To use this module
|
|
|
|
|
+to start Firefox 47 or older, you must pass C<marionette_enabled =>
|
|
|
|
|
+0>.
|
|
|
|
|
+
|
|
|
|
|
+ my $ff48 = Selenium::Firefox->new( marionette_enabled => 1 ); # defaults to 1
|
|
|
|
|
+ my $ff47 = Selenium::Firefox->new( marionette_enabled => 0 );
|
|
|
|
|
+
|
|
|
|
|
+=cut
|
|
|
|
|
|
|
|
-The firefox binary must have been built with this funtionality and it's
|
|
|
|
|
-available in L<all recent Firefox binaries|https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Builds>.
|
|
|
|
|
|
|
+has 'marionette_enabled' => (
|
|
|
|
|
+ is => 'lazy',
|
|
|
|
|
+ default => 1
|
|
|
|
|
+);
|
|
|
|
|
|
|
|
-Note: L<Selenium::Remote::Driver> does not yet provide a marionette
|
|
|
|
|
-client. It's up to the user to use a client or a marionette-to-webdriver
|
|
|
|
|
-proxy to communicate with the marionette server.
|
|
|
|
|
|
|
+=attr firefox_binary
|
|
|
|
|
|
|
|
- Selenium::Firefox->new( marionette_enabled => 1 );
|
|
|
|
|
|
|
+Optional: specify the path to the Firefox browser executable. Although
|
|
|
|
|
+we will attempt to locate this in your $PATH, you may specify it
|
|
|
|
|
+explicitly here. Note that path here must point to a file that exists
|
|
|
|
|
+and is executable, or we will croak.
|
|
|
|
|
|
|
|
-and Firefox will have 2 ports open. One for webdriver and one
|
|
|
|
|
-for marionette:
|
|
|
|
|
|
|
+For Firefox 48 and newer, this will be passed to C<geckodriver> such
|
|
|
|
|
+that it will attempt to start up the Firefox at the specified path.
|
|
|
|
|
|
|
|
- netstat -tlp | grep firefox
|
|
|
|
|
- tcp 0 0 localhost:9090 *:* LISTEN 23456/firefox
|
|
|
|
|
- tcp 0 0 localhost:2828 *:* LISTEN 23456/firefox
|
|
|
|
|
|
|
+For Firefox 47 and older, this browser path will be the file that we
|
|
|
|
|
+directly start up.
|
|
|
|
|
|
|
|
=cut
|
|
=cut
|
|
|
|
|
|
|
|
-has 'marionette_enabled' => (
|
|
|
|
|
- is => 'lazy',
|
|
|
|
|
- default => 0
|
|
|
|
|
|
|
+has 'firefox_binary' => (
|
|
|
|
|
+ is => 'ro',
|
|
|
|
|
+ coerce => \&coerce_firefox_binary,
|
|
|
|
|
+ predicate => 1,
|
|
|
|
|
+ builder => 'firefox_path'
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+
|
|
|
with 'Selenium::CanStartBinary';
|
|
with 'Selenium::CanStartBinary';
|
|
|
|
|
|
|
|
=attr custom_args
|
|
=attr custom_args
|
|
@@ -151,6 +212,12 @@ Optional: specify any additional command line arguments you'd like
|
|
|
invoked during the binary startup. See
|
|
invoked during the binary startup. See
|
|
|
L<Selenium::CanStartBinary/custom_args> for more information.
|
|
L<Selenium::CanStartBinary/custom_args> for more information.
|
|
|
|
|
|
|
|
|
|
+For Firefox 48 and newer, these arguments will be passed to
|
|
|
|
|
+geckodriver during start up.
|
|
|
|
|
+
|
|
|
|
|
+For Firefox 47 and older, these arguments will be passed to the
|
|
|
|
|
+Firefox browser during start up.
|
|
|
|
|
+
|
|
|
=attr startup_timeout
|
|
=attr startup_timeout
|
|
|
|
|
|
|
|
Optional: specify how long to wait for the binary to start itself and
|
|
Optional: specify how long to wait for the binary to start itself and
|
|
@@ -162,6 +229,23 @@ up to 20 seconds:
|
|
|
|
|
|
|
|
See L<Selenium::CanStartBinary/startup_timeout> for more information.
|
|
See L<Selenium::CanStartBinary/startup_timeout> for more information.
|
|
|
|
|
|
|
|
|
|
+=method shutdown_binary
|
|
|
|
|
+
|
|
|
|
|
+Call this method instead of L<Selenium::Remote::Driver/quit> to ensure
|
|
|
|
|
+that the binary executable is also closed, instead of simply closing
|
|
|
|
|
+the browser itself. If the browser is still around, it will call
|
|
|
|
|
+C<quit> for you. After that, it will try to shutdown the browser
|
|
|
|
|
+binary by making a GET to /shutdown and on Windows, it will attempt to
|
|
|
|
|
+do a C<taskkill> on the binary CMD window.
|
|
|
|
|
+
|
|
|
|
|
+ $self->shutdown_binary;
|
|
|
|
|
+
|
|
|
|
|
+It doesn't take any arguments, and it doesn't return anything.
|
|
|
|
|
+
|
|
|
|
|
+We do our best to call this when the C<$driver> option goes out of
|
|
|
|
|
+scope, but if that happens during global destruction, there's nothing
|
|
|
|
|
+we can do.
|
|
|
|
|
+
|
|
|
=cut
|
|
=cut
|
|
|
|
|
|
|
|
1;
|
|
1;
|