ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-WebDriver/README
Revision: 1.5
Committed: Wed Aug 29 05:55:23 2018 UTC (5 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-0_5
Changes since 1.4: +108 -11 lines
Log Message:
*** empty log message ***

File Contents

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