package Selenium::Remote::Spec; $Selenium::Remote::Spec::VERSION = '1.33'; use strict; use warnings; # ABSTRACT: Implement commands for Selenium::Remote::Driver use Carp qw{croak}; use List::Util qw{any}; use Moo; extends 'Selenium::Remote::Commands'; #Ripped from the headlines: https://w3c.github.io/webdriver/webdriver-spec.html #then add 2 params for our use #Method URI Template no_content_success internal_name Command our $spec = qq{ POST session 0 newSession New Session POST session 0 getCapabilities Get Capabilities (v2->v3 shim) DELETE session/:sessionId 1 quit Delete Session GET status 0 status Status GET session/:sessionId/timeouts 0 getTimeouts Get Timeouts POST session/:sessionId/timeouts 1 setTimeout Set Page Load timeout (v2->v3 shim) POST session/:sessionId/timeouts/async_script 1 setAsyncScriptTimeout Set Async script timeout (v2->v3 shim) POST session/:sessionId/timeouts/implicit_wait 1 setImplicitWaitTimeout Set Implicit wait timeout (v2->v3 shim) POST session/:sessionId/url 1 get Navigate To GET session/:sessionId/url 0 getCurrentUrl Get Current URL POST session/:sessionId/back 1 goBack Back POST session/:sessionId/forward 1 goForward Forward POST session/:sessionId/refresh 1 refresh Refresh GET session/:sessionId/title 0 getTitle Get Title GET session/:sessionId/window 0 getCurrentWindowHandle Get Currently Focused Window Handle DELETE session/:sessionId/window 1 close Close Currently Focused Window POST session/:sessionId/window 1 switchToWindow Switch To Window GET session/:sessionId/window/handles 0 getWindowHandles Get Window Handles POST session/:sessionId/frame 1 switchToFrame Switch To Frame POST session/:sessionId/frame/parent 1 switchToParentFrame Switch To Parent Frame GET session/:sessionId/window/rect 0 getWindowRect Get Window Size/Position (v2->v3 shim) POST session/:sessionId/window/rect 1 setWindowRect Set Window Size/Position (v2->v3 shim) POST session/:sessionId/window/maximize 1 maximizeWindow Maximize Window POST session/:sessionId/window/minimize 1 minimizeWindow Minimize Window POST session/:sessionId/window/fullscreen 1 fullscreenWindow Fullscreen Window GET session/:sessionId/element/active 0 getActiveElement Get Active Element POST session/:sessionId/element 0 findElement Find Element POST session/:sessionId/elements 0 findElements Find Elements POST session/:sessionId/element/:id/element 0 findChildElement Find Element From Element POST session/:sessionId/element/:id/elements 0 findChildElements Find Elements From Element GET session/:sessionId/element/:id/selected 0 isElementSelected Is Element Selected GET session/:sessionId/element/:id/attribute/:name 0 getElementAttribute Get Element Attribute GET session/:sessionId/element/:id/property/:name 0 getElementProperty Get Element Property GET session/:sessionId/element/:id/css/:propertyName 0 getElementValueOfCssProperty Get Element CSS Value GET session/:sessionId/element/:id/text 0 getElementText Get Element Text GET session/:sessionId/element/:id/name 0 getElementTagName Get Element Tag Name GET session/:sessionId/element/:id/rect 0 getElementRect Get Element Rect GET session/:sessionId/element/:id/enabled 0 isElementEnabled Is Element Enabled POST session/:sessionId/element/:id/click 1 clickElement Element Click POST session/:sessionId/element/:id/clear 1 clearElement Element Clear POST session/:sessionId/element/:id/value 1 sendKeysToElement Element Send Keys GET session/:sessionId/source 0 getPageSource Get Page Source POST session/:sessionId/execute/sync 0 executeScript Execute Script POST session/:sessionId/execute/async 0 executeAsyncScript Execute Async Script GET session/:sessionId/cookie 0 getAllCookies Get All Cookies GET session/:sessionId/cookie/:name 0 getCookieNamed Get Named Cookie POST session/:sessionId/cookie 1 addCookie Add Cookie DELETE session/:sessionId/cookie/:name 1 deleteCookieNamed Delete Cookie DELETE session/:sessionId/cookie 1 deleteAllCookies Delete All Cookies POST session/:sessionId/actions 1 generalAction Perform Actions DELETE session/:sessionId/actions 1 releaseGeneralAction Release Actions POST session/:sessionId/alert/dismiss 1 dismissAlert Dismiss Alert POST session/:sessionId/alert/accept 1 acceptAlert Accept Alert GET session/:sessionId/alert/text 0 getAlertText Get Alert Text POST session/:sessionId/alert/text 1 sendKeysToPrompt Send Alert Text GET session/:sessionId/screenshot 0 screenshot Take Screenshot GET session/:sessionId/moz/screenshot/full 0 mozScreenshotFull Take Full Screenshot GET session/:sessionId/element/:id/screenshot 0 elementScreenshot Take Element Screenshot }; our $spec_parsed; sub get_spec { return $spec_parsed if $spec_parsed; my @split = split( /\n/, $spec ); foreach my $line (@split) { next unless $line; my ( $method, $uri, $nc_success, $key, @description ) = split( / +/, $line ); $spec_parsed->{$key} = { method => $method, url => $uri, no_content_success => int($nc_success) , #XXX this *should* always be 0, but specs lie description => join( ' ', @description ), }; } return $spec_parsed; } has '_cmds' => ( is => 'lazy', reader => 'get_cmds', builder => \&get_spec, ); has '_caps' => ( is => 'lazy', reader => 'get_caps', builder => sub { return [ 'browserName', 'acceptInsecureCerts', 'browserVersion', 'platformName', 'proxy', 'pageLoadStrategy', 'setWindowRect', 'timeouts', 'unhandledPromptBehavior', 'moz:firefoxOptions', 'chromeOptions', ]; } ); has '_caps_map' => ( is => 'lazy', reader => 'get_caps_map', builder => sub { return { browserName => 'browserName', acceptSslCerts => 'acceptInsecureCerts', version => 'browserVersion', platform => 'platformName', proxy => 'proxy', }; } ); sub get_params { my ( $self, $args ) = @_; if ( !( defined $args->{'session_id'} ) ) { return; } #Allow fall-back in the event the command passed doesn't exist return unless $self->get_cmds()->{ $args->{command} }; my $url = $self->get_url( $args->{command} ); my $data = {}; # Do the var substitutions. $url =~ s/:sessionId/$args->{'session_id'}/; $url =~ s/:id/$args->{'id'}/; $url =~ s/:name/$args->{'name'}/; $url =~ s/:propertyName/$args->{'property_name'}/; $url =~ s/:other/$args->{'other'}/; $url =~ s/:windowHandle/$args->{'window_handle'}/; $data->{'method'} = $self->get_method( $args->{command} ); $data->{'no_content_success'} = $self->get_no_content_success( $args->{command} ); $data->{'url'} = $url; #URL & data polyfills for the way selenium2 used to do things, etc $data->{payload} = {}; if ( $args->{type} ) { $data->{payload}->{pageLoad} = $args->{ms} if $data->{url} =~ m/timeouts$/ && $args->{type} eq 'page load'; $data->{payload}->{script} = $args->{ms} if $data->{url} =~ m/timeouts$/ && $args->{type} eq 'script'; $data->{payload}->{implicit} = $args->{ms} if $data->{url} =~ m/timeouts$/ && $args->{type} eq 'implicit'; } #finder polyfills #orig: class, class_name, css, id, link, link_text, partial_link_text, tag_name, name, xpath #new: "css selector", "link text", "partial link text", "tag name", "xpath" #map: class, class_name, id, name, link = 'css selector' if ( $args->{using} && $args->{value} ) { $data->{payload}->{using} = 'css selector' if grep { $args->{using} eq $_ } ( 'id', 'class name', 'name' ); $data->{payload}->{value} = "[id='$args->{value}']" if $args->{using} eq 'id'; $data->{payload}->{value} = ".$args->{value}" if $args->{using} eq 'class name'; $data->{payload}->{value} = "[name='$args->{value}']" if $args->{using} eq 'name'; } if ( $data->{url} =~ s/timeouts\/async_script$/timeouts/g ) { $data->{payload}->{script} = $args->{ms}; $data->{payload}->{type} = 'script'; #XXX chrome doesn't follow the spec } if ( $data->{url} =~ s/timeouts\/implicit_wait$/timeouts/g ) { $data->{payload}->{implicit} = $args->{ms}; $data->{payload}->{type} = 'implicit'; #XXX chrome doesn't follow the spec } $data->{payload}->{value} = $args->{text} if $args->{text} && $args->{command} ne 'sendKeysToElement'; $data->{payload}->{handle} = $args->{window_handle} if grep { $args->{command} eq $_ } qw{fullscreenWindow minimizeWindow maximizeWindow}; return $data; } sub parse_response { my ( $self, undef, $resp ) = @_; if ( ref($resp) eq 'HASH' ) { if ( $resp->{cmd_status} && $resp->{cmd_status} eq 'OK' ) { return $resp->{cmd_return}; } my $msg = "Error while executing command"; if ( ref $resp->{cmd_return} eq 'HASH' ) { $msg .= ": $resp->{cmd_return}{error}" if $resp->{cmd_return}{error}; $msg .= ": $resp->{cmd_return}{message}" if $resp->{cmd_return}{message}; } else { $msg .= ": $resp->{cmd_return}"; } croak $msg; } return $resp; } #Utility sub get_spec_differences { my $v2_spec = Selenium::Remote::Commands->new()->get_cmds(); my $v3_spec = Selenium::Remote::Spec->new()->get_cmds(); foreach my $key ( keys(%$v2_spec) ) { print "v2 $key NOT present in v3 spec!!!\n" unless any { $_ eq $key } keys(%$v3_spec); } foreach my $key ( keys(%$v3_spec) ) { print "v3 $key NOT present in v2 spec!!!\n" unless any { $_ eq $key } keys(%$v2_spec); } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Selenium::Remote::Spec - Implement commands for Selenium::Remote::Driver =head1 VERSION version 1.33 =head1 DESCRIPTION Defines all the HTTP endpoints available to execute on a selenium server. If you have either a customized Selenium Server, or want new features you should update the _cmds hash. =for Pod::Coverage *EVERYTHING* =head1 Webdriver 3 capabilities WD3 giveth and taketh away some caps. Here's all you get: Browser name: "browserName" string Identifies the user agent. Browser version: "browserVersion" string Identifies the version of the user agent. Platform name: "platformName" string Identifies the operating system of the endpoint node. Accept insecure TLS certificates: "acceptInsecureCerts" boolean Indicates whether untrusted and self-signed TLS certificates are implicitly trusted on navigation for the duration of the session. Proxy configuration: "proxy" JSON Defines the current session’s proxy configuration. New Stuff: Page load strategy: "pageLoadStrategy" string Defines the current session’s page load strategy. Window dimensioning/positioning: "setWindowRect" boolean Indicates whether the remote end supports all of the commands in Resizing and Positioning Windows. Session timeouts configuration: "timeouts" JSON Describes the timeouts imposed on certain session operations. Unhandled prompt behavior: "unhandledPromptBehavior" string Describes the current session’s user prompt handler. =head1 SEE ALSO Please see those modules/websites for more information related to this module. =over 4 =item * L =back =head1 BUGS Please report any bugs or feature requests on the bugtracker website L When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. =head1 AUTHORS Current Maintainers: =over 4 =item * Daniel Gempesaw =item * Emmanuel Peroumalnaïk =back Previous maintainers: =over 4 =item * Luke Closs =item * Mark Stosberg =back Original authors: =over 4 =item * Aditya Ivaturi =back =head1 COPYRIGHT AND LICENSE Copyright (c) 2010-2011 Aditya Ivaturi, Gordon Child Copyright (c) 2014-2017 Daniel Gempesaw Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =cut