ErrorHandler.pm 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package Selenium::Remote::ErrorHandler;
  2. use strict;
  3. use warnings;
  4. # ABSTRACT: Error handler for Selenium::Remote::Driver
  5. use Moo;
  6. use Carp qw(croak);
  7. # We're going to handle only codes that are errors.
  8. # http://code.google.com/p/selenium/wiki/JsonWireProtocol
  9. has STATUS_CODE => (
  10. is => 'lazy',
  11. builder => sub {
  12. return {
  13. 7 => {
  14. 'code' => 'NO_SUCH_ELEMENT',
  15. 'msg' =>
  16. 'An element could not be located on the page using the given search parameters.',
  17. },
  18. 8 => {
  19. 'code' => 'NO_SUCH_FRAME',
  20. 'msg' =>
  21. 'A request to switch to a frame could not be satisfied because the frame could not be found.',
  22. },
  23. 9 => {
  24. 'code' => 'UNKNOWN_COMMAND',
  25. 'msg' =>
  26. 'The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource.',
  27. },
  28. 10 => {
  29. 'code' => 'STALE_ELEMENT_REFERENCE',
  30. 'msg' =>
  31. 'An element command failed because the referenced element is no longer attached to the DOM.',
  32. },
  33. 11 => {
  34. 'code' => 'ELEMENT_NOT_VISIBLE',
  35. 'msg' =>
  36. 'An element command could not be completed because the element is not visible on the page.',
  37. },
  38. 12 => {
  39. 'code' => 'INVALID_ELEMENT_STATE',
  40. 'msg' =>
  41. 'An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element).',
  42. },
  43. 13 => {
  44. 'code' => 'UNKNOWN_ERROR',
  45. 'msg' =>
  46. 'An unknown server-side error occurred while processing the command.',
  47. },
  48. 15 => {
  49. 'code' => 'ELEMENT_IS_NOT_SELECTABLE',
  50. 'msg' =>
  51. 'An attempt was made to select an element that cannot be selected.',
  52. },
  53. 19 => {
  54. 'code' => 'XPATH_LOOKUP_ERROR',
  55. 'msg' =>
  56. 'An error occurred while searching for an element by XPath.',
  57. },
  58. 21 => {
  59. 'code' => 'Timeout',
  60. 'msg' =>
  61. 'An operation did not complete before its timeout expired.',
  62. },
  63. 23 => {
  64. 'code' => 'NO_SUCH_WINDOW',
  65. 'msg' =>
  66. 'A request to switch to a different window could not be satisfied because the window could not be found.',
  67. },
  68. 24 => {
  69. 'code' => 'INVALID_COOKIE_DOMAIN',
  70. 'msg' =>
  71. 'An illegal attempt was made to set a cookie under a different domain than the current page.',
  72. },
  73. 25 => {
  74. 'code' => 'UNABLE_TO_SET_COOKIE',
  75. 'msg' =>
  76. 'A request to set a cookie\'s value could not be satisfied.',
  77. },
  78. 26 => {
  79. 'code' => 'UNEXPECTED_ALERT_OPEN',
  80. 'msg' => 'A modal dialog was open, blocking this operation',
  81. },
  82. 27 => {
  83. 'code' => 'NO_ALERT_OPEN_ERROR',
  84. 'msg' =>
  85. 'An attempt was made to operate on a modal dialog when one was not open.',
  86. },
  87. 28 => {
  88. 'code' => 'SCRIPT_TIMEOUT',
  89. 'msg' =>
  90. 'A script did not complete before its timeout expired.',
  91. },
  92. 29 => {
  93. 'code' => 'INVALID_ELEMENT_COORDINATES',
  94. 'msg' =>
  95. 'The coordinates provided to an interactions operation are invalid.',
  96. },
  97. 30 => {
  98. 'code' => 'IME_NOT_AVAILABLE',
  99. 'msg' => 'IME was not available.',
  100. },
  101. 31 => {
  102. 'code' => 'IME_ENGINE_ACTIVATION_FAILED',
  103. 'msg' => 'An IME engine could not be started.',
  104. },
  105. 32 => {
  106. 'code' => 'INVALID_SELECTOR',
  107. 'msg' => 'Argument was an invalid selector (e.g. XPath/CSS).',
  108. },
  109. };
  110. }
  111. );
  112. =head1 SUBROUTINES
  113. =head2 process_error (Selenium::Remote::Driver $driver, HTTP::Response $response)
  114. Instead of just returning the end user a server returned error code, this returns a more human readable & usable error message.
  115. Used internally in Selenium::Remote::Driver, but overriding this might be useful in some situations.
  116. You could additionally alter the STATUS_CODE parameter of this module to add extra handlers if the situation warrants it.
  117. =cut
  118. sub process_error {
  119. my ( $self, $resp ) = @_;
  120. # TODO: Handle screen if it sent back with the response. Either we could
  121. # let the end user handle it or we can save it an image file at a temp
  122. # location & return the path.
  123. # handle stacktrace-only responses by assuming unknown error
  124. my $is_stacktrace = !$resp->{status};
  125. $resp->{status} = 13 unless $resp->{status};
  126. my $ret;
  127. #XXX capitalization is inconsistent among geckodriver versions
  128. $ret->{'stackTrace'} = $resp->{'value'}->{'stacktrace'}
  129. // $resp->{'value'}->{'stackTrace'};
  130. $ret->{'error'} =
  131. $is_stacktrace
  132. ? $resp->{value}->{error}
  133. : $self->STATUS_CODE->{ $resp->{'status'} };
  134. $ret->{'message'} = $resp->{'value'}->{'message'};
  135. return $ret;
  136. }
  137. 1;
  138. __END__