NAME
    Test::Mojo::Role::Selenium - Test::Mojo in a real browser

SYNOPSIS
  External app
      use Mojo::Base -strict;
      use Test::Mojo::WithRoles "Selenium";
      use Test::More;

      $ENV{MOJO_SELENIUM_DRIVER} ||= 'Selenium::Chrome';

      my $t = Test::Mojo::WithRoles->new->setup_or_skip_all;

      $t->navigate_ok('/perldoc')
        ->live_text_is('a[href="#GUIDES"]' => 'GUIDES');

      $t->driver->execute_script(qq[document.querySelector("form").removeAttribute("target")]);
      $t->element_is_displayed("input[name=q]")
        ->send_keys_ok("input[name=q]", ["render", \"return"]);

      $t->wait_until(sub { $_->get_current_url =~ qr{q=render} })
        ->live_value_is("input[name=search]", "render");

      done_testing;

  Internal app
      use Mojo::Base -strict;
      use Test::Mojo::WithRoles "Selenium";
      use Test::More;

      my $t = Test::Mojo::WithRoles->new("MyApp")->setup_or_skip_all;

      # All the standard Test::Mojo methods are available
      ok $t->isa("Test::Mojo");
      ok $t->does("Test::Mojo::Role::Selenium");

      $t->navigate_ok("/")
        ->status_is(200)
        ->header_is("Server" => "Mojolicious (Perl)")
        ->text_is("div#message" => "Hello!")
        ->live_text_is("div#message" => "Hello!")
        ->live_element_exists("nav")
        ->element_is_displayed("nav")
        ->active_element_is("input[name=q]")
        ->send_keys_ok("input[name=q]", "Mojo")
        ->capture_screenshot;

      $t->submit_ok("form")
        ->status_is(200)
        ->current_url_like(qr{q=Mojo})
        ->live_element_exists("input[name=q][value=Mojo]");

      $t->click_ok("nav a.logo")->status_is(200);

      done_testing;

DESCRIPTION
    Test::Mojo::Role::Selenium is a role that extends Test::Mojo with
    additional methods which checks behaviour in a browser. All the heavy
    lifting is done by Selenium::Remote::Driver.

    Some of the Selenium::Remote::Driver methods are available directly in
    this role, while the rest are available through the object held by the
    "driver" attribute. Please let me know if you think more tests or
    methods should be provided directly by Test::Mojo::Role::Selenium.

    This role is EXPERIMENTAL and subject to change.

OPTIONAL DEPENDENCIES
    Selenium::Remote::Driver require some external dependencies to work.
    Here are a quick intro to install some of the dependencies to make this
    module work.

    * Selenium::Chrome

        # macOS
        $ brew install chromedriver

        # Ubuntu
        $ sudo apt-get install chromium-chromedriver

        # Run tests
        $ MOJO_SELENIUM_DRIVER=Selenium::Chrome prove -l

    * Selenium::PhantomJS

        # macOS
        $ brew install phantomjs

        # Ubuntu
        $ sudo apt-get install phantomjs

        # Run tests
        $ MOJO_SELENIUM_DRIVER=Selenium::PhantomJS prove -l

CAVEAT
    "tx" in Test::Mojo is only populated by this role, if the initial
    request is done by passing a relative path to "navigate_ok". This means
    that methods such as "header_is" in Test::Mojo will not work as expected
    (probably fail completely) if "navigate_ok" is issued with an absolute
    path like <http://mojolicious.org>.

ENVIRONMENT VARIABLES
  MOJO_SELENIUM_BASE_URL
    Setting this variable will make this test send the requests to a remote
    server, instead of starting a local server. Note that this will disable
    Test::Mojo methods such as "status_is", since "tx" in Test::Mojo will
    not be set. See also "CAVEAT".

  MOJO_SELENIUM_TEST_HOST
    In some cases you may want to override the host of your test server,
    when running Selenium on a separate server or in a pod-style networking
    environment this still retains the automatically generated port. This
    will not disable the Test::Mojo methods.

  MOJO_SELENIUM_DRIVER
    This variable can be set to a classname, such as Selenium::Chrome or
    Selenium::PhantomJS, which will force the selenium driver. It can also
    be used to pass on arguments to the driver's constructor. Example:

      MOJO_SELENIUM_DRIVER='Selenium::Remote::Driver&browser_name=firefox&port=4444'

    The arguments will be read using "parse" in Mojo::Parameters, which
    means they follow standard URL format rules.

