WebDriver2 — README

WebDriver2

WebDriver level 2 bindings implementing W3C's specification. Current implementation status is documented below.

Usage

Using a driver directly

To use a driver directly for driver-level endpoint commands, request a WD2::Component::Driver with Provider.get-driver: $browser, :$port. The test class will need to specify the browser and port upon instantiation:

	use WD2;
	use WD2::Component::Driver;
	
	my WD2::Component::Driver:D $driver =
		Provider.get-driver: 'chrome', port => 9515;

Most commands are Session or Element endpoints, though:

	use WD2::Component::Session;
	
	my WD2::Component::Session:D $session =
		$driver.new-session: %optional-capabilities-options;
	
	$session.navigate-to: $url-as-Str; # can be file path or web address

If no capabilities are given, the minimum, empty default will be supplied: { capabilities => { } }. Please see specification(s) for capability availability and format.

Some Element endpoints:

	use WD2::Component::Element;
	
	use WD2::Locators;
	
	my WD2::Component::Element:D $element =
		$session.find-element: By.id: 'identifier';
	$element.click;

In addition to locating Elements by ID, the standard locators are available:

	$element = $session.find-element: By.tag: 'input';
	$element = $session.find-element: By.css: 'body > div.head';
	# also By.link-text, By.partial-link-text, By.xpath

See below for status.

When finished:

	$session.delete;

Convenience Methods and Routines, Test Template

Methods

Some Session and Element convenience methods have been provided that are not part of the WebDriver2 specification. They are listed below at the end of the implementation status section.

Wait Routines

Since waiting for a condition to be true before moving to the next step is useful, several routines that poll state have also been provided:

	# relevant imports and declarations completed above
	use WD2::Wait::Common :ALL;
	
	my Duration:D $duration = Duration.new: 5;
	my Duration:D $interval = Duration.new: 1/10;
	my &wait-present = present $session, $locator, :$duration, :$interval, :soft;
	# do something...
	# then wait for 5 seconds, polling every .1 second,
	#   for an element to appear; don't throw an exception if it doesn't
	my WD2::Component::Element $element = wait-present;
	
	$element = $session.find-element: By.id: 'gets-removed';
	my &wait-stale = stale $element;
	# do something...
	# then wait for the element to be removed using default values;
	#   throw Timeout exception if it isn't
	wait-stale;
	
	my WD2::Component::Element $updatable =
		$session.find-element: By.id: 'updatable';
	my WD2::Component::Element $input =
		$session.find-element: By.id: 'text-input';
	my WD2::Component::Element $updater =
		$session.find-element: By.tag: 'button';
	my &wait-updated = text-to-be $updatable, 'new text';
	$input.send-keys: 'new text';
	$updater.click;
	wait-updated;

List with implementation status given below the endpoints table.

WD2::Test::Template

Test classes can implement the WD2::Test::Template role to avoid some boilerplate. The example test included with the distribution is explained here.

From xt/lib/Example.rakumod:

	use WD2::Test::Template;
	
	use WD2::Locators;
	use WD2::Wait::Common :presence;
	
	class Example does WD2::Test::Template {
		my IO::Path:D $html-file =
			$*PROGRAM.parent.sibling( 'content' ).add: 'test.html';
		
		has Str:D $.name = 'example';
		has Str:D $.description = 'example test description';
		has Int:D $.plan = 1;
		
		# included so that when run as part of the test suite,
		#   it will skip testing if the user has not requested
		#   driver testing.  This Should Be Omitted for normal
		#   user tests.
		method init {
			if %*ENV<DRIVER_TESTING> {
				self.WD2::Test::Template::init;
			} else {
				self.diag: 'DRIVER_TESTING was not set';
				self.pass: 'DRIVER_TESTING was not set';
				self.done-testing;
				exit;
			}
		}
		
		method test {
			$!session.navigate-to: 'file://' ~ $html-file.absolute;
			self.is: 'title', 'test', $!session.title;
			
			my Duration:D $duration = Duration.new: 5;
			my Duration:D $interval = Duration.new: 1/10;
			my By:D $locator = By.id: 'DNE';
			my &wait-present = present $!session, $locator, :$duration, :$interval, :soft;
			
			self.lives-ok: 'lives but False for element that DNE', {
				my WD2::Component::Element $element = wait-present;
				self.nok: 'no element found', $element;
			}
		}
	}

Implementing classes need to provide a test name and description and override the test method. The self.is: ... is provided by the WD2::Test::Adapter role via WD2::Test::Template (template role is the only import necessary). That and the related methods delegate to the Test routines but will run a handler if a test fails. The default handler takes a screenshot when called (see below for details and how to suppress this behavior). Note that the order of arguments are the reverse of the Test routines. This leaves the final position available for calculating the actual value.

Once such a class is written, it can be used in a test script.

From xt/05-test-template/example.rakutest:

	use lib <lib xt/lib>;
	
	use WD2::Test::Template;
	use Example;
	
	constant &MAIN = driver-test Example;

The script is just a wrapper that runs the test class. The driver-test sub is from the WD2::Test::Template compunit (hence the first import). It takes the test class and returns a sub suitable for use as a MAIN. The options provided are:

In addition, any extra named arguments will be passed to the test class, so that instance variables can be built from them.

TODO

  • cover all implemented endpoints with unit tests

  • add Rakudoc

  • browser support

  • implement the rest of the endpoints

Feedback

Suggestions, design recommendations, and feature requests welcome.

Safari Quirks

  • is displayed ( optional endpoint ) is not supported ( by Apple's design )

  • safaridriver ignores interactions with disabled elements instead of throwing the spec'd Element Not Interactable exception ( by Apple's design )

  • switch to parent frame switches to default content ( bug - needs investigation )

Implementation Status

  • X - Unsupported

  • "" - Planned

  • I - Implemented

  • ✓ - Implemented and tested

Locator Status

  • "" - Planned

  • I - Implemented

  • ✓ - Passing

Wait Status

  • "" - Planned

  • I - Implemented

  • ✓ - Passing

WebDriver2 v0.2.1

WebDriver level 2 bindings

Authors

    License

    Artistic-2.0

    Dependencies

    HTTP::UserAgent::StrictRakuAST::Utils

    Test Dependencies

    Provides

    • Action
    • Action-Factory
    • Action-Factory::Element
    • Action::Key
    • Action::Origin
    • Action::Pause
    • Action::Pointer
    • Action::Wheel
    • Provider
    • WD2::By::CSS
    • WD2::By::ID
    • WD2::By::Link-Text
    • WD2::By::Partial-Link-Text
    • WD2::By::Tag
    • WD2::By::XPath
    • WD2::Component::Driver
    • WD2::Component::Element
    • WD2::Component::Session
    • WD2::Component::Shadow
    • WD2::Debug
    • WD2::Endpoints
    • WD2::Endpoints::Error
    • WD2::Endpoints::Execution-Status
    • WD2::Endpoints::Result::X
    • WD2::Locators
    • WD2::Test::Adapter
    • WD2::Test::Template
    • WD2::Wait::Timeout::X

    Documentation

    The Camelia image is copyright 2009 by Larry Wall. "Raku" is a trademark of the Yet Another Society. All rights reserved.

    Built with Podlite — the markup and publishing tools behind this site.