ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-WebDriver/README
Revision: 1.1
Committed: Tue Aug 28 22:55:57 2018 UTC (5 years, 10 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

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