use strict; use warnings; use Test::More; use Test::Deep; use Test::Fatal; use Scalar::Util qw{looks_like_number}; use Selenium::Remote::Driver; use Selenium::Firefox::Profile; use Selenium::Remote::Spec; #So we only modify _request_new_session to get webd3 working. #As such, we should only test that. NEWSESS: { #TODO cover case where ISA Selenium::Firefox my $self = bless({ is_wd3 => 1 },"Selenium::Remote::Driver"); my $profile = Selenium::Firefox::Profile->new(); $profile->set_preference( 'browser.startup.homepage' => 'http://www.google.com', ); my $args = { desiredCapabilities => { browserName => 'firefox', version => 666, platform => 'ANY', javascript => 1, acceptSslCerts => 1, firefox_profile => $profile, pageLoadStrategy => 'none', proxy => { proxyType => 'direct', proxyAutoconfigUrl => 'http://localhost', ftpProxy => 'localhost:1234', httpProxy => 'localhost:1234', sslProxy => 'localhost:1234', socksProxy => 'localhost:1234', socksVersion => 2, noProxy => ['http://localhost'], }, extra_capabilities => { #TODO these need to be translated as moz:firefoxOptions => {} automatically, and then to be put in the main hash binary => '/usr/bin/firefox', args => ['-profile', '~/.mozilla/firefox/vbdgri9o.default'], #gotta check this gets overridden profile => 'some Base64 string of a zip file. I should really make this a feature', log => 'trace', #trace|debug|config|info|warn|error|fatal prefs => {}, #TODO check that this is auto-set above by the Selenium::Firefox::Profile stuff webdriverClick => 0, #This option is OP, *must* be set to false 24/7 }, }, }; no warnings qw{redefine once}; local *Selenium::Remote::RemoteConnection::request = sub {return { sessionId => 'zippy', cmd_status => 'OK', cmd_return => {capabilities => 'eee'} }}; local *File::Temp::Dir::dirname = sub { return '/tmp/zippy' }; use warnings; my ($args_modified,undef) = $self->_request_new_session($args); my $expected = { 'alwaysMatch' => { 'browserVersion' => 666, 'moz:firefoxOptions' => { 'args' => [ '-profile', '/tmp/zippy' ], 'binary' => '/usr/bin/firefox', 'log' => 'trace', 'prefs' => {}, 'profile' => 'some Base64 string of a zip file. I should really make this a feature', 'webdriverClick' => 0 }, 'platformName' => 'ANY', 'proxy' => { 'ftpProxy' => 'localhost:1234', 'httpProxy' => 'localhost:1234', 'noProxy' => [ 'http://localhost' ], 'proxyAutoconfigUrl' => 'http://localhost', 'proxyType' => 'direct', 'socksProxy' => 'localhost:1234', 'socksVersion' => 2, 'sslProxy' => 'localhost:1234' }, 'browserName' => 'firefox', 'pageLoadStrategy' => 'none', acceptInsecureCerts => 1, } }; is($self->{capabilities},'eee',"Caps set correctly in wd3 mode"); is_deeply($args_modified->{capabilities},$expected,"Desired capabilities correctly translated to Firefox (WD3)"); #$expected->{alwaysMatch}->{'goog:chromeOptions'} = $expected->{alwaysMatch}->{'moz:firefoxOptions'}; $expected->{alwaysMatch}->{'moz:firefoxOptions'} = {}; #$expected->{alwaysMatch}->{'goog:chromeOptions'}->{args} = ['-profile', '~/.mozilla/firefox/vbdgri9o.default']; $expected->{alwaysMatch}->{browserName} = 'chrome'; $args->{desiredCapabilities}->{browserName} = 'chrome'; ($args_modified,undef) = $self->_request_new_session($args); is_deeply($args_modified->{capabilities},$expected,"Desired capabilities correctly translated to Krom (WD3)"); } EXECOMMAND: { #_execute_command with payload 'hitting all the right buttons' #also check that fallback works w/ the right special missing word #also check capability shortcut my $self = bless({ is_wd3 => 1, capabilities => 'wakka wakka', browser_name => 'firefox' },"Selenium::Remote::Driver"); no warnings qw{redefine once}; local *Selenium::Remote::RemoteConnection::request = sub {return { sessionId => 'zippy', cmd_status => 'OK' }}; local *Selenium::Remote::Spec::get_params = sub { my ($self,$ret) = @_; $ret->{v3} = 1; return $ret; }; local *Selenium::Remote::Commands::get_params = sub { die 'whee' }; local *Selenium::Remote::Spec::parse_response = sub { my ($self,undef,$ret) = @_; $ret->{rv3} = 1; return $ret; }; local *Selenium::Remote::Commands::parse_response = sub { die 'zippy' }; use warnings; my ($input,$params) = ({ command => 'zippy'},{ ms => 1, type=> 1, text => 1, value => 1, using => 1}); my $ret = $self->_execute_command($input,$params); is($ret->{rv3},1,"v3 code walked in _execute_command on happy path"); $input->{command} = 'getCapabilities'; $ret = $self->_execute_command($input,$params); is($ret,'wakka wakka',"v3 code walked in _execute_command on getCapabilities path"); $input->{command} = 'HORGLE'; no warnings qw{redefine once}; local *Selenium::Remote::Spec::get_params = sub { return undef; }; local *Selenium::Remote::Commands::get_params = sub { die 'whee' }; local *Selenium::Remote::Spec::parse_response = sub { my ($self,undef,$ret) = @_; $ret->{rv3} = 1; return $ret; }; local *Selenium::Remote::Commands::parse_response = sub { die 'zippy' }; use warnings; $ret = exception { $self->_execute_command($input,$params) }; like($ret,qr/whee/,"v2 fallback walked in _execute_command on getCapabilities path"); } REMOTECONN: { my $self = bless({},'Selenium::Remote::RemoteConnection'); $self->remote_server_addr('eee'); $self->port(666); no warnings qw{redefine once}; local *LWP::UserAgent::request = sub { my ($self,$req) = @_; return $req }; use warnings; my $res = $self->request({ payload => { zippy => 1}, url => 'grid', method => 'eee' },{},1); is($res->content,'{"zippy":1}',"RemoteConnection payload shim works"); } #get_cmds, get_params, parse_response #get_caps and get_caps map have already been checked above in the _request_new_session code SPEC: { my $obj = Selenium::Remote::Spec->new(); my $cmds = $obj->get_cmds(); subtest "parsing of spec blob done correctly" => sub { foreach my $key (keys(%$cmds)) { like($cmds->{$key}->{url},qr/^session|status/,"url parsed for $key correctly"); is($cmds->{$key}->{url},$obj->get_url($key),"get_url accessor works for $key"); like($cmds->{$key}->{method},qr/^GET|POST|DELETE|PUT$/,"method parsed for $key correctly"); is($cmds->{$key}->{method},$obj->get_method($key),"get_method accessor works for $key"); ok($cmds->{$key}->{description},"description parsed for $key correctly"); ok(looks_like_number($cmds->{$key}->{no_content_success}),"no_content_success parsed for $key correctly"); is($cmds->{$key}->{no_content_success},$obj->get_no_content_success($key),"get_no_content_success accessor works for $key"); } }; } SPEC_PARAMS: { no warnings qw{redefine once}; local *Selenium::Remote::Spec::get_url = sub { return ':sessionId/:id/:name/:propertyName/:other/:windowHandle/timeouts' }; use warnings; my $obj = Selenium::Remote::Spec->new(); my $args = { session_id => 'a', id => 'man', name => 'a', property_name => 'plan', other => 'a canal', window_handle => 'panama', command => 'fullscreenWindow', ms => 666, type => 'page load', using => 'id', value => 'whee', text => 'zippy', }; my $expected = { 'method' => 'POST', 'no_content_success' => 1, 'url' => 'a/man/a/plan/a canal/panama/timeouts', 'payload' => { 'handle' => 'panama', 'pageLoad' => 666, 'using' => 'css selector', 'value' => 'zippy', }, }; is_deeply($obj->get_params($args),$expected,"get_params: var substitution works, payload construction works (mostly)"); $args->{type} = 'implicit'; $expected->{payload}{implicit} = 666; delete $expected->{payload}{pageLoad}; is_deeply($obj->get_params($args),$expected,"get_params: timeout payload mongling (implicit) works"); $args->{type} = 'script'; $expected->{payload}{script} = 666; delete $expected->{payload}{implicit}; is_deeply($obj->get_params($args),$expected,"get_params: timeout payload mongling (script) works"); no warnings qw{redefine once}; local *Selenium::Remote::Spec::get_url = sub { return ':sessionId/:id/:name/:propertyName/:other/:windowHandle/timeouts/async_script' }; use warnings; $args->{type} = 'page load'; delete $expected->{payload}{pageLoad}; $expected->{payload}{script} = 666; $expected->{payload}{type} = 'script'; is_deeply($obj->get_params($args),$expected,"get_params: async_script substitution works"); no warnings qw{redefine once}; local *Selenium::Remote::Spec::get_url = sub { return ':sessionId/:id/:name/:propertyName/:other/:windowHandle/timeouts/implicit_wait' }; use warnings; delete $expected->{payload}{script}; $expected->{payload}{implicit} = 666; $expected->{payload}{type} = 'implicit'; is_deeply($obj->get_params($args),$expected,"get_params: implicit_wait substitution works"); delete $args->{text}; $expected->{payload}{value} = "[id='whee']"; is_deeply($obj->get_params($args),$expected,"get_params: id css substitution works"); $args->{using} = 'class name'; $expected->{payload}{value} = ".whee"; is_deeply($obj->get_params($args),$expected,"get_params: class name css substitution works"); $args->{using} = 'name'; $expected->{payload}{value} = "[name='whee']"; is_deeply($obj->get_params($args),$expected,"get_params: name css substitution works"); } PARSE_RESP: { my $obj = Selenium::Remote::Spec->new(); my $expected = { error => 'ID10T', 'message' => 'Please insert another quarter'}; my $args = { cmd_status => 'OK', cmd_return => $expected, }; is_deeply($obj->parse_response(undef,$args),$expected,"parse_response works"); $args->{cmd_status} = 'NOT OK'; like(exception { $obj->parse_response(undef,$args) },qr/insert another quarter/i,"parse_response throws on failure"); } done_testing();