Skip to content

zjmarlow/WebDriver2

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

202 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 &wait-present = present $session, $locator, duration => 5, interval => 1/10, :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
	&wait-present();
	
	my WD2::Component::Element $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;
	
	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;
		}
	}

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:

option notes
Str $browser? if none is provided and there is a browser file in the test root (default ./xt), its value will be read and used. otherwise the test will fail
Str:D :$host = '127.0.0.1'
Int:D :$port = 9515 9515 was the default for chromedriver and edgedriver. it will likely need to be supplied when using firefox or safari, or if chromedriver or edgedriver is using a random port. the port can also be set when starting the driver (as opposed to or in addition to the script)
IO::Path(Str:D) :$test-root = 'xt'.IO currently unused
Int:D :$close-delay = 3 if set negative, the session will be left open when the script completes or if there is a fatal exception (except failed Session creation - in which case there will be no session to leave open). if the session is left open, the session-id will be given on STDOUT so that it can be used to close the session gracefully later. E.g., by using the provided bin/close-session.raku script: close-session --host=127.0.0.1 --port=9515 <browser>(required) <session-id>(required)
Bool:D :$no-auto-ss = False By default, in addition to screenshots Tests explicitly request, screenshots are taken anytime there is a failure (if using the provided WD2::Test::Adapter methods) or exception. set to suppress this behavior
Str:D :$debug(:$debug-level) = 'WARN' valid values: OFF, ERR, WARN, Info, trace, extra. debugging output has not been incorporated, yet

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.

Implementation Status

  • "" - Planned
  • NYI - will throw exception
  • I - Implemented
  • ✓ - Implemented and tested
  Windows Windows / Linux MacOS  
endpoint edge chrome firefox safari method
new session   $driver.new-session: { capabilities => { ... } }
delete session   $session.delete
status I I     $driver.status
get timeouts I I     $session.get-timeouts
set timeouts I I     $session.set-timeouts: Int $script, Int $page-load, Int $implicit
navigate to   $session.navigate-to: Str $url
get current url I I     $session.current-url
back I I     $session.back
forward I I     $session.forward
refresh I I     $session.refresh
get title   $session.title
get window handle I I     $session.get-window-handle
close window I I     $session.close-window
switch to window I I     $session.switch-to-window: $handle
get window handles I I     $session.window-handles
new window I I     $session.new-window: Str $type? where <tab window>.any
switch to frame   $session.switch-to: Int $frame-id $frame-element.switch-to
switch to parent frame I I     $session.switch-to-parent-frame
get window rect         $session.get-window-rect
set window rect I I     $session.set-window-rect: Int $width, Int $height, Int $x, Int $y
maximize window I I     $session.maximize-window
minimize window I I     $session.minimize-window
fullscreen window I I     $session.fullscreen-window
get active element I I     $session.active-element
get element shadow root I I     $element.shadow-root
find element   $session.find-element: By $locator
find elements   $session.find-elements: By $locator
find element from element   $element.find-element: By $locator
find elements from element   $element.find-elements: By $locator
find element from shadow root I I     $shadow-root.find-element: By $locator
find elements from shadow root I I     $shadow-root.find-elements: By $locator
is element selected I I     $element.is-element-selected
get element attribute   $element.attribute: Str $name
get element property   $element.property: Str $name
get element css value I I     $element.css-value: Str $css-prop
get element text   $element.text
get element tag name   $element.tag-name
get element rect I I     $element.rect
is element enabled   $element.is-enabled
get computed role I I     $element.computed-role
get computed label I I     $element.computed-label
element click   $element.click
element clear   $element.clear
element send keys   $element.send-keys: Str $text
get page source I I     $session.page-source
execute script I I     $session.execute-script: Str $scr, @args
execute async script I I     $session.execute-async-script: Str $scr, @args
get all cookies I I     $session.get-all-cookies
get named cookie I I     $session.get-named-cookie: Str $name
add cookie I I     $session.add-cookie: %cookie-spec

keys:

name* value* path domain secure httpOnly expiry sameSite

* required

delete cookie I I     $session.delete-cookie: Str $name
delete all cookies I I     $session.delete-all-cookies
perform actions NYI NYI NYI NYI $session.perform-actions
release actions NYI NYI NYI NYI $session.release-actions
dismiss alert I I     $session.dismiss-alert
accept alert   $session.accept-alert
get alert text   $session.alert-text
send alert text I I I   $session.send-alert-text: Str $text
take screenshot I I     $session.take-screenshot
take element screenshot I I     $element.take-element-screenshot
print page I I     $session.print-page
is-displayed ( optional endpoint ) I I     $element.is-displayed
present ( convenience method - not spec'd ) I I     $session.present: By $locator; $element.present: By $locator
id ( convenience method - not spec'd ) I I     $element.id
top ( convenience method - not spec'd ) I I     $session.top
switch-to ( convenience method - not spec'd ) I I     $frame-element.switch-to
select ( convenience method - not spec'd ) I I     $select-element.select: Str $option-text
selected-option ( convenience method - not spec'd ) I I     $select-element.selected-option
selected-value ( convenience method - not spec'd ) I I     $select-element.selected-value

Locator Status

  • "" - Planned
  • I - Implemented
  • ✓ - Passing
locator status
By.id
By.tag
By.css
By.xpath
By.link-text
By.partial-link-text

Wait Status

  • "" - Planned
  • I - Implemented
  • ✓ - Passing
routine status import with notes
base-waituse WD2::Wait :basebase wait routine. can be used to wait for arbitrary conditions
basic-opIuse WD2::Wait :basebasic wait - use operation's return value directly for truthiness
basic-trueIuse WD2::Wait :basicwait for identically True value
basic-so-trueIuse WD2::Wait :basicwait for truthiness
basic-to-trueIuse WD2::Wait :basicwait for falsiness and alter return value to be the opposite Bool value
basic-eqIuse WD2::Wait :basicwait for a specific value using eq
basic-equalsIuse WD2::Wait :basicwait for a specific value using ==
basic-acceptsIuse WD2::Wait :basicwait for a specific value using ~~
throwableIuse WD2::Wait :throwreturn (non-Falure) Exception, otherwise, the return value. used to build waits but is not one itself
expect-throwIuse WD2::Wait :throw$throwable-return.isa: Exception ?? False !! $result but True. used to build waits but is not one itself
expect-throw-typeIuse WD2::Wait :throwrethrow wrong type; return the type if it was expected; otherwise, return Error-Code (falsy). used to build waits but is not one itself
no-throwIuse WD2::Wait :throw$throwable-return.isa: Exception ?? $throwable-return but False !! $throwable-return. used to build waits but is not one itself
no-throw-typeIuse WD2::Wait :throwrethrow anything unexpected; return the expected type but False. used to build waits but is not one itself
presentuse WD2::Wait::Common :presence
absentuse WD2::Wait::Common :presence
staleuse WD2::Wait::Common :presence
displayeduse WD2::Wait::Common :presence
hiddenuse WD2::Wait::Common :presence
value-not-emptyIuse WD2::Wait::Common :value
value-to-eqIuse WD2::Wait::Common :value
value-to-beIuse WD2::Wait::Common :value
text-to-beIuse WD2::Wait::Common :value
title-to-beIuse WD2::Wait::Common :value

About

WebDriver level 2 bindings

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Raku 82.1%
  • HTML 17.8%
  • JavaScript 0.1%