NAME

    Firefox::Marionette - Automate the Firefox browser with the Marionette
    protocol

VERSION

    Version 1.60

SYNOPSIS

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        say $firefox->find_tag('title')->property('innerHTML'); # same as $firefox->title();
    
        say $firefox->html();
    
        $firefox->find_class('page-content')->find_id('metacpan_search-input')->type('Test::More');
    
        say "Height of page-content div is " . $firefox->find_class('page-content')->css('height');
    
        my $file_handle = $firefox->selfie();
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        $firefox->find_partial('Download')->click();

DESCRIPTION

    This is a client module to automate the Mozilla Firefox browser via the
    Marionette protocol
    <https://developer.mozilla.org/en-US/docs/Mozilla/QA/Marionette/Protocol>

CONSTANTS

 BCD_PATH

    returns the local path used for storing the brower compability data for
    the agent method when the stealth parameter is supplied to the new
    method. This database is built by the build-bcd-for-firefox
    <https://metacpan.org/pod/build-bcd-for-firefox> binary.

SUBROUTINES/METHODS

 accept_alert

    accepts a currently displayed modal message box

 accept_connections

    Enables or disables accepting new socket connections. By calling this
    method with false the server will not accept any further connections,
    but existing connections will not be forcible closed. Use true to
    re-enable accepting connections.

    Please note that when closing the connection via the client you can
    end-up in a non-recoverable state if it hasn't been enabled before.

 active_element

    returns the active element of the current browsing context's document
    element, if the document element is non-null.

 add_bookmark

    accepts a bookmark as a parameter and adds the specified bookmark to
    the Firefox places database.

        use Firefox::Marionette();
    
        my $bookmark = Firefox::Marionette::Bookmark->new(
                         url   => 'https://metacpan.org',
                         title => 'This is MetaCPAN!'
                                 );
        my $firefox = Firefox::Marionette->new()->add_bookmark($bookmark);

    This method returns itself to aid in chaining methods.

 add_certificate

    accepts a hash as a parameter and adds the specified certificate to the
    Firefox database with the supplied or default trust. Allowed keys are
    below;

      * path - a file system path to a single PEM encoded X.509 certificate
      <https://datatracker.ietf.org/doc/html/rfc7468#section-5>.

      * string - a string containing a single PEM encoded X.509 certificate
      <https://datatracker.ietf.org/doc/html/rfc7468#section-5>

      * trust - This is the trustargs
      <https://www.mankier.com/1/certutil#-t> value for NSS
      <https://wiki.mozilla.org/NSS>. If defaults to 'C,,';

    This method returns itself to aid in chaining methods.

        use Firefox::Marionette();
    
        my $pem_encoded_string = <<'_PEM_';
        -----BEGIN CERTIFICATE-----
        MII..
        -----END CERTIFICATE-----
        _PEM_
        my $firefox = Firefox::Marionette->new()->add_certificate(string => $pem_encoded_string);

 add_cookie

    accepts a single cookie object as the first parameter and adds it to
    the current cookie jar. This method returns itself to aid in chaining
    methods.

    This method throws an exception if you try to add a cookie for a
    different domain than the current document
    <https://developer.mozilla.org/en-US/docs/Web/WebDriver/Errors/InvalidCookieDomain>.

 add_header

    accepts a hash of HTTP headers to include in every future HTTP Request.

        use Firefox::Marionette();
        use UUID();
    
        my $firefox = Firefox::Marionette->new();
        my $uuid = UUID::uuid();
        $firefox->add_header( 'Track-my-automated-tests' => $uuid );
        $firefox->go('https://metacpan.org/');

    these headers are added to any existing headers. To clear headers, see
    the delete_header method

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->delete_header( 'Accept' )->add_header( 'Accept' => 'text/perl' )->go('https://metacpan.org/');

    will only send out an Accept
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept>
    header that looks like Accept: text/perl.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->add_header( 'Accept' => 'text/perl' )->go('https://metacpan.org/');

    by itself, will send out an Accept
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept>
    header that may resemble Accept:
    text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8,
    text/perl. This method returns itself to aid in chaining methods.

 add_login

    accepts a hash of the following keys;

      * host - The scheme + hostname of the page where the login applies,
      for example 'https://www.example.org'.

      * user - The username for the login.

      * password - The password for the login.

      * origin - The scheme + hostname that the form-based login was
      submitted to
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-action>.
      Forms with no action attribute default to submitting to the URL of
      the page containing the login form, so that is stored here. This
      field should be omitted (it will be set to undef) for http auth type
      authentications and "" means to match against any form action.

      * realm - The HTTP Realm for which the login was requested. When an
      HTTP server sends a 401 result, the WWW-Authenticate header includes
      a realm. See RFC 2617
      <https://datatracker.ietf.org/doc/html/rfc2617>. If the realm is not
      specified, or it was blank, the hostname is used instead. For HTML
      form logins, this field should not be specified.

      * user_field - The name attribute for the username input in a form.
      Non-form logins should not specify this field.

      * password_field - The name attribute for the password input in a
      form. Non-form logins should not specify this field.

    or a Firefox::Marionette::Login object as the first parameter and adds
    the login to the Firefox login database.

        use Firefox::Marionette();
        use UUID();
    
        my $firefox = Firefox::Marionette->new();
    
        # for http auth logins
    
        my $http_auth_login = Firefox::Marionette::Login->new(host => 'https://pause.perl.org', user => 'AUSER', password => 'qwerty', realm => 'PAUSE');
        $firefox->add_login($http_auth_login);
        $firefox->go('https://pause.perl.org/pause/authenquery')->accept_alert(); # this goes to the page and submits the http auth popup
    
        # for form based login
    
        my $form_login = Firefox::Marionette::Login(host => 'https://github.com', user => 'me2@example.org', password => 'uiop[]', user_field => 'login', password_field => 'password');
        $firefox->add_login($form_login);
    
        # or just directly
    
        $firefox->add_login(host => 'https://github.com', user => 'me2@example.org', password => 'uiop[]', user_field => 'login', password_field => 'password');

    Note for HTTP Authentication, the realm
    <https://datatracker.ietf.org/doc/html/rfc2617#section-2> must
    perfectly match the correct realm supplied by the server.

    This method returns itself to aid in chaining methods.

 add_site_header

    accepts a host name and a hash of HTTP headers to include in every
    future HTTP Request that is being sent to that particular host.

        use Firefox::Marionette();
        use UUID();
    
        my $firefox = Firefox::Marionette->new();
        my $uuid = UUID::uuid();
        $firefox->add_site_header( 'metacpan.org', 'Track-my-automated-tests' => $uuid );
        $firefox->go('https://metacpan.org/');

    these headers are added to any existing headers going to the
    metacpan.org site, but no other site. To clear site headers, see the
    delete_site_header method

 add_webauthn_authenticator

    accepts a hash of the following keys;

      * has_resident_key - boolean value to indicate if the authenticator
      will support client side discoverable credentials
      <https://www.w3.org/TR/webauthn-2/#client-side-discoverable-credential>

      * has_user_verification - boolean value to determine if the
      authenticator
      <https://www.w3.org/TR/webauthn-2/#virtual-authenticators> supports
      user verification
      <https://www.w3.org/TR/webauthn-2/#user-verification>.

      * is_user_consenting - boolean value to determine the result of all
      user consent <https://www.w3.org/TR/webauthn-2/#user-consent>
      authorization gestures
      <https://www.w3.org/TR/webauthn-2/#authorization-gesture>, and by
      extension, any test of user presence
      <https://www.w3.org/TR/webauthn-2/#test-of-user-presence> performed
      on the Virtual Authenticator
      <https://www.w3.org/TR/webauthn-2/#virtual-authenticators>. If set to
      true, a user consent will always be granted. If set to false, it will
      not be granted.

      * is_user_verified - boolean value to determine the result of User
      Verification <https://www.w3.org/TR/webauthn-2/#user-verification>
      performed on the Virtual Authenticator
      <https://www.w3.org/TR/webauthn-2/#virtual-authenticators>. If set to
      true, User Verification will always succeed. If set to false, it will
      fail.

      * protocol - the protocol spoken by the authenticator. This may be
      CTAP1_U2F, CTAP2 or CTAP2_1.

      * transport - the transport simulated by the authenticator. This may
      be BLE, HYBRID, INTERNAL, NFC, SMART_CARD or USB.

    It returns the newly created authenticator.

        use Firefox::Marionette();
        use Crypt::URandom();
    
        my $user_name = MIME::Base64::encode_base64( Crypt::URandom::urandom( 10 ), q[] ) . q[@example.com];
        my $firefox = Firefox::Marionette->new( webauthn => 0 );
        my $authenticator = $firefox->add_webauthn_authenticator( transport => Firefox::Marionette::WebAuthn::Authenticator::INTERNAL(), protocol => Firefox::Marionette::WebAuthn::Authenticator::CTAP2() );
        $firefox->go('https://webauthn.io');
        $firefox->find_id('input-email')->type($user_name);
        $firefox->find_id('register-button')->click();
        $firefox->await(sub { sleep 1; $firefox->find_class('alert-success'); });
        $firefox->find_id('login-button')->click();
        $firefox->await(sub { sleep 1; $firefox->find_class('hero confetti'); });

 add_webauthn_credential

    accepts a hash of the following keys;

      * authenticator - contains the authenticator that the credential will
      be added to. If this parameter is not supplied, the credential will
      be added to the default authenticator, if one exists.

      * host - contains the domain that this credential is to be used for.
      In the language of WebAuthn <https://www.w3.org/TR/webauthn-2>, this
      field is referred to as the relying party identifier
      <https://www.w3.org/TR/webauthn-2/#relying-party-identifier> or RP ID
      <https://www.w3.org/TR/webauthn-2/#rp-id>.

      * id - contains the unique id for this credential, also known as the
      Credential ID <https://www.w3.org/TR/webauthn-2/#credential-id>. If
      this is not supplied, one will be generated.

      * is_resident - contains a boolean that if set to true, a client-side
      discoverable credential
      <https://w3c.github.io/webauthn/#client-side-discoverable-credential>
      is created. If set to false, a server-side credential
      <https://w3c.github.io/webauthn/#server-side-credential> is created
      instead.

      * private_key - either a RFC5958
      <https://www.rfc-editor.org/rfc/rfc5958> encoded private key encoded
      using encode_base64url or a hash containing the following keys;

	* name - contains the name of the private key algorithm, such as
	"RSA-PSS" (the default), "RSASSA-PKCS1-v1_5", "ECDSA" or "ECDH".

	* size - contains the modulus length of the private key. This is
	only valid for "RSA-PSS" or "RSASSA-PKCS1-v1_5" private keys.

	* hash - contains the name of the hash algorithm, such as "SHA-512"
	(the default). This is only valid for "RSA-PSS" or
	"RSASSA-PKCS1-v1_5" private keys.

	* curve - contains the name of the curve for the private key, such
	as "P-384" (the default). This is only valid for "ECDSA" or "ECDH"
	private keys.

      * sign_count - contains the initial value for a signature counter
      <https://w3c.github.io/webauthn/#signature-counter> associated to the
      public key credential source
      <https://w3c.github.io/webauthn/#public-key-credential-source>. It
      will default to 0 (zero).

      * user - contains the userHandle
      <https://w3c.github.io/webauthn/#public-key-credential-source-userhandle>
      associated to the credential encoded using encode_base64url. This
      property is optional.

    It returns the newly created credential. If of course, the credential
    is just created, it probably won't be much good by itself. However, you
    can use it to recreate a credential, so long as you know all the
    parameters.

        use Firefox::Marionette();
        use Crypt::URandom();
    
        my $user_name = MIME::Base64::encode_base64( Crypt::URandom::urandom( 10 ), q[] ) . q[@example.com];
        my $firefox = Firefox::Marionette->new();
        $firefox->go('https://webauthn.io');
        $firefox->find_id('input-email')->type($user_name);
        $firefox->find_id('register-button')->click();
        $firefox->await(sub { sleep 1; $firefox->find_class('alert-success'); });
        $firefox->find_id('login-button')->click();
        $firefox->await(sub { sleep 1; $firefox->find_class('hero confetti'); });
        foreach my $credential ($firefox->webauthn_credentials()) {
            $firefox->delete_webauthn_credential($credential);

    # ... time passes ...

            $firefox->add_webauthn_credential(
                      id            => $credential->id(),
                      host          => $credential->host(),
                      user          => $credential->user(),
                      private_key   => $credential->private_key(),
                      is_resident   => $credential->is_resident(),
                      sign_count    => $credential->sign_count(),
                                  );
        }
        $firefox->go('about:blank');
        $firefox->clear_cache(Firefox::Marionette::Cache::CLEAR_COOKIES());
        $firefox->go('https://webauthn.io');
        $firefox->find_id('input-email')->type($user_name);
        $firefox->find_id('login-button')->click();
        $firefox->await(sub { sleep 1; $firefox->find_class('hero confetti'); });

 addons

    returns if pre-existing addons (extensions/themes) are allowed to run.
    This will be true for Firefox versions less than 55, as -safe-mode
    <http://kb.mozillazine.org/Command_line_arguments#List_of_command_line_arguments_.28incomplete.29>
    cannot be automated.

 agent

    accepts an optional value for the User-Agent
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>
    header and sets this using the profile preferences and inserting
    javascript into the current page. It returns the current value, such as
    'Mozilla/5.0 (<system-information>) <platform> (<platform-details>)
    <extensions>'. This value is retrieved with navigator.userAgent
    <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgent>.

    This method can be used to set a user agent string like so;

        use Firefox::Marionette();
        use strict;
    
        # useragents.me should only be queried once a month or less.
        # these UA strings should be cached locally.
    
        my %user_agent_strings = map { $_->{ua} => $_->{pct} } @{$firefox->json("https://www.useragents.me/api")->{data}};
        my ($user_agent) = reverse sort { $user_agent_strings{$a} <=> $user_agent_strings{$b} } keys %user_agent_strings;
    
        my $firefox = Firefox::Marionette->new();
        $firefox->agent($user_agent); # agent is now the most popular agent from useragents.me

    If the user agent string that is passed as a parameter looks like a
    Chrome <https://www.google.com/chrome/>, Edge
    <https://microsoft.com/edge> or Safari <https://www.apple.com/safari/>
    user agent string, then this method will also try and change other
    profile preferences to match the new agent string. These parameters
    are;

      * general.appversion.override

      * general.oscpu.override

      * general.platform.override

      * network.http.accept

      * network.http.accept-encoding

      * network.http.accept-encoding.secure

      * privacy.donottrackheader.enabled

    In addition, this method will accept a hash of values as parameters as
    well. When a hash is provided, this method will alter specific parts of
    the normal Firefox User Agent. These hash parameters are;

      * os - The desired operating system, known values are "linux",
      "win32", "darwin", "freebsd", "netbsd", "openbsd" and "dragonfly"

      * version - A specific version of firefox, such as 120.

      * arch - A specific version of the architecture, such as "x86_64" or
      "aarch64" or "s390x".

      * increment - A specific offset from the actual version of firefox,
      such as -5

    These parameters can be used to set a user agent string like so;

        use Firefox::Marionette();
        use strict;
    
        my $firefox = Firefox::Marionette->new();
        $firefox->agent(os => 'freebsd', version => 118);
    
        # user agent is now equal to
        # Mozilla/5.0 (X11; FreeBSD amd64; rv:109.0) Gecko/20100101 Firefox/118.0
    
        $firefox->agent(os => 'linux', arch => 's390x', version => 115);
        # user agent is now equal to
        # Mozilla/5.0 (X11; Linux s390x; rv:109.0) Gecko/20100101 Firefox/115.0

    If the stealth parameter has supplied to the new method, it will also
    attempt to create known specific javascript functions to imitate the
    required browser. If the database built by build-bcd-for-firefox
    <https://metacpan.org/pod/build-bcd-for-firefox> is accessible, then it
    will also attempt to delete/provide dummy implementations for the
    corresponding javascript attributes
    <https://github.com/mdn/browser-compat-data> for the desired browser.
    The following websites have been very useful in testing these ideas;

      * https://browserleaks.com/javascript

      * https://www.amiunique.org/fingerprint

      * https://bot.sannysoft.com/

      * https://lraj22.github.io/browserfeatcl/

    Importantly, this will break feature detection
    <https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection>
    for any website that relies on it.

    See IMITATING OTHER BROWSERS a discussion of these types of techniques.
    These changes are not foolproof, but it is interesting to see what can
    be done with modern browsers. All this behaviour should be regarded as
    extremely experimental and subject to change. Feedback welcome.

 alert_text

    Returns the message shown in a currently displayed modal message box

 alive

    This method returns true or false depending on if the Firefox process
    is still running.

 application_type

    returns the application type for the Marionette protocol. Should be
    'gecko'.

 arch

    returns the architecture of the machine running firefox. Should be
    something like 'x86_64' or 'arm'. This is only intended for test suite
    support.

 aria_label

    accepts an element as the parameter. It returns the ARIA label
    <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label>
    for the element.

 aria_role

    accepts an element as the parameter. It returns the ARIA role
    <https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles>
    for the element.

 async_script

    accepts a scalar containing a javascript function that is executed in
    the browser. This method returns itself to aid in chaining methods.

    The executing javascript is subject to the script timeout, which, by
    default is 30 seconds.

 attribute

    accepts an element as the first parameter and a scalar attribute name
    as the second parameter. It returns the initial value of the attribute
    with the supplied name. This method will return the initial content
    from the HTML source code, the property method will return the current
    content.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        my $element = $firefox->find_id('metacpan_search-input');
        !defined $element->attribute('value') or die "attribute is defined but did not exist in the html source!";
        $element->type('Test::More');
        !defined $element->attribute('value') or die "attribute has changed but only the property should have changed!";

 await

    accepts a subroutine reference as a parameter and then executes the
    subroutine. If a not found exception is thrown, this method will sleep
    for sleep_time_in_ms milliseconds and then execute the subroutine
    again. When the subroutine executes successfully, it will return what
    the subroutine returns.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new(sleep_time_in_ms => 5)->go('https://metacpan.org/');
    
        $firefox->find_id('metacpan_search-input')->type('Test::More');
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();

 back

    causes the browser to traverse one step backward in the joint history
    of the current browsing context. The browser will wait for the one step
    backward to complete or the session's page_load duration to elapse
    before returning, which, by default is 5 minutes. This method returns
    itself to aid in chaining methods.

 debug

    accept a boolean and return the current value of the debug setting.
    This allows the dynamic setting of debug.

 default_binary_name

    just returns the string 'firefox'. Only of interest when sub-classing.

 download

    accepts a URI and an optional timeout in seconds (the default is 5
    minutes) as parameters and downloads the URI in the background and
    returns a handle to the downloaded file.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
    
        my $handle = $firefox->download('https://raw.githubusercontent.com/david-dick/firefox-marionette/master/t/data/keepassxs.csv');
    
        foreach my $line (<$handle>) {
          print $line;
        }

 bookmarks

    accepts either a scalar or a hash as a parameter. The scalar may by the
    title of a bookmark or the URL of the bookmark. The hash may have the
    following keys;

      * title - The title of the bookmark.

      * url - The url of the bookmark.

    returns a list of all Firefox::Marionette::Bookmark objects that match
    the supplied parameters (if any).

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
    
        foreach my $bookmark ($firefox->bookmarks(title => 'This is MetaCPAN!')) {
          say "Bookmark found";
        }
    
        # OR
    
        foreach my $bookmark ($firefox->bookmarks()) {
          say "Bookmark found with URL " . $bookmark->url();
        }
    
        # OR
    
        foreach my $bookmark ($firefox->bookmarks('https://metacpan.org')) {
          say "Bookmark found";
        }

 browser_version

    This method returns the current version of firefox.

 bye

    accepts a subroutine reference as a parameter and then executes the
    subroutine. If the subroutine executes successfully, this method will
    sleep for sleep_time_in_ms milliseconds and then execute the subroutine
    again. When a not found exception is thrown, this method will return
    itself to aid in chaining methods.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        $firefox->find_id('metacpan_search-input')->type('Test::More');
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        $firefox->bye(sub { $firefox->find_name('metacpan_search-input') })->await(sub { $firefox->interactive() && $firefox->find_partial('Download') })->click();

 cache_keys

    returns the set of all cache keys from Firefox::Marionette::Cache.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        foreach my $key_name ($firefox->cache_keys()) {
          my $key_value = $firefox->check_cache_key($key_name);
          if (Firefox::Marionette::Cache->$key_name() != $key_value) {
            warn "This module this the value of $key_name is " . Firefox::Marionette::Cache->$key_name();
            warn "Firefox thinks the value of   $key_name is $key_value";
          }
        }

 capabilities

    returns the capabilities of the current firefox binary. You can
    retrieve timeouts or a proxy with this method.

 certificate_as_pem

    accepts a certificate stored in the Firefox database as a parameter and
    returns a PEM encoded X.509 certificate
    <https://datatracker.ietf.org/doc/html/rfc7468#section-5> as a string.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
    
        # Generating a ca-bundle.crt to STDOUT from the current firefox instance
    
        foreach my $certificate (sort { $a->display_name() cmp $b->display_name } $firefox->certificates()) {
            if ($certificate->is_ca_cert()) {
                print '# ' . $certificate->display_name() . "\n" . $firefox->certificate_as_pem($certificate) . "\n";
            }
        }

    The ca-bundle-for-firefox
    <https://metacpan.org/pod/ca-bundle-for-firefox> command that is
    provided as part of this distribution does this.

 certificates

    returns a list of all known certificates in the Firefox database.

        use Firefox::Marionette();
        use v5.10;
    
        # Sometimes firefox can neglect old certificates.  See https://bugzilla.mozilla.org/show_bug.cgi?id=1710716
    
        my $firefox = Firefox::Marionette->new();
        foreach my $certificate (grep { $_->is_ca_cert() && $_->not_valid_after() < time } $firefox->certificates()) {
            say "The " . $certificate->display_name() " . certificate has expired and should be removed";
            print 'PEM Encoded Certificate ' . "\n" . $firefox->certificate_as_pem($certificate) . "\n";
        }

    This method returns itself to aid in chaining methods.

 check_cache_key

    accepts a cache_key as a parameter.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        foreach my $key_name ($firefox->cache_keys()) {
          my $key_value = $firefox->check_cache_key($key_name);
          if (Firefox::Marionette::Cache->$key_name() != $key_value) {
            warn "This module this the value of $key_name is " . Firefox::Marionette::Cache->$key_name();
            warn "Firefox thinks the value of   $key_name is $key_value";
          }
        }

    This method returns the cache_key's actual value from firefox as a
    number. This may differ from the current value of the key from
    Firefox::Marionette::Cache as these values have changed as firefox has
    evolved.

 child_error

    This method returns the $? (CHILD_ERROR) for the Firefox process, or
    undefined if the process has not yet exited.

 chrome

    changes the scope of subsequent commands to chrome context. This allows
    things like interacting with firefox menu's and buttons outside of the
    browser window.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->chrome();
        $firefox->script(...); # running script in chrome context
        $firefox->content();

    See the context method for an alternative methods for changing the
    context.

 chrome_window_handle

    returns a server-assigned identifier for the current chrome window that
    uniquely identifies it within this Marionette instance. This can be
    used to switch to this window at a later point. This corresponds to a
    window that may itself contain tabs. This method is replaced by
    window_handle and appropriate context calls for Firefox 94 and after
    <https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/94#webdriver_conformance_marionette>.

 chrome_window_handles

    returns identifiers for each open chrome window for tests interested in
    managing a set of chrome windows and tabs separately. This method is
    replaced by window_handles and appropriate context calls for Firefox 94
    and after
    <https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/94#webdriver_conformance_marionette>.

 clear

    accepts a element as the first parameter and clears any user supplied
    input

 clear_cache

    accepts a single flag parameter, which can be an ORed set of keys from
    Firefox::Marionette::Cache and clears the appropriate sections of the
    cache. If no flags parameter is supplied, the default is CLEAR_ALL.
    Note that this method, unlike delete_cookies will actually delete all
    cookies for all hosts, not just the current webpage.

        use Firefox::Marionette();
        use Firefox::Marionette::Cache qw(:all);
    
        my $firefox = Firefox::Marionette->new()->go('https://do.lots.of.evil/')->clear_cache(); # default clear all
    
        $firefox->go('https://cookies.r.us')->clear_cache(CLEAR_COOKIES());

    This method returns itself to aid in chaining methods.

 clear_pref

    accepts a preference <http://kb.mozillazine.org/About:config> name and
    restores it to the original value. See the get_pref and set_pref
    methods to get a preference value and to set to it to a particular
    value. This method returns itself to aid in chaining methods.

        use Firefox::Marionette();
        my $firefox = Firefox::Marionette->new();
    
        $firefox->clear_pref('browser.search.defaultenginename');

 click

    accepts a element as the first parameter and sends a 'click' to it. The
    browser will wait for any page load to complete or the session's
    page_load duration to elapse before returning, which, by default is 5
    minutes. The click method is also used to choose an option in a select
    dropdown.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new(visible => 1)->go('https://ebay.com');
        my $select = $firefox->find_tag('select');
        foreach my $option ($select->find_tag('option')) {
            if ($option->property('value') == 58058) { # Computers/Tablets & Networking
                $option->click();
            }
        }

 close_current_chrome_window_handle

    closes the current chrome window (that is the entire window, not just
    the tabs). It returns a list of still available chrome window handles.
    You will need to switch_to_window to use another window.

 close_current_window_handle

    closes the current window/tab. It returns a list of still available
    window/tab handles.

 content

    changes the scope of subsequent commands to browsing context. This is
    the default for when firefox starts and restricts commands to operating
    in the browser window only.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->chrome();
        $firefox->script(...); # running script in chrome context
        $firefox->content();

    See the context method for an alternative methods for changing the
    context.

 context

    accepts a string as the first parameter, which may be either 'content'
    or 'chrome'. It returns the context type that is Marionette's current
    target for browsing context scoped commands.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
        if ($firefox->context() eq 'content') {
           say "I knew that was going to happen";
        }
        my $old_context = $firefox->context('chrome');
        $firefox->script(...); # running script in chrome context
        $firefox->context($old_context);

    See the content and chrome methods for alternative methods for changing
    the context.

 cookies

    returns the contents of the cookie jar in scalar or list context.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://github.com');
        foreach my $cookie ($firefox->cookies()) {
            if (defined $cookie->same_site()) {
                say "Cookie " . $cookie->name() . " has a SameSite of " . $cookie->same_site();
            } else {
                warn "Cookie " . $cookie->name() . " does not have the SameSite attribute defined";
            }
        }

 css

    accepts an element as the first parameter and a scalar CSS property
    name as the second parameter. It returns the value of the computed
    style for that property.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        say $firefox->find_id('metacpan_search-input')->css('height');

 current_chrome_window_handle

    see chrome_window_handle.

 delete_bookmark

    accepts a bookmark as a parameter and deletes the bookmark from the
    Firefox database.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
        foreach my $bookmark (reverse $firefox->bookmarks()) {
          if ($bookmark->parent_guid() ne Firefox::Marionette::Bookmark::ROOT()) {
            $firefox->delete_bookmark($bookmark);
          }
        }
        say "Bookmarks? We don't need no stinking bookmarks!";

    This method returns itself to aid in chaining methods.

 delete_certificate

    accepts a certificate stored in the Firefox database as a parameter and
    deletes/distrusts the certificate from the Firefox database.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
        foreach my $certificate ($firefox->certificates()) {
            if ($certificate->is_ca_cert()) {
                $firefox->delete_certificate($certificate);
            } else {
                say "This " . $certificate->display_name() " certificate is NOT a certificate authority, therefore it is not being deleted";
            }
        }
        say "Good luck visiting a HTTPS website!";

    This method returns itself to aid in chaining methods.

 delete_cookie

    deletes a single cookie by name. Accepts a scalar containing the cookie
    name as a parameter. This method returns itself to aid in chaining
    methods.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://github.com');
        foreach my $cookie ($firefox->cookies()) {
            warn "Cookie " . $cookie->name() . " is being deleted";
            $firefox->delete_cookie($cookie->name());
        }
        foreach my $cookie ($firefox->cookies()) {
            die "Should be no cookies here now";
        }

 delete_cookies

    Here be cookie monsters! Note that this method will only delete cookies
    for the current site. See clear_cache for an alternative. This method
    returns itself to aid in chaining methods.

 delete_header

    accepts a list of HTTP header names to delete from future HTTP
    Requests.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->delete_header( 'User-Agent', 'Accept', 'Accept-Encoding' );

    will remove the User-Agent
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>,
    Accept
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept> and
    Accept-Encoding
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding>
    headers from all future requests

    This method returns itself to aid in chaining methods.

 delete_login

    accepts a login as a parameter.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        foreach my $login ($firefox->logins()) {
            if ($login->user() eq 'me@example.org') {
                $firefox->delete_login($login);
            }
        }

    will remove the logins with the username matching 'me@example.org'.

    This method returns itself to aid in chaining methods.

 delete_logins

    This method empties the password database.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->delete_logins();

    This method returns itself to aid in chaining methods.

 delete_session

    deletes the current WebDriver session.

 delete_site_header

    accepts a host name and a list of HTTP headers names to delete from
    future HTTP Requests.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->delete_header( 'metacpan.org', 'User-Agent', 'Accept', 'Accept-Encoding' );

    will remove the User-Agent
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>,
    Accept
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept> and
    Accept-Encoding
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding>
    headers from all future requests to metacpan.org.

    This method returns itself to aid in chaining methods.

 delete_webauthn_all_credentials

    This method accepts an optional authenticator, in which case it will
    delete all credentials from this authenticator. If no parameter is
    supplied, the default authenticator will have all credentials deleted.

        my $firefox = Firefox::Marionette->new();
        my $authenticator = $firefox->add_webauthn_authenticator( transport => Firefox::Marionette::WebAuthn::Authenticator::INTERNAL(), protocol => Firefox::Marionette::WebAuthn::Authenticator::CTAP2() );
        $firefox->delete_webauthn_all_credentials($authenticator);
        $firefox->delete_webauthn_all_credentials();

 delete_webauthn_authenticator

    This method accepts an optional authenticator, in which case it will
    delete this authenticator from the current Firefox instance. If no
    parameter is supplied, the default authenticator will be deleted.

        my $firefox = Firefox::Marionette->new();
        my $authenticator = $firefox->add_webauthn_authenticator( transport => Firefox::Marionette::WebAuthn::Authenticator::INTERNAL(), protocol => Firefox::Marionette::WebAuthn::Authenticator::CTAP2() );
        $firefox->delete_webauthn_authenticator($authenticator);
        $firefox->delete_webauthn_authenticator();

 delete_webauthn_credential

    This method accepts either a credential and an authenticator, in which
    case it will remove the credential from the supplied authenticator or

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        my $authenticator = $firefox->add_webauthn_authenticator( transport => Firefox::Marionette::WebAuthn::Authenticator::INTERNAL(), protocol => Firefox::Marionette::WebAuthn::Authenticator::CTAP2() );
        foreach my $credential ($firefox->webauthn_credentials($authenticator)) {
            $firefox->delete_webauthn_credential($credential, $authenticator);
        }

    just a credential, in which case it will remove the credential from the
    default authenticator.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        ...
        foreach my $credential ($firefox->webauthn_credentials()) {
            $firefox->delete_webauthn_credential($credential);
        }

    This method returns itself to aid in chaining methods.

 developer

    returns true if the current version of firefox is a developer edition
    <https://www.mozilla.org/en-US/firefox/developer/> (does the minor
    version number end with an 'b\d+'?) version.

 dismiss_alert

    dismisses a currently displayed modal message box

 displays

    accepts an optional regex to filter against the usage for the display
    and returns a list of all the known displays
    <https://en.wikipedia.org/wiki/List_of_common_resolutions> as a
    Firefox::Marionette::Display.

        use Firefox::Marionette();
        use Encode();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new( visible => 1, kiosk => 1 )->go('http://metacpan.org');;
        my $element = $firefox->find_id('metacpan_search-input');
        foreach my $display ($firefox->displays(qr/iphone/smxi)) {
            say 'Can Firefox resize for "' . Encode::encode('UTF-8', $display->usage(), 1) . '"?';
            if ($firefox->resize($display->width(), $display->height())) {
                say 'Now displaying with a Pixel aspect ratio of ' . $display->par();
                say 'Now displaying with a Storage aspect ratio of ' . $display->sar();
                say 'Now displaying with a Display aspect ratio of ' . $display->dar();
            } else {
                say 'Apparently NOT!';
            }
        }

 downloaded

    accepts a filesystem path and returns a matching filehandle. This is
    trivial for locally running firefox, but sufficiently complex to
    justify the method for a remote firefox running over ssh.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new( host => '10.1.2.3' )->go('https://metacpan.org/');
    
        $firefox->find_class('page-content')->find_id('metacpan_search-input')->type('Test::More');
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        $firefox->find_partial('Download')->click();
    
        while(!$firefox->downloads()) { sleep 1 }
    
        foreach my $path ($firefox->downloads()) {
    
            my $handle = $firefox->downloaded($path);
    
            # do something with downloaded file handle
    
        }

 downloading

    returns true if any files in downloads end in .part

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        $firefox->find_class('page-content')->find_id('metacpan_search-input')->type('Test::More');
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        $firefox->find_partial('Download')->click();
    
        while(!$firefox->downloads()) { sleep 1 }
    
        while($firefox->downloading()) { sleep 1 }
    
        foreach my $path ($firefox->downloads()) {
            say $path;
        }

 downloads

    returns a list of file paths (including partial downloads) of downloads
    during this Firefox session.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        $firefox->find_class('page-content')->find_id('metacpan_search-input')->type('Test::More');
    
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        $firefox->find_partial('Download')->click();
    
        while(!$firefox->downloads()) { sleep 1 }
    
        foreach my $path ($firefox->downloads()) {
            say $path;
        }

 error_message

    This method returns a human readable error message describing how the
    Firefox process exited (assuming it started okay). On Win32 platforms
    this information is restricted to exit code.

 execute

    This utility method executes a command with arguments and returns
    STDOUT as a chomped string. It is a simple method only intended for the
    Firefox::Marionette::* modules.

 fill_login

    This method searches the Password Manager
    <https://support.mozilla.org/en-US/kb/password-manager-remember-delete-edit-logins>
    for an appropriate login for any form on the current page. The form
    must match the host, the action attribute and the user and password
    field names.

        use Firefox::Marionette();
        use IO::Prompt();
    
        my $firefox = Firefox::Marionette->new();
    
        my $firefox = Firefox::Marionette->new();
    
        my $url = 'https://github.com';
    
        my $user = 'me@example.org';
    
        my $password = IO::Prompt::prompt(-echo => q[*], "Please enter the password for the $user account when logging into $url:");
    
        $firefox->add_login(host => $url, user => $user, password => 'qwerty', user_field => 'login', password_field => 'password');
    
        $firefox->go("$url/login");
    
        $firefox->fill_login();

 find

    accepts an xpath expression <https://en.wikipedia.org/wiki/XPath> as
    the first parameter and returns the first element that matches this
    expression.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        $firefox->find('//input[@id="metacpan_search-input"]')->type('Test::More');
    
        # OR in list context 
    
        foreach my $element ($firefox->find('//input[@id="metacpan_search-input"]')) {
            $element->type('Test::More');
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has method.

 find_id

    accepts an id
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id>
    as the first parameter and returns the first element with a matching
    'id' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        $firefox->find_id('metacpan_search-input')->type('Test::More');
    
        # OR in list context 
    
        foreach my $element ($firefox->find_id('metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_id method.

 find_name

    This method returns the first element with a matching 'name' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_name('q')->type('Test::More');
    
        # OR in list context 
    
        foreach my $element ($firefox->find_name('q')) {
            $element->type('Test::More');
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_name method.

 find_class

    accepts a class name
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class>
    as the first parameter and returns the first element with a matching
    'class' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_class('form-control home-metacpan_search-input')->type('Test::More');
    
        # OR in list context 
    
        foreach my $element ($firefox->find_class('form-control home-metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_class method.

 find_selector

    accepts a CSS Selector
    <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors> as the
    first parameter and returns the first element that matches that
    selector.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_selector('input.home-metacpan_search-input')->type('Test::More');
    
        # OR in list context 
    
        foreach my $element ($firefox->find_selector('input.home-metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_selector method.

 find_tag

    accepts a tag name
    <https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName> as
    the first parameter and returns the first element with this tag name.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        my $element = $firefox->find_tag('input');
    
        # OR in list context 
    
        foreach my $element ($firefox->find_tag('input')) {
            # do something
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_tag method.

 find_link

    accepts a text string as the first parameter and returns the first link
    element that has a matching link text.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_link('API')->click();
    
        # OR in list context 
    
        foreach my $element ($firefox->find_link('API')) {
            $element->click();
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_link method.

 find_partial

    accepts a text string as the first parameter and returns the first link
    element that has a partially matching link text.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_partial('AP')->click();
    
        # OR in list context 
    
        foreach my $element ($firefox->find_partial('AP')) {
            $element->click();
        }

    If no elements are found, a not found exception will be thrown. For the
    same functionality that returns undef if no elements are found, see the
    has_partial method.

 forward

    causes the browser to traverse one step forward in the joint history of
    the current browsing context. The browser will wait for the one step
    forward to complete or the session's page_load duration to elapse
    before returning, which, by default is 5 minutes. This method returns
    itself to aid in chaining methods.

 full_screen

    full screens the firefox window. This method returns itself to aid in
    chaining methods.

 geo

    accepts an optional geo location object or the parameters for a geo
    location object, turns on the Geolocation API
    <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API> and
    returns the current value returned by calling the javascript
    getCurrentPosition
    <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition>
    method. This method is further discussed in the GEO LOCATION section.

    NOTE: firefox will only allow Geolocation
    <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation> calls to
    be made from secure contexts
    <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>
    and bizarrely, this does not include about:blank or similar. Therefore,
    you will need to load a page before calling the geo method.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( proxy => 'https://this.is.another.location:3128', geo => 1 );
    
        # Get geolocation for this.is.another.location (via proxy)
    
        $firefox->geo($firefox->json('https://freeipapi.com/api/json/'));
    
        # now google maps will show us in this.is.another.location
    
        $firefox->go('https://maps.google.com/');
    
        my $geo = $firefox->geo();
    
        warn "Apparently, we're now at " . join q[, ], $geo->latitude(), $geo->longitude();
    
        # OR the quicker setup (run this with perl -C)
    
        warn "Apparently, we're now at " . Firefox::Marionette->new( proxy => 'https://this.is.another.location:3128', geo => 'https://freeipapi.com/api/json/' )->go('https://maps.google.com/')->geo();

    NOTE: currently this call sets the location to be exactly what is
    specified. It will also attempt to modify the current timezone (if
    available in the geo location parameter) to match the specified
    timezone. This function should be considered experimental. Feedback
    welcome.

    If particular, the ipgeolocation API
    <https://ipgeolocation.io/documentation/ip-geolocation-api.html> is the
    only API that currently providing geolocation data and matching
    timezone data in one API call. If anyone finds/develops another similar
    API, I would be delighted to include support for it in this module.

 go

    Navigates the current browsing context to the given URI and waits for
    the document to load or the session's page_load duration to elapse
    before returning, which, by default is 5 minutes.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->go('https://metacpan.org/'); # will only return when metacpan.org is FULLY loaded (including all images / js / css)

    To make the go method return quicker, you need to set the page load
    strategy capability to an appropriate value, such as below;

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( capabilities => Firefox::Marionette::Capabilities->new( page_load_strategy => 'eager' ));
        $firefox->go('https://metacpan.org/'); # will return once the main document has been loaded and parsed, but BEFORE sub-resources (images/stylesheets/frames) have been loaded.

    When going directly to a URL that needs to be downloaded, please see
    BUGS AND LIMITATIONS for a necessary workaround and the download method
    for an alternative.

    This method returns itself to aid in chaining methods.

 get_pref

    accepts a preference <http://kb.mozillazine.org/About:config> name. See
    the set_pref and clear_pref methods to set a preference value and to
    restore it to it's original value. This method returns the current
    value of the preference.

        use Firefox::Marionette();
        my $firefox = Firefox::Marionette->new();
    
        warn "Your browser's default search engine is set to " . $firefox->get_pref('browser.search.defaultenginename');

 har

    returns a hashref representing the http archive
    <https://en.wikipedia.org/wiki/HAR_(file_format)> of the session. This
    function is subject to the script timeout, which, by default is 30
    seconds. It is also possible for the function to hang (until the script
    timeout) if the original devtools
    <https://developer.mozilla.org/en-US/docs/Tools> window is closed. The
    hashref has been designed to be accepted by the Archive::Har module.

        use Firefox::Marionette();
        use Archive::Har();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new(visible => 1, debug => 1, har => 1);
    
        $firefox->go("http://metacpan.org/");
    
        $firefox->find('//input[@id="metacpan_search-input"]')->type('Test::More');
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
    
        my $har = Archive::Har->new();
        $har->hashref($firefox->har());
    
        foreach my $entry ($har->entries()) {
            say $entry->request()->url() . " spent " . $entry->timings()->connect() . " ms establishing a TCP connection";
        }

 has

    accepts an xpath expression <https://en.wikipedia.org/wiki/XPath> as
    the first parameter and returns the first element that matches this
    expression.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        if (my $element = $firefox->has('//input[@id="metacpan_search-input"]')) {
            $element->type('Test::More');
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find method.

 has_id

    accepts an id
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id>
    as the first parameter and returns the first element with a matching
    'id' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        if (my $element = $firefox->has_id('metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_id
    method.

 has_name

    This method returns the first element with a matching 'name' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->has_name('q')) {
            $element->type('Test::More');
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_name
    method.

 has_class

    accepts a class name
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class>
    as the first parameter and returns the first element with a matching
    'class' property.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->has_class('form-control home-metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_class
    method.

 has_selector

    accepts a CSS Selector
    <https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors> as the
    first parameter and returns the first element that matches that
    selector.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->has_selector('input.home-metacpan_search-input')) {
            $element->type('Test::More');
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_selector
    method.

 has_tag

    accepts a tag name
    <https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName> as
    the first parameter and returns the first element with this tag name.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->has_tag('input')) {
            # do something
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_tag
    method.

 has_link

    accepts a text string as the first parameter and returns the first link
    element that has a matching link text.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->has_link('API')) {
            $element->click();
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_link
    method.

 has_partial

    accepts a text string as the first parameter and returns the first link
    element that has a partially matching link text.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $element = $firefox->find_partial('AP')) {
            $element->click();
        }

    If no elements are found, this method will return undef. For the same
    functionality that throws a not found exception, see the find_partial
    method.

 html

    returns the page source of the content document. This page source can
    be wrapped in html that firefox provides. See the json method for an
    alternative when dealing with response content types such as
    application/json and strip for an alternative when dealing with other
    non-html content types such as text/plain.

        use Firefox::Marionette();
        use v5.10;
    
        say Firefox::Marionette->new()->go('https://metacpan.org/')->html();

 import_bookmarks

    accepts a filesystem path to a bookmarks file and imports all the
    bookmarks in that file. It can deal with backups from Firefox
    <https://support.mozilla.org/en-US/kb/export-firefox-bookmarks-to-backup-or-transfer>,
    Chrome <https://support.google.com/chrome/answer/96816?hl=en> or Edge.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->import_bookmarks('/path/to/bookmarks_file.html');

    This method returns itself to aid in chaining methods.

 images

    returns a list of all of the following elements;

      * img <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img>

      * image inputs
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/image>

    as Firefox::Marionette::Image objects.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $link = $firefox->images()) {
            say "Found a image with width " . $image->width() . "px and height " . $image->height() . "px from " . $image->URL();
        }

    If no elements are found, this method will return undef.

 install

    accepts the following as the first parameter;

      * path to an xpi file
      <https://developer.mozilla.org/en-US/docs/Mozilla/XPI>.

      * path to a directory containing firefox extension source code
      <https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension>.
      This directory will be packaged up as an unsigned xpi file.

      * path to a top level file (such as manifest.json
      <https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Anatomy_of_a_WebExtension#manifest.json>)
      in a directory containing firefox extension source code
      <https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension>.
      This directory will be packaged up as an unsigned xpi file.

    and an optional true/false second parameter to indicate if the xpi file
    should be a temporary extension
    <https://extensionworkshop.com/documentation/develop/temporary-installation-in-firefox/>
    (just for the existence of this browser instance). Unsigned xpi files
    may only be loaded temporarily
    <https://wiki.mozilla.org/Add-ons/Extension_Signing> (except for
    nightly firefox installations
    <https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly>). It
    returns the GUID for the addon which may be used as a parameter to the
    uninstall method.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
    
        my $extension_id = $firefox->install('/full/path/to/gnu_terry_pratchett-0.4-an+fx.xpi');
    
        # OR downloading and installing source code
    
        system { 'git' } 'git', 'clone', 'https://github.com/kkapsner/CanvasBlocker.git';
    
        if ($firefox->nightly()) {
    
            $extension_id = $firefox->install('./CanvasBlocker'); # permanent install for unsigned packages in nightly firefox
    
        } else {
    
            $extension_id = $firefox->install('./CanvasBlocker', 1); # temp install for normal firefox
    
        }

 interactive

    returns true if document.readyState === "interactive" or if loaded is
    true

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_id('metacpan_search-input')->type('Type::More');
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
        while(!$firefox->interactive()) {
            # redirecting to Test::More page
        }

 is_displayed

    accepts an element as the first parameter. This method returns true or
    false depending on if the element is displayed
    <https://firefox-source-docs.mozilla.org/testing/marionette/internals/interaction.html#interaction.isElementDisplayed>.

 is_enabled

    accepts an element as the first parameter. This method returns true or
    false depending on if the element is enabled
    <https://w3c.github.io/webdriver/#is-element-enabled>.

 is_selected

    accepts an element as the first parameter. This method returns true or
    false depending on if the element is selected
    <https://w3c.github.io/webdriver/#dfn-is-element-selected>. Note that
    this method only makes sense for checkbox
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox>
    or radio
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/radio>
    inputs or option
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option>
    elements in a select
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select>
    dropdown.

 is_trusted

    accepts an certificate as the first parameter. This method returns true
    or false depending on if the certificate is a trusted CA certificate in
    the current profile.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new( profile_name => 'default' );
        foreach my $certificate ($firefox->certificates()) {
            if (($certificate->is_ca_cert()) && ($firefox->is_trusted($certificate))) {
                say $certificate->display_name() . " is a trusted CA cert in the current profile";
            } 
        } 

 json

    returns a JSON object that has been parsed from the page source of the
    content document. This is a convenience method that wraps the strip
    method.

        use Firefox::Marionette();
        use v5.10;
    
        say Firefox::Marionette->new()->go('https://fastapi.metacpan.org/v1/download_url/Firefox::Marionette")->json()->{version};

    In addition, this method can accept a URI as a parameter and retrieve
    that URI via the firefox fetch call
    <https://developer.mozilla.org/en-US/docs/Web/API/fetch> and
    transforming the body to JSON via firefox
    <https://developer.mozilla.org/en-US/docs/Web/API/Response/json_static>

        use Firefox::Marionette();
        use v5.10;
    
        say Firefox::Marionette->new()->json('https://freeipapi.com/api/json/')->{ipAddress};

 key_down

    accepts a parameter describing a key and returns an action for use in
    the perform method that corresponding with that key being depressed.

        use Firefox::Marionette();
        use Firefox::Marionette::Keys qw(:all);
    
        my $firefox = Firefox::Marionette->new();
    
        $firefox->chrome()->perform(
                                     $firefox->key_down(CONTROL()),
                                     $firefox->key_down('l'),
                                   )->release()->content();

 key_up

    accepts a parameter describing a key and returns an action for use in
    the perform method that corresponding with that key being released.

        use Firefox::Marionette();
        use Firefox::Marionette::Keys qw(:all);
    
        my $firefox = Firefox::Marionette->new();
    
        $firefox->chrome()->perform(
                                     $firefox->key_down(CONTROL()),
                                     $firefox->key_down('l'),
                                     $firefox->pause(20),
                                     $firefox->key_up('l'),
                                     $firefox->key_up(CONTROL())
                                   )->content();

 languages

    accepts an optional list of values for the Accept-Language
    <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language>
    header and sets this using the profile preferences. It returns the
    current values as a list, such as ('en-US', 'en').

 loaded

    returns true if document.readyState === "complete"

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        $firefox->find_id('metacpan_search-input')->type('Type::More');
        $firefox->await(sub { $firefox->find_class('autocomplete-suggestion'); })->click();
        while(!$firefox->loaded()) {
            # redirecting to Test::More page
        }

 logins

    returns a list of all Firefox::Marionette::Login objects available.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
        foreach my $login ($firefox->logins()) {
           say "Found login for " . $login->host() . " and user " . $login->user();
        }

 logins_from_csv

    accepts a filehandle as a parameter and then reads the filehandle for
    exported logins as CSV. This is known to work with the following
    formats;

      * Bitwarden CSV
      <https://bitwarden.com/help/article/condition-bitwarden-import/>

      * LastPass CSV
      <https://support.logmeininc.com/lastpass/help/how-do-i-nbsp-export-stored-data-from-lastpass-using-a-generic-csv-file>

      * KeePass CSV <https://keepass.info/help/base/importexport.html#csv>

    returns a list of Firefox::Marionette::Login objects.

        use Firefox::Marionette();
        use FileHandle();
    
        my $handle = FileHandle->new('/path/to/last_pass.csv');
        my $firefox = Firefox::Marionette->new();
        foreach my $login (Firefox::Marionette->logins_from_csv($handle)) {
            $firefox->add_login($login);
        }

 logins_from_xml

    accepts a filehandle as a parameter and then reads the filehandle for
    exported logins as XML. This is known to work with the following
    formats;

      * KeePass 1.x XML
      <https://keepass.info/help/base/importexport.html#xml>

    returns a list of Firefox::Marionette::Login objects.

        use Firefox::Marionette();
        use FileHandle();
    
        my $handle = FileHandle->new('/path/to/keepass1.xml');
        my $firefox = Firefox::Marionette->new();
        foreach my $login (Firefox::Marionette->logins_from_csv($handle)) {
            $firefox->add_login($login);
        }

 logins_from_zip

    accepts a filehandle as a parameter and then reads the filehandle for
    exported logins as a zip file. This is known to work with the following
    formats;

      * 1Password Unencrypted Export format
      <https://support.1password.com/1pux-format/>

    returns a list of Firefox::Marionette::Login objects.

        use Firefox::Marionette();
        use FileHandle();
    
        my $handle = FileHandle->new('/path/to/1Passwordv8.1pux');
        my $firefox = Firefox::Marionette->new();
        foreach my $login (Firefox::Marionette->logins_from_zip($handle)) {
            $firefox->add_login($login);
        }

 links

    returns a list of all of the following elements;

      * anchor
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a>

      * area
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/area>

      * frame
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/frame>

      * iframe
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe>

      * meta
      <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta>

    as Firefox::Marionette::Link objects.

    This method is subject to the implicit timeout, which, by default is 0
    seconds.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        if (my $link = $firefox->links()) {
            if ($link->tag() eq 'a') {
                warn "Found a hyperlink to " . $link->URL();
            }
        }

    If no elements are found, this method will return undef.

 macos_binary_paths

    returns a list of filesystem paths that this module will check for
    binaries that it can automate when running on MacOS
    <https://en.wikipedia.org/wiki/MacOS>. Only of interest when
    sub-classing.

 marionette_protocol

    returns the version for the Marionette protocol. Current most recent
    version is '3'.

 maximise

    maximises the firefox window. This method returns itself to aid in
    chaining methods.

 mime_types

    returns a list of MIME types that will be downloaded by firefox and
    made available from the downloads method

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new(mime_types => [ 'application/pkcs10' ])
    
        foreach my $mime_type ($firefox->mime_types()) {
            say $mime_type;
        }

 minimise

    minimises the firefox window. This method returns itself to aid in
    chaining methods.

 mouse_down

    accepts a parameter describing which mouse button the method should
    apply to (left, middle or right) and returns an action for use in the
    perform method that corresponding with a mouse button being depressed.

 mouse_move

    accepts a element parameter, or a ( x => 0, y => 0 ) type hash manually
    describing exactly where to move the mouse to and returns an action for
    use in the perform method that corresponding with such a mouse
    movement, either to the specified co-ordinates or to the middle of the
    supplied element parameter. Other parameters that may be passed are
    listed below;

      * origin - the origin of the C(<x => 0, y => 0)> co-ordinates. Should
      be either viewport, pointer or an element.

      * duration - Number of milliseconds over which to distribute the
      move. If not defined, the duration defaults to 0.

    This method returns itself to aid in chaining methods.

 mouse_up

    accepts a parameter describing which mouse button the method should
    apply to (left, middle or right) and returns an action for use in the
    perform method that corresponding with a mouse button being released.

 new

    accepts an optional hash as a parameter. Allowed keys are below;

      * addons - should any firefox extensions and themes be available in
      this session. This defaults to "0".

      * binary - use the specified path to the Firefox
      <https://firefox.org/> binary, rather than the default path.

      * capabilities - use the supplied capabilities object, for example to
      set whether the browser should accept insecure certs or whether the
      browser should use a proxy.

      * chatty - Firefox is extremely chatty on the network, including
      checking for the latest malware/phishing sites, updates to
      firefox/etc. This option is therefore off ("0") by default, however,
      it can be switched on ("1") if required. Even with chatty switched
      off, connections to firefox.settings.services.mozilla.com will still
      be made <https://bugzilla.mozilla.org/show_bug.cgi?id=1598562#c13>.
      The only way to prevent this seems to be to set
      firefox.settings.services.mozilla.com to 127.0.0.1 via /etc/hosts
      <https://en.wikipedia.org/wiki//etc/hosts>. NOTE: that this option
      only works when profile_name/profile is not specified.

      * console - show the browser console
      <https://developer.mozilla.org/en-US/docs/Tools/Browser_Console/>
      when the browser is launched. This defaults to "0" (off). See CONSOLE
      LOGGING for a discussion of how to send log messages to the console.

      * debug - should firefox's debug to be available via STDERR. This
      defaults to "0". Any ssh connections will also be printed to STDERR.
      This defaults to "0" (off). This setting may be updated by the debug
      method. If this option is not a boolean (0|1), the value will be
      passed to the MOZ_LOG
      <https://firefox-source-docs.mozilla.org/networking/http/logging.html>
      option on the command line of the firefox binary to allow extra
      levels of debug.

      * developer - only allow a developer edition
      <https://www.mozilla.org/en-US/firefox/developer/> to be launched.
      This defaults to "0" (off).

      * devtools - begin the session with the devtools
      <https://developer.mozilla.org/en-US/docs/Tools> window opened in a
      separate window.

      * geo - setup the browser preferences
      <http://kb.mozillazine.org/About:config> to allow the Geolocation API
      <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API> to
      work. If the value for this key is a URI object or a string beginning
      with '^(?:data|http)', this object will be retrieved using the json
      method and the response will used to build a GeoLocation object,
      which will be sent to the geo method. If the value for this key is a
      hash, the hash will be used to build a GeoLocation object, which will
      be sent to the geo method.

      * height - set the height
      <http://kb.mozillazine.org/Command_line_arguments#List_of_command_line_arguments_.28incomplete.29>
      of the initial firefox window

      * har - begin the session with the devtools
      <https://developer.mozilla.org/en-US/docs/Tools> window opened in a
      separate window. The HAR Export Trigger
      <https://addons.mozilla.org/en-US/firefox/addon/har-export-trigger/>
      addon will be loaded into the new session automatically, which means
      that -safe-mode
      <http://kb.mozillazine.org/Command_line_arguments#List_of_command_line_arguments_.28incomplete.29>
      will not be activated for this session AND this functionality will
      only be available for Firefox 61+.

      * host - use ssh <https://man.openbsd.org/ssh.1> to create and
      automate firefox on the specified host. See REMOTE AUTOMATION OF
      FIREFOX VIA SSH and NETWORK ARCHITECTURE. The user will default to
      the current user name (see the user parameter to change this).
      Authentication should be via public keys loaded into the local
      ssh-agent <https://man.openbsd.org/ssh-agent>.

      * implicit - a shortcut to allow directly providing the implicit
      timeout, instead of needing to use timeouts from the capabilities
      parameter. Overrides all longer ways.

      * index - a parameter to allow the user to specify a specific firefox
      instance to survive and reconnect to. It does not do anything else at
      the moment. See the survive parameter.

      * kiosk - start the browser in kiosk
      <https://support.mozilla.org/en-US/kb/firefox-enterprise-kiosk-mode>
      mode.

      * mime_types - any MIME types that Firefox will encounter during this
      session. MIME types that are not specified will result in a hung
      browser (the File Download popup will appear).

      * nightly - only allow a nightly release
      <https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly> to
      be launched. This defaults to "0" (off).

      * port - if the "host" parameter is also set, use ssh
      <https://man.openbsd.org/ssh.1> to create and automate firefox via
      the specified port. See REMOTE AUTOMATION OF FIREFOX VIA SSH and
      NETWORK ARCHITECTURE.

      * page_load - a shortcut to allow directly providing the page_load
      timeout, instead of needing to use timeouts from the capabilities
      parameter. Overrides all longer ways.

      * profile - create a new profile based on the supplied profile. NOTE:
      firefox ignores any changes made to the profile on the disk while it
      is running, instead, use the set_pref and clear_pref methods to make
      changes while firefox is running.

      * profile_name - pick a specific existing profile to automate, rather
      than creating a new profile. Firefox <https://firefox.com> refuses to
      allow more than one instance of a profile to run at the same time.
      Profile names can be obtained by using the
      Firefox::Marionette::Profile::names() method. The following
      conditions are required to use existing profiles;

	* the preference security.webauth.webauthn_enable_softtoken must be
	set to true in the profile OR

	* the webauth parameter to this method must be set to 0

      NOTE: firefox ignores any changes made to the profile on the disk
      while it is running, instead, use the set_pref and clear_pref methods
      to make changes while firefox is running.

      * proxy - this is a shortcut method for setting a proxy using the
      capabilities parameter above. It accepts a proxy URL, with the
      following allowable schemes, 'http' and 'https'. It also allows a
      reference to a list of proxy URLs which will function as list of
      proxies that Firefox will try in left to right order
      <https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file#description>
      until a working proxy is found. See REMOTE AUTOMATION OF FIREFOX VIA
      SSH, NETWORK ARCHITECTURE and SETTING UP SOCKS SERVERS USING SSH.

      * reconnect - an experimental parameter to allow a reconnection to
      firefox that a connection has been discontinued. See the survive
      parameter.

      * scp - force the scp protocol when transferring files to remote
      hosts via ssh. See REMOTE AUTOMATION OF FIREFOX VIA SSH and the
      --scp-only option in the ssh-auth-cmd-marionette
      <https://metacpan.org/pod/ssh-auth-cmd-marionette> script in this
      distribution.

      * script - a shortcut to allow directly providing the script timeout,
      instead of needing to use timeouts from the capabilities parameter.
      Overrides all longer ways.

      * seer - this option is switched off "0" by default. When it is
      switched on "1", it will activate the various speculative and
      pre-fetch options for firefox. NOTE: that this option only works when
      profile_name/profile is not specified.

      * sleep_time_in_ms - the amount of time (in milliseconds) that this
      module should sleep when unsuccessfully calling the subroutine
      provided to the await or bye methods. This defaults to "1"
      millisecond.

      * stealth - stops navigator.webdriver
      <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver>
      from being accessible by the current web page. This is achieved by
      loading an extension
      <https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions>,
      which will automatically switch on the addons parameter for the new
      method. This is extremely experimental. See IMITATING OTHER BROWSERS
      for a discussion.

      * survive - if this is set to a true value, firefox will not
      automatically exit when the object goes out of scope. See the
      reconnect parameter for an experimental technique for reconnecting.

      * trust - give a path to a root certificate
      <https://en.wikipedia.org/wiki/Root_certificate> encoded as a PEM
      encoded X.509 certificate
      <https://datatracker.ietf.org/doc/html/rfc7468#section-5> that will
      be trusted for this session.

      * timeouts - a shortcut to allow directly providing a timeout object,
      instead of needing to use timeouts from the capabilities parameter.
      Overrides the timeouts provided (if any) in the capabilities
      parameter.

      * trackable - if this is set, profile preferences will be set to make
      it harder to be tracked by the browsers fingerprint
      <https://en.wikipedia.org/wiki/Device_fingerprint#Browser_fingerprint>
      across browser restarts. This is on by default, but may be switched
      off by setting it to 0;

      * user - if the "host" parameter is also set, use ssh
      <https://man.openbsd.org/ssh.1> to create and automate firefox with
      the specified user. See REMOTE AUTOMATION OF FIREFOX VIA SSH and
      NETWORK ARCHITECTURE. The user will default to the current user name.
      Authentication should be via public keys loaded into the local
      ssh-agent <https://man.openbsd.org/ssh-agent>.

      * via - specifies a proxy jump box
      <https://man.openbsd.org/ssh_config#ProxyJump> to be used to connect
      to a remote host. See the host parameter.

      * visible - should firefox be visible on the desktop. This defaults
      to "0". When moving from a X11 platform to another X11 platform, you
      can set visible to 'local' to enable X11 forwarding
      <https://man.openbsd.org/ssh#X>. See X11 FORWARDING WITH FIREFOX.

      * waterfox - only allow a binary that looks like a waterfox version
      <https://www.waterfox.net/> to be launched.

      * webauthn - a boolean parameter to determine whether or not to add a
      webauthn authenticator after the connection is established. The
      default is to add a webauthn authenticator for Firefox after version
      118.

      * width - set the width
      <http://kb.mozillazine.org/Command_line_arguments#List_of_command_line_arguments_.28incomplete.29>
      of the initial firefox window

    This method returns a new Firefox::Marionette object, connected to an
    instance of firefox <https://firefox.com>. In a non MacOS/Win32/Cygwin
    environment, if necessary (no DISPLAY variable can be found and the
    visible parameter to the new method has been set to true) and possible
    (Xvfb can be executed successfully), this method will also
    automatically start an Xvfb <https://en.wikipedia.org/wiki/Xvfb>
    instance.

        use Firefox::Marionette();
    
        my $remote_darwin_firefox = Firefox::Marionette->new(
                         debug => 'timestamp,nsHttp:1',
                         host => '10.1.2.3',
                         trust => '/path/to/root_ca.pem',
                         binary => '/Applications/Firefox.app/Contents/MacOS/firefox'
                                                            ); # start a temporary profile for a remote firefox and load a new CA into the temp profile
        ...
    
        foreach my $profile_name (Firefox::Marionette::Profile->names()) {
            my $firefox_with_existing_profile = Firefox::Marionette->new( profile_name => $profile_name, visible => 1 );
            ...
        }

 new_window

    accepts an optional hash as the parameter. Allowed keys are below;

      * focus - a boolean field representing if the new window be opened in
      the foreground (focused) or background (not focused). Defaults to
      false.

      * private - a boolean field representing if the new window should be
      a private window. Defaults to false.

      * type - the type of the new window. Can be one of 'tab' or 'window'.
      Defaults to 'tab'.

    Returns the window handle for the new window.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
    
        my $window_handle = $firefox->new_window(type => 'tab');
    
        $firefox->switch_to_window($window_handle);

 new_session

    creates a new WebDriver session. It is expected that the caller
    performs the necessary checks on the requested capabilities to be
    WebDriver conforming. The WebDriver service offered by Marionette does
    not match or negotiate capabilities beyond type and bounds checks.

 nightly

    returns true if the current version of firefox is a nightly release
    <https://www.mozilla.org/en-US/firefox/channel/desktop/#nightly> (does
    the minor version number end with an 'a1'?)

 paper_sizes

    returns a list of all the recognised names for paper sizes, such as A4
    or LEGAL.

 pause

    accepts a parameter in milliseconds and returns a corresponding action
    for the perform method that will cause a pause in the chain of actions
    given to the perform method.

 pdf

    accepts a optional hash as the first parameter with the following
    allowed keys;

      * landscape - Paper orientation. Boolean value. Defaults to false

      * margin - A hash describing the margins. The hash may have the
      following optional keys, 'top', 'left', 'right' and 'bottom'. All
      these keys are in cm and default to 1 (~0.4 inches)

      * page - A hash describing the page. The hash may have the following
      keys; 'height' and 'width'. Both keys are in cm and default to US
      letter size. See the 'size' key.

      * page_ranges - A list of the pages to print. Available for Firefox
      96
      <https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/96#webdriver_conformance_marionette>
      and after.

      * print_background - Print background graphics. Boolean value.
      Defaults to false.

      * raw - rather than a file handle containing the PDF, the binary PDF
      will be returned.

      * scale - Scale of the webpage rendering. Defaults to 1.
      shrink_to_fit should be disabled to make scale work.

      * size - The desired size (width and height) of the pdf, specified by
      name. See the page key for an alternative and the paper_sizes method
      for a list of accepted page size names.

      * shrink_to_fit - Whether or not to override page size as defined by
      CSS. Boolean value. Defaults to true.

    returns a File::Temp object containing a PDF encoded version of the
    current page for printing.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        my $handle = $firefox->pdf();
        foreach my $paper_size ($firefox->paper_sizes()) {
                $handle = $firefox->pdf(size => $paper_size, landscape => 1, margin => { top => 0.5, left => 1.5 });
                ...
                print $firefox->pdf(page => { width => 21, height => 27 }, raw => 1);
                ...
        }

 percentage_visible

    accepts an element as the first parameter and returns the percentage of
    that element that is currently visible in the viewport
    <https://developer.mozilla.org/en-US/docs/Glossary/Viewport>. It
    achieves this by determining the co-ordinates of the DOMRect
    <https://developer.mozilla.org/en-US/docs/Web/API/DOMRect> with a
    getBoundingClientRect
    <https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect>
    call and then using elementsFromPoint
    <https://developer.mozilla.org/en-US/docs/Web/API/Document/elementsFromPoint>
    and getComputedStyle
    <https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle>
    calls to determine how the percentage of the DOMRect that is visible to
    the user. The getComputedStyle call is used to determine the state of
    the visibility
    <https://developer.mozilla.org/en-US/docs/Web/CSS/visibility> and
    display <https://developer.mozilla.org/en-US/docs/Web/CSS/display>
    attributes.

        use Firefox::Marionette();
        use Encode();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new( visible => 1, kiosk => 1 )->go('http://metacpan.org');;
        my $element = $firefox->find_id('metacpan_search-input');
        my $totally_viewable_percentage = $firefox->percentage_visible($element); # search box is slightly hidden by different effects
        foreach my $display ($firefox->displays()) {
            if ($firefox->resize($display->width(), $display->height())) {
                if ($firefox->percentage_visible($element) < $totally_viewable_percentage) {
                   say 'Search box stops being fully viewable with ' . Encode::encode('UTF-8', $display->usage());
                   last;
                }
            }
        }

 perform

    accepts a list of actions (see mouse_up, mouse_down, mouse_move, pause,
    key_down and key_up) and performs these actions in sequence. This
    allows fine control over interactions, including sending right clicks
    to the browser and sending Control, Alt and other special keys. The
    release method will complete outstanding actions (such as mouse_up or
    key_up actions).

        use Firefox::Marionette();
        use Firefox::Marionette::Keys qw(:all);
        use Firefox::Marionette::Buttons qw(:all);
    
        my $firefox = Firefox::Marionette->new();
    
        $firefox->chrome()->perform(
                                     $firefox->key_down(CONTROL()),
                                     $firefox->key_down('l'),
                                     $firefox->key_up('l'),
                                     $firefox->key_up(CONTROL())
                                   )->content();
    
        $firefox->go('https://metacpan.org');
        my $help_button = $firefox->find_class('btn search-btn help-btn');
        $firefox->perform(
                                      $firefox->mouse_move($help_button),
                                      $firefox->mouse_down(RIGHT_BUTTON()),
                                      $firefox->pause(4),
                                      $firefox->mouse_up(RIGHT_BUTTON()),
                    );

    See the release method for an alternative for manually specifying all
    the mouse_up and key_up methods

 profile_directory

    returns the profile directory used by the current instance of firefox.
    This is mainly intended for debugging firefox. Firefox is not designed
    to cope with these files being altered while firefox is running.

 property

    accepts an element as the first parameter and a scalar attribute name
    as the second parameter. It returns the current value of the property
    with the supplied name. This method will return the current content,
    the attribute method will return the initial content from the HTML
    source code.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
        my $element = $firefox->find_id('metacpan_search-input');
        $element->property('value') eq '' or die "Initial property should be the empty string";
        $element->type('Test::More');
        $element->property('value') eq 'Test::More' or die "This property should have changed!";
    
        # OR getting the innerHTML property
    
        my $title = $firefox->find_tag('title')->property('innerHTML'); # same as $firefox->title();

 pwd_mgr_lock

    Accepts a new primary password
    <https://support.mozilla.org/en-US/kb/use-primary-password-protect-stored-logins>
    and locks the Password Manager
    <https://support.mozilla.org/en-US/kb/password-manager-remember-delete-edit-logins>
    with it.

        use Firefox::Marionette();
        use IO::Prompt();
    
        my $firefox = Firefox::Marionette->new();
        my $password = IO::Prompt::prompt(-echo => q[*], "Please enter the password for the Firefox Password Manager:");
        $firefox->pwd_mgr_lock($password);
        $firefox->pwd_mgr_logout();
        # now no-one can access the Password Manager Database without the value in $password

    This method returns itself to aid in chaining methods.

 pwd_mgr_login

    Accepts the primary password
    <https://support.mozilla.org/en-US/kb/use-primary-password-protect-stored-logins>
    and allows the user to access the Password Manager
    <https://support.mozilla.org/en-US/kb/password-manager-remember-delete-edit-logins>.

        use Firefox::Marionette();
        use IO::Prompt();
    
        my $firefox = Firefox::Marionette->new( profile_name => 'default' );
        my $password = IO::Prompt::prompt(-echo => q[*], "Please enter the password for the Firefox Password Manager:");
        $firefox->pwd_mgr_login($password);
        ...
        # access the Password Database.
        ...
        $firefox->pwd_mgr_logout();
        ...
        # no longer able to access the Password Database.

    This method returns itself to aid in chaining methods.

 pwd_mgr_logout

    Logs the user out of being able to access the Password Manager
    <https://support.mozilla.org/en-US/kb/password-manager-remember-delete-edit-logins>.

        use Firefox::Marionette();
        use IO::Prompt();
    
        my $firefox = Firefox::Marionette->new( profile_name => 'default' );
        my $password = IO::Prompt::prompt(-echo => q[*], "Please enter the password for the Firefox Password Manager:");
        $firefox->pwd_mgr_login($password);
        ...
        # access the Password Database.
        ...
        $firefox->pwd_mgr_logout();
        ...
        # no longer able to access the Password Database.

    This method returns itself to aid in chaining methods.

 pwd_mgr_needs_login

    returns true or false if the Password Manager
    <https://support.mozilla.org/en-US/kb/password-manager-remember-delete-edit-logins>
    has been locked and needs a primary password
    <https://support.mozilla.org/en-US/kb/use-primary-password-protect-stored-logins>
    to access it.

        use Firefox::Marionette();
        use IO::Prompt();
    
        my $firefox = Firefox::Marionette->new( profile_name => 'default' );
        if ($firefox->pwd_mgr_needs_login()) {
          my $password = IO::Prompt::prompt(-echo => q[*], "Please enter the password for the Firefox Password Manager:");
          $firefox->pwd_mgr_login($password);
        }

 quit

    Marionette will stop accepting new connections before ending the
    current session, and finally attempting to quit the application. This
    method returns the $? (CHILD_ERROR) value for the Firefox process

 rect

    accepts a element as the first parameter and returns the current
    position and size of the element

 refresh

    refreshes the current page. The browser will wait for the page to
    completely refresh or the session's page_load duration to elapse before
    returning, which, by default is 5 minutes. This method returns itself
    to aid in chaining methods.

 release

    completes any outstanding actions issued by the perform method.

        use Firefox::Marionette();
        use Firefox::Marionette::Keys qw(:all);
        use Firefox::Marionette::Buttons qw(:all);
    
        my $firefox = Firefox::Marionette->new();
    
        $firefox->chrome()->perform(
                                     $firefox->key_down(CONTROL()),
                                     $firefox->key_down('l'),
                                   )->release()->content();
    
        $firefox->go('https://metacpan.org');
        my $help_button = $firefox->find_class('btn search-btn help-btn');
        $firefox->perform(
                                      $firefox->mouse_move($help_button),
                                      $firefox->mouse_down(RIGHT_BUTTON()),
                                      $firefox->pause(4),
                    )->release();

 resize

    accepts width and height parameters in a list and then attempts to
    resize the entire browser to match those parameters. Due to the
    oddities of various window managers, this function needs to manually
    calculate what the maximum and minimum sizes of the display is. It does
    this by;

    1 performing a maximise, then

    2 caching the browser's current width and height as the maximum width
    and height. It

    3 then calls resizeTo
    <https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeTo> to
    resize the window to 0,0

    4 wait for the browser to send a resize
    <https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event>
    event.

    5 cache the browser's current width and height as the minimum width and
    height

    6 if the requested width and height are outside of the maximum and
    minimum widths and heights return false

    7 if the requested width and height matches the current width and
    height return itself to aid in chaining methods. Otherwise,

    8 call resizeTo
    <https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeTo> for
    the requested width and height

    9 wait for the resize
    <https://developer.mozilla.org/en-US/docs/Web/API/Window/resize_event>
    event

    This method returns itself to aid in chaining methods if the method
    succeeds, otherwise it returns false.

        use Firefox::Marionette();
        use Encode();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new( visible => 1, kiosk => 1 )->go('http://metacpan.org');;
        if ($firefox->resize(1024, 768)) {
            say 'We are showing an XGA display';
        } else {
           say 'Resize failed to work';
        }

 resolve

    accepts a hostname as an argument and resolves it to a list of matching
    IP addresses. It can also accept an optional hash containing additional
    keys, described in Firefox::Marionette::DNS.

        use Firefox::Marionette();
        use v5.10;
    
        my $ssh_server = 'remote.example.org';
        my $firefox = Firefox::Marionette->new( host => $ssh_server );
        my $hostname = 'metacpan.org';
        foreach my $ip_address ($firefox->resolve($hostname)) {
           say "$hostname resolves to $ip_address at $ssh_server";
        }
        $firefox = Firefox::Marionette->new();
        foreach my $ip_address ($firefox->resolve($hostname, flags => Firefox::Marionette::DNS::RESOLVE_REFRESH_CACHE() | Firefox::Marionette::DNS::RESOLVE_BYPASS_CACHE(), type => Firefox::Marionette::DNS::RESOLVE_TYPE_DEFAULT())) {
           say "$hostname resolves to $ip_address;
        }

 restart

    restarts the browser. After the restart, capabilities should be
    restored. The same profile settings should be applied, but the current
    state of the browser (such as the uri will be reset (like after a
    normal browser restart). This method is primarily intended for use by
    the update method. Not sure if this is useful by itself.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
    
        $firefox->restart(); # but why?

    This method returns itself to aid in chaining methods.

 root_directory

    this is the root directory for the current instance of firefox. The
    directory may exist on a remote server. For debugging purposes only.

 screen_orientation

    returns the current browser orientation. This will be one of the valid
    primary orientation values 'portrait-primary', 'landscape-primary',
    'portrait-secondary', or 'landscape-secondary'. This method is only
    currently available on Android (Fennec).

 script

    accepts a scalar containing a javascript function body that is executed
    in the browser, and an optional hash as a second parameter. Allowed
    keys are below;

      * args - The reference to a list is the arguments passed to the
      function body.

      * filename - Filename of the client's program where this script is
      evaluated.

      * line - Line in the client's program where this script is evaluated.

      * new - Forces the script to be evaluated in a fresh sandbox. Note
      that if it is undefined, the script will normally be evaluated in a
      fresh sandbox.

      * sandbox - Name of the sandbox to evaluate the script in. The
      sandbox is cached for later re-use on the same window
      <https://developer.mozilla.org/en-US/docs/Web/API/Window> object if
      new is false. If he parameter is undefined, the script is evaluated
      in a mutable sandbox. If the parameter is "system", it will be
      evaluated in a sandbox with elevated system privileges, equivalent to
      chrome space.

      * timeout - A timeout to override the default script timeout, which,
      by default is 30 seconds.

    Returns the result of the javascript function. When a parameter is an
    element (such as being returned from a find type operation), the script
    method will automatically translate that into a javascript object.
    Likewise, when the result being returned in a script method is an
    element <https://dom.spec.whatwg.org/#concept-element> it will be
    automatically translated into a perl object.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new()->go('https://metacpan.org/');
    
        if (my $element = $firefox->script('return document.getElementsByName("metacpan_search-input")[0];')) {
            say "Lucky find is a " . $element->tag_name() . " element";
        }
    
        my $search_input = $firefox->find_id('metacpan_search-input');
    
        $firefox->script('arguments[0].style.backgroundColor = "red"', args => [ $search_input ]); # turn the search input box red

    The executing javascript is subject to the script timeout, which, by
    default is 30 seconds.

 selfie

    returns a File::Temp object containing a lossless PNG image screenshot.
    If an element is passed as a parameter, the screenshot will be
    restricted to the element.

    If an element is not passed as a parameter and the current context is
    'chrome', a screenshot of the current viewport will be returned.

    If an element is not passed as a parameter and the current context is
    'content', a screenshot of the current frame will be returned.

    The parameters after the element parameter are taken to be a optional
    hash with the following allowed keys;

      * hash - return a SHA256 hex encoded digest of the PNG image rather
      than the image itself

      * full - take a screenshot of the whole document unless the first
      element parameter has been supplied.

      * raw - rather than a file handle containing the screenshot, the
      binary PNG image will be returned.

      * scroll - scroll to the element supplied

      * highlights - a reference to a list containing elements to draw a
      highlight around. Not available in Firefox 70
      <https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/70#WebDriver_conformance_Marionette>
      onwards.

 scroll

    accepts a element as the first parameter and scrolls
    <https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView>
    to it. The optional second parameter is the same as for the
    scrollInfoView method.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new(visible => 1)->go('https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView');
        my $link = $firefox->find_id('content')->find_link('Examples');
        $firefox->scroll($link);
        $firefox->scroll($link, 1);
        $firefox->scroll($link, { behavior => 'smooth', block => 'center' });
        $firefox->scroll($link, { block => 'end', inline => 'nearest' });

 send_alert_text

    sends keys to the input field of a currently displayed modal message
    box

 set_javascript

    accepts a parameter for the the profile preference value of
    javascript.enabled
    <https://support.mozilla.org/en-US/kb/javascript-settings-for-interactive-web-pages#w_for-advanced-users>.
    This method returns itself to aid in chaining methods.

 set_pref

    accepts a preference <http://kb.mozillazine.org/About:config> name and
    the new value to set it to. See the get_pref and clear_pref methods to
    get a preference value and to restore it to it's original value. This
    method returns itself to aid in chaining methods.

        use Firefox::Marionette();
        my $firefox = Firefox::Marionette->new();
        ...
        $firefox->set_pref('browser.search.defaultenginename', 'DuckDuckGo');

 shadow_root

    accepts an element as a parameter and returns it's ShadowRoot
    <https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot> as a
    shadow root object or throws an exception.

        use Firefox::Marionette();
        use Cwd();
    
        my $firefox = Firefox::Marionette->new()->go('file://' . Cwd::cwd() . '/t/data/elements.html');
    
        $firefox->find_class('add')->click();
        my $custom_square = $firefox->find_tag('custom-square');
        my $shadow_root = $firefox->shadow_root($custom_square);
    
        foreach my $element (@{$firefox->script('return arguments[0].children', args => [ $shadow_root ])}) {
            warn $element->tag_name();
        }

    See the FINDING ELEMENTS IN A SHADOW DOM section for how to delve into
    a shadow DOM
    <https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM>.

 shadowy

    accepts an element as a parameter and returns true if the element has a
    ShadowRoot
    <https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot> or false
    otherwise.

        use Firefox::Marionette();
        use Cwd();
    
        my $firefox = Firefox::Marionette->new()->go('file://' . Cwd::cwd() . '/t/data/elements.html');
        $firefox->find_class('add')->click();
        my $custom_square = $firefox->find_tag('custom-square');
        if ($firefox->shadowy($custom_square)) {
            my $shadow_root = $firefox->find_tag('custom-square')->shadow_root();
            warn $firefox->script('return arguments[0].innerHTML', args => [ $shadow_root ]);
            ...
        }

    This function will probably be used to see if the shadow_root method
    can be called on this element without raising an exception.

 sleep_time_in_ms

    accepts a new time to sleep in await or bye methods and returns the
    previous time. The default time is "1" millisecond.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new(sleep_time_in_ms => 5); # setting default time to 5 milliseconds
    
        my $old_time_in_ms = $firefox->sleep_time_in_ms(8); # setting default time to 8 milliseconds, returning 5 (milliseconds)

 ssh_local_directory

    returns the path to the local directory for the ssh connection (if
    any). For debugging purposes only.

 strip

    returns the page source of the content document after an attempt has
    been made to remove typical firefox html wrappers of non html content
    types such as text/plain and application/json. See the json method for
    an alternative when dealing with response content types such as
    application/json and html for an alternative when dealing with html
    content types. This is a convenience method that wraps the html method.

        use Firefox::Marionette();
        use JSON();
        use v5.10;
    
        say JSON::decode_json(Firefox::Marionette->new()->go("https://fastapi.metacpan.org/v1/download_url/Firefox::Marionette")->strip())->{version};

    Note that this method will assume the bytes it receives from the html
    method are UTF-8 encoded and will translate accordingly, throwing an
    exception in the process if the bytes are not UTF-8 encoded.

 switch_to_frame

    accepts a frame as a parameter and switches to it within the current
    window.

 switch_to_parent_frame

    set the current browsing context for future commands to the parent of
    the current browsing context

 switch_to_window

    accepts a window handle (either the result of window_handles or a
    window name as a parameter and switches focus to this window.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->version
        my $original_window = $firefox->window_handle();
        $firefox->new_window( type => 'tab' );
        $firefox->new_window( type => 'window' );
        $firefox->switch_to_window($original_window);
        $firefox->go('https://metacpan.org');

 tag_name

    accepts a Firefox::Marionette::Element object as the first parameter
    and returns the relevant tag name. For example 'a
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a>' or
    'input
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input>'.

 text

    accepts a element as the first parameter and returns the text that is
    contained by that element (if any)

 timeouts

    returns the current timeouts for page loading, searching, and scripts.

 tz

    accepts a Olson TZ identifier
    <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List> as
    the first parameter. This method returns itself to aid in chaining
    methods.

 title

    returns the current title
    <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title> of
    the window.

 type

    accepts an element as the first parameter and a string as the second
    parameter. It sends the string to the specified element in the current
    page, such as filling out a text box. This method returns itself to aid
    in chaining methods.

 uname

    returns the $^O ($OSNAME) compatible string to describe the platform
    where firefox is running.

 update

    queries the Update Services and applies any available updates. Restarts
    the browser if necessary to complete the update. This function is
    experimental and currently has not been successfully tested on Win32 or
    MacOS.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
    
        my $update = $firefox->update();
    
        while($update->successful()) {
            $update = $firefox->update();
        }
    
        say "Updated to " . $update->display_version() . " - Build ID " . $update->build_id();
    
        $firefox->quit();

    returns a status object that contains useful information about any
    updates that occurred.

 uninstall

    accepts the GUID for the addon to uninstall. The GUID is returned when
    from the install method. This method returns itself to aid in chaining
    methods.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
    
        my $extension_id = $firefox->install('/full/path/to/gnu_terry_pratchett-0.4-an+fx.xpi');
    
        # do something
    
        $firefox->uninstall($extension_id); # not recommended to uninstall this extension IRL.

 uri

    returns the current URI of current top level browsing context for
    Desktop. It is equivalent to the javascript document.location.href

 webauthn_authenticator

    returns the default WebAuthn authenticator created when the new method
    was called.

 webauthn_credentials

    This method accepts an optional authenticator, in which case it will
    return all the credentials attached to this authenticator. If no
    parameter is supplied, credentials from the default authenticator will
    be returned.

        use Firefox::Marionette();
        use v5.10;
    
        my $firefox = Firefox::Marionette->new();
        foreach my $credential ($firefox->webauthn_credentials()) {
           say "Credential host is " . $credential->host();
        }
    
        # OR
    
        my $authenticator = $firefox->add_webauthn_authenticator( transport => Firefox::Marionette::WebAuthn::Authenticator::INTERNAL(), protocol => Firefox::Marionette::WebAuthn::Authenticator::CTAP2() );
        foreach my $credential ($firefox->webauthn_credentials($authenticator)) {
           say "Credential host is " . $credential->host();
        }

 webauthn_set_user_verified

    This method accepts a boolean for the is_user_verified field and an
    optional authenticator (the default authenticator will be used
    otherwise). It sets the is_user_verified field to the supplied boolean
    value.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        $firefox->webauthn_set_user_verified(1);

 wheel

    accepts a element parameter, or a ( x => 0, y => 0 ) type hash manually
    describing exactly where to move the mouse from and returns an action
    for use in the perform method that corresponding with such a wheel
    action, either to the specified co-ordinates or to the middle of the
    supplied element parameter. Other parameters that may be passed are
    listed below;

      * origin - the origin of the C(<x => 0, y => 0)> co-ordinates. Should
      be either viewport, pointer or an element.

      * duration - Number of milliseconds over which to distribute the
      move. If not defined, the duration defaults to 0.

      * deltaX - the change in X co-ordinates during the wheel. If not
      defined, deltaX defaults to 0.

      * deltaY - the change in Y co-ordinates during the wheel. If not
      defined, deltaY defaults to 0.

 win32_organisation

    accepts a parameter of a Win32 product name and returns the matching
    organisation. Only of interest when sub-classing.

 win32_product_names

    returns a hash of known Windows product names (such as 'Mozilla
    Firefox') with priority orders. The lower the priority will determine
    the order that this module will check for the existence of this
    product. Only of interest when sub-classing.

 window_handle

    returns the current window's handle. On desktop this typically
    corresponds to the currently selected tab. returns an opaque
    server-assigned identifier to this window that uniquely identifies it
    within this Marionette instance. This can be used to switch to this
    window at a later point. This is the same as the window
    <https://developer.mozilla.org/en-US/docs/Web/API/Window> object in
    Javascript.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new();
        my $original_window = $firefox->window_handle();
        my $javascript_window = $firefox->script('return window'); # only works for Firefox 121 and later
        if ($javascript_window ne $original_window) {
            die "That was unexpected!!! What happened?";
        }

 window_handles

    returns a list of top-level browsing contexts. On desktop this
    typically corresponds to the set of open tabs for browser windows, or
    the window itself for non-browser chrome windows. Each window handle is
    assigned by the server and is guaranteed unique, however the return
    array does not have a specified ordering.

        use Firefox::Marionette();
        use 5.010;
    
        my $firefox = Firefox::Marionette->new();
        my $original_window = $firefox->window_handle();
        $firefox->new_window( type => 'tab' );
        $firefox->new_window( type => 'window' );
        say "There are " . $firefox->window_handles() . " tabs open in total";
        say "Across " . $firefox->chrome()->window_handles()->content() . " chrome windows";

 window_rect

    accepts an optional position and size as a parameter, sets the current
    browser window to that position and size and returns the previous
    position, size and state of the browser window. If no parameter is
    supplied, it returns the current position, size and state of the
    browser window.

 window_type

    returns the current window's type. This should be 'navigator:browser'.

 xvfb_pid

    returns the pid of the xvfb process if it exists.

 xvfb_display

    returns the value for the DISPLAY environment variable if one has been
    generated for the xvfb environment.

 xvfb_xauthority

    returns the value for the XAUTHORITY environment variable if one has
    been generated for the xvfb environment

NETWORK ARCHITECTURE

    This module allows for a complicated network architecture, including
    SSH and HTTP proxies.

      my $firefox = Firefox::Marionette->new(
                      host  => 'Firefox.runs.here'
                      via   => 'SSH.Jump.Box',
                      trust => '/path/to/ca-for-squid-proxy-server.crt',
                      proxy => 'https://Squid.Proxy.Server:3128'
                         )->go('https://Target.Web.Site');

    produces the following effect, with an ascii box representing a
    separate network node.

         ---------          ----------         -----------
         | Perl  |  SSH     | SSH    |  SSH    | Firefox |
         | runs  |--------->| Jump   |-------->| runs    |
         | here  |          | Box    |         | here    |
         ---------          ----------         -----------
                                                    |
         ----------          ----------             |
         | Target |  HTTPS   | Squid  |    TLS      |
         | Web    |<---------| Proxy  |<-------------
         | Site   |          | Server |
         ----------          ----------

    In addition, the proxy parameter can be used to specify multiple
    proxies using a reference to a list.

      my $firefox = Firefox::Marionette->new(
                      host  => 'Firefox.runs.here'
                      trust => '/path/to/ca-for-squid-proxy-server.crt',
                      proxy => [ 'https://Squid1.Proxy.Server:3128', 'https://Squid2.Proxy.Server:3128' ]
                         )->go('https://Target.Web.Site');

    When firefox gets a list of proxies, it will use the first one that
    works. In addition, it will perform a basic form of proxy failover,
    which may involve a failed network request before it fails over to the
    next proxy. In the diagram below, Squid1.Proxy.Server is the first
    proxy in the list and will be used exclusively, unless it is
    unavailable, in which case Squid2.Proxy.Server will be used.

                                              ----------
                                         TLS  | Squid1 |
                                       ------>| Proxy  |-----
                                       |      | Server |    |
         ---------      -----------    |      ----------    |       -----------
         | Perl  | SSH  | Firefox |    |                    | HTTPS | Target  |
         | runs  |----->| runs    |----|                    ------->| Web     |
         | here  |      | here    |    |                    |       | Site    |
         ---------      -----------    |      ----------    |       -----------
                                       | TLS  | Squid2 |    |
                                       ------>| Proxy  |-----
                                              | Server |
                                              ----------

    See the REMOTE AUTOMATION OF FIREFOX VIA SSH section for more options.

    See SETTING UP SOCKS SERVERS USING SSH for easy proxying via ssh
    <https://man.openbsd.org/ssh>

    See GEO LOCATION section for how to combine this with providing
    appropriate browser settings for the end point.

AUTOMATING THE FIREFOX PASSWORD MANAGER

    This module allows you to login to a website without ever directly
    handling usernames and password details. The Password Manager may be
    preloaded with appropriate passwords and locked, like so;

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( profile_name => 'locked' ); # using a pre-built profile called 'locked'
        if ($firefox->pwd_mgr_needs_login()) {
            my $new_password = IO::Prompt::prompt(-echo => q[*], 'Enter the password for the locked profile:');
            $firefox->pwd_mgr_login($password);
        } else {
            my $new_password = IO::Prompt::prompt(-echo => q[*], 'Enter the new password for the locked profile:');
            $firefox->pwd_mgr_lock($password);
        }
        ...
        $firefox->pwd_mgr_logout();

    Usernames and passwords (for both HTTP Authentication popups and HTML
    Form based logins) may be added, viewed and deleted.

        use WebService::HIBP();
    
        my $hibp = WebService::HIBP->new();
    
        $firefox->add_login(host => 'https://github.com', user => 'me@example.org', password => 'qwerty', user_field => 'login', password_field => 'password');
        $firefox->add_login(host => 'https://pause.perl.org', user => 'AUSER', password => 'qwerty', realm => 'PAUSE');
        ...
        foreach my $login ($firefox->logins()) {
            if ($hibp->password($login->password())) { # does NOT send the password to the HIBP webservice
                warn "HIBP reports that your password for the " . $login->user() " account at " . $login->host() . " has been found in a data breach";
                $firefox->delete_login($login); # how could this possibly help?
            }
        }

    And used to fill in login prompts without explicitly knowing the
    account details.

        $firefox->go('https://pause.perl.org/pause/authenquery')->accept_alert(); # this goes to the page and submits the http auth popup
    
        $firefox->go('https://github.com/login')->fill_login(); # fill the login and password fields without needing to see them

GEO LOCATION

    The firefox Geolocation API
    <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API> can
    be used by supplying the geo parameter to the new method and then
    calling the geo method (from a secure context
    <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>).

    The geo method can accept various specific latitude and longitude
    parameters as a list, such as;

        $firefox->geo(latitude => -37.82896, longitude => 144.9811);
    
        OR
    
        $firefox->geo(lat => -37.82896, long => 144.9811);
    
        OR
    
        $firefox->geo(lat => -37.82896, lng => 144.9811);
    
        OR
    
        $firefox->geo(lat => -37.82896, lon => 144.9811);

    or it can be passed in as a reference, such as;

        $firefox->geo({ latitude => -37.82896, longitude => 144.9811 });

    the combination of a variety of parameter names and the ability to pass
    parameters in as a reference means it can be deal with various geo
    location websites, such as;

        $firefox->geo($firefox->json('https://freeipapi.com/api/json/')); # get geo location from current IP address
    
        $firefox->geo($firefox->json('https://geocode.maps.co/search?street=101+Collins+St&city=Melbourne&state=VIC&postalcode=3000&country=AU&format=json')->[0]); # get geo location of street address
    
        $firefox->geo($firefox->json('http://api.positionstack.com/v1/forward?access_key=' . $access_key . '&query=101+Collins+St,Melbourne,VIC+3000')->{data}->[0]); # get geo location of street address using api key
    
        $firefox->geo($firefox->json('https://api.ipgeolocation.io/ipgeo?apiKey=' . $api_key)); # get geo location from current IP address
    
        $firefox->geo($firefox->json('http://api.ipstack.com/142.250.70.206?access_key=' . $api_key)); # get geo location from specific IP address (http access only for free)

    These sites were active at the time this documentation was written, but
    mainly function as an illustration of the flexibility of geo and json
    methods in providing the desired location to the Geolocation API
    <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API>.

    As mentioned in the geo method documentation, the ipgeolocation API
    <https://ipgeolocation.io/documentation/ip-geolocation-api.html> is the
    only API that currently providing geolocation data and matching
    timezone data in one API call. If this url is used, the tz method will
    be automatically called to set the timezone to the matching timezone
    for the geographic location.

CONSOLE LOGGING

    Sending debug to the console can be quite confusing in firefox, as some
    techniques won't work in chrome context. The following example can be
    quite useful.

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( visible => 1, devtools => 1, console => 1, devtools => 1 );
    
        $firefox->script( q[console.log("This goes to devtools b/c it's being generated in content mode")]);
    
        $firefox->chrome()->script( q[console.log("Can't be seen b/c it's in chrome mode")]);
    
        $firefox->chrome()->script( q[const { console } = ChromeUtils.import("resource://gre/modules/Console.jsm"); console.log("Find me in the browser console in chrome mode")]);
    
        # This won't work b/c of permissions
        #
        # $firefox->content()->script( q[const { console } = ChromeUtils.import("resource://gre/modules/Console.jsm"); console.log("Find me in the browser console in content mode")]);

REMOTE AUTOMATION OF FIREFOX VIA SSH

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( host => 'remote.example.org', debug => 1 );
        $firefox->go('https://metacpan.org/');
    
        # OR specify a different user to login as ...
        
        my $firefox = Firefox::Marionette->new( host => 'remote.example.org', user => 'R2D2', debug => 1 );
        $firefox->go('https://metacpan.org/');
    
        # OR specify a different port to connect to
        
        my $firefox = Firefox::Marionette->new( host => 'remote.example.org', port => 2222, debug => 1 );
        $firefox->go('https://metacpan.org/');
    
        # OR use a proxy host to jump via to the final host
    
        my $firefox = Firefox::Marionette->new(
                                                 host  => 'remote.example.org',
                                                 port  => 2222,
                                                 via   => 'user@secure-jump-box.example.org:42222',
                                                 debug => 1,
                                              );
        $firefox->go('https://metacpan.org/');

    This module has support for creating and automating an instance of
    Firefox on a remote node. It has been tested against a number of
    operating systems, including recent version of Windows 10 or Windows
    Server 2019
    <https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse>,
    OS X, and Linux and BSD distributions. It expects to be able to login
    to the remote node via public key authentication. It can be further
    secured via the command
    <https://man.openbsd.org/sshd#command=_command_> option in the OpenSSH
    <https://www.openssh.com/> authorized_keys
    <https://man.openbsd.org/sshd#AUTHORIZED_KEYS_FILE_FORMAT> file such
    as;

        no-agent-forwarding,no-pty,no-X11-forwarding,permitopen="127.0.0.1:*",command="/usr/local/bin/ssh-auth-cmd-marionette" ssh-rsa AAAA ... == user@server

    As an example, the ssh-auth-cmd-marionette
    <https://metacpan.org/pod/ssh-auth-cmd-marionette> command is provided
    as part of this distribution.

    The module will expect to access private keys via the local ssh-agent
    <https://man.openbsd.org/ssh-agent> when authenticating.

    When using ssh, Firefox::Marionette will attempt to pass the TMPDIR
    <https://en.wikipedia.org/wiki/TMPDIR> environment variable across the
    ssh connection to make cleanups easier. In order to allow this, the
    AcceptEnv <https://man.openbsd.org/sshd_config#AcceptEnv> setting in
    the remote sshd configuration should be set to allow TMPDIR, which will
    look like;

        AcceptEnv TMPDIR

    This module uses ControlMaster
    <https://man.openbsd.org/ssh_config#ControlMaster> functionality when
    using ssh, for a useful speedup of executing remote commands.
    Unfortunately, when using ssh to move from a cygwin
    <https://gcc.gnu.org/wiki/SSH_connection_caching>, Windows 10 or
    Windows Server 2019
    <https://docs.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse>
    node to a remote environment, we cannot use ControlMaster, because at
    this time, Windows does not support ControlMaster
    <https://github.com/Microsoft/vscode-remote-release/issues/96> and
    therefore this type of automation is still possible, but slower than
    other client platforms.

    The NETWORK ARCHITECTURE section has an example of a more complicated
    network design.

WEBGL

    There are a number of steps to getting WebGL
    <https://en.wikipedia.org/wiki/WebGL> to work correctly;

    1. The addons parameter to the new method must be set. This will
    disable -safe-mode
    <http://kb.mozillazine.org/Command_line_arguments#List_of_command_line_arguments_.28incomplete.29>

    2. The visible parameter to the new method must be set. This is due to
    an existing bug in Firefox
    <https://bugzilla.mozilla.org/show_bug.cgi?id=1375585>.

    3. It can be tricky getting WebGL <https://en.wikipedia.org/wiki/WebGL>
    to work with a Xvfb <https://en.wikipedia.org/wiki/Xvfb> instance.
    glxinfo <https://dri.freedesktop.org/wiki/glxinfo/> can be useful to
    help debug issues in this case. The mesa-dri-drivers rpm is also
    required for Redhat systems.

    With all those conditions being met, WebGL
    <https://en.wikipedia.org/wiki/WebGL> can be enabled like so;

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( addons => 1, visible => 1 );
        if ($firefox->script(q[let c = document.createElement('canvas'); return c.getContext('webgl2') ? true : c.getContext('experimental-webgl') ? true : false;])) {
            $firefox->go("https://get.webgl.org/");
        } else {
            die "WebGL is not supported";
        }

FINDING ELEMENTS IN A SHADOW DOM

    One aspect of Web Components
    <https://developer.mozilla.org/en-US/docs/Web/API/Web_components> is
    the shadow DOM
    <https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM>.
    When you need to explore the structure of a custom element
    <https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements>,
    you need to access it via the shadow DOM. The following is an example
    of navigating the shadow DOM via a html file included in the test suite
    of this package.

        use Firefox::Marionette();
        use Cwd();
    
        my $firefox = Firefox::Marionette->new();
        my $firefox_marionette_directory = Cwd::cwd();
        $firefox->go("file://$firefox_marionette_directory/t/data/elements.html");
    
        my $shadow_root = $firefox->find_tag('custom-square')->shadow_root();
    
        my $outer_div = $firefox->find_id('outer-div', $shadow_root);

    So, this module is designed to allow you to navigate the shadow DOM
    using normal find methods, but you must get the shadow element's shadow
    root and use that as the root for the search into the shadow DOM. An
    important caveat is that xpath
    <https://bugzilla.mozilla.org/show_bug.cgi?id=1822311> and tag name
    <https://bugzilla.mozilla.org/show_bug.cgi?id=1822321> strategies do
    not officially work yet (and also the class name and name strategies).
    This module works around the tag name, class name and name deficiencies
    by using the matching css selector search if the original search throws
    a recognisable exception. Therefore these cases may be considered to be
    extremely experimental and subject to change when Firefox gets the
    "correct" functionality.

IMITATING OTHER BROWSERS

    There are a collection of methods and techniques that may be useful if
    you would like to change your geographic location or how the browser
    appears to your web site.

      * the stealth parameter of the new method. This method will stop the
      browser reporting itself as a robot and will also (when combined with
      the agent method, change other javascript characteristics to match
      the User Agent
      <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>
      string.

      * the agent method, which if supplied a recognisable User Agent
      <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent>,
      will attempt to change other attributes to match the desired browser.
      This is extremely experimental and feedback is welcome.

      * the geo method, which allows the modification of the Geolocation
      <https://developer.mozilla.org/en-US/docs/Web/API/Geolocation>
      reported by the browser, but not the location produced by mapping the
      external IP address used by the browser (see the NETWORK ARCHITECTURE
      section for a discussion of different types of proxies that can be
      used to change your external IP address).

      * the languages method, which can change the requested languages
      <https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language>
      for your browser session.

      * the tz method, which can change the timezone
      <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List>
      for your browser session.

    This list of methods may grow.

WEBSITES THAT BLOCK AUTOMATION

    Marionette by design
    <https://developer.mozilla.org/en-US/docs/Web/API/Navigator/webdriver>
    allows web sites to detect that the browser is being automated. Firefox
    no longer (since version 88)
    <https://bugzilla.mozilla.org/show_bug.cgi?id=1632821> allows you to
    disable this functionality while you are automating the browser, but
    this can be overridden with the stealth parameter for the new method.
    This is extremely experimental and feedback is welcome.

    If the web site you are trying to automate mysteriously fails when you
    are automating a workflow, but it works when you perform the workflow
    manually, you may be dealing with a web site that is hostile to
    automation. I would be very interested if you can supply a test case.

    At the very least, under these circumstances, it would be a good idea
    to be aware that there's an ongoing arms race
    <https://en.wikipedia.org/wiki/Web_scraping#Methods_to_prevent_web_scraping>,
    and potential legal issues
    <https://en.wikipedia.org/wiki/Web_scraping#Legal_issues> in this area.

X11 FORWARDING WITH FIREFOX

    X11 Forwarding <https://man.openbsd.org/ssh#X> allows you to launch a
    remote firefox via ssh and have it visually appear in your local X11
    desktop. This can be accomplished with the following code;

        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new(
                                                 host    => 'remote-x11.example.org',
                                                 visible => 'local',
                                                 debug   => 1,
                                              );
        $firefox->go('https://metacpan.org');

    Feedback is welcome on any odd X11 workarounds that might be required
    for different platforms.

UBUNTU AND FIREFOX DELIVERED VIA SNAP

    Ubuntu 22.04 LTS
    <https://ubuntu.com/blog/ubuntu-22-04-lts-whats-new-linux-desktop> is
    packaging firefox as a snap <https://ubuntu.com/blog/whats-in-a-snap>.
    This breaks the way that this module expects to be able to run,
    specifically, being able to setup a firefox profile in a systems
    temporary directory (/tmp or $TMPDIR in most Unix based systems) and
    allow the operating system to cleanup old directories caused by
    exceptions / network failures / etc.

    Because of this design decision, attempting to run a snap version of
    firefox will simply result in firefox hanging, unable to read it's
    custom profile directory and hence unable to read the marionette port
    configuration entry.

    Which would be workable except that; there does not appear to be _any_
    way to detect that a snap firefox will run (/usr/bin/firefox is a bash
    shell which eventually runs the snap firefox), so there is no way to
    know (heuristics aside) if a normal firefox or a snap firefox will be
    launched by execing 'firefox'.

    It seems the only way to fix this issue (as documented in more than a
    few websites) is;

    1. sudo snap remove firefox

    2. sudo add-apt-repository -y ppa:mozillateam/ppa

    3. sudo apt update

    4. sudo apt install -t 'o=LP-PPA-mozillateam' firefox

    5. echo -e "Package: firefox*\nPin: release
    o=LP-PPA-mozillateam\nPin-Priority: 501" >/tmp/mozillateamppa

    6. sudo mv /tmp/mozillateamppa /etc/apt/preferences.d/mozillateamppa

    If anyone is aware of a reliable method to detect if a snap firefox is
    going to launch vs a normal firefox, I would love to know about it.

    This technique is used in the setup-for-firefox-marionette-build.sh
    script in this distribution.

DIAGNOSTICS

    Failed to correctly setup the Firefox process

      The module was unable to retrieve a session id and capabilities from
      Firefox when it requests a new_session as part of the initial setup
      of the connection to Firefox.

    Failed to correctly determined the Firefox process id through the
    initial connection capabilities

      The module was found that firefox is reporting through it's
      Capabilities object a different process id than this module was
      using. This is probably a bug in this module's logic. Please report
      as described in the BUGS AND LIMITATIONS section below.

    '%s --version' did not produce output that could be parsed. Assuming
    modern Marionette is available:%s

      The Firefox binary did not produce a version number that could be
      recognised as a Firefox version number.

    Failed to create process from '%s':%s

      The module was to start Firefox process in a Win32 environment.
      Something is seriously wrong with your environment.

    Failed to redirect %s to %s:%s

      The module was unable to redirect a file handle's output. Something
      is seriously wrong with your environment.

    Failed to exec %s:%s

      The module was unable to run the Firefox binary. Check the path is
      correct and the current user has execute permissions.

    Failed to fork:%s

      The module was unable to fork itself, prior to executing a command.
      Check the current ulimit for max number of user processes.

    Failed to open directory '%s':%s

      The module was unable to open a directory. Something is seriously
      wrong with your environment.

    Failed to close directory '%s':%s

      The module was unable to close a directory. Something is seriously
      wrong with your environment.

    Failed to open '%s' for writing:%s

      The module was unable to create a file in your temporary directory.
      Maybe your disk is full?

    Failed to open temporary file for writing:%s

      The module was unable to create a file in your temporary directory.
      Maybe your disk is full?

    Failed to close '%s':%s

      The module was unable to close a file in your temporary directory.
      Maybe your disk is full?

    Failed to close temporary file:%s

      The module was unable to close a file in your temporary directory.
      Maybe your disk is full?

    Failed to create temporary directory:%s

      The module was unable to create a directory in your temporary
      directory. Maybe your disk is full?

    Failed to clear the close-on-exec flag on a temporary file:%s

      The module was unable to call fcntl using F_SETFD for a file in your
      temporary directory. Something is seriously wrong with your
      environment.

    Failed to seek to start of temporary file:%s

      The module was unable to seek to the start of a file in your
      temporary directory. Something is seriously wrong with your
      environment.

    Failed to create a socket:%s

      The module was unable to even create a socket. Something is seriously
      wrong with your environment.

    Failed to connect to %s on port %d:%s

      The module was unable to connect to the Marionette port. This is
      probably a bug in this module's logic. Please report as described in
      the BUGS AND LIMITATIONS section below.

    Firefox killed by a %s signal (%d)

      Firefox crashed after being hit with a signal.

    Firefox exited with a %d

      Firefox has exited with an error code

    Failed to bind socket:%s

      The module was unable to bind a socket to any port. Something is
      seriously wrong with your environment.

    Failed to close random socket:%s

      The module was unable to close a socket without any reads or writes
      being performed on it. Something is seriously wrong with your
      environment.

    moz:headless has not been determined correctly

      The module was unable to correctly determine whether Firefox is
      running in "headless" or not. This is probably a bug in this module's
      logic. Please report as described in the BUGS AND LIMITATIONS section
      below.

    %s method requires a Firefox::Marionette::Element parameter

      This function was called incorrectly by your code. Please supply a
      Firefox::Marionette::Element parameter when calling this function.

    Failed to write to temporary file:%s

      The module was unable to write to a file in your temporary directory.
      Maybe your disk is full?

    Failed to close socket to firefox:%s

      The module was unable to even close a socket. Something is seriously
      wrong with your environment.

    Failed to send request to firefox:%s

      The module was unable to perform a syswrite on the socket connected
      to firefox. Maybe firefox crashed?

    Failed to read size of response from socket to firefox:%s

      The module was unable to read from the socket connected to firefox.
      Maybe firefox crashed?

    Failed to read response from socket to firefox:%s

      The module was unable to read from the socket connected to firefox.
      Maybe firefox crashed?

CONFIGURATION AND ENVIRONMENT

    Firefox::Marionette requires no configuration files or environment
    variables. It will however use the DISPLAY and XAUTHORITY environment
    variables to try to connect to an X Server. It will also use the
    HTTP_PROXY, HTTPS_PROXY, FTP_PROXY and ALL_PROXY environment variables
    as defaults if the session capabilities do not specify proxy
    information.

DEPENDENCIES

    Firefox::Marionette requires the following non-core Perl modules

      * JSON

      * URI

      * XML::Parser

      * Time::Local

INCOMPATIBILITIES

    None reported. Always interested in any products with marionette
    support that this module could be patched to work with.

BUGS AND LIMITATIONS

 DOWNLOADING USING GO METHOD

    When using the go method to go directly to a URL containing a
    downloadable file, Firefox can hang. You can work around this by
    setting the page_load_strategy to none like below;

        #! /usr/bin/perl
    
        use strict;
        use warnings;
        use Firefox::Marionette();
    
        my $firefox = Firefox::Marionette->new( capabilities => Firefox::Marionette::Capabilities->new( page_load_strategy => 'none' ) );
        $firefox->go("https://github.com/david-dick/firefox-marionette/archive/refs/heads/master.zip");
        while(!$firefox->downloads()) { sleep 1 }
        while($firefox->downloading()) { sleep 1 }
        foreach my $path ($firefox->downloads()) {
            warn "$path has been downloaded";
        }
        $firefox->quit();

    Also, check out the download method for an alternative.

 MISSING METHODS

    Currently the following Marionette methods have not been implemented;

      * WebDriver:SetScreenOrientation

    To report a bug, or view the current list of bugs, please visit
    https://github.com/david-dick/firefox-marionette/issues

SEE ALSO

      * MozRepl

      * Selenium::Firefox

      * Firefox::Application

      * Mozilla::Mechanize

      * Gtk2::MozEmbed

AUTHOR

    David Dick <ddick@cpan.org>

ACKNOWLEDGEMENTS

    Thanks to the entire Mozilla organisation for a great browser and to
    the team behind Marionette for providing an interface for automation.

    Thanks to Jan Odvarko <http://www.softwareishard.com/blog/about/> for
    creating the HAR Export Trigger
    <https://github.com/firefox-devtools/har-export-trigger> extension for
    Firefox.

    Thanks to Mike Kaply <https://mike.kaply.com/about/> for his post
    <https://mike.kaply.com/2015/02/10/installing-certificates-into-firefox/>
    describing importing certificates into Firefox.

    Thanks also to the authors of the documentation in the following
    sources;

      * Marionette Protocol
      <https://firefox-source-docs.mozilla.org/testing/marionette/marionette/index.html>

      * Marionette driver.js
      <https://hg.mozilla.org/mozilla-central/file/tip/remote/marionette/driver.sys.mjs>

      * about:config <http://kb.mozillazine.org/About:config_entries>

      * nsIPrefService interface
      <https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIPrefService>

LICENSE AND COPYRIGHT

    Copyright (c) 2024, David Dick <ddick@cpan.org>. All rights reserved.

    This module is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself. See "perlartistic" in
    perlartistic.

    The Firefox::Marionette::Extension::HarExportTrigger module includes
    the HAR Export Trigger
    <https://github.com/firefox-devtools/har-export-trigger> extension
    which is licensed under the Mozilla Public License 2.0
    <https://www.mozilla.org/en-US/MPL/2.0/>.

DISCLAIMER OF WARRANTY

    BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
    FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT
    WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER
    PARTIES PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND,
    EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
    YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
    NECESSARY SERVICING, REPAIR, OR CORRECTION.

    IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
    REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENCE, BE LIABLE
    TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL, OR
    CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
    SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
    RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
    FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
    SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    DAMAGES.