{-# OPTIONS_HADDOCK hide #-}

module WebDriverPreCore.Error
  ( ErrorType (..),
    WebDriverException (..),
    JSONEncodeException (..),
    errorDescription,
    toErrorType,
    toErrorCode,
    parseWebDriverException,
    parseErrorType,
  )
where

import AesonUtils (jsonToText)
import Control.Exception (Exception (..))
import Data.Aeson (FromJSON (..), Options (..), Value, defaultOptions, genericParseJSON, withObject)
import Data.Aeson.Types (Parser, parseEither, parseMaybe, (.:))
import Data.Bifunctor (first)
import Data.Char (isUpper, toLower)
import Data.Function ((&))
import Data.Text as T (Text, concat, pack, toTitle, unpack, words)
import GHC.Generics (Generic)
import Text.Read (readEither)
import WebDriverPreCore.Internal.HTTPBidiCommon (JSUInt (..))
import Prelude as P hiding (error, words)

{-
Error Code 	HTTP Status 	JSON Error Code 	Description
element click intercepted 	400 	element click intercepted 	The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked.
element not interactable 	400 	element not interactable 	A command could not be completed because the element is not pointer- or keyboard interactable.
insecure certificate 	400 	insecure certificate 	Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate.
invalid argument 	400 	invalid argument 	The arguments passed to a command are either invalid or malformed.
invalid cookie domain 	400 	invalid cookie domain 	An illegal attempt was made to set a cookie under a different domain than the current page.
invalid element state 	400 	invalid element state 	A command could not be completed because the element is in an invalid state, e.g. attempting to clear an element that isn't both editable and resettable.
invalid selector 	400 	invalid selector 	Argument was an invalid selector.
invalid session id 	404 	invalid session id 	Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it's not active.
javascript error 	500 	javascript error 	An error occurred while executing JavaScript supplied by the user.
move target out of bounds 	500 	move target out of bounds 	The target for mouse interaction is not in the browser's viewport and cannot be brought into that viewport.
no such alert 	404 	no such alert 	An attempt was made to operate on a modal dialog when one was not open.
no such cookie 	404 	no such cookie 	No cookie matching the given path name was found amongst the associated cookies of session's current browsing context's active document.
no such element 	404 	no such element 	An element could not be located on the page using the given search parameters.
no such frame 	404 	no such frame 	A command to switch to a frame could not be satisfied because the frame could not be found.
no such window 	404 	no such window 	A command to switch to a window could not be satisfied because the window could not be found.
no such shadow root 	404 	no such shadow root 	The element does not have a shadow root.
script timeout error 	500 	script timeout 	A script did not complete before its timeout expired.
session not created 	500 	session not created 	A new session could not be created.
stale element reference 	404 	stale element reference 	A command failed because the referenced element is no longer attached to the DOM.
detached shadow root 	404 	detached shadow root 	A command failed because the referenced shadow root is no longer attached to the DOM.
timeout 	500 	timeout 	An operation did not complete before its timeout expired.
unable to set cookie 	500 	unable to set cookie 	A command to set a cookie's value could not be satisfied.
unable to capture screen 	500 	unable to capture screen 	A screen capture was made impossible.
unexpected alert open 	500 	unexpected alert open 	A modal dialog was open, blocking this operation.
unknown command 	404 	unknown command 	A command could not be executed because the remote end is not aware of it.
unknown error 	500 	unknown error 	An unknown error occurred in the remote end while processing the command.
unknown method 	405 	unknown method 	The requested command matched a known URL but did not match any method for that URL.
unsupported operation 	500 	unsupported operation 	Indicates that a command that should have executed properly cannot be supported for some reason.
-}

-- | Known WevDriver Error Types
--
-- [spec](https://www.w3.org/TR/2025/WD-webdriver2-20251028/#errors)
data ErrorType
  = ElementClickIntercepted
  | ElementNotInteractable
  | InsecureCertificate
  | InvalidArgument
  | InvalidCookieDomain
  | InvalidElementState
  | InvalidSelector
  | InvalidSessionId
  | JavascriptError
  | MoveTargetOutOfBounds
  | NoSuchAlert
  | NoSuchCookie
  | NoSuchElement
  | NoSuchFrame
  | NoSuchWindow
  | NoSuchShadowRoot
  | ScriptTimeout
  | SessionNotCreated
  | StaleElementReference
  | DetachedShadowRoot
  | Timeout
  | UnableToSetCookie
  | UnableToCaptureScreen
  | UnexpectedAlertOpen
  | UnknownCommand
  | UnknownError
  | UnknownMethod
  | UnsupportedOperation
  | --- Bidi
    InvalidWebExtension
  | NoSuchClientWindow
  | NoSuchHandle
  | NoSuchHistoryEntry
  | NoSuchNetworkCollector
  | NoSuchIntercept
  | NoSuchNetworkData
  | NoSuchNode
  | NoSuchRequest
  | NoSuchScript
  | NoSuchStoragePartition
  | NoSuchUserContext
  | NoSuchWebExtension
  | UnableToCloseBrowser
  | UnableToSetFileInput
  | UnavailableNetworkData
  | UnderspecifiedStoragePartition
  deriving (ErrorType -> ErrorType -> Bool
(ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> Bool) -> Eq ErrorType
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: ErrorType -> ErrorType -> Bool
== :: ErrorType -> ErrorType -> Bool
$c/= :: ErrorType -> ErrorType -> Bool
/= :: ErrorType -> ErrorType -> Bool
Eq, ReadPrec [ErrorType]
ReadPrec ErrorType
Int -> ReadS ErrorType
ReadS [ErrorType]
(Int -> ReadS ErrorType)
-> ReadS [ErrorType]
-> ReadPrec ErrorType
-> ReadPrec [ErrorType]
-> Read ErrorType
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS ErrorType
readsPrec :: Int -> ReadS ErrorType
$creadList :: ReadS [ErrorType]
readList :: ReadS [ErrorType]
$creadPrec :: ReadPrec ErrorType
readPrec :: ReadPrec ErrorType
$creadListPrec :: ReadPrec [ErrorType]
readListPrec :: ReadPrec [ErrorType]
Read, Int -> ErrorType -> ShowS
[ErrorType] -> ShowS
ErrorType -> String
(Int -> ErrorType -> ShowS)
-> (ErrorType -> String)
-> ([ErrorType] -> ShowS)
-> Show ErrorType
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ErrorType -> ShowS
showsPrec :: Int -> ErrorType -> ShowS
$cshow :: ErrorType -> String
show :: ErrorType -> String
$cshowList :: [ErrorType] -> ShowS
showList :: [ErrorType] -> ShowS
Show, Eq ErrorType
Eq ErrorType =>
(ErrorType -> ErrorType -> Ordering)
-> (ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> Bool)
-> (ErrorType -> ErrorType -> ErrorType)
-> (ErrorType -> ErrorType -> ErrorType)
-> Ord ErrorType
ErrorType -> ErrorType -> Bool
ErrorType -> ErrorType -> Ordering
ErrorType -> ErrorType -> ErrorType
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: ErrorType -> ErrorType -> Ordering
compare :: ErrorType -> ErrorType -> Ordering
$c< :: ErrorType -> ErrorType -> Bool
< :: ErrorType -> ErrorType -> Bool
$c<= :: ErrorType -> ErrorType -> Bool
<= :: ErrorType -> ErrorType -> Bool
$c> :: ErrorType -> ErrorType -> Bool
> :: ErrorType -> ErrorType -> Bool
$c>= :: ErrorType -> ErrorType -> Bool
>= :: ErrorType -> ErrorType -> Bool
$cmax :: ErrorType -> ErrorType -> ErrorType
max :: ErrorType -> ErrorType -> ErrorType
$cmin :: ErrorType -> ErrorType -> ErrorType
min :: ErrorType -> ErrorType -> ErrorType
Ord, ErrorType
ErrorType -> ErrorType -> Bounded ErrorType
forall a. a -> a -> Bounded a
$cminBound :: ErrorType
minBound :: ErrorType
$cmaxBound :: ErrorType
maxBound :: ErrorType
Bounded, Int -> ErrorType
ErrorType -> Int
ErrorType -> [ErrorType]
ErrorType -> ErrorType
ErrorType -> ErrorType -> [ErrorType]
ErrorType -> ErrorType -> ErrorType -> [ErrorType]
(ErrorType -> ErrorType)
-> (ErrorType -> ErrorType)
-> (Int -> ErrorType)
-> (ErrorType -> Int)
-> (ErrorType -> [ErrorType])
-> (ErrorType -> ErrorType -> [ErrorType])
-> (ErrorType -> ErrorType -> [ErrorType])
-> (ErrorType -> ErrorType -> ErrorType -> [ErrorType])
-> Enum ErrorType
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: ErrorType -> ErrorType
succ :: ErrorType -> ErrorType
$cpred :: ErrorType -> ErrorType
pred :: ErrorType -> ErrorType
$ctoEnum :: Int -> ErrorType
toEnum :: Int -> ErrorType
$cfromEnum :: ErrorType -> Int
fromEnum :: ErrorType -> Int
$cenumFrom :: ErrorType -> [ErrorType]
enumFrom :: ErrorType -> [ErrorType]
$cenumFromThen :: ErrorType -> ErrorType -> [ErrorType]
enumFromThen :: ErrorType -> ErrorType -> [ErrorType]
$cenumFromTo :: ErrorType -> ErrorType -> [ErrorType]
enumFromTo :: ErrorType -> ErrorType -> [ErrorType]
$cenumFromThenTo :: ErrorType -> ErrorType -> ErrorType -> [ErrorType]
enumFromThenTo :: ErrorType -> ErrorType -> ErrorType -> [ErrorType]
Enum)

instance FromJSON ErrorType where
  parseJSON :: Value -> Parser ErrorType
  parseJSON :: Value -> Parser ErrorType
parseJSON = String -> (Object -> Parser ErrorType) -> Value -> Parser ErrorType
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"ErrorType" ((Object -> Parser ErrorType) -> Value -> Parser ErrorType)
-> (Object -> Parser ErrorType) -> Value -> Parser ErrorType
forall a b. (a -> b) -> a -> b
$ \Object
o -> do
    errCode <- Object
o Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"error"
    case toErrorType errCode of
      Left Text
e -> String -> Parser ErrorType
forall a. String -> Parser a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> Parser ErrorType) -> String -> Parser ErrorType
forall a b. (a -> b) -> a -> b
$ String
"Unknown ErrorType code: " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> Text -> String
unpack Text
e
      Right ErrorType
et -> ErrorType -> Parser ErrorType
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ErrorType
et

toErrorType :: Text -> Either Text ErrorType
toErrorType :: Text -> Either Text ErrorType
toErrorType =
  (String -> Text)
-> Either String ErrorType -> Either Text ErrorType
forall a b c. (a -> b) -> Either a c -> Either b c
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first String -> Text
pack (Either String ErrorType -> Either Text ErrorType)
-> (Text -> Either String ErrorType)
-> Text
-> Either Text ErrorType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Either String ErrorType
forall a. Read a => String -> Either String a
readEither (String -> Either String ErrorType)
-> (Text -> String) -> Text -> Either String ErrorType
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
unpack (Text -> String) -> (Text -> Text) -> Text -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
T.concat ([Text] -> Text) -> (Text -> [Text]) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> [Text] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Text -> Text
T.toTitle ([Text] -> [Text]) -> (Text -> [Text]) -> Text -> [Text]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
T.words

toErrorCode :: ErrorType -> Text
toErrorCode :: ErrorType -> Text
toErrorCode =
  String -> Text
pack (String -> Text) -> (ErrorType -> String) -> ErrorType -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
P.unwords ([String] -> String)
-> (ErrorType -> [String]) -> ErrorType -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
splitCamel (String -> [String])
-> (ErrorType -> String) -> ErrorType -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ErrorType -> String
forall a. Show a => a -> String
show
  where
    splitCamel :: String -> [String]
    splitCamel :: String -> [String]
splitCamel = \case
      [] -> []
      (Char
x : String
xs) ->
        let (String
w, String
rest) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isUpper String
xs
         in (Char -> Char
toLower Char
x Char -> ShowS
forall a. a -> [a] -> [a]
: String
w) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String -> [String]
splitCamel String
rest

errorDescription :: ErrorType -> Text
errorDescription :: ErrorType -> Text
errorDescription = \case
  ErrorType
ElementClickIntercepted -> Text
"The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested clicked"
  ErrorType
ElementNotInteractable -> Text
"A command could not be completed because the element is not pointer- or keyboard interactable"
  ErrorType
InsecureCertificate -> Text
"Navigation caused the user agent to hit a certificate warning, which is usually the result of an expired or invalid TLS certificate"
  ErrorType
InvalidArgument -> Text
"The arguments passed to a command are either invalid or malformed"
  ErrorType
InvalidCookieDomain -> Text
"An illegal attempt was made to set a cookie under a different domain than the current page"
  ErrorType
InvalidElementState -> Text
"A command could not be completed because the element is in an invalid state, e.g. attempting to clear an element that isn't both editable and resettable"
  ErrorType
InvalidSelector -> Text
"Argument was an invalid selector"
  ErrorType
InvalidSessionId -> Text
"Occurs if the given session id is not in the list of active sessions, meaning the session either does not exist or that it's not active"
  ErrorType
JavascriptError -> Text
"An error occurred while executing JavaScript supplied by the user"
  ErrorType
MoveTargetOutOfBounds -> Text
"The target for mouse interaction is not in the browser's viewport and cannot be brought into that viewport"
  ErrorType
NoSuchAlert -> Text
"An attempt was made to operate on a modal dialog when one was not open"
  ErrorType
NoSuchCookie -> Text
"No cookie matching the given path name was found amongst the associated cookies of session's current browsing context's active document"
  ErrorType
NoSuchElement -> Text
"An element could not be located on the page using the given search parameters"
  ErrorType
NoSuchFrame -> Text
"A command to switch to a frame could not be satisfied because the frame could not be found"
  ErrorType
NoSuchWindow -> Text
"A command to switch to a window could not be satisfied because the window could not be found"
  ErrorType
NoSuchShadowRoot -> Text
"The element does not have a shadow root"
  ErrorType
ScriptTimeout -> Text
"A script did not complete before its timeout expired"
  ErrorType
SessionNotCreated -> Text
"A new session could not be created"
  ErrorType
StaleElementReference -> Text
"A command failed because the referenced element is no longer attached to the DOM"
  ErrorType
DetachedShadowRoot -> Text
"A command failed because the referenced shadow root is no longer attached to the DOM"
  ErrorType
Timeout -> Text
"An operation did not complete before its timeout expired"
  -- Description from the BiDi spec differs from WebDriver spec
  -- UnableToSetCookie -> "A command to set a cookie's value could not be satisfied."
  ErrorType
UnableToSetCookie -> Text
"Tried to create a cookie, but the user agent rejected it"
  ErrorType
UnableToCaptureScreen -> Text
"A screen capture was made impossible"
  ErrorType
UnexpectedAlertOpen -> Text
"A modal dialog was open, blocking this operation"
  ErrorType
UnknownCommand -> Text
"A command could not be executed because the remote end is not aware of it"
  ErrorType
UnknownError -> Text
"An unknown error occurred in the remote end while processing the command"
  ErrorType
UnknownMethod -> Text
"The requested command matched a known URL but did not match any method for that URL"
  ErrorType
UnsupportedOperation -> Text
"Indicates that a command that should have executed properly cannot be supported for some reason"
  -- Bidi
  ErrorType
InvalidWebExtension -> Text
"Tried to install an invalid web extension"
  ErrorType
NoSuchClientWindow -> Text
"Tried to interact with an unknown client window"
  ErrorType
NoSuchNetworkCollector -> Text
"Tried to remove an unknown collector"
  ErrorType
NoSuchHandle -> Text
"Tried to deserialize an unknown RemoteObjectReference"
  ErrorType
NoSuchHistoryEntry -> Text
"Tried to navigate to an unknown session history entry"
  ErrorType
NoSuchIntercept -> Text
"Tried to remove an unknown network intercept"
  ErrorType
NoSuchNetworkData -> Text
"Tried to reference an unknown network data"
  ErrorType
NoSuchNode -> Text
"Tried to deserialize an unknown SharedReference"
  ErrorType
NoSuchRequest -> Text
"Tried to continue an unknown request"
  ErrorType
NoSuchScript -> Text
"Tried to remove an unknown preload script"
  ErrorType
NoSuchStoragePartition -> Text
"Tried to access data in a non-existent storage partition"
  ErrorType
NoSuchUserContext -> Text
"Tried to reference an unknown user context"
  ErrorType
NoSuchWebExtension -> Text
"Tried to reference an unknown web extension"
  ErrorType
UnableToCloseBrowser -> Text
"Tried to close the browser, but failed to do so"
  ErrorType
UnableToSetFileInput -> Text
"Tried to set a file input, but failed to do so"
  ErrorType
UnavailableNetworkData -> Text
"Tried to get network data which was not collected or already evicted"
  ErrorType
UnderspecifiedStoragePartition -> Text
"Tried to interact with data in a storage partition which was not adequately specified"

data WebDriverException
  = ResponseParseException
      { WebDriverException -> Text
message :: Text,
        WebDriverException -> Value
response :: Value
      }
  | UnrecognisedErrorTypeException {WebDriverException -> Text
errorType :: Text, response :: Value}
  | JSONEncodeException JSONEncodeException
  | ProtocolException
      { WebDriverException -> ErrorType
error :: ErrorType,
        WebDriverException -> Text
description :: Text,
        message :: Text,
        WebDriverException -> Maybe Text
stacktrace :: Maybe Text,
        WebDriverException -> Maybe Value
errorData :: Maybe Value,
        response :: Value
      }
  deriving (WebDriverException -> WebDriverException -> Bool
(WebDriverException -> WebDriverException -> Bool)
-> (WebDriverException -> WebDriverException -> Bool)
-> Eq WebDriverException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: WebDriverException -> WebDriverException -> Bool
== :: WebDriverException -> WebDriverException -> Bool
$c/= :: WebDriverException -> WebDriverException -> Bool
/= :: WebDriverException -> WebDriverException -> Bool
Eq, Int -> WebDriverException -> ShowS
[WebDriverException] -> ShowS
WebDriverException -> String
(Int -> WebDriverException -> ShowS)
-> (WebDriverException -> String)
-> ([WebDriverException] -> ShowS)
-> Show WebDriverException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> WebDriverException -> ShowS
showsPrec :: Int -> WebDriverException -> ShowS
$cshow :: WebDriverException -> String
show :: WebDriverException -> String
$cshowList :: [WebDriverException] -> ShowS
showList :: [WebDriverException] -> ShowS
Show, Eq WebDriverException
Eq WebDriverException =>
(WebDriverException -> WebDriverException -> Ordering)
-> (WebDriverException -> WebDriverException -> Bool)
-> (WebDriverException -> WebDriverException -> Bool)
-> (WebDriverException -> WebDriverException -> Bool)
-> (WebDriverException -> WebDriverException -> Bool)
-> (WebDriverException -> WebDriverException -> WebDriverException)
-> (WebDriverException -> WebDriverException -> WebDriverException)
-> Ord WebDriverException
WebDriverException -> WebDriverException -> Bool
WebDriverException -> WebDriverException -> Ordering
WebDriverException -> WebDriverException -> WebDriverException
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: WebDriverException -> WebDriverException -> Ordering
compare :: WebDriverException -> WebDriverException -> Ordering
$c< :: WebDriverException -> WebDriverException -> Bool
< :: WebDriverException -> WebDriverException -> Bool
$c<= :: WebDriverException -> WebDriverException -> Bool
<= :: WebDriverException -> WebDriverException -> Bool
$c> :: WebDriverException -> WebDriverException -> Bool
> :: WebDriverException -> WebDriverException -> Bool
$c>= :: WebDriverException -> WebDriverException -> Bool
>= :: WebDriverException -> WebDriverException -> Bool
$cmax :: WebDriverException -> WebDriverException -> WebDriverException
max :: WebDriverException -> WebDriverException -> WebDriverException
$cmin :: WebDriverException -> WebDriverException -> WebDriverException
min :: WebDriverException -> WebDriverException -> WebDriverException
Ord, (forall x. WebDriverException -> Rep WebDriverException x)
-> (forall x. Rep WebDriverException x -> WebDriverException)
-> Generic WebDriverException
forall x. Rep WebDriverException x -> WebDriverException
forall x. WebDriverException -> Rep WebDriverException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. WebDriverException -> Rep WebDriverException x
from :: forall x. WebDriverException -> Rep WebDriverException x
$cto :: forall x. Rep WebDriverException x -> WebDriverException
to :: forall x. Rep WebDriverException x -> WebDriverException
Generic)

data JSONEncodeException = MkJSONEncodeException
  { JSONEncodeException -> Text
message :: Text,
    JSONEncodeException -> Text
responseText :: Text
  }
  deriving (Int -> JSONEncodeException -> ShowS
[JSONEncodeException] -> ShowS
JSONEncodeException -> String
(Int -> JSONEncodeException -> ShowS)
-> (JSONEncodeException -> String)
-> ([JSONEncodeException] -> ShowS)
-> Show JSONEncodeException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> JSONEncodeException -> ShowS
showsPrec :: Int -> JSONEncodeException -> ShowS
$cshow :: JSONEncodeException -> String
show :: JSONEncodeException -> String
$cshowList :: [JSONEncodeException] -> ShowS
showList :: [JSONEncodeException] -> ShowS
Show, JSONEncodeException -> JSONEncodeException -> Bool
(JSONEncodeException -> JSONEncodeException -> Bool)
-> (JSONEncodeException -> JSONEncodeException -> Bool)
-> Eq JSONEncodeException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: JSONEncodeException -> JSONEncodeException -> Bool
== :: JSONEncodeException -> JSONEncodeException -> Bool
$c/= :: JSONEncodeException -> JSONEncodeException -> Bool
/= :: JSONEncodeException -> JSONEncodeException -> Bool
Eq, Eq JSONEncodeException
Eq JSONEncodeException =>
(JSONEncodeException -> JSONEncodeException -> Ordering)
-> (JSONEncodeException -> JSONEncodeException -> Bool)
-> (JSONEncodeException -> JSONEncodeException -> Bool)
-> (JSONEncodeException -> JSONEncodeException -> Bool)
-> (JSONEncodeException -> JSONEncodeException -> Bool)
-> (JSONEncodeException
    -> JSONEncodeException -> JSONEncodeException)
-> (JSONEncodeException
    -> JSONEncodeException -> JSONEncodeException)
-> Ord JSONEncodeException
JSONEncodeException -> JSONEncodeException -> Bool
JSONEncodeException -> JSONEncodeException -> Ordering
JSONEncodeException -> JSONEncodeException -> JSONEncodeException
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: JSONEncodeException -> JSONEncodeException -> Ordering
compare :: JSONEncodeException -> JSONEncodeException -> Ordering
$c< :: JSONEncodeException -> JSONEncodeException -> Bool
< :: JSONEncodeException -> JSONEncodeException -> Bool
$c<= :: JSONEncodeException -> JSONEncodeException -> Bool
<= :: JSONEncodeException -> JSONEncodeException -> Bool
$c> :: JSONEncodeException -> JSONEncodeException -> Bool
> :: JSONEncodeException -> JSONEncodeException -> Bool
$c>= :: JSONEncodeException -> JSONEncodeException -> Bool
>= :: JSONEncodeException -> JSONEncodeException -> Bool
$cmax :: JSONEncodeException -> JSONEncodeException -> JSONEncodeException
max :: JSONEncodeException -> JSONEncodeException -> JSONEncodeException
$cmin :: JSONEncodeException -> JSONEncodeException -> JSONEncodeException
min :: JSONEncodeException -> JSONEncodeException -> JSONEncodeException
Ord, (forall x. JSONEncodeException -> Rep JSONEncodeException x)
-> (forall x. Rep JSONEncodeException x -> JSONEncodeException)
-> Generic JSONEncodeException
forall x. Rep JSONEncodeException x -> JSONEncodeException
forall x. JSONEncodeException -> Rep JSONEncodeException x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. JSONEncodeException -> Rep JSONEncodeException x
from :: forall x. JSONEncodeException -> Rep JSONEncodeException x
$cto :: forall x. Rep JSONEncodeException x -> JSONEncodeException
to :: forall x. Rep JSONEncodeException x -> JSONEncodeException
Generic)

instance FromJSON JSONEncodeException

instance Exception WebDriverException where
  displayException :: WebDriverException -> String
  displayException :: WebDriverException -> String
displayException =
    Text -> String
unpack (Text -> String)
-> (WebDriverException -> Text) -> WebDriverException -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
      ResponseParseException {Text
message :: WebDriverException -> Text
message :: Text
message, Value
response :: WebDriverException -> Value
response :: Value
response} ->
        Text
"Error parsing WebDriver response: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
message
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\nResponse was:\n"
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Value -> Text
jsonToText Value
response
      UnrecognisedErrorTypeException {Value
response :: WebDriverException -> Value
response :: Value
response} ->
        Text
"Unrecognised WebDriver error type in response:\n"
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Value -> Text
jsonToText Value
response
      JSONEncodeException MkJSONEncodeException {Text
message :: JSONEncodeException -> Text
message :: Text
message, Text
responseText :: JSONEncodeException -> Text
responseText :: Text
responseText} ->
        Text
"Error converting WebDriver response to JSON: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
message
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\nResponse text was:\n"
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
responseText
      ProtocolException {ErrorType
error :: WebDriverException -> ErrorType
error :: ErrorType
error, Text
description :: WebDriverException -> Text
description :: Text
description, Text
message :: WebDriverException -> Text
message :: Text
message, Maybe Text
stacktrace :: WebDriverException -> Maybe Text
stacktrace :: Maybe Text
stacktrace} ->
        Text
"Error executing WebDriver command: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\nError Type: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ErrorType -> Text
toErrorCode ErrorType
error
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\nDescription: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
description
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\nMessage: "
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
message
          Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> (Text -> Text) -> Maybe Text -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" (\Text
st -> Text
"\nStacktrace: \n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
st) Maybe Text
stacktrace


