ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-WebDriver/README
Revision: 1.3
Committed: Tue Aug 28 23:33:10 2018 UTC (5 years, 9 months ago) by root
Branch: MAIN
CVS Tags: rel-0_1
Changes since 1.2: +38 -27 lines
Log Message:
0.1

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     This module aims to implement the W3C WebDriver specification which is
27     the standardised equivalent to the Selenium WebDriver API., which in
28     turn aims at remotely controlling web browsers such as Firefox or
29     Chromium.
30    
31     At the time of this writing, it was only available as a draft document,
32     so changes will be expected. Also, only geckodriver did implement it, or
33     at least, most of it.
34    
35     To make most of this module, or, in fact, to make any reasonable use of
36     this module, you would need to refer tot he W3C WebDriver document,
37     which can be found here <https://w3c.github.io/webdriver/>:
38    
39     https://w3c.github.io/webdriver/
40    
41     CREATING WEBDRIVER OBJECTS
42     new AnyEvent::WebDriver key => value...
43 root 1.3 Create a new WebDriver object. Example for a remote WebDriver
44 root 1.1 connection (the only type supported at the moment):
45    
46     my $wd = new AnyEvent::WebDriver host => "localhost", port => 4444;
47    
48     Supported keys are:
49    
50     endpoint => $string
51     For remote connections, the endpoint to connect to (defaults to
52     "http://localhost:4444").
53    
54     proxy => $proxyspec
55     The proxy to use (same as the "proxy" argument used by
56     AnyEvent::HTTP). The default is "undef", which disables proxies.
57     To use the system-provided proxy (e.g. "http_proxy" environment
58     variable), specify a value of "default".
59    
60     autodelete => $boolean
61     If true (the default), then automatically execute
62     "delete_session" when the WebDriver object is destroyed with an
63     active session. IF set to a false value, then the session will
64     continue to exist.
65    
66 root 1.3 timeout => $seconds
67     The HTTP timeout, in (fractional) seconds (default: 300, but
68     this will likely drastically reduce). This timeout is reset on
69     any activity, so it is not an overall request timeout. Also,
70     individual requests might extend this timeout if they are known
71     to take longer.
72    
73 root 1.1 SIMPLIFIED API
74     This section documents the simplified API, which is really just a very
75     thin wrapper around the WebDriver protocol commands. They all block
76     (using AnyEvent condvars) the caller until the result is available, so
77     must not be called from an event loop callback - see "EVENT BASED API"
78     for an alternative.
79    
80 root 1.3 The method names are pretty much taken directly from the W3C WebDriver
81 root 1.1 specification, e.g. the request documented in the "Get All Cookies"
82     section is implemented via the "get_all_cookies" method.
83    
84 root 1.3 The order is the same as in the WebDriver draft at the time of this
85 root 1.1 writing, and only minimal massaging is done to request parameters and
86     results.
87    
88     SESSIONS
89     $wd->new_session ({ key => value... })
90 root 1.3 Try to connect to the WebDriver and initialize a new session with a
91     "new session" command, passing the given key-value pairs as value
92     (e.g. "capabilities").
93 root 1.1
94     No session-dependent methods must be called before this function
95 root 1.3 returns successfully, and only one session can be created per
96     WebDriver object.
97 root 1.1
98 root 1.3 On success, "$wd->{sid}" is set to the session ID, and
99 root 1.1 "$wd->{capabilities}" is set to the returned capabilities.
100    
101 root 1.3 my $wd = new AnyEvent::Selenium endpoint => "http://localhost:4545";
102 root 1.1
103     $wd->new_session ({
104     capabilities => {
105     pageLoadStrategy => "normal",
106     }.
107     });
108    
109     $wd->delete_session
110     Deletes the session - the WebDriver object must not be used after
111     this call.
112    
113     $timeouts = $wd->get_timeouts
114     Get the current timeouts, e.g.:
115    
116     my $timeouts = $wd->get_timeouts;
117 root 1.3 => { implicit => 0, pageLoad => 300000, script => 30000 }
118 root 1.1
119     $wd->set_timeouts ($timeouts)
120     Sets one or more timeouts, e.g.:
121    
122     $wd->set_timeouts ({ script => 60000 });
123    
124     NAVIGATION
125     $wd->navigate_to ($url)
126     Navigates to the specified URL.
127    
128     $url = $wd->get_current_url
129 root 1.3 Queries the current page URL as set by "navigate_to".
130 root 1.1
131     $wd->back
132     The equivalent of pressing "back" in the browser.
133    
134     $wd->forward
135     The equivalent of pressing "forward" in the browser.
136    
137     $wd->refresh
138     The equivalent of pressing "refresh" in the browser.
139    
140     $title = $wd->get_title
141     Returns the current document title.
142    
143     COMMAND CONTEXTS
144     $handle = $wd->get_window_handle
145     Returns the current window handle.
146    
147     $wd->close_window
148     Closes the current browsing context.
149    
150     $wd->switch_to_window ($handle)
151     Changes the current browsing context to the given window.
152    
153     $handles = $wd->get_window_handles
154     Return the current window handles as an array-ref of handle IDs.
155    
156     $handles = $wd->switch_to_frame ($frame)
157 root 1.3 Switch to the given frame identified by $frame, which must be either
158     "undef" to go back to the top-level browsing context, an integer to
159     select the nth subframe, or an element object (as e.g. returned by
160     the "element_object" method.
161 root 1.1
162     $handles = $wd->switch_to_parent_frame
163     Switch to the parent frame.
164    
165     $rect = $wd->get_window_rect
166     Return the current window rect, e.g.:
167    
168     $rect = $wd->get_window_rect
169 root 1.3 => { height => 1040, width => 540, x => 0, y => 0 }
170 root 1.1
171     $wd->set_window_rect ($rect)
172     Sets the window rect.
173    
174     $wd->maximize_window
175     $wd->minimize_window
176     $wd->fullscreen_window
177 root 1.3 Changes the window size by either maximising, minimising or making
178     it fullscreen. In my experience, this will timeout if no window
179 root 1.1 manager is running.
180    
181     ELEMENT RETRIEVAL
182     $element_id = $wd->find_element ($location_strategy, $selector)
183     Finds the first element specified by the given selector and returns
184 root 1.3 its web element ID (the strong, not the object from the protocol).
185 root 1.1 Raises an error when no element was found.
186    
187     $element = $wd->find_element ("css selector" => "body a");
188     $element = $wd->find_element ("link text" => "Click Here For Porn");
189     $element = $wd->find_element ("partial link text" => "orn");
190     $element = $wd->find_element ("tag name" => "input");
191     $element = $wd->find_element ("xpath" => '//input[@type="text"]');
192 root 1.3 => e.g. "decddca8-5986-4e1d-8c93-efe952505a5f"
193 root 1.1
194     $element_ids = $wd->find_elements ($location_strategy, $selector)
195     As above, but returns an arrayref of all found element IDs.
196    
197     $element_id = $wd->find_element_from_element ($element_id,
198     $location_strategy, $selector)
199     Like "find_element", but looks only inside the specified $element.
200    
201     $element_ids = $wd->find_elements_from_element ($element_id,
202     $location_strategy, $selector)
203     Like "find_elements", but looks only inside the specified $element.
204    
205     my $head = $wd->find_element ("tag name" => "head");
206     my $links = $wd->find_elements_from_element ($head, "tag name", "link");
207    
208     $element_id = $wd->get_active_element
209     Returns the active element.
210    
211     ELEMENT STATE
212     $bool = $wd->is_element_selected
213     Returns whether the given input or option element is selected or
214     not.
215    
216     $string = $wd->get_element_attribute ($element_id, $name)
217     Returns the value of the given attribute.
218    
219     $string = $wd->get_element_property ($element_id, $name)
220     Returns the value of the given property.
221    
222     $string = $wd->get_element_css_value ($element_id, $name)
223 root 1.3 Returns the value of the given CSS value.
224 root 1.1
225     $string = $wd->get_element_text ($element_id)
226     Returns the (rendered) text content of the given element.
227    
228     $string = $wd->get_element_tag_name ($element_id)
229     Returns the tag of the given element.
230    
231     $rect = $wd->get_element_rect ($element_id)
232 root 1.3 Returns the element rect(angle) of the given element.
233 root 1.1
234     $bool = $wd->is_element_enabled
235     Returns whether the element is enabled or not.
236    
237     ELEMENT INTERACTION
238     $wd->element_click ($element_id)
239     Clicks the given element.
240    
241     $wd->element_clear ($element_id)
242     Clear the contents of the given element.
243    
244     $wd->element_send_keys ($element_id, $text)
245     Sends the given text as key events to the given element.
246    
247     DOCUMENT HANDLING
248     $source = $wd->get_page_source
249     Returns the (HTML/XML) page source of the current document.
250    
251     $results = $wd->execute_script ($javascript, $args)
252     Synchronously execute the given script with given arguments and
253     return its results ($args can be "undef" if no arguments are
254     wanted/needed).
255    
256     $ten = $wd->execute_script ("return arguments[0]+arguments[1]", [3, 7]);
257    
258     $results = $wd->execute_async_script ($javascript, $args)
259     Similar to "execute_script", but doesn't wait for script to return,
260     but instead waits for the script to call its last argument, which is
261     added to $args automatically.
262    
263     $twenty = $wd->execute_async_script ("arguments[0](20)", undef);
264    
265     COOKIES
266     $cookies = $wd->get_all_cookies
267     Returns all cookies, as an arrayref of hashrefs.
268    
269     # google surely sets a lot of cookies without my consent
270     $wd->navigate_to ("http://google.com");
271     use Data::Dump;
272     ddx $wd->get_all_cookies;
273    
274     $cookie = $wd->get_named_cookie ($name)
275     Returns a single cookie as a hashref.
276    
277     $wd->add_cookie ($cookie)
278     Adds the given cookie hashref.
279    
280     $wd->delete_cookie ($name)
281     Delete the named cookie.
282    
283     $wd->delete_all_cookies
284     Delete all cookies.
285    
286     ACTIONS
287     $wd->perform_actions ($actions)
288     Perform the given actions (an arrayref of action specifications
289     simulating user activity). For further details, read the spec.
290    
291     An example to get you started:
292    
293     $wd->navigate_to ("https://duckduckgo.com/html");
294     $wd->set_timeouts ({ implicit => 10000 });
295     my $input = $wd->find_element ("css selector", 'input[type="text"]');
296     $wd->perform_actions ([
297     {
298     id => "myfatfinger",
299     type => "pointer",
300     pointerType => "touch",
301     actions => [
302     { type => "pointerMove", duration => 100, origin => $wd->element_object ($input), x => 40, y => 5 },
303     { type => "pointerDown", button => 1 },
304     { type => "pause", duration => 40 },
305     { type => "pointerUp", button => 1 },
306     ],
307     },
308     {
309     id => "mykeyboard",
310     type => "key",
311     actions => [
312     { type => "pause" },
313     { type => "pause" },
314     { type => "pause" },
315     { type => "pause" },
316     { type => "keyDown", value => "a" },
317     { type => "pause", duration => 100 },
318     { type => "keyUp", value => "a" },
319     { type => "pause", duration => 100 },
320     { type => "keyDown", value => "b" },
321     { type => "pause", duration => 100 },
322     { type => "keyUp", value => "b" },
323     { type => "pause", duration => 2000 },
324     { type => "keyDown", value => "\x{E007}" }, # enter
325     { type => "pause", duration => 100 },
326     { type => "keyUp", value => "\x{E007}" }, # enter
327     { type => "pause", duration => 5000 },
328     ],
329     },
330     ]);
331    
332     $wd->release_actions
333     Release all keys and pointer buttons currently depressed.
334    
335     USER PROMPTS
336     $wd->dismiss_alert
337     Dismiss a simple dialog, if present.
338    
339     $wd->accept_alert
340     Accept a simple dialog, if present.
341    
342     $text = $wd->get_alert_text
343     Returns the text of any simple dialog.
344    
345     $text = $wd->send_alert_text
346     Fills in the user prompt with the given text.
347    
348     SCREEN CAPTURE
349     $wd->take_screenshot
350 root 1.3 Create a screenshot, returning it as a PNG image in a "data:" URL.
351 root 1.1
352     $wd->take_element_screenshot ($element_id)
353     Accept a simple dialog, if present.
354    
355     HELPER METHODS
356 root 1.3 $object = AnyEvent::WebDriver->element_object ($element_id)
357 root 1.1 $object = $wd->element_object ($element_id)
358 root 1.3 Encoding element IDs in data structures is done by representing them
359     as an object with a special key and the element ID as value. This
360 root 1.1 helper method does this for you.
361    
362     EVENT BASED API
363     This module wouldn't be a good AnyEvent citizen if it didn't have a true
364     event-based API.
365    
366     In fact, the simplified API, as documented above, is emulated via the
367     event-based API and an "AUTOLOAD" function that automatically provides
368     blocking wrappers around the callback-based API.
369    
370     Every method documented in the "SIMPLIFIED API" section has an
371     equivalent event-based method that is formed by appending a underscore
372     ("_") to the method name, and appending a callback to the argument list
373     (mnemonic: the underscore indicates the "the action is not yet finished"
374     after the call returns).
375    
376     For example, instead of a blocking calls to "new_session", "navigate_to"
377     and "back", you can make a callback-based ones:
378    
379     my $cv = AE::cv;
380    
381     $wd->new_session ({}, sub {
382     my ($status, $value) = @_,
383    
384     die "error $value->{error}" if $status ne "200";
385    
386     $wd->navigate_to_ ("http://www.nethype.de", sub {
387    
388     $wd->back_ (sub {
389     print "all done\n";
390     $cv->send;
391     });
392    
393     });
394     });
395    
396     $cv->recv;
397    
398     While the blocking methods "croak" on errors, the callback-based ones
399     all pass two values to the callback, $status and $res, where $status is
400 root 1.3 the HTTP status code (200 for successful requests, typically 4xx or 5xx
401 root 1.1 for errors), and $res is the value of the "value" key in the JSON
402     response object.
403    
404     Other than that, the underscore variants and the blocking variants are
405     identical.
406    
407     LOW LEVEL API
408 root 1.3 All the simplified API methods are very thin wrappers around WebDriver
409     commands of the same name. They are all implemented in terms of the
410 root 1.1 low-level methods ("req", "get", "post" and "delete"), which exists in
411     blocking and callback-based variants ("req_", "get_", "post_" and
412     "delete_").
413    
414     Examples are after the function descriptions.
415    
416     $wd->req_ ($method, $uri, $body, $cb->($status, $value))
417     $value = $wd->req ($method, $uri, $body)
418     Appends the $uri to the "endpoint/session/{sessionid}/" URL and
419     makes a HTTP $method request ("GET", "POST" etc.). "POST" requests
420     can provide a UTF-8-encoded JSON text as HTTP request body, or the
421     empty string to indicate no body is used.
422    
423     For the callback version, the callback gets passed the HTTP status
424     code (200 for every successful request), and the value of the
425     "value" key in the JSON response object as second argument.
426    
427     $wd->get_ ($uri, $cb->($status, $value))
428     $value = $wd->get ($uri)
429     Simply a call to "req_" with $method set to "GET" and an empty body.
430    
431     $wd->post_ ($uri, $data, $cb->($status, $value))
432     $value = $wd->post ($uri, $data)
433     Simply a call to "req_" with $method set to "POST" - if $body is
434     "undef", then an empty object is send, otherwise, $data must be a
435     valid request object, which gets encoded into JSON for you.
436    
437     $wd->delete_ ($uri, $cb->($status, $value))
438     $value = $wd->delete ($uri)
439     Simply a call to "req_" with $method set to "DELETE" and an empty
440     body.
441    
442     Example: implement "get_all_cookies", which is a simple "GET" request
443     without any parameters:
444    
445     $cookies = $wd->get ("cookie");
446    
447     Example: implement "execute_script", which needs some parameters:
448    
449     $results = $wd->post ("execute/sync" => { script => "$javascript", args => [] });
450    
451     Example: call "find_elements" to find all "IMG" elements, stripping the
452     returned element objects to only return the element ID strings:
453    
454     my $elems = $wd->post (elements => { using => "css selector", value => "img" });
455    
456 root 1.3 # yes, the W3C found an interesting way around the typelessness of JSON
457 root 1.1 $_ = $_->{"element-6066-11e4-a52e-4f735466cecf"}
458     for @$elems;
459    
460     HISTORY
461 root 1.2 This module was unintentionally created (it started inside some quickly
462     hacked-together script) simply because I couldn't get the existing
463 root 1.1 "Selenium::Remote::Driver" module to work, ever, despite multiple
464     attempts over the years and trying to report multiple bugs, which have
465     been completely ignored. It's also not event-based, so, yeah...
466    
467     AUTHOR
468     Marc Lehmann <schmorp@schmorp.de>
469     http://anyevent.schmorp.de
470