packages feed

webdriver 0.1 → 0.2

raw patch · 10 files changed

+233/−101 lines, 10 files

Files

+ CHANGELOG.md view
@@ -0,0 +1,24 @@+#Change Log++## hs-webdriver 0.2++### API changes+* FailedCommandInfo changed so that it stores a WDSession rather than just a Maybe SessionId, thus providing server host and port information as well as the session ID.+* As a result, mkFailedcommandInfo is now String -> WD FailedCommandInfo, since it requires access to the WDSession state.+* HTML5StorageType changed to the more accurate WebStorageType++### new features+* general documentation improvements+* the uploadFile, uploadRawFile, and uploadZipEntry functions, which support uploading file contents to the remote server++## hs-webdriver 0.1++### API changes+* getWindowSize, setWindowSize, getWindowPos, and setWindowPos have all been deprived of their WindowHandle argument. This is due to the fact that using unfocused windows with those commands causes undefined behavior. ++### new features+* the mkCookie function for convenient cookie construction+* the focusFrame function for focusing to individual frames+* the setPageLoadTimeout function+* the maximize function for maximizing windows+* support for HTML 5 web storage
+ TODO view
@@ -0,0 +1,33 @@+for next minor releases++-- add special web-driver specific FF profile setters, either as special+functions or via documentation++-- add opera config++-- improve documentation. Document errors better. Provide more+module introductions+  -- provide examples+    -- basic runSession usage+    -- intermediate usage+    -- explicit waits usage+    -- firefox profile usage+    -- REPL usage+++for 1.0++-- overload WD commands in typeclass+-- add WDSettings, use WDSession as internal State type. +-- allow settings to automatically load drivers. add modules with driver loading+functions+-- allow setting to modify HTTP headers++++miscellaneous unsorted++-- use http-conduit and attoparsec-conduit to stream JSON data. use request methods from http-types++-- use ReaderT to store WDVersion for use with implicit configurations.+
Test/WebDriver/Commands.hs view
@@ -42,17 +42,22 @@        , moveTo, moveToCenter, moveToFrom        , clickWith, MouseButton(..)        , mouseDown, mouseUp, withMouseDown, doubleClick-         -- * Touch gestures-       , touchClick, touchDown, touchUp, touchMove-       , touchScroll, touchScrollFrom, touchDoubleClick-       , touchLongClick, touchFlick, touchFlickFrom          -- * Screen orientation        , Orientation(..)        , getOrientation, setOrientation          -- * Geo-location        , getLocation, setLocation-         -- * HTML 5 web storage+         -- * HTML 5 Web Storage        , storageSize, getAllKeys, deleteAllKeys, getKey, setKey, deleteKey+         -- * Uploading files to remote server+         -- |These functions allow you to upload a file to a remote server. +         -- Note that this operation isn't supported by all WebDriver servers,+         -- and the location where the file is stored is not standardized.+       , uploadFile, uploadRawFile, uploadZipEntry+         -- * Touch gestures+       , touchClick, touchDown, touchUp, touchMove+       , touchScroll, touchScrollFrom, touchDoubleClick+       , touchLongClick, touchFlick, touchFlickFrom          -- * IME support                      , availableIMEEngines, activeIMEEngine, checkIMEActive        , activateIME, deactivateIME@@ -67,9 +72,11 @@ import Data.Aeson import qualified Data.Text as T import Data.Text (Text, splitOn, append)-import Data.ByteString (ByteString)+import Data.ByteString as SBS (ByteString, concat) import Data.ByteString.Base64 as B64+import Data.ByteString.Lazy as LBS (ByteString, toChunks) import Network.URI+import Codec.Archive.Zip  import Control.Applicative import Control.Monad.State.Strict@@ -122,7 +129,7 @@         allFields = ["type" .= ("implicit" :: String)] ++ msField  -- |Sets the amount of time we wait for an asynchronous script to return a --- result+-- result. setScriptTimeout :: Integer -> WD ()  setScriptTimeout ms =   doSessCommand POST "/timeouts/async_script" (object msField)@@ -131,6 +138,7 @@   where msField   = ["ms" .= ms]         allFields = ["type" .= ("script" :: String)] ++ msField +-- |Sets the amount of time to wait for a page to finish loading before throwing a 'Timeout' exception setPageLoadTimeout :: Integer -> WD () setPageLoadTimeout ms = doSessCommand POST "/timeouts" params   where params = object ["type" .= ("page load" :: String)@@ -195,7 +203,7 @@     timeout err = throwIO err          -- |Grab a screenshot of the current page as a PNG image-screenshot :: WD ByteString+screenshot :: WD SBS.ByteString screenshot = B64.decodeLenient <$> doSessCommand GET "/screenshot" ()   @@ -509,20 +517,49 @@                                                        "longitude",                                                        "altitude") -storageSize :: HTML5StorageType -> WD Integer+-- |Uploads a file from the local filesystem by its file path.+uploadFile :: FilePath -> WD ()+uploadFile path = uploadZipEntry =<< liftIO (readEntry [] path)+  +-- |Uploads a raw bytestring with associated file info.+uploadRawFile :: FilePath          -- ^File path to use with this bytestring.+                 -> Integer        -- ^Modification time +                                   -- (in seconds since Unix epoch).+                 -> LBS.ByteString -- ^ The file contents as a lazy ByteString+                 -> WD ()+uploadRawFile path t str = uploadZipEntry (toEntry path t str)+++-- |Lowest level interface to the file uploading mechanism.+-- This allows you to specify the exact details of+-- the zip entry sent across network.+uploadZipEntry :: Entry -> WD ()+uploadZipEntry = doSessCommand POST "/file" . single "file" +                 . B64.encode . SBS.concat . toChunks +                 . fromArchive . (`addEntryToArchive` emptyArchive)++-- |Get the current number of keys in a web storage area.+storageSize :: WebStorageType -> WD Integer storageSize s = doStorageCommand GET s "/size" () -getAllKeys :: HTML5StorageType -> WD [Text]+-- |Get a list of all keys from a web storage area.+getAllKeys :: WebStorageType -> WD [Text] getAllKeys s = doStorageCommand GET s "" () -deleteAllKeys :: HTML5StorageType -> WD ()+-- |Delete all keys within a given web storage area.+deleteAllKeys :: WebStorageType -> WD () deleteAllKeys s = doStorageCommand DELETE s "" () -getKey :: HTML5StorageType -> Text ->  WD Text+-- |Get the value associated with a key in the given web storage area.+-- Unset keys result in empty strings, since the Web Storage spec+-- makes no distinction between the empty string and an undefined value.+getKey :: WebStorageType -> Text ->  WD Text getKey s k = doStorageCommand GET s ("/key/" `T.append` k) () -setKey :: HTML5StorageType -> Text -> Text -> WD Text+-- |Set a key in the given web storage area.+setKey :: WebStorageType -> Text -> Text -> WD Text setKey s k v = doStorageCommand POST s "" . object $ ["key"   .= k,-                                                      "value" .= v ]            -deleteKey :: HTML5StorageType -> Text -> WD ()+                                                      "value" .= v ]+-- |Delete a key in the given web storage area. +deleteKey :: WebStorageType -> Text -> WD () deleteKey s k = doStorageCommand POST s ("/key/" `T.append` k) ()
Test/WebDriver/Commands/Internal.hs view
@@ -31,7 +31,7 @@ doWinCommand = doWinCommand' []  doStorageCommand :: (ToJSON a, FromJSON b) =>-                    RequestMethod -> HTML5StorageType -> Text -> a -> WD b+                    RequestMethod -> WebStorageType -> Text -> a -> WD b doStorageCommand = doStorageCommand' []  doCommand' :: (ToJSON a, FromJSON b) => @@ -67,7 +67,7 @@   doSessCommand' h m (T.concat ["/element/", e, path]) a  doStorageCommand' :: (ToJSON a, FromJSON b) =>-                     [Header] -> RequestMethod -> HTML5StorageType -> Text -> a+                     [Header] -> RequestMethod -> WebStorageType -> Text -> a                      -> WD b doStorageCommand' h m s path a = doSessCommand' h m (T.concat ["/", s', path]) a   where s' = case s of
Test/WebDriver/Commands/Wait.hs view
@@ -20,10 +20,10 @@ import Prelude hiding (catch)  instance Exception ExpectFailed--- |An exception representing a failure of an expected condition.+-- |An exception representing the failure of an expected condition. data ExpectFailed = ExpectFailed deriving (Show, Eq, Typeable) --- |Raises ExpectFailed.+-- |throws 'ExpectFailed'. This is nice for writing your own abstractions. unexpected :: WD a unexpected = throwIO ExpectFailed @@ -44,15 +44,21 @@ (<||>) :: Monad m => m Bool -> m Bool -> m Bool (<||>) = liftM2 (||) ++-- |Apply a predicate to every element in a list, and expect that at least one+-- succeeds. expectAny :: (a -> WD Bool) -> [a] -> WD () expectAny p xs = expect . or =<< mapM p xs +-- |Apply a predicate to every element in a list, and expect that all succeed. expectAll :: (a -> WD Bool) -> [a] -> WD () expectAll p xs = expect . and =<< mapM p xs  -- |Wait until either the given action succeeds or the timeout is reached. -- The action will be retried every .25 seconds until no ExpectFailed or--- NoSuchElement exceptions occur. The timeout value is expressed in seconds.+-- NoSuchElement exceptions occur. If the timeout is reached, then a +-- 'Test.WebDriver.Timeout' exception will be raised. The timeout value is +-- expressed in seconds. waitUntil :: Double -> WD a -> WD a waitUntil = waitUntil' 250000 @@ -70,12 +76,12 @@                                        handleExpectFailed (_ :: ExpectFailed) = retry --- |Like waitWhile, but retries the action until it fails or until the timeout+-- |Like 'waitUntil', but retries the action until it fails or until the timeout -- is exceeded. waitWhile :: Double -> WD a -> WD () waitWhile = waitWhile' 250000 --- |Like waitWhile', but retries the action until it either fails or +-- |Like 'waitUntil\'', but retries the action until it either fails or  -- until the timeout is exceeded. waitWhile' :: Int -> Double -> WD a -> WD () waitWhile' = wait' handler
Test/WebDriver/Firefox/Profile.hs view
@@ -65,7 +65,13 @@                       }                     deriving (Eq, Show) --- |A Firefox preference. This is the subset of JSON values that excludes++-- |Represents a Firefox profile that has been prepared for +-- network transmission. The profile cannot be modified in this form.+newtype PreparedFirefoxProfile = PreparedFirefoxProfile ByteString+  deriving (Eq, Show, ToJSON, FromJSON)++-- |A Firefox preference value. This is the subset of JSON values that excludes -- arrays and objects. data FirefoxPref = PrefInteger !Integer                  | PrefDouble  !Double@@ -81,12 +87,7 @@     PrefBool  b   -> toJSON b  --- |Represents a Firefox profile that has been prepared for --- network transmission. The profile cannot be modified in this form.-newtype PreparedFirefoxProfile = PreparedFirefoxProfile ByteString-  deriving (Eq, Show, ToJSON, FromJSON) - instance Exception ProfileParseError -- |An error occured while attempting to parse a profile's prefs.js file  newtype ProfileParseError = ProfileParseError String@@ -191,7 +192,6 @@                    $ parseOnly prefsParser s  -- |Prepare a FirefoxProfile for network transmission.--- -- Internally, this function constructs a Firefox profile within a temp  -- directory, archives it as a zip file, and then base64 encodes the zipped  -- data. The temporary directory is deleted afterwards@@ -228,7 +228,7 @@  -- |Apply a function on an automatically generated default profile, and -- prepare the result. The FirefoxProfile passed to the handler function is--- the same one used by sessions when no Firefox profile is specified+-- the default profile used by sessions when Nothing is specified prepareTempProfile :: MonadIO m =>                       (FirefoxProfile -> FirefoxProfile)                       -> m PreparedFirefoxProfile
Test/WebDriver/Internal.hs view
@@ -104,7 +104,7 @@   sess <- get   errInfo <- fromJSON' val   let screen = B64.decodeLenient <$> errScreen errInfo -      errInfo' = errInfo { errSessId = wdSessId sess +      errInfo' = errInfo { errSess = sess                           , errScreen = screen }        e errType = throwIO $ FailedCommand errType errInfo'   case status of
Test/WebDriver/JSON.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}--- |A collection of convenience functions for using and parsing JSON valus+-- |A collection of convenience functions for using and parsing JSON values -- within 'WD'. All monadic parse errors are converted to asynchronous  -- 'BadJSON' exceptions. module Test.WebDriver.JSON 
Test/WebDriver/Types.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable,     TemplateHaskell, OverloadedStrings, ExistentialQuantification, -    MultiParamTypeClasses, TypeFamilies, NoMonoLocalBinds #-}+    MultiParamTypeClasses, TypeFamilies, NoMonoLocalBinds +  #-} {-# OPTIONS_HADDOCK not-home #-} module Test.WebDriver.Types         ( -- * WebDriver sessions@@ -9,7 +10,10 @@        , Capabilities(..), defaultCaps, allCaps        , Platform(..), ProxyType(..)          -- ** Browser-specific configuration-       , Browser(..), firefox, chrome, ie, opera, iPhone, iPad, android+       , Browser(..), +         -- ** Default settings for browsers+         firefox, chrome, ie, opera, iPhone, iPad, android+       , FFLogPref          -- * WebDriver objects and command-specific types        , Element(..)        , WindowHandle(..), currentWindow@@ -19,7 +23,7 @@        , Cookie(..), mkCookie        , Orientation(..)        , MouseButton(..)-       , HTML5StorageType(..)+       , WebStorageType(..)          -- * Exceptions        , InvalidURL(..), NoSessionId(..), BadJSON(..)        , HTTPStatusUnknown(..), HTTPConnError(..)@@ -38,7 +42,7 @@ import Network.Stream (ConnError)  -import Data.Text as Text (toLower, toUpper)+import Data.Text as Text (toLower, toUpper, unpack) import Data.Text (Text) import Data.ByteString (ByteString) @@ -48,14 +52,16 @@ import Control.Monad.State.Strict import Control.Monad.Base import Control.Monad.Trans.Control+import Data.Maybe import Data.Word import Data.String+import Text.Show import Data.Default import qualified Data.Char as C   {- |A monadic interface to the WebDriver server. This monad is a simple, strict -wrapper over 'IO', threading session information between sequential commands+layer over 'IO', threading session information between sequential commands -} newtype WD a = WD (StateT WDSession IO a)   deriving (Functor, Monad, MonadState WDSession, MonadIO@@ -112,11 +118,14 @@                              wdHost   :: String                              -- |Port number of the server                            , wdPort   :: Word16-                             -- |An opaque reference identifying the session.+                             -- |An opaque reference identifying the session to+                             -- use with 'WD' commands.                              -- A value of Nothing indicates that a session -                             -- hasn't been created yet. To create new sessions,-                             -- use the 'Test.WebDriver.Commands.createSession' -                             -- and 'Test.WebDriver.runSession' functions.+                             -- hasn't been created yet.+                             -- Sessions can be created within 'WD' via the+                             -- 'Test.WebDriver.createSession', or created+                             -- and closed automatically with +                             -- 'Test.WebDriver.runSession'                            , wdSessId :: Maybe SessionId                             } deriving (Eq, Show) @@ -139,7 +148,7 @@ it's created. In this usage, fields that are set to Nothing indicate that we have no preference for that capability. -* When returned by 'Test.WebDriver.Commands.getCaps', it's used to+* When received from the server , it's used to describe the actual capabilities given to us by the WebDriver server. Here a value of Nothing indicates that the server doesn't support the capability. Thus, for Maybe Bool fields, both Nothing and@@ -189,8 +198,8 @@                      }  -- |Default capabilities. This is the same as the 'Default' instance, but with --- a more specific type. By default we use Firefox of an unspecified version --- with default settings on whatever platform is available. +-- less polymorphism. By default, we use 'firefox' of an unspecified 'version' +-- with default system-wide proxy settings on whatever 'platform' is available. -- All Maybe Bool capabilities are set to Nothing (no preference). defaultCaps :: Capabilities defaultCaps = def@@ -214,7 +223,7 @@         -- |Browser setting and browser-specific capabilities.-data Browser = Firefox { -- |The firefox profile to use. If Nothing, a+data Browser = Firefox { -- |The firefox profile to use. If Nothing,                          -- a default temporary profile is automatically created                          -- and used.                          ffProfile :: Maybe PreparedFirefoxProfile@@ -224,7 +233,10 @@                          -- system-based default.                        , ffBinary :: Maybe FilePath                        }-             | Chrome { chromeDriverVersion :: Maybe String +             | Chrome { -- |Version of the Chrome Webdriver server server to use.+                        -- for more information on chromedriver see+                        -- <http://code.google.com/p/selenium/wiki/ChromeDriver>+                        chromeDriverVersion :: Maybe String                          -- |Path to Chrome binary. If Nothing, use a sensible                         -- system-based default.                       , chromeBinary :: Maybe FilePath@@ -237,7 +249,7 @@              | IE { ignoreProtectedModeSettings :: Bool                   --, useLegacyInternalServer     :: Bool                   }-             | Opera -- ^ Opera-specific configuration coming soon!+             | Opera -- ^ (Opera-specific configuration coming soon!)              | HTMLUnit              | IPhone               | IPad@@ -296,7 +308,7 @@                deriving (Eq, Show)  --- |For Firefox sessions; indicates Firefox's log level+-- |For 'Firefox' sessions; indicates Firefox's log level data FFLogPref = LogOff | LogSevere | LogWarning | LogInfo | LogConfig               | LogFine | LogFiner | LogFinest | LogAll              deriving (Eq, Show, Ord, Bounded, Enum)@@ -339,8 +351,8 @@                       deriving (Eq, Show, Typeable)  instance Exception FailedCommand--- |This exception encapsulates many different kinds of exceptions that can--- occur when a command fails. +-- |This exception encapsulates a broad variety of exceptions that can+-- occur when a command fails. data FailedCommand = FailedCommand FailedCommandType FailedCommandInfo                    deriving (Eq, Show, Typeable) @@ -373,31 +385,35 @@                        deriving (Eq, Ord, Enum, Bounded, Show)  -- |Detailed information about the failed command provided by the server.-data FailedCommandInfo = FailedCommandInfo { errMsg    :: String-                                           , errSessId :: Maybe SessionId +data FailedCommandInfo = FailedCommandInfo { -- |The error message.+                                             errMsg    :: String+                                             -- |The session associated with +                                             -- the exception.+                                           , errSess :: WDSession +                                             -- |A screen shot of the focused window+                                             -- when the exception occured,+                                             -- if provided.                                            , errScreen :: Maybe ByteString+                                             -- |The "class" in which the exception+                                             -- was raised, if provided.                                            , errClass  :: Maybe String+                                             -- |A stack trace of the exception.                                            , errStack  :: [StackFrame]                                            }                        deriving (Eq)   -- |Constructs a FailedCommandInfo from only an error message.-mkFailedCommandInfo :: String -> FailedCommandInfo-mkFailedCommandInfo m = FailedCommandInfo {errMsg = m-                                          , errSessId = Nothing-                                          , errScreen = Nothing-                                          , errClass  = Nothing-                                          , errStack  = []-                                          }+mkFailedCommandInfo :: String -> WD FailedCommandInfo+mkFailedCommandInfo m = do+  sess <- get+  return $ FailedCommandInfo {errMsg = m , errSess = sess , errScreen = Nothing+                             , errClass  = Nothing , errStack  = [] }  -- |Convenience function to throw a 'FailedCommand' locally with no server-side  -- info present. failedCommand :: FailedCommandType -> String -> WD a-failedCommand t m = throwIO . FailedCommand t =<< getCmdInfo-  where getCmdInfo = do-          sessId <- wdSessId <$> get-          return $ (mkFailedCommandInfo m) { errSessId = sessId }+failedCommand t m = throwIO . FailedCommand t =<< mkFailedCommandInfo m  -- |An individual stack frame from the stack trace provided by the server  -- during a FailedCommand.@@ -406,15 +422,24 @@                              , sfMethodName :: String                              , sfLineNumber :: Word                              }-                deriving (Show, Eq)+                deriving (Eq) --- |Cookies are delicious delicacies.+-- |Cookies are delicious delicacies. When sending cookies to the server, a value+-- of Nothing indicates that the server should use a default value. When receiving+-- cookies from the server, a value of Nothing indicates that the server is unable+-- to specify the value. data Cookie = Cookie { cookName   :: Text-                     , cookValue  :: Text-                     , cookPath   :: Maybe Text-                     , cookDomain :: Maybe Text-                     , cookSecure :: Maybe Bool-                     , cookExpiry :: Maybe Integer+                     , cookValue  :: Text          -- ^ +                     , cookPath   :: Maybe Text    -- ^path of this cookie.+                                                   -- if Nothing, defaults to /+                     , cookDomain :: Maybe Text    -- ^domain of this cookie.+                                                   -- if Nothing, the current pages+                                                   -- domain is used+                     , cookSecure :: Maybe Bool    -- ^Is this cookie secure?+                     , cookExpiry :: Maybe Integer -- ^Expiry date expressed as+                                                   -- seconds since the Unix epoch+                                                   -- Nothing indicates that the +                                                   -- cookie never expires                      } deriving (Eq, Show)                -- |Creates a Cookie with only a name and value specified. All other@@ -429,7 +454,7 @@ data Selector = ById Text                 | ByName Text               | ByClass Text -- ^ (Note: multiple classes are not  -                             -- allowed. For more control, use ByCSS)+                             -- allowed. For more control, use 'ByCSS')               | ByTag Text                           | ByLinkText Text                      | ByPartialLinkText Text@@ -450,22 +475,36 @@                  deriving (Eq, Show, Ord, Bounded, Enum)  --- |A type to specify HTML 5 storage type-data HTML5StorageType = LocalStorage | SessionStorage -                      deriving (Eq, Show, Ord, Bounded, Enum)+-- |An HTML 5 storage type+data WebStorageType = LocalStorage | SessionStorage +                    deriving (Eq, Show, Ord, Bounded, Enum)  instance Show FailedCommandInfo where --todo: pretty print-  show i =   showString "{errMsg = "     . shows (errMsg i) -           . showString ", errSessId = " . shows (errSessId i)-           . showString ", errScreen = " . screen-           . showString ", errClass = "  . shows (errClass i)-           . showString ", errStack = "  . shows (errStack i) -           $ "}"-    where screen = showString $ case errScreen i of -                                  Just _  -> "Just \"...\""-                                  Nothing -> "Nothing"-            +  show i = showChar '\n' +           . showString "Session: " . sess +           . showChar '\n'+           . showString className . showString ": " . showString (errMsg i)+           . showChar '\n'+           . foldl (\f s-> f . showString "  " . shows s) id (errStack i)+           $ ""+    where+      className = fromMaybe "<unknown exception>" . errClass $ i+      +      sess = showString sessId . showString " at " +             . showString host . showChar ':' . shows port+        where+          WDSession {wdHost = host, wdPort = port, wdSessId = msid } = errSess i+          sessId = case msid of+            Just (SessionId sid) -> unpack sid+            Nothing -> "<no session id>" +instance Show StackFrame where+  show f = showString (sfClassName f) . showChar '.' +           . showString (sfMethodName f) . showChar ' '+           . showParen True ( showString (sfFileName f) . showChar ':'+                              . shows (sfLineNumber f))+           $ "\n"+ instance FromJSON Element where   parseJSON (Object o) = Element <$> o .: "ELEMENT"   parseJSON v = typeMismatch "Element" v@@ -544,7 +583,7 @@ instance FromJSON FailedCommandInfo where   parseJSON (Object o) =      FailedCommandInfo <$> (req "message" >>= maybe (return "") return)-                      <*> pure Nothing+                      <*> pure undefined                       <*> opt "screen"     Nothing                       <*> opt "class"      Nothing                       <*> opt "stackTrace" []
webdriver.cabal view
@@ -1,5 +1,5 @@ Name: webdriver-Version: 0.1+Version: 0.2 Cabal-Version: >= 1.6 License: BSD3 License-File: LICENSE@@ -9,30 +9,25 @@ Category: Web, Browser, Testing Synopsis: a Haskell client for the Selenium WebDriver protocol Build-type: Simple-Extra-source-files: README.md+Extra-source-files: README.md, TODO, CHANGELOG.md Description:-        A Selenium WebDriver client for the Haskell-        programming language. You can use it to automate browser-        sessions for testing, system administration, etc.-+        A Selenium WebDriver client for Haskell. +        You can use it to automate browser sessions +        for testing, system administration, etc.+        .         For more information about Selenium itself, see         <http://seleniumhq.org/>-+        .         To find out what's been changed in this version and others,-        see the changelog at +        see the change log at          <https://github.com/kallisti-dev/hs-webdriver/blob/master/CHANGELOG.md> --source-repository this-  type: git-  location: git://github.com/kallisti-dev/hs-webdriver.git-  tag: 0- source-repository head   type: git   location: git://github.com/kallisti-dev/hs-webdriver.git    library+  ghc-options: -Wall       build-depends:   base == 4.*                  , aeson >= 0.4 && < 0.7                  , HTTP >= 4000.1 && < 4000.3@@ -67,5 +62,3 @@    other-modules:   Test.WebDriver.Internal                    Test.WebDriver.Types.Internal--  ghc-options: -Wall