github.com/bazelbuild/rules_webtesting@v0.2.0/go/webdriver/webdriver_error.go (about) 1 // Copyright 2016 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package webdriver 16 17 import ( 18 "encoding/json" 19 "fmt" 20 ) 21 22 type errorDatum struct { 23 Status int 24 Error string 25 HTTPStatus int 26 W3C bool 27 } 28 29 var errorData = []errorDatum{ 30 { 31 0, "Success", 200, false, 32 }, 33 { 34 6, "invalid session id", 404, true, 35 }, 36 { 37 7, "no such element", 404, true, 38 }, 39 { 40 8, "no such frame", 404, true, 41 }, 42 { 43 9, "unknown command", 404, true, 44 }, 45 { 46 10, "stale element reference", 400, true, 47 }, 48 { 49 11, "ElementNotVisible", 400, false, 50 }, 51 { 52 12, "invalid element state", 400, true, 53 }, 54 { 55 13, "unknown error", 500, true, 56 }, 57 { 58 15, "element not selectable", 400, true, 59 }, 60 { 61 17, "javascript error", 500, true, 62 }, 63 { 64 19, "XPathLookupError", 400, false, 65 }, 66 { 67 21, "timeout", 408, true, 68 }, 69 { 70 23, "no such window", 400, true, 71 }, 72 { 73 24, "invalid cookie domain", 400, true, 74 }, 75 { 76 25, "unable to set cookie", 500, true, 77 }, 78 { 79 26, "unexpected alert open", 500, true, 80 }, 81 { 82 27, "no such alert", 400, true, 83 }, 84 { 85 28, "script timeout", 408, true, 86 }, 87 { 88 29, "invalid element coordinates", 400, true, 89 }, 90 { 91 30, "IMENotAvailable", 500, false, 92 }, 93 { 94 31, "IMEEngineActivationFailed", 500, false, 95 }, 96 { 97 32, "invalid selector", 400, true, 98 }, 99 { 100 33, "session not created", 500, true, 101 }, 102 { 103 34, "move target out of bounds", 400, true, 104 }, 105 { 106 -1, "element not interactable", 400, true, 107 }, 108 { 109 -1, "invalid argument", 400, true, 110 }, 111 { 112 -1, "no such cookie", 404, true, 113 }, 114 { 115 -1, "unable to capture screen", 500, true, 116 }, 117 { 118 -1, "unknown method", 405, true, 119 }, 120 { 121 -1, "unsupported operation", 500, true, 122 }, 123 } 124 125 type webDriverError struct { 126 errDatum errorDatum 127 value interface{} 128 message string 129 stackTrace interface{} 130 } 131 132 func newWebDriverError(resp *jsonResp) error { 133 return &webDriverError{ 134 errDatum: errDatum(resp), 135 value: errValue(resp), 136 message: errMessage(resp), 137 stackTrace: errStackTrace(resp), 138 } 139 } 140 141 func errDatum(resp *jsonResp) errorDatum { 142 if resp.Error != "" { 143 for _, cand := range errorData { 144 if cand.Error == resp.Error { 145 return cand 146 } 147 } 148 } 149 if value, ok := resp.Value.(map[string]interface{}); ok { 150 if e, ok := value["error"].(string); ok && e != "" { 151 for _, cand := range errorData { 152 if cand.Error == e { 153 return cand 154 } 155 } 156 } 157 } 158 if resp.Status != nil && *resp.Status != 0 { 159 for _, cand := range errorData { 160 if cand.Status == *resp.Status { 161 return cand 162 } 163 } 164 } 165 status := -1 166 if resp.Status != nil { 167 status = *resp.Status 168 } 169 return errorDatum{status, resp.Error, 500, false} 170 } 171 172 func errMessage(resp *jsonResp) string { 173 if resp.Message != "" { 174 return resp.Message 175 } 176 value, _ := resp.Value.(map[string]interface{}) 177 message, _ := value["message"].(string) 178 return message 179 } 180 181 func errStackTrace(resp *jsonResp) interface{} { 182 if resp.StackTrace != nil { 183 return resp.StackTrace 184 } 185 value, _ := resp.Value.(map[string]interface{}) 186 return value["stacktrace"] 187 } 188 189 func errValue(resp *jsonResp) interface{} { 190 if resp.Value != nil { 191 return resp.Value 192 } 193 val := map[string]interface{}{} 194 if resp.Message != "" { 195 val["message"] = resp.Message 196 } 197 if resp.StackTrace != nil { 198 val["stacktrace"] = resp.StackTrace 199 } 200 return val 201 } 202 203 func (e *webDriverError) Component() string { 204 return compName 205 } 206 207 func (e *webDriverError) Error() string { 208 message := e.value 209 if mapValue, ok := message.(map[string]interface{}); ok { 210 if m, ok := mapValue["message"]; ok { 211 message = m 212 } 213 } 214 215 if e.errDatum.W3C { 216 return fmt.Sprintf("[%s] (%s) %v", e.Component(), e.errDatum.Error, message) 217 } 218 219 return fmt.Sprintf("[%s] (%d) %v", e.Component(), e.errDatum.Status, message) 220 } 221 222 // IsWebDriverError returns true if err is a WebDriver Error. 223 func IsWebDriverError(err error) bool { 224 _, ok := err.(*webDriverError) 225 return ok 226 } 227 228 // ErrorStatus returns the WebDriver status for err. 229 func ErrorStatus(err error) int { 230 we, ok := err.(*webDriverError) 231 if !ok { 232 return 13 233 } 234 if we.errDatum.Status <= 0 { 235 return 13 236 } 237 return we.errDatum.Status 238 } 239 240 // ErrorValue returns the WebDriver value for err. 241 func ErrorValue(err error) interface{} { 242 we, ok := err.(*webDriverError) 243 if !ok { 244 return map[string]interface{}{"message": err.Error()} 245 } 246 return we.value 247 } 248 249 // ErrorStackTrace returns the WebDriver value for err. 250 func ErrorStackTrace(err error) interface{} { 251 we, ok := err.(*webDriverError) 252 if !ok { 253 return nil 254 } 255 return we.stackTrace 256 } 257 258 // ErrorMessage returns the WebDriver value for err. 259 func ErrorMessage(err error) string { 260 we, ok := err.(*webDriverError) 261 if !ok { 262 return err.Error() 263 } 264 return we.message 265 } 266 267 // ErrorError returns the WebDriver error for err. 268 func ErrorError(err error) string { 269 we, ok := err.(*webDriverError) 270 if !ok { 271 return "unknown error" 272 } 273 if !we.errDatum.W3C || we.errDatum.Error == "" { 274 return "unknown error" 275 } 276 return we.errDatum.Error 277 } 278 279 // ErrorHTTPStatus returns the HTTP status code that is associated with err. 280 func ErrorHTTPStatus(err error) int { 281 we, ok := err.(*webDriverError) 282 if !ok { 283 return 500 284 } 285 return we.errDatum.HTTPStatus 286 287 } 288 289 // MarshalError generates the WebDriver JSON wire protocol HTTP response body for err. 290 func MarshalError(err error) ([]byte, error) { 291 body := map[string]interface{}{ 292 "status": ErrorStatus(err), 293 "value": ErrorValue(err), 294 "error": ErrorError(err), 295 "message": ErrorMessage(err), 296 } 297 298 st := ErrorStackTrace(err) 299 if st != nil { 300 body["stacktrace"] = st 301 } 302 303 return json.Marshal(body) 304 } 305 306 // ErrorFromStatus constructs a WebDriver error from an OSS status code and message. 307 func ErrorFromStatus(status int, message string) error { 308 errDatum := errorDatum{ 309 Status: status, 310 Error: "", 311 HTTPStatus: 500, 312 W3C: false, 313 } 314 315 for _, cand := range errorData { 316 if cand.Status == status { 317 errDatum = cand 318 break 319 } 320 } 321 322 var value interface{} 323 if message != "" { 324 value = map[string]interface{}{"message": message} 325 } 326 327 return &webDriverError{ 328 errDatum: errDatum, 329 value: value, 330 message: message, 331 } 332 } 333 334 // ErrorFromError constructs a WebDriver error from an W3C error string and message. 335 func ErrorFromError(err, message string) error { 336 errDatum := errorDatum{ 337 Status: 13, 338 Error: err, 339 HTTPStatus: 500, 340 W3C: false, 341 } 342 343 for _, cand := range errorData { 344 if cand.Error == err { 345 errDatum = cand 346 break 347 } 348 } 349 350 var value interface{} 351 if message != "" { 352 value = map[string]interface{}{"message": message} 353 } 354 355 return &webDriverError{ 356 errDatum: errDatum, 357 value: value, 358 message: message, 359 } 360 }