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  }