packages feed

webdriver 0.3.3 → 0.4

raw patch · 12 files changed

+168/−109 lines, 12 filesdep ~base64-bytestringdep ~data-defaultdep ~filepath

Dependency ranges changed: base64-bytestring, data-default, filepath, temporary, transformers, transformers-base, unordered-containers, vector, zip-archive

Files

CHANGELOG.md view
@@ -1,27 +1,43 @@-# Change Log+#Change Log -## hs-webdriver 0.3.3+##hs-webdriver 0.4 +###API changes+* finallyClose and closeOnException are now overloaded on the WebDriver class.+* NoSessionId and doSessCommand were moved from Test.WebDriver.Classes to Test.WebDriver.Commands.Internal+ ###bug fixes-*The default preferences used by Selenium are now merged into the preferences of Firefox profiles loaded from disk.-*addExtension will now correctly add extension directories to a profile.+* fixed a typo in the export list of Firefox.Profile; deleteFile is now correctly exported instead of removeFile from System.Directory +* fixed an error in the JSON representation of MouseButton +###new features+* A new module, Test.WebDriver.Commands.Internal, which exports some low-level functions used to implement the high-level interface. This makes it possible for library users to extend hs-webdriver with nonstandard or unimplemented features.++## hs-webdriver 0.3.3+ ###API changes * The representation of profile files has been changed to use a HashMap instead of an association list. This ensures that destination paths are always unique. +###bug fixes+* The default preferences used by Selenium are now merged into the preferences of Firefox profiles loaded from disk.+* addExtension will now correctly add extension directories to a profile.++###known issues+* Because of the way loadProfile currently adds directories to the profileFiles HashMap, it's possible for extensions added via addExtension to be overriden by the extensions originally listed in the on-disk extensions directory.+ ###new features -*It's now possible to add entire directories to a profile in pure code using addFile and addExtension.-*new functions in Common.Profile: unionProfiles, onProfileFiles, onProfilePrefs-*new function in Commands.Wait: onTimeout-*the WD monad now has a MonadCatchIO instance, as an alternative to lifted-base for exception handling+* It's now possible to add entire directories to a profile in pure code using addFile and addExtension.+* new functions in Common.Profile: unionProfiles, onProfileFiles, onProfilePrefs+* new function in Commands.Wait: onTimeout+* the WD monad now has a MonadCatchIO instance, as an alternative to lifted-base for exception handling   ## hs-webdriver 0.3.2.1  ###bug fixes-*Removed a bug in waitWhile' that resulted in an infinite loop-*Fixed the incorrect representation of JSON profiles-*Fixed relative path issues when zipping profile directories from disk+* Removed a bug in waitWhile' that resulted in an infinite loop+* Fixed the incorrect representation of JSON profiles+* Fixed relative path issues when zipping profile directories from disk  ## hs-webdriver 0.3.2 @@ -43,7 +59,7 @@ * loadProfile now properly loads an entire Firefox profile from disk, rather than just the extensions and preferences.  ###known issues-*An issue involving lazy bytestring IO in the zip-archive package means that unusually large profiles might exceed the OSes open file limit.+* An issue involving lazy bytestring IO in the zip-archive package means that unusually large profiles might exceed the OSes open file limit.  ###new features * several new functions for working with Firefox/Opera profiles have been added. This includes functions for loading large profiles from disk, functions for working with zipped profiles, and functions for adding arbitrary files to a profile in pure code. 
TODO view
@@ -6,7 +6,8 @@  -- add support for Opera profiles --- improve documentation. Document errors.+-- improve documentation+  -- document errors.   -- provide examples     -- basic runSession usage     -- intermediate usage@@ -33,3 +34,5 @@ misc. unsorted  --Use lazy ByteString where possible. patch base64-bytestring to work with lazy bytestrings++--consider adding withSession to SessionState so that it can be overloaded easily, or rewriting it so that it's overloaded but not a method itself.
src/Test/WebDriver.hs view
@@ -7,14 +7,14 @@          WD(..), WDSession(..), defaultSession, SessionId(..)          -- * Running WebDriver tests        , runWD, runSession, withSession, finallyClose, closeOnException+         -- * WebDriver commands+       , module Test.WebDriver.Commands          -- * Capabilities and configuration        , Capabilities(..), defaultCaps, allCaps        , Platform(..), ProxyType(..)          -- ** Browser-specific configuration        , Browser(..), LogPref(..)        , firefox, chrome, ie, opera, iPhone, iPad, android-         -- * WebDriver commands-       , module Test.WebDriver.Commands          -- * Exceptions        , module Test.WebDriver.Exceptions        ) where
src/Test/WebDriver/Classes.hs view
@@ -7,23 +7,15 @@          SessionState(..), modifySession          -- ** WebDriver sessions        , WDSession(..), SessionId(..), defaultSession-         -- **Convenience function for :sessionId URLs-       , doSessCommand-         -- * No Session Exception-       , NoSessionId(..)        ) where  --import Test.WebDriver.Internal import Data.Aeson import Network.HTTP (RequestMethod(..)) -import qualified Data.Text as T import Data.Text (Text)  import Control.Monad.Trans.Control-import Control.Exception.Lifted (Exception, throwIO)-import Data.Typeable- import Control.Monad.Trans.Maybe import Control.Monad.Trans.Identity import Control.Monad.List@@ -102,29 +94,6 @@ newtype SessionId = SessionId Text                   deriving (Eq, Ord, Show, Read,                              FromJSON, ToJSON)---instance Exception NoSessionId--- |A command requiring a session ID was attempted when no session ID was --- available.-newtype NoSessionId = NoSessionId String -                 deriving (Eq, Show, Typeable)----- |This a convenient wrapper around 'doCommand' that automatically prepends--- the session URL parameter to the wire command URL. For example, passing--- a URL of "/refresh" will expand to "/session/:sessionId/refresh".-doSessCommand :: (WebDriver wd, ToJSON a, FromJSON b) => -                  RequestMethod -> Text -> a -> wd b-doSessCommand method path args = do-  WDSession { wdSessId = mSessId } <- getSession-  case mSessId of -      Nothing -> throwIO . NoSessionId $ msg-        where -          msg = "doSessCommand: No session ID found for relative URL "-                ++ show path-      Just (SessionId sId) -> doCommand method -                              (T.concat ["/session/", sId, path]) args   instance SessionState m => SessionState (LS.StateT s m) where
src/Test/WebDriver/Commands.hs view
@@ -1,5 +1,5 @@ {-# LANGUAGE OverloadedStrings, ScopedTypeVariables, ExistentialQuantification,-             GeneralizedNewtypeDeriving, TemplateHaskell #-}+             TemplateHaskell #-} -- |This module exports basic WD actions that can be used to interact with a -- browser session. module Test.WebDriver.Commands @@ -18,6 +18,7 @@        , findElem, findElems, findElemFrom, findElemsFrom          -- ** Interacting with elements        , click, submit, getText+         -- *** Sending key inputs to elements        , sendKeys, sendRawKeys, clearInput          -- ** Element information        , attr, cssProp, elemPos, elemSize@@ -70,6 +71,7 @@        , serverStatus        ) where +import Test.WebDriver.Commands.Internal import Test.WebDriver.Classes import Test.WebDriver.JSON import Test.WebDriver.Capabilities@@ -93,7 +95,6 @@ import Control.Exception.Lifted (throwIO, catch, handle) import Data.Word import Data.String (fromString)-import Data.Default import qualified Data.Char as C  import Prelude hiding (catch)@@ -112,7 +113,7 @@   sessUrl <- doCommand POST "/session" . single "desiredCapabilities" $ caps   let sessId = SessionId . last . filter (not . T.null) . splitOn "/" $  sessUrl   modifySession $ \sess -> sess {wdSessId = Just sessId}-  return =<< getSession+  getSession  -- |Retrieve a list of active sessions and their 'Capabilities'. sessions :: WebDriver wd => wd [(SessionId, Capabilities)]@@ -263,18 +264,6 @@ focusFrame :: WebDriver wd => FrameSelector -> wd () focusFrame s = doSessCommand POST "/frame" . single "id" $ s  -{- |An opaque identifier for a browser window -}-newtype WindowHandle = WindowHandle Text-                     deriving (Eq, Ord, Show, Read, -                               FromJSON, ToJSON)-instance Default WindowHandle where-  def = currentWindow---- |A special 'WindowHandle' that always refers to the currently focused window.--- This is also used by the 'Default' instance.-currentWindow :: WindowHandle-currentWindow = WindowHandle "current"- -- |Returns a handle to the currently focused window getCurrentWindow :: WebDriver wd => wd WindowHandle getCurrentWindow = doSessCommand GET "/window_handle" ()@@ -313,11 +302,6 @@ setWindowPos :: WebDriver wd => (Int, Int) -> wd () setWindowPos = doWinCommand POST currentWindow "/position" . pair ("x","y") -doWinCommand :: (WebDriver wd, ToJSON a, FromJSON b) => -                 RequestMethod -> WindowHandle -> Text -> a -> wd b-doWinCommand m (WindowHandle w) path a = -  doSessCommand m (T.concat ["/window/", w, path]) a- -- |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@@ -389,17 +373,6 @@ getTitle :: WebDriver wd => wd Text getTitle = doSessCommand GET "/title" () -{- |An opaque identifier for a web page element. -}-newtype Element = Element Text-                  deriving (Eq, Ord, Show, Read)--instance FromJSON Element where-  parseJSON (Object o) = Element <$> o .: "ELEMENT"-  parseJSON v = typeMismatch "Element" v--instance ToJSON Element where-  toJSON (Element e) = object ["ELEMENT" .= e]- -- |Specifies element(s) within a DOM tree using various selection methods. data Selector = ById Text                 | ByName Text@@ -522,11 +495,6 @@ (</=>) :: WebDriver wd => Element -> Element -> wd Bool e1 </=> e2 = not <$> (e1 <==> e2) -doElemCommand :: (WebDriver wd, ToJSON a, FromJSON b) => -                  RequestMethod -> Element -> Text -> a -> wd b-doElemCommand m (Element e) path a =-  doSessCommand m (T.concat ["/element/", e, path]) a- -- |A screen orientation data Orientation = Landscape | Portrait                  deriving (Eq, Show, Ord, Bounded, Enum)@@ -585,14 +553,16 @@                  deriving (Eq, Show, Ord, Bounded, Enum)  instance ToJSON MouseButton where-  toJSON = String . toUpper . fromString . show+  toJSON = toJSON . fromEnum    instance FromJSON MouseButton where-  parseJSON (String jStr) = case toLower jStr of-    "left"   -> return LeftButton-    "middle" -> return MiddleButton-    "right"  -> return RightButton-    err      -> fail $ "Invalid MouseButton string " ++ show err+  parseJSON v = do+    n <- parseJSON v+    case n :: Integer of+      0 -> return LeftButton+      1 -> return MiddleButton+      2 -> return RightButton+      err -> fail $ "Invalid JSON for MouseButton: " ++ show err   parseJSON v = typeMismatch "MouseButton" v  -- |Click at the current mouse position with the given mouse button.@@ -710,10 +680,6 @@                  . fromArchive . (`addEntryToArchive` emptyArchive)  --- |An HTML 5 storage type-data WebStorageType = LocalStorage | SessionStorage -                    deriving (Eq, Show, Ord, Bounded, Enum)- -- |Get the current number of keys in a web storage area. storageSize :: WebDriver wd => WebStorageType -> wd Integer storageSize s = doStorageCommand GET s "/size" ()@@ -726,6 +692,10 @@ deleteAllKeys :: WebDriver wd => WebStorageType -> wd () deleteAllKeys s = doStorageCommand DELETE s "" () +-- |An HTML 5 storage type+data WebStorageType = LocalStorage | SessionStorage +                    deriving (Eq, Show, Ord, Bounded, Enum)+           -- |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.@@ -740,11 +710,15 @@ deleteKey :: WebDriver wd => WebStorageType -> Text -> wd () deleteKey s k = doStorageCommand POST s ("/key/" `T.append` k) () +-- |A wrapper around 'doStorageCommand' to create web storage URLs. doStorageCommand :: (WebDriver wd, ToJSON a, FromJSON b) =>                      RequestMethod -> WebStorageType -> Text -> a -> wd b doStorageCommand m s path a = doSessCommand m (T.concat ["/", s', path]) a   where s' = case s of           LocalStorage -> "local_storage"           SessionStorage -> "session_storage"-          +++-- Moving this closer to the definition of Cookie seems to cause strange compile +-- errors, so I'm leaving it here for now. $( deriveToJSON (map C.toLower . drop 4) ''Cookie )
+ src/Test/WebDriver/Commands/Internal.hs view
@@ -0,0 +1,93 @@+{-# LANGUAGE OverloadedStrings, DeriveDataTypeable, GeneralizedNewtypeDeriving  #-}+{-# OPTIONS_HADDOCK not-home #-}+-- |Internal functions used to implement the functions exported by +-- "Test.WebDriver.Commands". These may be useful for implementing non-standard +-- webdriver commands.+module Test.WebDriver.Commands.Internal +       (-- * Low-level webdriver functions+         doCommand+        -- ** Commands with :sessionId URL parameter+       , doSessCommand, SessionId(..)+        -- ** Commands with element :id URL parameters+       , doElemCommand, Element(..)+        -- ** Commands with :windowHandle URL parameters+       , doWinCommand, WindowHandle(..), currentWindow+        -- * Exceptions+       , NoSessionId(..)+       ) where++import Test.WebDriver.Classes++import Data.Aeson+import Data.Aeson.Types+import Data.Text (Text)+import qualified Data.Text as T+import Control.Exception.Lifted+import Data.Typeable+import Data.Default+import Control.Applicative++{- |An opaque identifier for a web page element. -}+newtype Element = Element Text+                  deriving (Eq, Ord, Show, Read)++instance FromJSON Element where+  parseJSON (Object o) = Element <$> o .: "ELEMENT"+  parseJSON v = typeMismatch "Element" v++instance ToJSON Element where+  toJSON (Element e) = object ["ELEMENT" .= e]+++{- |An opaque identifier for a browser window -}+newtype WindowHandle = WindowHandle Text+                     deriving (Eq, Ord, Show, Read, +                               FromJSON, ToJSON)+instance Default WindowHandle where+  def = currentWindow++-- |A special 'WindowHandle' that always refers to the currently focused window.+-- This is also used by the 'Default' instance.+currentWindow :: WindowHandle+currentWindow = WindowHandle "current"++instance Exception NoSessionId+-- |A command requiring a session ID was attempted when no session ID was +-- available.+newtype NoSessionId = NoSessionId String +                 deriving (Eq, Show, Typeable)++-- |This a convenient wrapper around 'doCommand' that automatically prepends+-- the session URL parameter to the wire command URL. For example, passing+-- a URL of \"/refresh\" will expand to \"/session/:sessionId/refresh\", where+-- :sessionId is a URL parameter as described in +-- <http://code.google.com/p/selenium/wiki/JsonWireProtocol>+doSessCommand :: (WebDriver wd, ToJSON a, FromJSON b) => +                  RequestMethod -> Text -> a -> wd b+doSessCommand method path args = do+  WDSession { wdSessId = mSessId } <- getSession+  case mSessId of +      Nothing -> throwIO . NoSessionId $ msg+        where +          msg = "doSessCommand: No session ID found for relative URL "+                ++ show path+      Just (SessionId sId) -> doCommand method +                              (T.concat ["/session/", sId, path]) args++-- |A wrapper around 'doSessCommand' to create element URLs.+-- For example, passing a URL of "/active" will expand to +-- \"/session/:sessionId/element/:id/active\", where :sessionId and :id are URL+-- parameters as described in the wire protocol.+doElemCommand :: (WebDriver wd, ToJSON a, FromJSON b) => +                  RequestMethod -> Element -> Text -> a -> wd b+doElemCommand m (Element e) path a =+  doSessCommand m (T.concat ["/element/", e, path]) a++-- |A wrapper around 'doSessCommand' to create window handle URLS.+-- For example, passing a URL of \"/size\" will expand to+-- \"/session/:sessionId/window/:windowHandle/\", where :sessionId and +-- :windowHandle are URL parameters as described in the wire protocol+doWinCommand :: (WebDriver wd, ToJSON a, FromJSON b) => +                 RequestMethod -> WindowHandle -> Text -> a -> wd b+doWinCommand m (WindowHandle w) path a = +  doSessCommand m (T.concat ["/window/", w, path]) a
src/Test/WebDriver/Commands/Wait.hs view
@@ -49,7 +49,7 @@ 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+-- The action will be retried every .5 seconds until no 'ExpectFailed' or -- 'FailedCommand' 'NoSuchElement' exceptions occur. If the timeout is reached,  -- then a 'Timeout' exception will be raised. The timeout value  -- is expressed in seconds.
src/Test/WebDriver/Exceptions.hs view
@@ -7,5 +7,5 @@        , mkFailedCommandInfo, failedCommand        )where import Test.WebDriver.Internal-import Test.WebDriver.Classes import Test.WebDriver.JSON+import Test.WebDriver.Commands.Internal
src/Test/WebDriver/Firefox/Profile.hs view
@@ -14,7 +14,7 @@          -- * Extensions        , addExtension, deleteExtension, hasExtension          -- * Other files and directories-       , addFile, removeFile, hasFile+       , addFile, deleteFile, hasFile          -- * Miscellaneous profile operations        , unionProfiles, onProfileFiles, onProfilePrefs          -- * Loading and preparing profiles
src/Test/WebDriver/JSON.hs view
@@ -1,7 +1,10 @@ {-# LANGUAGE OverloadedStrings, FlexibleContexts, DeriveDataTypeable #-} -- |A collection of convenience functions for using and parsing JSON values--- within 'WD'. All monadic parse errors are converted to asynchronous +-- within 'WD'. All monadic parse errors are converted to asynchronous -- 'BadJSON' exceptions.+-- +-- These functions are used internally to implement webdriver commands, and may+-- be useful for implementing non-standard commands. module Test.WebDriver.JSON         ( -- * Access a JSON object key          (!:)
src/Test/WebDriver/Monad.hs view
@@ -65,11 +65,11 @@  -- |A finalizer ensuring that the session is always closed at the end of  -- the given 'WD' action, regardless of any exceptions.-finallyClose:: WD a -> WD a +finallyClose:: WebDriver wd => wd a -> wd a  finallyClose wd = closeOnException wd <* closeSession  -- |A variant of 'finallyClose' that only closes the session when an  -- asynchronous exception is thrown, but otherwise leaves the session open -- if the action was successful.-closeOnException :: WD a -> WD a+closeOnException :: WebDriver wd => wd a -> wd a closeOnException wd = wd `onException` closeSession
webdriver.cabal view
@@ -1,5 +1,5 @@ Name: webdriver-Version: 0.3.3+Version: 0.4 Cabal-Version: >= 1.6 License: BSD3 License-File: LICENSE@@ -37,21 +37,21 @@                  , bytestring == 0.9.*                  , text >= 0.7 && < 0.12                  , time == 1.*-                 , transformers >= 0.2-                 , zip-archive >= 0.1.1.7+                 , transformers >= 0.2 && < 0.5+                 , zip-archive >= 0.1.1.8 && < 0.3                  , directory == 1.*-                 , filepath >=1.1-                 , unordered-containers >= 0.1.3+                 , filepath == 1.*+                 , unordered-containers >= 0.1.3 && < 0.4                  , attoparsec == 0.10.*                  , monad-control == 0.3.*-                 , transformers-base < 1.0-                 , vector >= 0.3+                 , transformers-base >= 0.1 && < 1.0+                 , vector >= 0.3 && < 0.11                  , lifted-base == 0.1.*                  , MonadCatchIO-transformers >= 0.3 && < 0.4                  , filesystem-trees >= 0.1.0.2 && < 0.2-                 , data-default-                 , temporary-                 , base64-bytestring+                 , data-default >= 0.2 && < 1.0+                 , temporary >= 1.0 && < 2.0+                 , base64-bytestring == 0.1.*                  , cond >= 0.3 && < 0.5    exposed-modules: Test.WebDriver@@ -60,6 +60,7 @@                    Test.WebDriver.Exceptions                    Test.WebDriver.Commands                    Test.WebDriver.Commands.Wait+                   Test.WebDriver.Commands.Internal                    Test.WebDriver.Common.Profile                    Test.WebDriver.Firefox.Profile                    Test.WebDriver.Chrome.Extension