parseWebDriverException :: Text -> Value -> WebDriverException
parseWebDriverException :: Text -> Value -> WebDriverException
parseWebDriverException Text
errInfo Value
response =
  (Value -> Parser Text) -> Value -> Maybe Text
forall a b. (a -> Parser b) -> a -> Maybe b
parseMaybe Value -> Parser Text
getErrorProp Value
response
    Maybe Text
-> (Maybe Text -> WebDriverException) -> WebDriverException
forall a b. a -> (a -> b) -> b
& WebDriverException
-> (Text -> WebDriverException) -> Maybe Text -> WebDriverException
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
      (Text -> WebDriverException
parserErr (Text
errInfo Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"Could not find 'error' property in response\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Value -> Text
jsonToText Value
response))
      ( (Text -> WebDriverException)
-> (ErrorType -> WebDriverException)
-> Either Text ErrorType
-> WebDriverException
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
          ((Text -> Value -> WebDriverException)
-> Value -> Text -> WebDriverException
forall a b c. (a -> b -> c) -> b -> a -> c
flip Text -> Value -> WebDriverException
UnrecognisedErrorTypeException Value
response)
          ErrorType -> WebDriverException
mkWebDriverException
          (Either Text ErrorType -> WebDriverException)
-> (Text -> Either Text ErrorType) -> Text -> WebDriverException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either Text ErrorType
toErrorType
      )
  where
    parserErr :: Text -> WebDriverException
