CanStartBinary.t 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. use strict;
  2. use warnings;
  3. use File::Which qw/which/;
  4. use Selenium::Chrome;
  5. use Selenium::Firefox;
  6. use Selenium::Firefox::Binary;
  7. use Selenium::PhantomJS;
  8. use Sub::Install;
  9. use Test::Fatal;
  10. use Test::More;
  11. unless ( $ENV{RELEASE_TESTING} ) {
  12. plan skip_all => "Author tests not required for installation.";
  13. }
  14. PHANTOMJS: {
  15. SKIP: {
  16. my $has_phantomjs = which('phantomjs');
  17. skip 'Phantomjs binary not found in path', 3
  18. unless $has_phantomjs;
  19. skip 'PhantomJS binary not found in path', 3
  20. unless is_proper_phantomjs_available();
  21. my $phantom = Selenium::PhantomJS->new;
  22. is( $phantom->browser_name, 'phantomjs', 'binary phantomjs is okay');
  23. isnt( $phantom->port, 4444, 'phantomjs can start up its own binary');
  24. ok( Selenium::CanStartBinary::probe_port( $phantom->port ), 'the phantomjs binary is listening on its port');
  25. }
  26. }
  27. MANUAL: {
  28. ok( exception { PhantomJS->new( binary => '/bad/executable') },
  29. 'we throw if the user specified binary is not executable');
  30. SKIP: {
  31. my $phantom_binary = which('phantomjs');
  32. skip 'PhantomJS needed for manual binary path tests', 2
  33. unless $phantom_binary;
  34. my $manual_phantom = Selenium::PhantomJS->new(
  35. binary => $phantom_binary
  36. );
  37. isnt( $manual_phantom->port, 4444, 'manual phantom can start up user specified binary');
  38. ok( Selenium::CanStartBinary::probe_port( $manual_phantom->port ), 'the manual chrome binary is listening on its port');
  39. }
  40. }
  41. CHROME: {
  42. SKIP: {
  43. my $has_chromedriver = which('chromedriver');
  44. skip 'Chrome binary not found in path', 3
  45. unless $has_chromedriver;
  46. my $chrome = Selenium::Chrome->new(
  47. custom_args => ' --fake-arg'
  48. );
  49. like( $chrome->_construct_command, qr/--fake-arg/, 'can pass custom args');
  50. ok( $chrome->browser_name eq 'chrome', 'convenience chrome is okay' );
  51. isnt( $chrome->port, 4444, 'chrome can start up its own binary' );
  52. like( $chrome->_binary_args, qr/--url-base=wd\/hub/, 'chrome has correct webdriver context' );
  53. ok( Selenium::CanStartBinary::probe_port( $chrome->port ), 'the chrome binary is listening on its port');
  54. }
  55. }
  56. FIREFOX: {
  57. SKIP: {
  58. skip 'Firefox will not start up on UNIX without a display', 6
  59. if ($^O ne 'MSWin32' && ! $ENV{DISPLAY});
  60. SKIP: {
  61. my $has_geckodriver = which('geckodriver');
  62. skip 'Firefox geckodriver not found in path', 3
  63. unless $has_geckodriver;
  64. my $firefox = Selenium::Firefox->new;
  65. isnt( $firefox->port, 4444, 'firefox can start up its own binary');
  66. ok(Selenium::CanStartBinary::probe_port($firefox->port),
  67. 'the firefox binary is listening on its port');
  68. ok(Selenium::CanStartBinary::probe_port($firefox->marionette_port),
  69. 'the firefox binary is listening on its marionette port');
  70. EXECUTE_SCRIPT: {
  71. $firefox->get("https://www.google.com");
  72. my $elem = $firefox->find_element('div', 'css');
  73. my $script_elem = $firefox->execute_script('return arguments[0]', $elem);
  74. isa_ok($script_elem, 'Selenium::Remote::WebElement', 'execute_script element return');
  75. is($elem->id, $script_elem->id, 'Sync script returns identical WebElement id');
  76. my $async = q{
  77. var callback = arguments[arguments.length - 1];
  78. callback(arguments[0]);
  79. };
  80. my $async_elem = $firefox->execute_async_script($async, $elem);
  81. isa_ok($async_elem, 'Selenium::Remote::WebElement', 'execute_async_script element return');
  82. is($elem->id, $async_elem->id, 'Async script returns identical WebElement id');
  83. }
  84. $firefox->shutdown_binary;
  85. }
  86. SKIP: {
  87. # These are admittedly a very brittle test, so it's getting
  88. # skipped almost all the time.
  89. my $ff47_binary = '/Applications/Firefox47.app/Contents/MacOS/firefox-bin';
  90. skip 'Firefox 47 compatibility tests require FF47 to be installed', 3
  91. unless -x $ff47_binary;
  92. my $ff47 = Selenium::Firefox->new(
  93. marionette_enabled => 0,
  94. firefox_binary => $ff47_binary
  95. );
  96. isnt( $ff47->port, 4444, 'older Firefox47 can start up its own binary');
  97. ok( Selenium::CanStartBinary::probe_port( $ff47->port ),
  98. 'the older Firefox47 is listening on its port');
  99. $ff47->shutdown_binary;
  100. PROFILE: {
  101. my $encoded = 0;
  102. {
  103. package FFProfile;
  104. use Moo;
  105. extends 'Selenium::Firefox::Profile';
  106. sub _encode { $encoded++ };
  107. 1;
  108. }
  109. my $p = FFProfile->new;
  110. # we don't need to keep this browser object around at all,
  111. # we just want to run through the construction and confirm
  112. # that nothing gets encoded
  113. Selenium::Firefox->new(
  114. marionette_enabled => 0,
  115. firefox_binary => $ff47_binary,
  116. firefox_profile => $p
  117. )->shutdown_binary;
  118. is($encoded, 0, 'older Firefox47 does not encode profile unnecessarily');
  119. }
  120. }
  121. }
  122. }
  123. TIMEOUT: {
  124. SKIP: {
  125. my $has_geckodriver = which('geckodriver');
  126. skip 'Firefox geckodriver not found in path', 1
  127. unless $has_geckodriver;
  128. my $binary = Selenium::Firefox::Binary::firefox_path();
  129. skip 'Firefox browser not found in path', 1
  130. unless $binary;
  131. # Override the binary command construction so that no web driver
  132. # will start up.
  133. Sub::Install::reinstall_sub({
  134. code => sub { return '' },
  135. into => 'Selenium::CanStartBinary',
  136. as => '_construct_command'
  137. });
  138. my $start = time;
  139. eval { Selenium::Firefox->new( startup_timeout => 1 ) };
  140. # The test leaves a bit of a cushion to handle any unexpected
  141. # latency issues when starting up the browser - the important part
  142. # is that our timeout duration is _not_ the default 10 seconds.
  143. ok( time - $start < 10, 'We can specify how long to wait for a binary to be available' );
  144. }
  145. }
  146. FIXED_PORTS: {
  147. SKIP: {
  148. my $has_geckodriver = which('geckodriver');
  149. skip 'Firefox geckodriver not found in path', 1
  150. unless $has_geckodriver;
  151. my $firefox;
  152. my $port = 50000;
  153. my $socket = IO::Socket::INET->new(
  154. LocalHost => '127.0.0.1',
  155. LocalPort => $port,
  156. Proto => 'tcp',
  157. Listen => 5,
  158. ) or BAIL_OUT("Can't bind tcp port $port: $!");
  159. isa_ok(
  160. exception {
  161. Selenium::Firefox->new(
  162. binary_port => $port,
  163. fixed_ports => 1,
  164. );
  165. },
  166. qr/port $port is not free and have requested fixed ports/,
  167. "Driver failed to be created because input port $port is already occupied and flag fixed_ports is true"
  168. );
  169. $firefox = try {
  170. Selenium::Firefox->new(
  171. binary_port => $port,
  172. );
  173. };
  174. my $non_fixed_port = $firefox->port;
  175. cmp_ok($non_fixed_port, '>=', $port, "Driver could not acquire already occupied $port and a higer port $non_fixed_port was acquired");
  176. $firefox->shutdown_binary();
  177. $socket->close();
  178. }
  179. }
  180. sub is_proper_phantomjs_available {
  181. my $ver = `phantomjs --version` // '';
  182. chomp $ver;
  183. $ver =~ s/^(\d\.\d).*/$1/;
  184. return $ver >= 1.9;
  185. }
  186. done_testing;