ATTRIBUTES
  driver
      $driver = $self->driver;

    An instance of Selenium::Remote::Driver.

  driver_args
      $hash = $self->driver_args;
      $self = $self->driver_args({driver_class => "Selenium::PhantomJS"});

    Used to set args passed on to the "driver" on construction time. In
    addition, a special key "driver_class" can be set to use another driver
    class, than the default Selenium::PhantomJS.

    Note that the environment variavble "MOJO_SELENIUM_DRIVER" can also be
    used to override the driver class.

  screenshot_directory
      $path = $self->screenshot_directory;
      $self = $self->screenshot_directory(File::Spec->tmpdir);

    Where screenshots are saved.

  screenshots
      $array = $self->screenshots;

    Holds an array ref with paths to all the screenshots taken with
    "capture_screenshot".

METHODS
  active_element_is
      $self = $self->active_element_is("input[name=username]");

    Checks that the current active element on the page match the selector.

  capture_screenshot
      $self = $self->capture_screenshot;
      $self = $self->capture_screenshot("%t-page-x");
      $self = $self->capture_screenshot("%0-%t-%n"); # default

    Capture screenshot to "screenshot_directory" with filename specified by
    the input format. The format supports these special strings:

      Format | Description
      -------|----------------------
      %t     | Start time for script
      %0     | Name of script
      %n     | Auto increment

  click_ok
      $self = $self->click_ok("a");
      $self = $self->click_ok;

    Click on an element matching the selector or click on the currently
    active element.

  current_url_is
      $self = $self->current_url_is("http://mojolicious.org/");
      $self = $self->current_url_is("/whatever");

    Test the current browser URL against an absolute URL. A relative URL
    will be converted to an absolute URL, using "MOJO_SELENIUM_BASE_URL".

  current_url_like
      $self = $self->current_url_like(qr{/whatever});

    Test the current browser URL against a regex.

  element_is_displayed
      $self = $self->element_is_displayed("nav");

    Test if an element is displayed on the web page.

    See "is_displayed" in Selenium::Remote::WebElement.

  element_is_hidden
      $self = $self->element_is_hidden("nav");

    Test if an element is hidden on the web page.

    See "is_hidden" in Selenium::Remote::WebElement.

  go_back
      $self = $self->go_back;

    Equivalent to hitting the back button on the browser.

    See "go_back" in Selenium::Remote::Driver.

  go_forward
      $self = $self->go_forward;

    Equivalent to hitting the forward button on the browser.

    See "go_forward" in Selenium::Remote::Driver.

  if_tx
      $self = $self->if_tx(sub { ... }, @args);
      $self = $self->if_tx($method, @args);

    Call either a code ref or a method on $self if "tx" in Test::Mojo is
    defined. "tx()" is undefined if "navigate_ok" is called on an external
    resource.

    Examples:

      $self->if_tx(status_is => 200);

  live_element_count_is
      $self = $self->live_element_count_is("a", 12);

    Checks that the selector finds the correct number of elements in the
    browser.

    See "element_count_is" in Test::Mojo.

  live_element_exists
      $self = $self->live_element_exists("div.content");

    Checks that the selector finds an element in the browser.

    See "element_exists" in Test::Mojo.

  live_element_exists_not
      $self = $self->live_element_exists_not("div.content");

    Checks that the selector does not find an element in the browser.

      $self = $self->live_element_exists("div.foo");

    See "element_exists_not" in Test::Mojo.

  live_text_is
      $self = $self->live_text_is("div.name", "Mojo");

    Checks text content of the CSS selectors first matching HTML element in
    the browser matches the given string.

  live_text_like
      $self = $self->live_text_is("div.name", qr{Mojo});

    Checks text content of the CSS selectors first matching HTML element in
    the browser matches the given regex.

  live_value_is
      $self = $self->live_value_is("div.name", "Mojo");

    Checks value of the CSS selectors first matching HTML element in the
    browser matches the given string.

  live_value_like
      $self = $self->live_value_like("div.name", qr{Mojo});

    Checks value of the CSS selectors first matching HTML element in the
    browser matches the given regex.

  navigate_ok
      $self = $self->navigate_ok("/");
      $self = $self->navigate_ok("http://mojolicious.org/");

    Open a browser window and go to the given location.

  new
      $self = $class->new;
      $self = $class->new($app);

    Same as "new" in Test::Mojo, but will not build $app if
    "MOJO_SELENIUM_BASE_URL" is set.

  refresh
      $self = $self->refresh;

    Equivalent to hitting the refresh button on the browser.

    See "refresh" in Selenium::Remote::Driver.

  send_keys_ok
      $self->send_keys_ok("input[name=name]", ["web", \"space", "framework"]);
      $self->send_keys_ok(undef, [\"return"]);

    Used to send keys to a given element. Scalar refs will be sent as
    Selenium::Remote::WDKeys strings. Passing in "undef" as the first
    argument will cause the keys to be sent to the currently active element.

    List of some of the special keys:

    * alt, control, shift

    * right_arrow, down_arrow, left_arrow, up_arrow

    * backspace, clear, delete, enter, return, escape, space, tab

    * f1, f2, ..., f12

    * command_meta, pause

  set_window_size
      $self = $self->set_window_size([$width, $height]);
      $self = $self->set_window_size([375, 667]);

    Set the browser window size.

  setup_or_skip_all
      $self = $self->setup_or_skip_all;

    Will "skip_all" in skip all#Test::More tests unless "TEST_SELENIUM" is
    set and and "driver" can be built.

    Will also set "MOJO_SELENIUM_BASE_URL" if "TEST_SELENIUM" looks like a
    URL.

  submit_ok
      $self = $self->submit_ok("form");

    Submit a form, either by selector or the current active form.

    See "submit" in Selenium::Remote::WebElement.

  toggle_checked_ok
      $self = $self->toggle_checked_ok("input[name=human]");

    Used to toggle the "checked" attribute either with a click event or
    fallback to javascript.

    TODO: The implementation might change in the future.

  wait_for
      $self = $self->wait_for(0.2);
      $self = $self->wait_for('[name="agree"]', "test description");
      $self = $self->wait_for('[name="agree"]:enabled');
      $self = $self->wait_for('[name="agree"]:selected');
      $self = $self->wait_for('[href="/"]:visible');
      $self = $self->wait_for('[href="/hidden"]:hidden');

    Simpler version of "wait_for" for the most common use cases:

    Number
      Allows the browser and server to run for a given interval in seconds.
      This is useful if you want the browser to receive data from the server
      or simply let "setTimeout()" in JavaScript run.

    String
      Wait for an element matching the CSS selector with some additional
      modifiers: :enabled, :hidden, :selected and :visible.

      Check out Selenium::Remote::WebElement for details about the
      modifiers.

  wait_until
      $self = $self->wait_until(sub { my $self = shift; return 1 }, \%args);
      $self = $self->wait_until(sub { $_->get_current_url =~ /foo/ }, \%args);

      # Use it as a sleep(0.8)
      $self = $self->wait_until(sub { 0 }, {timeout => 0.8, skip => 1});

    Start Mojo::IOLoop and run it until the callback returns true. Note that
    $_[0] is $self and $_ is "driver". %args is optional, but can contain
    these values:

      {
        interval => $seconds, # Default: 0.5
        timeout  => $seconds, # Default: 60
        skip     => $bool,    # Default: 0
      }

  window_size_is
      $self = $self->window_size_is([$width, $height]);
      $self = $self->window_size_is([375, 667]);

    Test if window has the expected width and height.

AUTHOR
    Jan Henning Thorsen

COPYRIGHT AND LICENSE
    Copyright (C) 2014, Jan Henning Thorsen

    This program is free software, you can redistribute it and/or modify it
    under the terms of the Artistic License version 2.0.

SEE ALSO
    Test::Mojo.

    Selenium::Remote::Driver

