NAME
Test::Mojo::Role::Selenium - Test::Mojo in a real browser
SYNOPSIS
External app
use Mojo::Base -strict;
use Test::More;
$ENV{MOJO_SELENIUM_BASE_URL} ||= 'http://mojolicious.org';
$ENV{MOJO_SELENIUM_DRIVER} ||= 'Selenium::Chrome';
my $t = Test::Mojo->with_roles("+Selenium")->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::More;
my $t = Test::Mojo->with_roles("+Selenium")->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 create an issue if you think more tests or methods should be provided directly by Test::Mojo::Role::Selenium.
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.
-
# macOS $ brew install chromedriver # Ubuntu $ sudo apt-get install chromium-chromedriver # Run tests $ MOJO_SELENIUM_DRIVER=Selenium::Chrome prove -l
CAVEAT
"tx" in Test::Mojo is only populated, if the request went through an "Internal app". This means that methods such as "header_is" in Test::Mojo will not work or probably fail completely when testing an "External app".
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".
This variable will get the value of "TEST_SELENIUM" if it looks like a URL.
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 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.
TEST_SELENIUM
This variable must be set to a true value for "setup_or_skip_all" to not skip this test. Will also set "MOJO_SELENIUM_BASE_URL" if it looks like an URL.
ATTRIBUTES
driver
$driver = $self->driver;
An instance of Selenium::Remote::Driver.
driver_args
$hash = $self->driver_args;
$self = $self->driver_args({driver_class => "Selenium::Chrome"});
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.
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.
wait_for
$self = $self->wait_for(0.2);
$self = $self->wait_for('[name="agree"]', "test description");
$self = $self->wait_for('[name="agree"]:enabled', {interval => 1.5, timeout => 10});
$self = $self->wait_for('[name="agree"]:selected');
$self = $self->wait_for('[href="/"]:visible');
$self = $self->wait_for('[href="/hidden"]:hidden');
$self = $self->wait_for('[name=checkbox]:checked');
Simpler version of "wait_until" 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.