parserErr Text
message = ResponseParseException {Text
message :: Text
message :: Text
message, Value
response :: Value
response :: Value
response}
    mkWebDriverException :: ErrorType -> WebDriverException {-  -}
    mkWebDriverException :: ErrorType -> WebDriverException
mkWebDriverException ErrorType
et =
      (Value -> Parser WebDriverExceptionRaw)
-> Value -> Either String WebDriverExceptionRaw
forall a b. (a -> Parser b) -> a -> Either String b
parseEither Value -> Parser WebDriverExceptionRaw
forall a. FromJSON a => Value -> Parser a
parseJSON Value
response
        Either String WebDriverExceptionRaw
-> (Either String WebDriverExceptionRaw -> WebDriverException)
-> WebDriverException
forall a b. a -> (a -> b) -> b
& (String -> WebDriverException)
-> (WebDriverExceptionRaw -> WebDriverException)
-> Either String WebDriverExceptionRaw
-> WebDriverException
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either
          (\String
msg -> Text -> WebDriverException
parserErr (Text -> WebDriverException) -> Text -> WebDriverException
forall a b. (a -> b) -> a -> b
$ Text
"Error object parsing failed:\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> String -> Text
pack String
msg Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"\n" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Value -> Text
jsonToText Value
response)
          \MkWebDriverExceptionRaw {Maybe Value
Maybe Text
Maybe JSUInt
Text
error :: Text
message :: Text
biDiId :: Maybe JSUInt
stacktrace :: Maybe Text
errorData :: Maybe Value
error :: WebDriverExceptionRaw -> Text
message :: WebDriverExceptionRaw -> Text
biDiId :: WebDriverExceptionRaw -> Maybe JSUInt
stacktrace :: WebDriverExceptionRaw -> Maybe Text
errorData :: WebDriverExceptionRaw -> Maybe Value
..} ->
            ProtocolException
              { error :: ErrorType
error = ErrorType
et,
                description :: Text
description = ErrorType -> Text
errorDescription ErrorType
et,
                Value
response :: Value
response :: Value
response,
                Text
message :: Text
message :: Text
message,
                Maybe Text
stacktrace :: Maybe Text
stacktrace :: Maybe Text
stacktrace,
                Maybe Value
errorData :: Maybe Value
errorData :: Maybe Value
errorData
              }

