ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-WebDriver/README
Revision: 1.9
Committed: Fri Sep 27 03:31:02 2019 UTC (4 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-1_01
Changes since 1.8: +19 -14 lines
Log Message:
1.01

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