File Coverage

blib/lib/Selenium/Client/Commands.pm
Criterion Covered Total %
statement 9 32 28.1
branch 0 4 0.0
condition n/a
subroutine 3 13 23.0
pod 0 5 0.0
total 12 54 22.2


line stmt bran cond sub pod time code
1             package Selenium::Client::Commands;
2             $Selenium::Client::Commands::VERSION = '2.01';
3             # ABSTRACT: Map commands from Selenium 3 to 4
4              
5 2     2   227367 use strict;
  2         4  
  2         117  
6 2     2   15 use warnings;
  2         3  
  2         140  
7              
8 2     2   618 use Carp::Always;
  2         946  
  2         17  
9              
10             # Polyfill from Selenium 4's spec to JSONWire + Selenium 3
11             my %using = (
12             'class name' => sub { ( "css selector", ".$_[0]" ) },
13             'name' => sub { ( "css selector", "[name='$_[0]']" ) },
14             'id' => sub { ( "css selector", "#$_[0]" ) },
15             );
16              
17             sub _toughshit {
18 0     0     my ( $session, $params, $cmd ) = @_;
19 0           die "Sorry, Selenium 4 does not support $cmd! Try downgrading your browser, driver binary, Selenium JAR and so forth to something that understands JSONWire protocol, Selenium 3, or use playwright which supports all this functionality and more.";
20             }
21              
22             sub _emit {
23 0     0     my ( $session, $ret ) = @_;
24 0           return $ret;
25             }
26              
27             sub _emit_null_ok {
28 0     0     my ( $session, $ret ) = @_;
29 0           return !defined $ret;
30             }
31              
32             sub _timeout {
33 0     0     my ( $session, $params ) = @_;
34 0           return $session->SetTimeouts(%$params);
35             }
36              
37             sub _sess_uc {
38 0     0     my ( $session, $params, $cmd ) = @_;
39 0           $cmd = ucfirst($cmd);
40 0 0         die "NO SESSION PROVIDED!" unless $session;
41 0           return $session->$cmd(%$params);
42             }
43              
44             my %command_map = (
45             'status' => {
46             driver => 1,
47             execute => sub {
48             my ( $driver, $params ) = @_;
49             return $driver->Status();
50             },
51             parse => sub {
52             my ( $driver, $ret ) = @_;
53             return $ret;
54             },
55             },
56             'newSession' => {
57             driver => 1,
58             execute => sub {
59             my ( $driver, $params ) = @_;
60             foreach my $key ( keys(%$params) ) {
61              
62             #XXX may not be the smartest idea
63             delete $params->{$key} unless $params->{$key};
64             }
65              
66             my %in = %$params ? ( capabilities => { alwaysMatch => $params } ) : ();
67              
68             #XXX TODO the params we build here are worse than what is autobuilt by default. Ignore them totally.
69             my @ret = $driver->NewSession();
70             return [@ret];
71             },
72             parse => sub {
73             my ( $driver, $ret ) = @_;
74             my ( $capabilities, $session ) = @$ret;
75             return { capabilities => $capabilities, session => $session };
76             },
77             },
78             'setTimeout' => {
79             execute => \&_timeout,
80             parse => \&_emit,
81             },
82             'setAsyncScriptTimeout' => {
83             execute => \&_timeout,
84             parse => \&_emit,
85             },
86             'setImplicitWaitTimeout' => {
87             execute => \&_timeout,
88             parse => \&_emit,
89             },
90             'getTimeouts' => {
91             execute => sub {
92             my ( $session, $params ) = @_;
93             return $session->GetTimeouts();
94             },
95             parse => \&_emit,
96             },
97              
98             #TODO murder the driver object too
99             'quit' => {
100             execute => sub {
101             my ( $session, $params ) = @_;
102             return $session->DeleteSession( sessionid => $session->{sessionid} );
103             },
104             parse => \&_emit_null_ok,
105             },
106             'getCurrentWindowHandle' => {
107             execute => sub {
108             my ( $session, $params ) = @_;
109             return $session->GetWindowHandle(%$params);
110             },
111             parse => \&_emit,
112             },
113             'getWindowHandles' => {
114             execute => \&_sess_uc,
115             parse => \&_emit,
116             },
117              
118             #TODO May require output filtering
119             'getWindowSize' => {
120             execute => sub {
121             my ( $session, $params ) = @_;
122             return $session->GetWindowRect(%$params);
123             },
124             parse => \&_emit,
125             },
126             'getWindowPosition' => {
127             execute => sub {
128             my ( $session, $params ) = @_;
129             return $session->GetWindowRect(%$params);
130             },
131             parse => \&_emit,
132             },
133             'getWindowRect' => {
134             execute => \&_sess_uc,
135             parse => \&_emit,
136             },
137             'setWindowRect' => {
138             execute => \&_sess_uc,
139             parse => \&_emit,
140             },
141             'maximizeWindow' => {
142             execute => \&_sess_uc,
143             parse => \&_emit,
144             },
145             'minimizeWindow' => {
146             execute => \&_sess_uc,
147             parse => \&_emit,
148             },
149             'fullscreenWindow' => {
150             execute => \&_sess_uc,
151             parse => \&_emit,
152             },
153             'setWindowSize' => {
154             execute => sub {
155             my ( $session, $params ) = @_;
156             return $session->SetWindowRect(%$params);
157             },
158             parse => \&_emit_null_ok,
159             },
160             'setWindowPosition' => {
161             execute => sub {
162             my ( $session, $params ) = @_;
163             return $session->SetWindowRect(%$params);
164             },
165             parse => \&_emit_null_ok,
166             },
167             'getCurrentUrl' => {
168             execute => sub {
169             my ( $session, $params ) = @_;
170             return $session->GetCurrentURL(%$params);
171             },
172             parse => \&_emit,
173             },
174             'get' => {
175             execute => sub {
176             my ( $session, $params ) = @_;
177             return $session->NavigateTo(%$params);
178             },
179             parse => \&_emit_null_ok,
180             },
181             'goForward' => {
182             execute => sub {
183             my ( $session, $params ) = @_;
184             return $session->Forward(%$params);
185             },
186             parse => \&_emit_null_ok,
187             },
188             'goBack' => {
189             execute => sub {
190             my ( $session, $params ) = @_;
191             return $session->Back(%$params);
192             },
193             parse => \&_emit_null_ok,
194             },
195             'refresh' => {
196             execute => \&_sess_uc,
197             parse => \&_emit,
198             },
199             'executeScript' => {
200             execute => \&_sess_uc,
201             parse => \&_emit,
202             },
203             'executeAsyncScript' => {
204             execute => \&_sess_uc,
205             parse => \&_emit,
206             },
207             'screenshot' => {
208             execute => sub {
209             my ( $session, $params ) = @_;
210             $session->TakeScreenshot(%$params);
211             },
212             parse => \&_emit,
213             },
214             'elementScreenshot' => {
215             session => 1,
216             execute => sub {
217             my ( $session, $params ) = @_;
218             $session->TakeElementScreenshot(%$params);
219             },
220             parse => \&_emit,
221             },
222             'availableEngines' => {
223             execute => \&_toughshit,
224             },
225             'switchToFrame' => {
226             execute => \&_sess_uc,
227             parse => \&_emit_null_ok,
228             },
229             'switchToParentFrame' => {
230             execute => \&_sess_uc,
231             parse => \&_emit_null_ok,
232             },
233             'switchToWindow' => {
234             execute => \&_sess_uc,
235             parse => \&_emit_null_ok,
236             },
237             'getAllCookies' => {
238             execute => \&_sess_uc,
239             parse => \&_emit,
240             },
241             'getCookieNamed' => {
242             execute => sub {
243             my ( $session, $params ) = @_;
244             return $session->GetNamedCookie(%$params);
245             },
246             parse => \&_emit,
247             },
248             'addCookie' => {
249             execute => \&_sess_uc,
250             parse => \&_emit_null_ok,
251             },
252             'deleteAllCookies' => {
253             execute => \&_sess_uc,
254             parse => \&_emit_null_ok,
255             },
256             'deleteCookieNamed' => {
257             execute => sub {
258             my ( $session, $params ) = @_;
259             return $session->DeleteCookie(%$params);
260             },
261             parse => \&_emit,
262             },
263             'getPageSource' => {
264             execute => \&_sess_uc,
265             parse => \&_emit,
266             },
267             'getTitle' => {
268             execute => \&_sess_uc,
269             parse => \&_emit,
270             },
271             'findElement' => {
272             scd => 1,
273             execute => sub {
274             my ( $driver, $params ) = @_;
275              
276             # Fix old selector types
277             ( $params->{using}, $params->{value} ) = $using{ $params->{using} }->( $params->{value} ) if exists $using{ $params->{using} };
278             my $element = $driver->session->FindElement(%$params);
279             return $element;
280             },
281             parse => \&_emit,
282             },
283             'findElements' => {
284             scd => 1,
285             execute => sub {
286             my ( $driver, $params ) = @_;
287              
288             # Fix old selector types
289             ( $params->{using}, $params->{value} ) = $using{ $params->{using} }->( $params->{value} ) if exists $using{ $params->{using} };
290             my @elements = $driver->session->FindElements(%$params);
291             return wantarray ? @elements : \@elements;
292             },
293             parse => \&_emit,
294             },
295             'getActiveElement' => {
296             execute => \&_sess_uc,
297             parse => \&_emit,
298             },
299             'describeElement' => {
300             execute => \&_toughshit,
301             },
302             'findChildElement' => {
303             execute => \&_toughshit,
304             },
305             'findChildElements' => {
306             execute => \&_toughshit,
307             },
308             'clickElement' => {
309             execute => sub {
310             my ( $element, $params ) = @_;
311             $element->ElementClick(%$params);
312             },
313             parse => \&_emit_null_ok,
314             },
315              
316             # TODO polyfill as send enter?
317             'submitElement' => {
318             execute => \&_toughshit,
319             },
320             'sendKeysToElement' => {
321             execute => sub {
322             my ( $element, $params ) = @_;
323             $element->ElementSendKeys(%$params);
324             },
325             parse => \&_emit,
326             },
327             'sendKeysToActiveElement' => {
328             execute => \&_toughshit,
329             },
330             'sendModifier' => {
331             execute => \&_toughshit,
332             },
333             'isElementSelected' => {
334             execute => \&_sess_uc,
335             parse => \&_emit,
336             },
337              
338             # TODO polyfill
339             'setElementSelected' => {
340             execute => \&_toughshit,
341             },
342             'toggleElement' => {
343             execute => \&_toughshit,
344             },
345             'isElementEnabled' => {
346             element => 1,
347             execute => \&_sess_uc,
348             parse => \&_emit,
349             },
350             'getElementLocation' => {
351             execute => sub {
352             my ( $element, $params ) = @_;
353             return $element->GetElementRect(%$params);
354             },
355             parse => \&_emit,
356             },
357             'getElementRect' => {
358             execute => \&_sess_uc,
359             parse => \&_emit,
360             },
361             'getElementLocationInView' => {
362             execute => \&_toughshit,
363             },
364             'getElementTagName' => {
365             execute => \&_sess_uc,
366             parse => \&_emit,
367             },
368             'clearElement' => {
369             execute => sub {
370             my ( $element, $params ) = @_;
371             return $element->ElementClear(%$params);
372             },
373             parse => \&_emit,
374             },
375             'getElementAttribute' => {
376             execute => \&_sess_uc,
377             parse => \&_emit,
378             },
379             'getElementProperty' => {
380             execute => \&_sess_uc,
381             parse => \&_emit,
382             },
383              
384             # TODO polyfills
385             'elementEquals' => {
386             execute => \&_toughshit,
387             },
388             'isElementDisplayed' => {
389             execute => \&_toughshit,
390             },
391             'close' => {
392             execute => sub {
393             my ( $session, $params ) = @_;
394             $session->CloseWindow(%$params);
395             },
396             parse => \&_emit_null_ok,
397             },
398             'getElementSize' => {
399             execute => sub {
400             my ( $element, $params ) = @_;
401             return $element->GetElementRect(%$params);
402             },
403             parse => \&_emit,
404             },
405             'getElementText' => {
406             execute => \&_sess_uc,
407             parse => \&_emit,
408             },
409             'getElementValueOfCssProperty' => {
410             execute => sub {
411             my ( $element, $params ) = @_;
412             return $element->GetElementCSSValue(%$params);
413             },
414             parse => \&_emit,
415             },
416             'mouseMoveToLocation' => {
417             execute => \&_toughshit,
418             },
419             'getAlertText' => {
420             execute => \&_sess_uc,
421             parse => \&_emit,
422             },
423             'sendKeysToPrompt' => {
424             execute => sub {
425             my ( $session, $params ) = @_;
426             $session->SendAlertText(%$params);
427             },
428             parse => \&_emit_null_ok,
429             },
430             'acceptAlert' => {
431             execute => \&_sess_uc,
432             parse => \&_emit_null_ok,
433             },
434             'dismissAlert' => {
435             execute => \&_sess_uc,
436             parse => \&_emit_null_ok,
437             },
438             'click' => {
439             execute => \&_toughshit,
440             },
441             'doubleClick' => {
442             execute => \&_toughshit,
443             },
444             'buttonDown' => {
445             execute => \&_toughshit,
446             },
447             'buttonUp' => {
448             execute => \&_toughshit,
449             },
450             'uploadFile' => {
451             execute => \&_toughshit,
452             },
453             'getLocalStorageItem' => {
454             execute => \&_toughshit,
455             },
456             'deleteLocalStorageItem' => {
457             execute => \&_toughshit,
458             },
459             'cacheStatus' => {
460             execute => \&_toughshit,
461             },
462             'setGeolocation' => {
463             execute => \&_toughshit,
464             },
465             'getGeolocation' => {
466             execute => \&_toughshit,
467             },
468             'getLog' => {
469             execute => \&_toughshit,
470             },
471             'getLogTypes' => {
472             execute => \&_toughshit,
473             },
474             'setOrientation' => {
475             execute => \&_toughshit,
476             },
477             'getOrientation' => {
478             execute => \&_toughshit,
479             },
480              
481             # firefox extension
482             'setContext' => {
483             execute => \&_toughshit,
484             },
485             'getContext' => {
486             execute => \&_toughshit,
487             },
488              
489             # geckodriver workarounds
490             'executeScriptGecko' => {
491             execute => \&_toughshit,
492             },
493             'executeAsyncScriptGecko' => {
494             execute => \&_toughshit,
495             },
496             generalAction => {
497             session => 1,
498             execute => sub {
499             my ( $session, $params ) = @_;
500             return $session->PerformActions(%$params);
501             },
502             parse => \&_emit_null_ok,
503             },
504             releaseGeneralAction => {
505             session => 1,
506             execute => sub {
507             my ( $session, $params ) = @_;
508             return $session->ReleaseActions(%$params);
509             },
510             parse => \&_emit_null_ok,
511             },
512             );
513              
514             sub new {
515 0     0 0   my $class = shift;
516 0           return bless( {}, $class );
517             }
518              
519             # Act like S::R::C
520             sub parse_response {
521 0     0 0   my ( $self, $driver, $command, $response ) = @_;
522 0           return $command_map{$command}{parse}->( $driver, $response );
523             }
524              
525             # Act like S::R::RR
526             sub request {
527 0     0 0   my ( $self, $driver, $command, $args ) = @_;
528 0 0         die "No such command $command" unless ref $command_map{$command} eq 'HASH';
529 0           return $command_map{$command}{execute}->( $driver, $args, $command );
530             }
531              
532             sub needs_driver {
533 0     0 0   my ( $self, $command ) = @_;
534 0           return $command_map{$command}{driver};
535             }
536              
537             sub needs_scd {
538 0     0 0   my ( $self, $command ) = @_;
539 0           return $command_map{$command}{scd};
540             }
541              
542             1;
543              
544             __END__
545              
546             =pod
547              
548             =encoding UTF-8
549              
550             =head1 NAME
551              
552             Selenium::Client::Commands - Map commands from Selenium 3 to 4
553              
554             =head1 VERSION
555              
556             version 2.01
557              
558             =head1 SEE ALSO
559              
560             Please see those modules/websites for more information related to this module.
561              
562             =over 4
563              
564             =item *
565              
566             L<Selenium::Client|Selenium::Client>
567              
568             =back
569              
570             =head1 BUGS
571              
572             Please report any bugs or feature requests on the bugtracker website
573             L<https://github.com/troglodyne-internet-widgets/selenium-client-perl/issues>
574              
575             When submitting a bug or request, please include a test-file or a
576             patch to an existing test-file that illustrates the bug or desired
577             feature.
578              
579             =head1 AUTHORS
580              
581             Current Maintainers:
582              
583             =over 4
584              
585             =item *
586              
587             George S. Baugh <george@troglodyne.net>
588              
589             =back
590              
591             =head1 COPYRIGHT AND LICENSE
592              
593             Copyright (c) 2024 Troglodyne LLC
594              
595              
596             Permission is hereby granted, free of charge, to any person obtaining a copy
597             of this software and associated documentation files (the "Software"), to deal
598             in the Software without restriction, including without limitation the rights
599             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
600             copies of the Software, and to permit persons to whom the Software is
601             furnished to do so, subject to the following conditions:
602             The above copyright notice and this permission notice shall be included in all
603             copies or substantial portions of the Software.
604             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
605             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
606             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
607             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
608             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
609             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
610             SOFTWARE.
611              
612             =cut