getErrorProp :: Value -> Parser Text
getErrorProp :: Value -> Parser Text
getErrorProp =
  String -> (Object -> Parser Text) -> Value -> Parser Text
forall a. String -> (Object -> Parser a) -> Value -> Parser a
withObject String
"error" (Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"error")

parseErrorType :: Value -> Maybe ErrorType
parseErrorType :: Value -> Maybe ErrorType
parseErrorType Value
resp =
  case Text -> Value -> WebDriverException
parseWebDriverException Text
"parse error type result" Value
resp of
    ProtocolException {ErrorType
error :: WebDriverException -> ErrorType
error :: ErrorType
error} -> ErrorType -> Maybe ErrorType
forall a. a -> Maybe a
Just ErrorType
error
    JSONEncodeException {} -> Maybe ErrorType
forall a. Maybe a
Nothing
    ResponseParseException {} -> Maybe ErrorType
forall a. Maybe a
Nothing
    UnrecognisedErrorTypeException {} -> Maybe ErrorType
forall a. Maybe a
Nothing

data WebDriverExceptionRaw = MkWebDriverExceptionRaw
  { WebDriverExceptionRaw -> Text
error :: Text,
    WebDriverExceptionRaw -> Text
message :: Text,
    WebDriverExceptionRaw -> Maybe JSUInt
biDiId :: Maybe JSUInt,
    WebDriverExceptionRaw -> Maybe Text
stacktrace :: Maybe Text,
    WebDriverExceptionRaw -> Maybe Value
errorData :: Maybe Value
  }
  deriving (Int -> WebDriverExceptionRaw -> ShowS
[WebDriverExceptionRaw] -> ShowS
WebDriverExceptionRaw -> String
(Int -> WebDriverExceptionRaw -> ShowS)
-> (WebDriverExceptionRaw -> String)
-> ([WebDriverExceptionRaw] -> ShowS)
-> Show WebDriverExceptionRaw
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> WebDriverExceptionRaw -> ShowS
showsPrec :: Int -> WebDriverExceptionRaw -> ShowS
$cshow :: WebDriverExceptionRaw -> String
show :: WebDriverExceptionRaw -> String
$cshowList :: [WebDriverExceptionRaw] -> ShowS
showList :: [WebDriverExceptionRaw] -> ShowS
Show, WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool
(WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool)
-> (WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool)
-> Eq WebDriverExceptionRaw
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool
== :: WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool
$c/= :: WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool
/= :: WebDriverExceptionRaw -> WebDriverExceptionRaw -> Bool
Eq, (forall x. WebDriverExceptionRaw -> Rep WebDriverExceptionRaw x)
-> (forall x. Rep WebDriverExceptionRaw x -> WebDriverExceptionRaw)
-> Generic WebDriverExceptionRaw
forall x. Rep WebDriverExceptionRaw x -> WebDriverExceptionRaw
forall x. WebDriverExceptionRaw -> Rep WebDriverExceptionRaw x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. WebDriverExceptionRaw -> Rep WebDriverExceptionRaw x
from :: forall x. WebDriverExceptionRaw -> Rep WebDriverExceptionRaw x
$cto :: forall x. Rep WebDriverExceptionRaw x -> WebDriverExceptionRaw
to :: forall x. Rep WebDriverExceptionRaw x -> WebDriverExceptionRaw
Generic)

