File: response.rb

package info (click to toggle)
ruby-selenium-webdriver 3.142.7%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 1,592 kB
  • sloc: ruby: 6,740; javascript: 85; makefile: 3
file content (136 lines) | stat: -rw-r--r-- 4,025 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# frozen_string_literal: true

# Licensed to the Software Freedom Conservancy (SFC) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The SFC licenses this file
# to you 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.

module Selenium
  module WebDriver
    module Remote
      # @api private
      class Response
        STACKTRACE_KEY = 'stackTrace'

        attr_reader :code, :payload
        attr_writer :payload

        def initialize(code, payload = nil)
          @code    = code
          @payload = payload || {}

          assert_ok
        end

        def error
          klass = Error.for_code(status) || return

          ex = klass.new(error_message)
          ex.set_backtrace(caller)
          add_backtrace ex

          ex
        end

        def error_message
          val = value

          case val
          when Hash
            msg = val['message']
            return 'unknown error' unless msg

            msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
            msg << " (#{val['class']})" if val['class']
            msg
          when String
            val
          else
            "unknown error, status=#{status}: #{val.inspect}"
          end
        end

        def [](key)
          @payload[key]
        end

        private

        def assert_ok
          e = error
          raise e if e
          return unless @code.nil? || @code >= 400

          raise Error::ServerError, self
        end

        def add_backtrace(ex)
          return unless error_payload.is_a?(Hash)

          # Legacy Firefox returns String in ['value'], while we expect Hash.
          # Use #dig when Firefox legacy is removed (4.0).
          server_trace = error_payload[STACKTRACE_KEY] ||
                         error_payload[STACKTRACE_KEY.downcase] ||
                         (error_payload['value'] && error_payload['value'][STACKTRACE_KEY])
          return unless server_trace

          backtrace = case server_trace
                      when Array
                        backtrace_from_remote(server_trace)
                      when String
                        server_trace.split("\n")
                      end

          ex.set_backtrace(backtrace + ex.backtrace)
        end

        def backtrace_from_remote(server_trace)
          server_trace.map { |frame|
            next unless frame.is_a?(Hash)

            file = frame['fileName']
            line = frame['lineNumber']
            meth = frame['methodName']

            class_name = frame['className']
            file = "#{class_name}(#{file})" if class_name

            meth = 'unknown' if meth.nil? || meth.empty?

            "[remote server] #{file}:#{line}:in `#{meth}'"
          }.compact
        end

        def error_payload
          # Even errors are wrapped in 'value' for w3c
          # Grab 'value' key for error, leave original payload alone and let the bridge process
          @error_payload ||= !@payload.key?('sessionId') ? @payload['value'] : @payload
        end

        def status
          return unless error_payload.is_a? Hash

          @status ||= error_payload['status'] || error_payload['error']
        end

        def value
          return unless error_payload.is_a? Hash

          @value ||= error_payload['value'] || error_payload['message']
        end
      end # Response
    end # Remote
  end # WebDriver
end # Selenium