package Selenium::Remote::Spec;
$Selenium::Remote::Spec::VERSION = '1.27';
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/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.27
=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<Selenium::Remote::Driver|Selenium::Remote::Driver>
=back
=head1 BUGS
Please report any bugs or feature requests on the bugtracker website
L<https://github.com/teodesian/Selenium-Remote-Driver/issues>
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 <gempesaw@gmail.com>
=item *
Emmanuel Peroumalnaïk <peroumalnaik.emmanuel@gmail.com>
=back
Previous maintainers:
=over 4
=item *
Luke Closs <cpan@5thplane.com>
=item *
Mark Stosberg <mark@stosberg.com>
=back
Original authors:
=over 4
=item *
Aditya Ivaturi <ivaturi@gmail.com>
=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