instance FromJSON WebDriverExceptionRaw where
  parseJSON :: Value -> Parser WebDriverExceptionRaw
  parseJSON :: Value -> Parser WebDriverExceptionRaw
parseJSON =
    Options -> Value -> Parser WebDriverExceptionRaw
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
genericParseJSON
      Options
defaultOptions
        { omitNothingFields = True,
          fieldLabelModifier = \case
            String
"data" -> String
"errorData"
            String
"id" -> String
"biDiId"
            String
other -> String
other
        }

{- FROM BIDI

- get compiling
   check empty result
- try known missign Bidi demos
- review unit tests
- a couple of integration demos
  - http - element does not exist
  - bidi specific - element does not exist

data DriverError = MkDriverError
  { id :: Maybe JSUInt,
    error :: ErrorCode,
    description :: Text,
    message :: Text,
    stacktrace :: Maybe Text,
    extensions :: EmptyResult
  }
  deriving (Show, Generic, Eq)

instance FromJSON DriverError where
  parseJSON :: Value -> Parser DriverError
  parseJSON = withObject "Driver Error" $ \o -> do
    id' <- o .: "id"
    error' <- o .: "error"
    message <- o .: "message"
    stacktrace <- o .: "stacktrace"
    pure $
      MkDriverError
        { id = id',
          error = error',
          description = errorDescription error',
          message,
          stacktrace,
          extensions =
            MkEmptyResult $
              subtractProps
                [ "id",module ErrorCoverageTest where

                  "type",
                  "error",
                  "description",
                  "message",
                  "stacktrace"
                ]
                o
        }
-}