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 . 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