The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Test::Lithium - Selenium Tests in Perl!

DESCRIPTION

Test::Lithium provides an easy-to-use framework for writing automated, browser-based tests in Perl, and then running them against a Selenium grid/hub, a standalone browser or standalone headless browser, read; phantomjs's ghostdriver.

Coupled with Synacor::Test::Catalyst, you have a powerful test framework, to ensure quality compliance of your frontend.

Or, combined with a check framework and phantomjs selenium hub, a dynamic, and wieldy synthetic monitoring enviroment.

CONNECTING

The first thing you'll want to do is connect up to a Selenium grid:

    #!perl
    use Test::More;
    use Test::Lithium;

    configure_webdriver(
        host    => 'localhost',
        port    => 6789,
        browser => 'firefox',
        site    => 'http://www.google.com',
    );

    start_webdriver;

The start_webdriver call will try to connect to the grid (in the example, localhost:6789), for up to 30 seconds before calling BAIL_OUT and terminating the test.

You can skip the call to configure_webdriver, in which case sane defaults will be used.

If you have a ~/.webdriverrc file, it is read in (as a YAML file) and used as the configuration, as if you had called configure_webdriver. This is the preferred method of configuring Selenium.

Testing

Once you're hooked up to the grid, it's time to start writing some tests!

    #!perl
    use Test::More;
    use Test::Lithium;

    start_webdriver; # using ~/.webdriverrc
    visit '/';
    maximize;

    click '#go';
    wait_until_present 'div ul.results', "Waiting for results";
    is_visible '#go-again', "The go-again button should be visible";

    stop_webdriver;
    done_testing;

This test visits the root of the site, then maximizes the window. This helps immensely with troubleshooting and debugging of failed tests.

