Chrome.pm 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package Selenium::Chrome;
  2. # ABSTRACT: A convenience package for creating a Chrome instance
  3. use File::Which qw/which/;
  4. use IO::Socket::INET;
  5. use Selenium::Waiter qw/wait_until/;
  6. use Moo;
  7. use namespace::clean;
  8. extends 'Selenium::Remote::Driver';
  9. =head1 SYNOPSIS
  10. my $driver = Selenium::Chrome->new;
  11. =cut
  12. my $default_binary_server = '127.0.0.1';
  13. my $default_binary_port = 9515;
  14. has '+browser_name' => (
  15. is => 'ro',
  16. default => sub { 'chrome' }
  17. );
  18. # By shadowing the parent's port function, we can set the port in
  19. # _build_binary_mode's builder
  20. has '+port' => (
  21. is => 'lazy'
  22. );
  23. has 'binary_mode' => (
  24. is => 'ro',
  25. init_arg => undef,
  26. builder => 1
  27. );
  28. sub _build_binary_mode {
  29. my ($self) = @_;
  30. if (! $self->has_remote_server_addr && ! $self->has_port) {
  31. my $executable = _find_executable('chromedriver');
  32. my $port = _find_open_port_above($default_binary_port);
  33. my $command = _construct_command($executable, $port);
  34. system($command);
  35. my $success = wait_until { _probe_port($port) } timeout => 10;
  36. if ($success) {
  37. $self->port($port);
  38. }
  39. else {
  40. warn qq(
  41. Unable to start up the chromedriver binary via:
  42. $command
  43. We'll try falling back to standard Remote Driver mode via the webdriver.chrome.driver property...
  44. );
  45. }
  46. return 1;
  47. }
  48. else {
  49. return 0;
  50. }
  51. }
  52. sub _find_executable {
  53. my ($binary) = @_;
  54. my $executable = which($binary);
  55. if (not defined $executable) {
  56. warn q(
  57. Unable to find the chromedriver binary in your $PATH. Please download the server from http://chromedriver.storage.googleapis.com/index.html and place it somewhere on your $PATH. More info is available at http://code.google.com/p/selenium/wiki/ChromeDriver.
  58. We'll try falling back to standard Remote Driver mode via the webdriver.chrome.driver property...
  59. );
  60. }
  61. return $executable;
  62. }
  63. sub _construct_command {
  64. my ($executable, $port) = @_;
  65. my %args = (
  66. 'base-url' => 'wd/hub',
  67. 'port' => $port
  68. );
  69. my @args = map { '--' . $_ . '=' . $args{$_} } keys %args;
  70. return join(' ', ($executable, @args, '> /dev/null 2>&1 &') );
  71. }
  72. sub _find_open_port_above {
  73. my ($port) = @_;
  74. my $free_port = wait_until {
  75. if (_probe_port($port)) {
  76. $port++;
  77. return 0;
  78. }
  79. else {
  80. return $port;
  81. }
  82. };
  83. return $free_port;
  84. }
  85. sub _probe_port {
  86. my ($port) = @_;
  87. return IO::Socket::INET->new(
  88. PeerAddr => $default_binary_server,
  89. PeerPort => $port,
  90. Timeout => 3
  91. );
  92. }
  93. sub DEMOLISH {
  94. my ($self) = @_;
  95. my $port = $self->port;
  96. my $ua = LWP::UserAgent->new;
  97. $ua->get($default_binary_server . ':' . $port . '/wd/hub/shutdown');
  98. }
  99. 1;