ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-WebDriver/README
Revision: 1.10
Committed: Sat Mar 28 17:06:20 2020 UTC (4 years, 3 months ago) by root
Branch: MAIN
CVS Tags: rel-1_2, HEAD
Changes since 1.9: +58 -18 lines
Log Message:
1.2

File Contents

# User Rev Content
1 root 1.1 NAME
2     AnyEvent::WebDriver - control browsers using the W3C WebDriver protocol
3    
4     SYNOPSIS
5 root 1.8 # start geckodriver(chromedriver or any other webdriver via the shell
6     $ geckodriver -b myfirefox/firefox --log trace --port 4444
7     # chromedriver --port=4444
8 root 1.1
9     # then use it
10     use AnyEvent::WebDriver;
11    
12     # create a new webdriver object
13     my $wd = new AnyEvent::WebDriver;
14    
15     # create a new session with default capabilities.
16     $wd->new_session ({});
17    
18     $wd->navigate_to ("https://duckduckgo.com/html");
19 root 1.7 my $searchbox = $wd->find_element (css => 'input[type="text"]');
20 root 1.1
21     $wd->element_send_keys ($searchbox => "free software");
22 root 1.7 $wd->element_click ($wd->find_element (css => 'input[type="submit"]'));
23 root 1.1
24 root 1.7 # session gets autodeleted by default, so wait a bit
25 root 1.1 sleep 10;
26    
27 root 1.7 # this is an example of an action sequence
28     $wd->actions
29     ->move ($wd->find_element (...), 40, 5)
30     ->click
31     ->type ("some text")
32     ->key ("{Enter}")
33     ->perform;
34    
35 root 1.1 DESCRIPTION
36 root 1.8 This module aims to implement the W3C WebDriver
37     <https://www.w3.org/TR/webdriver1/> specification which is the
38     standardised equivalent to the Selenium WebDriver API, which in turn
39     aims at remotely controlling web browsers such as Firefox or Chromium.
40 root 1.1
41 root 1.7 One of the design goals of this module was to stay very close to the
42     language and words used in the WebDriver specification itself, so to
43     make most of this module, or, in fact, to make any reasonable use of
44 root 1.4 this module, you would need to refer to the W3C WebDriver
45     recommendation, which can be found here
46     <https://www.w3.org/TR/webdriver1/>:
47 root 1.1
48 root 1.4 https://www.w3.org/TR/webdriver1/
49 root 1.1
50 root 1.10 Mozilla's "geckodriver" has had webdriver support for a long time, while
51 root 1.8 "chromedriver" only has basic and mostly undocumented webdriver support
52 root 1.9 as of release 77.
53 root 1.8
54 root 1.10 In Debian GNU/Linux, you can install the chromedriver for chromium via
55     the "chromium-driver" package. Unfortunately, there is no (working)
56     package for geckodriver, but you can download it from github
57     <https://github.com/mozilla/geckodriver/releases>.
58    
59 root 1.4 CONVENTIONS
60     Unless otherwise stated, all delays and time differences in this module
61 root 1.10 are represented as an integer number of milliseconds, which is perhaps
62     surprising to users of my other modules but is what the WebDriver spec
63     uses.
64 root 1.4
65     WEBDRIVER OBJECTS
66 root 1.1 new AnyEvent::WebDriver key => value...
67 root 1.3 Create a new WebDriver object. Example for a remote WebDriver
68 root 1.1 connection (the only type supported at the moment):
69    
70 root 1.8 my $wd = new AnyEvent::WebDriver endpoint => "http://localhost:4444";
71 root 1.1
72     Supported keys are:
73    
74     endpoint => $string
75     For remote connections, the endpoint to connect to (defaults to
76     "http://localhost:4444").
77    
78     proxy => $proxyspec
79     The proxy to use (same as the "proxy" argument used by
80     AnyEvent::HTTP). The default is "undef", which disables proxies.
81     To use the system-provided proxy (e.g. "http_proxy" environment
82 root 1.10 variable), specify the string "default".
83 root 1.1
84     autodelete => $boolean
85     If true (the default), then automatically execute
86     "delete_session" when the WebDriver object is destroyed with an
87 root 1.9 active session. If set to a false value, then the session will
88 root 1.1 continue to exist.
89    
90 root 1.9 Note that due to bugs in perl that are unlikely to get fixed,
91     "autodelete" is likely ineffective during global destruction and
92     might even crash your process, so you should ensure objects go
93     out of scope before that, or explicitly call "delete_session",
94     if you want the session to be cleaned up.
95    
96 root 1.3 timeout => $seconds
97 root 1.9 The HTTP timeout, in (fractional) seconds (default: 300). This
98     timeout is reset on any activity, so it is not an overall
99     request timeout. Also, individual requests might extend this
100     timeout if they are known to take longer.
101 root 1.3
102 root 1.6 persistent => 1 | "undef"
103     If true (the default) then persistent connections will be used
104     for all requests, which assumes you have a reasonably stable
105     connection (such as to "localhost" :) and that the WebDriver has
106     a persistent timeout much higher than what AnyEvent::HTTP uses.
107    
108     You can force connections to be closed for non-idempotent
109 root 1.8 requests (the safe default of AnyEvent::HTTP) by setting this to
110     "undef".
111 root 1.6
112 root 1.4 $al = $wd->actions
113     Creates an action list associated with this WebDriver. See ACTION
114     LISTS, below, for full details.
115    
116 root 1.5 $sessionstring = $wd->save_session
117     Save the current session in a string so it can be restored load with
118     "load_session". Note that only the session data itself is stored
119     (currently the session id and capabilities), not the endpoint
120     information itself.
121    
122     The main use of this function is in conjunction with disabled
123     "autodelete", to save a session to e.g., and restore it later. It
124 root 1.6 could presumably used for other applications, such as using the same
125     session from multiple processes and so on.
126 root 1.5
127     $wd->load_session ($sessionstring)
128     $wd->set_session ($sessionid, $capabilities)
129     Starts using the given session, as identified by $sessionid.
130     $capabilities should be the original session capabilities, although
131     the current version of this module does not make any use of it.
132    
133     The $sessionid is stored in "$wd->{sid}" (and could be fetched form
134     there for later use), while the capabilities are stored in
135     "$wd->{capabilities}".
136    
137 root 1.1 SIMPLIFIED API
138     This section documents the simplified API, which is really just a very
139 root 1.8 thin wrapper around the WebDriver protocol commands. They all block the
140     caller until the result is available (using AnyEvent condvars), so must
141     not be called from an event loop callback - see "EVENT BASED API" for an
142     alternative.
143 root 1.1
144 root 1.3 The method names are pretty much taken directly from the W3C WebDriver
145 root 1.1 specification, e.g. the request documented in the "Get All Cookies"
146     section is implemented via the "get_all_cookies" method.
147    
148 root 1.3 The order is the same as in the WebDriver draft at the time of this
149 root 1.1 writing, and only minimal massaging is done to request parameters and
150     results.
151    
152     SESSIONS
153     $wd->new_session ({ key => value... })
154 root 1.3 Try to connect to the WebDriver and initialize a new session with a
155     "new session" command, passing the given key-value pairs as value
156     (e.g. "capabilities").
157 root 1.1
158     No session-dependent methods must be called before this function
159 root 1.3 returns successfully, and only one session can be created per
160     WebDriver object.
161 root 1.1
162 root 1.3 On success, "$wd->{sid}" is set to the session ID, and
163 root 1.1 "$wd->{capabilities}" is set to the returned capabilities.
164    
165 root 1.6 Simple example of creating a WebDriver object and a new session:
166 root 1.5
167 root 1.8 my $wd = new AnyEvent::WebDriver endpoint => "http://localhost:4444";
168 root 1.5 $wd->new_session ({});
169    
170     Real-world example with capability negotiation:
171 root 1.1
172     $wd->new_session ({
173     capabilities => {
174 root 1.5 alwaysMatch => {
175     pageLoadStrategy => "eager",
176     unhandledPromptBehavior => "dismiss",
177     # proxy => { proxyType => "manual", httpProxy => "1.2.3.4:56", sslProxy => "1.2.3.4:56" },
178     },
179     firstMatch => [
180     {
181     browserName => "firefox",
182     "moz:firefoxOptions" => {
183     binary => "firefox/firefox",
184 root 1.8 args => ["-devtools", "-headless"],
185 root 1.5 prefs => {
186     "dom.webnotifications.enabled" => \0,
187 root 1.6 "dom.push.enabled" => \0,
188 root 1.5 "dom.disable_beforeunload" => \1,
189     "browser.link.open_newwindow" => 3,
190     "browser.link.open_newwindow.restrictions" => 0,
191     "dom.popup_allowed_events" => "",
192     "dom.disable_open_during_load" => \1,
193     },
194     },
195     },
196     {
197 root 1.8 browserName => "chrome",
198     "goog:chromeOptions" => {
199     binary => "/bin/chromium",
200     args => ["--no-sandbox", "--headless"],
201     prefs => {
202     # ...
203     },
204     },
205     },
206     {
207 root 1.5 # generic fallback
208     },
209     ],
210    
211     },
212 root 1.1 });
213    
214 root 1.5 Firefox-specific capability documentation can be found on MDN
215     <https://developer.mozilla.org/en-US/docs/Web/WebDriver/Capabilities
216     >, Chrome-specific capability documentation might be found here
217     <http://chromedriver.chromium.org/capabilities>, but the latest
218 root 1.8 release at the time of this writing (chromedriver 77) has
219 root 1.9 essentially no documentation about webdriver capabilities (even MDN
220     has better documentation about chromwedriver!)
221 root 1.5
222     If you have URLs for Safari/IE/Edge etc. capabilities, feel free to
223     tell me about them.
224    
225 root 1.1 $wd->delete_session
226     Deletes the session - the WebDriver object must not be used after
227 root 1.9 this call (except for calling this method).
228    
229     This method is always safe to call and will not do anything if there
230     is no active session.
231 root 1.1
232     $timeouts = $wd->get_timeouts
233     Get the current timeouts, e.g.:
234    
235     my $timeouts = $wd->get_timeouts;
236 root 1.3 => { implicit => 0, pageLoad => 300000, script => 30000 }
237 root 1.1
238     $wd->set_timeouts ($timeouts)
239     Sets one or more timeouts, e.g.:
240    
241     $wd->set_timeouts ({ script => 60000 });
242    
243     NAVIGATION
244     $wd->navigate_to ($url)
245     Navigates to the specified URL.
246    
247     $url = $wd->get_current_url
248 root 1.3 Queries the current page URL as set by "navigate_to".
249 root 1.1
250     $wd->back
251     The equivalent of pressing "back" in the browser.
252    
253     $wd->forward
254     The equivalent of pressing "forward" in the browser.
255    
256     $wd->refresh
257     The equivalent of pressing "refresh" in the browser.
258    
259     $title = $wd->get_title
260     Returns the current document title.
261    
262     COMMAND CONTEXTS
263     $handle = $wd->get_window_handle
264     Returns the current window handle.
265    
266     $wd->close_window
267     Closes the current browsing context.
268    
269     $wd->switch_to_window ($handle)
270     Changes the current browsing context to the given window.
271    
272     $handles = $wd->get_window_handles
273     Return the current window handles as an array-ref of handle IDs.
274    
275     $handles = $wd->switch_to_frame ($frame)
276 root 1.3 Switch to the given frame identified by $frame, which must be either
277     "undef" to go back to the top-level browsing context, an integer to
278 root 1.4 select the nth subframe, or an element object.
279 root 1.1
280     $handles = $wd->switch_to_parent_frame
281     Switch to the parent frame.
282    
283     $rect = $wd->get_window_rect
284 root 1.6 Return the current window rect(angle), e.g.:
285 root 1.1
286     $rect = $wd->get_window_rect
287 root 1.3 => { height => 1040, width => 540, x => 0, y => 0 }
288 root 1.1
289     $wd->set_window_rect ($rect)
290 root 1.7 Sets the window rect(angle), e.g.:
291    
292     $wd->set_window_rect ({ width => 780, height => 560 });
293     $wd->set_window_rect ({ x => 0, y => 0, width => 780, height => 560 });
294 root 1.1
295     $wd->maximize_window
296     $wd->minimize_window
297     $wd->fullscreen_window
298 root 1.3 Changes the window size by either maximising, minimising or making
299     it fullscreen. In my experience, this will timeout if no window
300 root 1.1 manager is running.
301    
302     ELEMENT RETRIEVAL
303 root 1.5 To reduce typing and memory strain, the element finding functions accept
304     some shorter and hopefully easier to remember aliases for the standard
305     locator strategy values, as follows:
306    
307     Alias Locator Strategy
308     css css selector
309     link link text
310     substr partial link text
311     tag tag name
312    
313     $element = $wd->find_element ($locator_strategy, $selector)
314 root 1.1 Finds the first element specified by the given selector and returns
315 root 1.4 its element object. Raises an error when no element was found.
316 root 1.1
317 root 1.6 Examples showing all standard locator strategies:
318    
319 root 1.1 $element = $wd->find_element ("css selector" => "body a");
320     $element = $wd->find_element ("link text" => "Click Here For Porn");
321     $element = $wd->find_element ("partial link text" => "orn");
322     $element = $wd->find_element ("tag name" => "input");
323     $element = $wd->find_element ("xpath" => '//input[@type="text"]');
324 root 1.4 => e.g. { "element-6066-11e4-a52e-4f735466cecf" => "decddca8-5986-4e1d-8c93-efe952505a5f" }
325 root 1.1
326 root 1.6 Same examples using aliases provided by this module:
327    
328     $element = $wd->find_element (css => "body a");
329     $element = $wd->find_element (link => "Click Here For Porn");
330     $element = $wd->find_element (substr => "orn");
331     $element = $wd->find_element (tag => "input");
332    
333 root 1.5 $elements = $wd->find_elements ($locator_strategy, $selector)
334 root 1.4 As above, but returns an arrayref of all found element objects.
335 root 1.1
336 root 1.5 $element = $wd->find_element_from_element ($element, $locator_strategy,
337 root 1.4 $selector)
338 root 1.1 Like "find_element", but looks only inside the specified $element.
339    
340 root 1.4 $elements = $wd->find_elements_from_element ($element,
341 root 1.5 $locator_strategy, $selector)
342 root 1.1 Like "find_elements", but looks only inside the specified $element.
343    
344     my $head = $wd->find_element ("tag name" => "head");
345     my $links = $wd->find_elements_from_element ($head, "tag name", "link");
346    
347 root 1.4 $element = $wd->get_active_element
348 root 1.1 Returns the active element.
349    
350     ELEMENT STATE
351     $bool = $wd->is_element_selected
352     Returns whether the given input or option element is selected or
353     not.
354    
355 root 1.4 $string = $wd->get_element_attribute ($element, $name)
356 root 1.1 Returns the value of the given attribute.
357    
358 root 1.4 $string = $wd->get_element_property ($element, $name)
359 root 1.1 Returns the value of the given property.
360    
361 root 1.4 $string = $wd->get_element_css_value ($element, $name)
362 root 1.3 Returns the value of the given CSS value.
363 root 1.1
364 root 1.4 $string = $wd->get_element_text ($element)
365 root 1.1 Returns the (rendered) text content of the given element.
366    
367 root 1.4 $string = $wd->get_element_tag_name ($element)
368 root 1.1 Returns the tag of the given element.
369    
370 root 1.4 $rect = $wd->get_element_rect ($element)
371 root 1.3 Returns the element rect(angle) of the given element.
372 root 1.1
373     $bool = $wd->is_element_enabled
374     Returns whether the element is enabled or not.
375    
376     ELEMENT INTERACTION
377 root 1.4 $wd->element_click ($element)
378 root 1.1 Clicks the given element.
379    
380 root 1.4 $wd->element_clear ($element)
381 root 1.1 Clear the contents of the given element.
382    
383 root 1.4 $wd->element_send_keys ($element, $text)
384 root 1.7 Sends the given text as key events to the given element. Key input
385     state can be cleared by embedding "\x{e000}" in $text. Presumably,
386     you can embed modifiers using their unicode codepoints, but the
387     specification is less than clear to mein this area.
388 root 1.1
389     DOCUMENT HANDLING
390     $source = $wd->get_page_source
391     Returns the (HTML/XML) page source of the current document.
392    
393     $results = $wd->execute_script ($javascript, $args)
394     Synchronously execute the given script with given arguments and
395     return its results ($args can be "undef" if no arguments are
396     wanted/needed).
397    
398     $ten = $wd->execute_script ("return arguments[0]+arguments[1]", [3, 7]);
399    
400     $results = $wd->execute_async_script ($javascript, $args)
401     Similar to "execute_script", but doesn't wait for script to return,
402     but instead waits for the script to call its last argument, which is
403     added to $args automatically.
404    
405     $twenty = $wd->execute_async_script ("arguments[0](20)", undef);
406    
407     COOKIES
408     $cookies = $wd->get_all_cookies
409     Returns all cookies, as an arrayref of hashrefs.
410    
411     # google surely sets a lot of cookies without my consent
412     $wd->navigate_to ("http://google.com");
413     use Data::Dump;
414     ddx $wd->get_all_cookies;
415    
416     $cookie = $wd->get_named_cookie ($name)
417     Returns a single cookie as a hashref.
418    
419     $wd->add_cookie ($cookie)
420     Adds the given cookie hashref.
421    
422     $wd->delete_cookie ($name)
423     Delete the named cookie.
424    
425     $wd->delete_all_cookies
426     Delete all cookies.
427    
428     ACTIONS
429     $wd->perform_actions ($actions)
430     Perform the given actions (an arrayref of action specifications
431 root 1.4 simulating user activity, or an "AnyEvent::WebDriver::Actions"
432     object). For further details, read the spec or the section "ACTION
433     LISTS", below.
434    
435     An example to get you started (see the next example for a mostly
436     equivalent example using the "AnyEvent::WebDriver::Actions" helper
437     API):
438 root 1.1
439     $wd->navigate_to ("https://duckduckgo.com/html");
440     my $input = $wd->find_element ("css selector", 'input[type="text"]');
441     $wd->perform_actions ([
442     {
443     id => "myfatfinger",
444     type => "pointer",
445     pointerType => "touch",
446     actions => [
447 root 1.4 { type => "pointerMove", duration => 100, origin => $input, x => 40, y => 5 },
448 root 1.7 { type => "pointerDown", button => 0 },
449 root 1.1 { type => "pause", duration => 40 },
450 root 1.7 { type => "pointerUp", button => 0 },
451 root 1.1 ],
452     },
453     {
454     id => "mykeyboard",
455     type => "key",
456     actions => [
457     { type => "pause" },
458     { type => "pause" },
459     { type => "pause" },
460     { type => "pause" },
461     { type => "keyDown", value => "a" },
462     { type => "pause", duration => 100 },
463     { type => "keyUp", value => "a" },
464     { type => "pause", duration => 100 },
465     { type => "keyDown", value => "b" },
466     { type => "pause", duration => 100 },
467     { type => "keyUp", value => "b" },
468     { type => "pause", duration => 2000 },
469     { type => "keyDown", value => "\x{E007}" }, # enter
470     { type => "pause", duration => 100 },
471     { type => "keyUp", value => "\x{E007}" }, # enter
472     { type => "pause", duration => 5000 },
473     ],
474     },
475     ]);
476    
477 root 1.4 And here is essentially the same (except for fewer pauses) example
478 root 1.7 as above, using the much simpler "AnyEvent::WebDriver::Actions" API:
479 root 1.4
480     $wd->navigate_to ("https://duckduckgo.com/html");
481     my $input = $wd->find_element ("css selector", 'input[type="text"]');
482     $wd->actions
483     ->move ($input, 40, 5, "touch1")
484 root 1.6 ->click
485     ->key ("a")
486     ->key ("b")
487 root 1.7 ->pause (2000) # so you can watch leisurely
488     ->key ("{Enter}")
489     ->pause (5000) # so you can see the result
490 root 1.4 ->perform;
491    
492 root 1.1 $wd->release_actions
493     Release all keys and pointer buttons currently depressed.
494    
495     USER PROMPTS
496     $wd->dismiss_alert
497     Dismiss a simple dialog, if present.
498    
499     $wd->accept_alert
500     Accept a simple dialog, if present.
501    
502     $text = $wd->get_alert_text
503     Returns the text of any simple dialog.
504    
505     $text = $wd->send_alert_text
506     Fills in the user prompt with the given text.
507    
508     SCREEN CAPTURE
509     $wd->take_screenshot
510 root 1.10 Create a screenshot, returning it as a PNG image. To decode and
511     save, you could do something like:
512    
513     use MIME::Base64 ();
514    
515     my $screenshot = $wd->take_screenshot;
516    
517     open my $fh, ">", "screenshot.png" or die "screenshot.png: $!\n";
518    
519     syswrite $fh, MIME::Base64::decode_base64 $screenshot;
520 root 1.1
521 root 1.4 $wd->take_element_screenshot ($element)
522 root 1.8 Similar to "take_screenshot", but only takes a screenshot of the
523     bounding box of a single element.
524 root 1.1
525 root 1.10 Compatibility note: As of chrome version 80, I found that the
526     screenshot scaling is often wrong (the screenshot is much smaller
527     than the element normally displays) unless chrome runs in headless
528     mode. The spec does allow for any form of scaling, so this is not
529     strictly a bug in chrome, but of course it diminishes trhe
530     screenshot functionality.
531    
532     PRINT
533     $wd->print_page (key => value...)
534     Create a printed version of the document, returning it as a PDF
535     document encoded as base64. See "take_screenshot" for an example on
536     how to decode and save such a string.
537    
538     This command takes a lot of optional parameters, see the print
539     section <https://www.w3.org/TR/webdriver2/#print> of the WebDriver
540     specification for details.
541    
542     This command is taken from a draft document, so it might change in
543     the future.
544    
545 root 1.4 ACTION LISTS
546     Action lists can be quite complicated. Or at least it took a while for
547     me to twist my head around them. Basically, an action list consists of a
548     number of sources representing devices (such as a finger, a mouse, a pen
549 root 1.10 or a keyboard) and a list of actions for each source, in a timeline.
550 root 1.4
551     An action can be a key press, a pointer move or a pause (time delay).
552    
553 root 1.7 While you can provide these action lists manually, it is (hopefully)
554     less cumbersome to use the API described in this section to create them.
555 root 1.4
556     The basic process of creating and performing actions is to create a new
557     action list, adding action sources, followed by adding actions. Finally
558     you would "perform" those actions on the WebDriver.
559    
560     Most methods here are designed to chain, i.e. they return the web
561     actions object, to simplify multiple calls.
562    
563 root 1.7 Also, while actions from different sources can happen "at the same time"
564 root 1.10 in the WebDriver protocol, this class by default ensures that actions
565     will execute in the order specified.
566 root 1.7
567 root 1.4 For example, to simulate a mouse click to an input element, followed by
568     entering some text and pressing enter, you can use this:
569    
570     $wd->actions
571 root 1.7 ->click (0, 100)
572 root 1.4 ->type ("some text")
573 root 1.5 ->key ("{Enter}")
574 root 1.4 ->perform;
575    
576 root 1.10 By default, "keyboard" and "mouse" input sources are provided and used.
577     You can create your own sources and use them when adding events. The
578     above example could be more verbosely written like this:
579 root 1.4
580     $wd->actions
581 root 1.6 ->source ("mouse", "pointer", pointerType => "mouse")
582     ->source ("kbd", "key")
583 root 1.7 ->click (0, 100, "mouse")
584 root 1.6 ->type ("some text", "kbd")
585     ->key ("{Enter}", "kbd")
586 root 1.4 ->perform;
587    
588 root 1.6 When you specify the event source explicitly it will switch the current
589 root 1.4 "focus" for this class of device (all keyboards are in one class, all
590     pointer-like devices such as mice/fingers/pens are in one class), so you
591 root 1.10 don't have to specify the source for subsequent actions that are on the
592     same class.
593 root 1.4
594     When you use the sources "keyboard", "mouse", "touch1".."touch3", "pen"
595     without defining them, then a suitable default source will be created
596     for them.
597    
598     $al = new AnyEvent::WebDriver::Actions
599     Create a new empty action list object. More often you would use the
600 root 1.5 "$wd->action_list" method to create one that is already associated
601 root 1.4 with a given web driver.
602    
603     $al = $al->source ($id, $type, key => value...)
604 root 1.6 The first time you call this with a given ID, this defines the event
605 root 1.4 source using the extra parameters. Subsequent calls merely switch
606     the current source for its event class.
607    
608     It's not an error to define built-in sources (such as "keyboard" or
609     "touch1") differently then the defaults.
610    
611     Example: define a new touch device called "fatfinger".
612    
613     $al->source (fatfinger => "pointer", pointerType => "touch");
614    
615 root 1.6 Example: define a new touch device called "fatfinger".
616 root 1.4
617     $al->source (fatfinger => "pointer", pointerType => "touch");
618    
619 root 1.6 Example: switch default keyboard source to "kbd1", assuming it is of
620     "key" class.
621    
622     $al->source ("kbd1");
623    
624 root 1.4 $al = $al->pause ($duration)
625     Creates a pause with the given duration. Makes sure that time
626     progresses in any case, even when $duration is 0.
627    
628     $al = $al->pointer_down ($button, $source)
629     $al = $al->pointer_up ($button, $source)
630 root 1.7 Press or release the given button. $button defaults to 0.
631 root 1.4
632     $al = $al->click ($button, $source)
633     Convenience function that creates a button press and release action
634 root 1.7 without any delay between them. $button defaults to 0.
635 root 1.4
636     $al = $al->doubleclick ($button, $source)
637     Convenience function that creates two button press and release
638     action pairs in a row, with no unnecessary delay between them.
639 root 1.7 $button defaults to 0.
640 root 1.4
641 root 1.10 $al = $al->move ($origin, $x, $y, $duration, $source)
642 root 1.4 Moves a pointer to the given position, relative to origin (either
643 root 1.10 "viewport", "pointer" or an element object. The coordinates will be
644     truncated to integer values.
645 root 1.4
646 root 1.7 $al = $al->cancel ($source)
647     Executes a pointer cancel action.
648    
649 root 1.10 $al = $al->key_down ($key, $source)
650     $al = $al->key_up ($key, $source)
651 root 1.4 Press or release the given key.
652    
653 root 1.5 $al = $al->key ($key, $source)
654 root 1.10 Peess and release the given key in one go, without unnecessary
655     delay.
656 root 1.5
657     A special syntax, "{keyname}" can be used for special keys - all the
658 root 1.10 special key names from the second table in section 17.4.2
659 root 1.5 <https://www.w3.org/TR/webdriver1/#keyboard-actions> of the
660 root 1.10 WebDriver recommendation can be used - prefix with "Shift-Space". to
661     get the shifted version, as in "Shift-"
662 root 1.5
663     Example: press and release "a".
664    
665     $al->key ("a");
666    
667     Example: press and release the "Enter" key:
668    
669     $al->key ("\x{e007}");
670    
671     Example: press and release the "enter" key using the special key
672     name syntax:
673    
674     $al->key ("{Enter}");
675    
676     $al = $al->type ($string, $source)
677     Convenience method to simulate a series of key press and release
678 root 1.7 events for the keys in $string, one pair per extended unicode
679     grapheme cluster. There is no syntax for special keys, everything
680     will be typed "as-is" if possible.
681 root 1.5
682 root 1.4 $al->perform ($wd)
683 root 1.6 Finalises and compiles the list, if not done yet, and calls
684 root 1.4 "$wd->perform" with it.
685    
686     If $wd is undef, and the action list was created using the
687     "$wd->actions" method, then perform it against that WebDriver
688     object.
689    
690     There is no underscore variant - call the "perform_actions_" method
691     with the action object instead.
692    
693     $al->perform_release ($wd)
694     Exactly like "perform", but additionally call "release_actions"
695     afterwards.
696    
697     ($actions, $duration) = $al->compile
698     Finalises and compiles the list, if not done yet, and returns an
699     actions object suitable for calls to "$wd->perform_actions". When
700     called in list context, additionally returns the total duration of
701     the action list.
702    
703     Since building large action lists can take nontrivial amounts of
704     time, it can make sense to build an action list only once and then
705     perform it multiple times.
706    
707 root 1.9 No additional actions must be added after compiling an action list.
708 root 1.1
709     EVENT BASED API
710     This module wouldn't be a good AnyEvent citizen if it didn't have a true
711     event-based API.
712    
713     In fact, the simplified API, as documented above, is emulated via the
714     event-based API and an "AUTOLOAD" function that automatically provides
715     blocking wrappers around the callback-based API.
716    
717     Every method documented in the "SIMPLIFIED API" section has an
718     equivalent event-based method that is formed by appending a underscore
719     ("_") to the method name, and appending a callback to the argument list
720     (mnemonic: the underscore indicates the "the action is not yet finished"
721     after the call returns).
722    
723     For example, instead of a blocking calls to "new_session", "navigate_to"
724     and "back", you can make a callback-based ones:
725    
726     my $cv = AE::cv;
727    
728     $wd->new_session ({}, sub {
729     my ($status, $value) = @_,
730    
731     die "error $value->{error}" if $status ne "200";
732    
733     $wd->navigate_to_ ("http://www.nethype.de", sub {
734    
735     $wd->back_ (sub {
736     print "all done\n";
737     $cv->send;
738     });
739    
740     });
741     });
742    
743     $cv->recv;
744    
745     While the blocking methods "croak" on errors, the callback-based ones
746     all pass two values to the callback, $status and $res, where $status is
747 root 1.3 the HTTP status code (200 for successful requests, typically 4xx or 5xx
748 root 1.1 for errors), and $res is the value of the "value" key in the JSON
749     response object.
750    
751     Other than that, the underscore variants and the blocking variants are
752     identical.
753    
754     LOW LEVEL API
755 root 1.3 All the simplified API methods are very thin wrappers around WebDriver
756     commands of the same name. They are all implemented in terms of the
757 root 1.7 low-level methods ("req", "get", "post" and "delete"), which exist in
758 root 1.1 blocking and callback-based variants ("req_", "get_", "post_" and
759     "delete_").
760    
761     Examples are after the function descriptions.
762    
763     $wd->req_ ($method, $uri, $body, $cb->($status, $value))
764     $value = $wd->req ($method, $uri, $body)
765     Appends the $uri to the "endpoint/session/{sessionid}/" URL and
766     makes a HTTP $method request ("GET", "POST" etc.). "POST" requests
767     can provide a UTF-8-encoded JSON text as HTTP request body, or the
768     empty string to indicate no body is used.
769    
770     For the callback version, the callback gets passed the HTTP status
771     code (200 for every successful request), and the value of the
772     "value" key in the JSON response object as second argument.
773    
774     $wd->get_ ($uri, $cb->($status, $value))
775     $value = $wd->get ($uri)
776     Simply a call to "req_" with $method set to "GET" and an empty body.
777    
778     $wd->post_ ($uri, $data, $cb->($status, $value))
779     $value = $wd->post ($uri, $data)
780     Simply a call to "req_" with $method set to "POST" - if $body is
781     "undef", then an empty object is send, otherwise, $data must be a
782     valid request object, which gets encoded into JSON for you.
783    
784     $wd->delete_ ($uri, $cb->($status, $value))
785     $value = $wd->delete ($uri)
786     Simply a call to "req_" with $method set to "DELETE" and an empty
787     body.
788    
789     Example: implement "get_all_cookies", which is a simple "GET" request
790     without any parameters:
791    
792     $cookies = $wd->get ("cookie");
793    
794     Example: implement "execute_script", which needs some parameters:
795    
796     $results = $wd->post ("execute/sync" => { script => "$javascript", args => [] });
797    
798 root 1.4 Example: call "find_elements" to find all "IMG" elements:
799 root 1.1
800 root 1.4 $elems = $wd->post (elements => { using => "css selector", value => "img" });
801 root 1.1
802     HISTORY
803 root 1.2 This module was unintentionally created (it started inside some quickly
804     hacked-together script) simply because I couldn't get the existing
805 root 1.8 "Selenium::Remote::Driver" module to work reliably, ever, despite
806     multiple attempts over the years and trying to report multiple bugs,
807     which have been completely ignored. It's also not event-based, so,
808     yeah...
809 root 1.1
810     AUTHOR
811     Marc Lehmann <schmorp@schmorp.de>
812     http://anyevent.schmorp.de
813