Once its all loaded, the HTML element with an ID of go (using CSS selector syntax, #go) will be clicked.

The wait_until_present line spins for up to 30 seconds, waiting for the target elements to be present in the DOM (although not necessarily visible).

Finally, is_visible checks to see that an element with an ID of go-again is present in the DOM and visible. If either of those two assertions fail, the test will fail.

When you are all done with your Selenium session, you should disconnect, via stop_webdriver, to ensure that resources on the grid get freed properly (Selenium can be a bit of a pain if you don't).

SKIPPING TESTS

When it comes time to run unit tests outside of your local environment (say on a shared CI build box) you probably don't want to run the full gamut of Selenium tests. You may not even have access to a grid from CI!

Using Test::More's plan skip_all feature, you can safely skip each of your Selenium tests based on the value returned by TEST_WEBDRIVER, which ensures that a suitable environment is available:

    #!perl
    use Test::More;
    use Test::Lithium;

    plan skip_all => 'skipping Selenium browser-based tests'
        unless TEST_WEBDRIVER;

FUNCTIONS

configure_webdriver(%opts)

Configure the connection to the Selenium grid.

The following options are currently understood:

    host

    The IP address or hostname of the box running the Selenium grid. This is not necessarily the same as the machine running the browser.

    port

    TCP port of the Selenium grid server.

    browser

    Name of the browser type to request for the session.

    site

    The base URL to use for all unqualified page requests (i.e. where is /?)

    Note that if you use Synacor::Test::Catalyst, you don't have to set this one explicitly; start_catalyst() will wire you up to the correct endpoint out of the box.

All options must be specified.

start_webdriver()

Connect to the Selenium grid and initiate a new testing session.

stop_webdriver()

Shut down and disconnect from the Selenium grid, or webdriver server.

webdriver_driver()

Returns a reference to the web driver used for testing, in case you need to inspect it or otherwise use it directly.

TEST_WEBDRIVER()

Test shim to skip tests in a testing plan. see above for example.

new_window($url, $name, $timeout, $msg)

Create a new window, opened to $url. The window name will be $name.

close_window()

Close the current window. Useful when combined with new_window.

update_windows()

Force update the local window list, this facilitates window titles and order are maintained locally to ensure consistency. This function is not needed if strict windows updates are enabled.

relaxed_window_updates()

Disabled the automatic window updating to improve performance.

strict_window_updates()

Increase the granularity of window ordering and names to facility finding and or closing windows.

visit($page, $timeout, $msg)

This function does not run any test assertions.

refresh($msg)

Refresh the current window.

address_bar()

Retrieve the value of the address bar, the current location.

    Returns the current window's url.

This function does not run any test assertions.

focus_window($type => $value)

Select and focus a named or numbered window:

    focus_window name => 'popup33';
    focus_window number => 1;       # first popup

focus_frame($selector, $timeout, $msg)

Change the CSS element search scope by selecting an iframe by css selector, default (original page/context). When switching frames, the entire DOM context is switched to the newly selected iframe. You will have to reset your context to go to select any elements outside of the current iframe.

maximize($window)

Maximize the named window, or the currently selected / focused window (if $window is undefined).

wait_for_page($timeout)

After a page-load operation, wait for the page to finish loading, up to $timeout seconds. Default $timeout is 30 seconds.

Be careful to only call this method after a page-load operation, like clicking on a link that will load a new page.

wait_until_present($selector, $timeout, $msg)

Wait, for up to $timeout seconds, until the target element exists in the DOM. Default $timeout is 30 seconds.

until_present($selector, $timeout, $msg)

Alias for wait_until_present

wait_until_not_present($selector, $timeout, $msg)

Wait, for up to $timeout seconds, until the target element no longer exists in the DOM. Default $timeout is 30 seconds.

until_not_present($selector, $timeout, $msg)

Alias for wait_until_not_present

wait_until_visible($selector, $timeout, $msg)

Wait, for up to $timeout seconds, until the target element exists in the DOM and is visible. Default $timeout is 30 seconds.

until_visible($selector, $timeout, $msg)

Alias for wait_until_visible

wait_until_not_visible($selector, $timeout, $msg)

Wait, for up to $timeout seconds, until the target element exists in the DOM but is not visible. Default $timeout is 30 seconds.

until_not_visible($selector, $timeout, $msg)

Alias for wait_until_not_visible

present($selector)

Returns a boolean indicating whether the given CSS selector is present in the DOM.

is_present($selector, $msg)

Assert that the targeted element does not exist in the DOM.

isnt_present($selector, $msg)

Assert that the targeted element exists in the DOM.

visible($selector)

Returns a boolean indicating whether the given CSS selector is present in the DOM and is visible.

is_visible($selector, $msg)

Assert that the targeted element exists in the DOM and is visible.

isnt_visible($selector, $msg)

Assert that the targeted element exists in the DOM but is not visible.

text($selector)

Retrieve the inner text of the targeted element.

Note: wait_until_present will be called on $selector, implicitly.

get_text($selector)

Alias function for text

value($selector)

Retrieve the form field value of the targeted element.

attribute($selector, $attribute)

Retrieve the attribute from a targeted element.

Note: wait_until_present will be called on $selector, implicitly.

html($selector)

Retrieve the inner HTML of the targeted element, via Javascript.

Note: wait_until_present will be called on $selector, implicitly.

location($selector, $x, $y, %timeout)

Retrieve the x and y coordinantes of the targeted element.

Note: wait_until_present will be called on $selector, implicitly.

runjs($code)

Run arbitrary Javascript in the currently selected window. All code will have window. prepended to it (effectively). This still alows calls like jQuery selectors and simple function calls, but doesn't allow some syntax.

This function does not run any test assertions.

freeze

Pause the client side javascript application, for ease of finding DOM elements and other necessities.

The function that is run is: window.synacor.testing.freeze()

This function must return 1 upon success, and 0 upon failure (if it is unable to freeze).

thaw

Un-freeze/continue running the client side javascript with: window.synacor.testing.thaw()

This function must return 1 upon success, and 0 upon failure (if it is unable to thaw).

type($selector, $value, $msg)

Enter $value into the targeted input field.

click($selector, $msg)

Click on the targeted $selector.

click_at($selector, $x, $y, $msg)

Initiate a click inside of the $selector element, using ($x, $y) as coordinates relative to the upper-left hand corner of the element.

mouseover($selector, $msg)

Fire the mouseover event on $selector

check($selector, $msg)

Check the targeted checkbox.

uncheck($selector, $msg)

Uncheck the targeted checkbox.

Select the dropdown option with the given label (not the value).

Opts can be any of:

method

Method to use for identifying values ('value', or 'label'). Defaults to 'label'.

timeout

Timeout for finding/selecting the dropdown.

msg

Message to use for test output.

Retrieve the list of labels from the given SELECT element, as a list.

Options can be any of:

data

Type of dropdown values to return (either 'label', or 'value'). Defaults to 'label'.

timeout

Timeout for finding the dropdown and getting its values.

msg

Message to usefor test output.

xpath_count($selector)

Count how many elements match the xpath selector.

This function does not run any test assertions.

dev_pause($msg)

Pause the entire test, until someone presses enter at the console. This is useful for troubleshooting / debugging failing tests, since it lets you interact with the browser on the Selenium node.

If given, $msg will be printed out as a diagnostic, to remind you why you pasused. In any case, the message "PAUSED (press Enter to continue)" will be printed as a diagnostic.

This function does not run any test assertions.

screenshot($fn, $msg)

Take a screenshot of the currently selected window and save it to $fn.

An optional message can be provided by the second argument, which will be printed to screen as a TAP diagnostic message.

resize($x, $y, $msg, $timeout)

Change the size of the currently active window. parameters are X size, Y size, the message and timeout all parameters are optional, X and Y default to HD (1920x1080) and Timeout is set to the global timeout of 3 seconds. The default message is sensible.

source

Returns the current source code of the active window.

wait_for_window

Wait for the currently active window to finish loading. IE the native javascript function of document.ready to return "complete"

window_titles

Get an array of window titles.

    Returns an array of window titles in order the were opened

title

Returns the active window's title.

wait_for_it

Takes a code ref and timeout, and waits for that coderef to return true, or for the timeout to expire. This is a test assertion, so if timeout expires, the test will fail.

alert_text($test_name)

Retrieves the text of an alert dialog.

type_alert($text, $test_name)

Sets the javascript alert() text.

cancel_alert($test_name)

Cancels an alert() dialog prompted by javascript.

confirm_alert($test_name)

Confirms an alert() dialog prompted by javascript.

AUTHOR

Written by Dan Molik <dan at d3fy dot net> James Hunt <james at jameshunt dot us>