Giter Site home page Giter Site logo

haskell-webdriver / haskell-webdriver Goto Github PK

View Code? Open in Web Editor NEW
188.0 188.0 72.0 913 KB

A Haskell client for the Selenium WebDriver protocol.

Home Page: http://hackage.haskell.org/package/webdriver

License: BSD 3-Clause "New" or "Revised" License

Haskell 95.86% HTML 2.70% Shell 1.44%

haskell-webdriver's Introduction

Welcome to webdriver

Hackage webdriver

haskell-webdriver is a Selenium WebDriver client for the Haskell programming language. You can use it to automate browser sessions for testing, system administration, etc.

For more information about Selenium itself, see http://seleniumhq.org/

Contents

Installation

haskell-webdriver uses the Cabal build system to configure, build, install, and generate documentation on multiple platforms.

For more information on using Cabal and its various installation options, see the Cabal User's Guide at http://www.haskell.org/cabal/users-guide/index.html

Installation from Hackage

haskell-webdriver is hosted on Hackage under the name webdriver. Thus, the simplest way to download and install the most recent version of haskell-webdriver is to run:

cabal install webdriver

There are also options to do system-wide installation, version selection, and other build options; see cabal-install documentation.

Installation from this repository

To build and install a git revision for a single user on your system, run these commands from within the repository directory

Using cabal-install

cabal install

Using Cabal

For systems without cabal-install available, you can also run the Setup.hs script, as such:

runhaskell Setup.hs configure --user
runhaskell Setup.hs build
runhaskell Setup.hs install

For more build options, please refer to the Cabal documentation.

Getting Started

WebDriver is a client-server protocol. Since haskell-webdriver only implements a WebDriver client, you must have a WebDriver server to which you can connect in order to make use of this library.

Using the Selenium Server

While you can use any WebDriver server out there, probably the simplest server to use with haskell-webdriver is Selenium Server. You'll need an installation of the Java runtime to use this server. Once you've downloaded Selenium Server to your current working directory, you can start the server with this shell command:

java -jar selenium-server-standalone-*.jar

The server should now be listening at localhost on port 4444.

Currently, haskell-webdriver only supports selenium version 2. The beginner example was tested with selenium-server-standalone-2.53.1.

Hello, World!

With the Selenium server running locally, you're ready to write browser automation scripts in Haskell.

A simple example can be found here, written in literate Haskell so that you can compile it with GHC yourself. It is very beginner friendly and assumes no prior knowledge of Haskell. For other examples see the examples and test/etc directory.

Integration with Haskell Testing Frameworks

This package does not provide utilities to integrate with popular Haskell testing frameworks. However, other packages exist for this purpose:

Documentation

Documentation for haskell-webdriver is available on Hackage at http://hackage.haskell.org/package/webdriver. You can also generate local HTML documentation from this source revision with the following shell command:

runhaskell Setup.hs haddock

Haddock will generate documentation and save it in dist/doc/html/webdriver

haskell-webdriver's People

Contributors

achudnov avatar aycanirican avatar beerendlauwers avatar chpatrick avatar cristhianmotoche avatar damiencourousse avatar davecturner avatar ddssff avatar dten avatar echaozh avatar enolan avatar erratic-pattern avatar fisx avatar freizl avatar jcristovao avatar lukerandall avatar madjar avatar matil019 avatar melrief avatar meteficha avatar msewell17 avatar ocharles avatar robertmassaioli avatar ryantm avatar saturday06 avatar skellora avatar snoyberg avatar swamp-agr avatar thomasjm avatar yigitozkavci avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haskell-webdriver's Issues

problems with selenium-server-standalone-2.35.0

Environment: Windows 7, webdriver-0.5.1, ghc-7.6, firefox 23.0.1
When I use selenium-server-standalone-2.33.0.jar all is ok.

Prelude> :m Test.WebDriver
Prelude Test.WebDriver> runWD defaultSession $ createSession allCaps
...
Loading package zip-archive-0.1.3.4 ... linking ... done.
Loading package webdriver-0.5.1 ... linking ... done.
WDSession {wdHost = "127.0.0.1", wdPort = 4444, wdBasePath = "/wd/hub", wdSessId = Just (SessionId "ac4cc864-63f1-42a1-8
67a-98e723271d75")}
Prelude Test.WebDriver>

When I use selenium-server-standalone-2.35.0.jar I have problems:

Prelude Test.WebDriver> runWD defaultSession $ createSession allCaps
*** Exception: BadJSON "when expecting a Text, encountered Object instead"
Prelude Test.WebDriver>

Log of selenium-server doesn't contain errors and firefox starts successfully

C:\selenium>java -jar c:\selenium\selenium-server-standalone-2.35.0.jar
рту 22, 2013 1:37:28 PM org.openqa.grid.selenium.GridLauncher main
INFO: Launching a standalone server
13:37:28.303 INFO - Java: Oracle Corporation 23.7-b01
13:37:28.304 INFO - OS: Windows 7 6.1 amd64
13:37:28.312 INFO - v2.35.0, with Core v2.35.0. Built from revision c916b9d
13:37:28.396 INFO - RemoteWebDriver instances should connect to: http://127.0.0.
1:4444/wd/hub
13:37:28.397 INFO - Version Jetty/5.1.x
13:37:28.397 INFO - Started HttpContext[/selenium-server/driver,/selenium-server
/driver]
13:37:28.398 INFO - Started HttpContext[/selenium-server,/selenium-server]
13:37:28.398 INFO - Started HttpContext[/,/]
13:37:28.432 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@5bb79d
4f
13:37:28.433 INFO - Started HttpContext[/wd,/wd]
13:37:28.442 INFO - Started SocketListener on 0.0.0.0:4444
13:37:28.442 INFO - Started org.openqa.jetty.jetty.Server@7f08d052
13:38:09.818 INFO - Executing: [new session: {platform=ANY, javascriptEnabled=tr
ue, acceptSslCerts=true, firefox_binary=null, browserName=firefox, rotatable=tru
e, locationContextEnabled=true, version=null, loggingPrefs=org.openqa.selenium.l
ogging.L..., firefox_profile=null, databaseEnabled=true, cssSelectorsEnabled=tru
e, handlesAlerts=true, browserConnectionEnabled=true, proxy={proxyType=SYSTEM},
webStorageEnabled=true, nativeEvents=true, applicationCacheEnabled=true, takesSc
reenshot=true}] at URL: /session)
13:38:09.828 INFO - Creating a new session for Capabilities [{platform=ANY, java
scriptEnabled=true, acceptSslCerts=true, firefox_binary=null, browserName=firefo
x, rotatable=true, locationContextEnabled=true, version=null, loggingPrefs=org.o
penqa.selenium.logging.LoggingPreferences@5613e573, firefox_profile=null, databa
seEnabled=true, cssSelectorsEnabled=true, handlesAlerts=true, browserConnectionE
nabled=true, nativeEvents=true, webStorageEnabled=true, proxy={proxyType=SYSTEM}
, applicationCacheEnabled=true, takesScreenshot=true}]
13:38:17.788 INFO - Done: /session

Fails on Windows w/o MSYS

C:\Documents and Settings*>cabal install webdriver
Resolving dependencies...
Configuring network-2.4.1.0...
cabal: The package has a './configure' script. This requires a Unix compatibility toolchain such as MinGW+MSYS or Cygwin.
Configuring unix-2.6.0.1...
cabal: The package has a './configure' script. This requires a Unix compatibility toolchain such as MinGW+MSYS or Cygwin.

Why does it need unix package on Windows at all?

Click the button with a native JS

Hi!

I need to click some button, but not with a click function, but with a native JS. I see a special function for this task, executeJS. So this is my code:

    ...
    button <- findElement . ById $ "clearCart"
    info <- elemInfo button
    executeJS [JSArg info] "arguments[0].click();"
    ...

But I got a runtime error:

BadJSON "when expecting a (), encountered Null instead"

How can I fix it?

Add definitions for keys?

I have the following definitions:

backspace, enter, escape :: Text
(backspace, enter, escape) = ("\xE003", "\xE007", "\xE00C")

shift, control, alt, command :: Text
(shift, control, alt, command) = ("\xE008", "\xE009", "\xE00A", "\xE03D")
...

It'd be useful to have a .Keys module (designed to be imported qualified) providing said definitions, to allow something like this:

    sendKeys ("Some category" <> K.enter) =<< select ".add-category"

I can think of several alternatives to this:

  • the definitions might be called like enter_ and then there'd be no need for qualified imports
  • there might be a sendKeys' function handling input of the form foo{enter}bar{shift} (or something like that)
  • both things at once

If you want, I will make a pull request.

(Also, the link in the description of sendKeys is broken.)

New hackage release?

I have a couple packages I want to release that depend on git head of this package.

Webdriver 0.8.0.1 doesn't work with aeson before 0.10

Compiling with stackage LTS (which uses aeson 0.8 still) results in the compile error

src/Test/WebDriver/Commands.hs:216:55:
    Could not deduce (ToJSON (f JSArg)) arising from a use of ‘pair’
    from the context (Foldable f, FromJSON a, WebDriver wd)
      bound by the type signature for
                 executeJS :: (Foldable f, FromJSON a, WebDriver wd) =>
                              f JSArg -> Text -> wd a
      at src/Test/WebDriver/Commands.hs:213:14-78
    In the second argument of ‘(.)’, namely ‘pair ("args", "script")’
    In the expression:
      doSessCommand methodPost "/execute" . pair ("args", "script")
    In the expression:
      doSessCommand methodPost "/execute" . pair ("args", "script")
      $ (a, s)

src/Test/WebDriver/Commands.hs:228:61:
    Could not deduce (ToJSON (f JSArg)) arising from a use of ‘pair’
    from the context (Foldable f, FromJSON a, WebDriver wd)
      bound by the type signature for
                 asyncJS :: (Foldable f, FromJSON a, WebDriver wd) =>
                            f JSArg -> Text -> wd (Maybe a)
      at src/Test/WebDriver/Commands.hs:225:12-84
    In the second argument of ‘(.)’, namely ‘pair ("args", "script")’
    In the expression:
      doSessCommand methodPost "/execute_async" . pair ("args", "script")
    In the expression:
      doSessCommand methodPost "/execute_async" . pair ("args", "script")
      $ (a, s)

Doing some investigation, it looks like the instance (Foldable f, ToJSON a) => ToJSON (f a) was only added in aeson version 0.10. The simplest fix is just to call toList explicitly. If I changed executeJs and asyncJs to call toList on the parameter a, everything compiles.

Compilation fails against http-client >= 0.5.0

webdriver has problems compiling against versions of http-client >= 0.5.0. It gives the following error:

src\Test\WebDriver\Internal.hs:16:82: error:
    Module
    `Network.HTTP.Client'
    does not export
    `HttpException(ResponseTimeout)'

It seems the latest versions of http-client made changes to the HttpException datatype.

Using chromedriver does not work

Consider the following test file (using my base path pull request):

{-# LANGUAGE OverloadedStrings #-}

import Test.WebDriver

main :: IO ()
main = runSession session caps testWD
  where
    session = defaultSession { wdPort     = 9515
                             , wdBasePath = "" }
    caps = defaultCaps { browser = chrome }

testWD :: WD ()
testWD = do
  openPage "http://www.google.com/"
  searchBox <- findElem (ByName "q")
  sendKeys "yesodweb" searchBox
  submit searchBox

What I get is

$ runhaskell webdriver.hs
webdriver.hs: HTTPStatusUnknown (3,0,3) "See Other "

However, a Chrome window is opened and using Wireshark I see that chromedriver did return a new session ID:

POST /session HTTP/1.1
Connection: close
User-Agent: haskell-HTTP/4000.2.3
Host: 127.0.0.1:9515
Accept: application/json;charset=UTF-8
Content-Type: application/json;charset=UTF-8
Content-Length: 451

{"desiredCapabilities":{"handlesAlerts":null,"chrome.switches":[],"takesScreenshot":null,"locationContextEnabled":null,"javascriptEnabled":null,"rotatable":null,"cssSelectorsEnabled":null,"databaseEnabled":null,"applicationCacheEnabled":null,"proxy":{"proxyType":"SYSTEM"},"webStorageEnabled":null,"browserConnectionEnabled":null,"acceptSslCerts":null,"platform":"ANY","nativeEvents":null,"browserName":"chrome","version":null,"chrome.extensions":[]}}
HTTP/1.1 303 See Other
connection:close
content-type:application/json; charset=utf-8
location:/session/5a09d158240152c716198fb75b290c9b
content-length:66

{"status":303,"value":"/session/5a09d158240152c716198fb75b290c9b"}

Am I doing something wrong? How do you use Chrome with webdriver?

Selenium and PAC proxy: empty path to PAC-file in Firefox

Hi again!

I try to use a proxy capability. When I use Manual proxy setting - it works like a charm: I see corresponding proxy settings in the Network settings of the Firefox (started by Selenium standalone server). But when I try to use PAC proxy, I got a problem.

This is my code:

capabilities :: Capabilities
capabilities = defaultCaps { proxy = pacBasedProxy }
  where
    pacBasedProxy = PAC { autoConfigUrl = pathToBrowserPACFileAsURL }

Function pathToBrowserPACFileAsURL returns a file path to the PAC-file (like file:///tmp/selenium-pac-test). File actually exists, its content is correct (I've checked it). But if I look in the Network setting of the Firefox - I see an empty path to the PAC-file:

alt text

As you can see, PAC proxy option is active, but path to the PAC-file is empty... Obviuosly, PAC-based proxy doesn't work in this case...

This is what I see in the Selenium server's log:

Executing: [new session: Capabilities [{proxy={autoConfigUrl=file:///tmp/selenium-pac-test, proxyType=PAC}, loggingPrefs=org.openqa.selenium.logging.LoggingPreferences@27d3164b, browserName=firefox, platform=ANY}]])

Selenium see that I want to use PAC-based proxy, but why is path to the PAC-file empty? How can I fix it?

Install fail when using docker haskell

Not sure it's duplicated or not. When I try to install the library in Docker haskell ( https://hub.docker.com/_/haskell/ ) with command

cabal update; cabal install webdriver;

I got the error message:

src/Test/WebDriver/Internal.hs:16:82: error:
    Module
    ‘Network.HTTP.Client’
    does not export
    ‘HttpException(ResponseTimeout)’
cabal: Leaving directory '/tmp/cabal-tmp-59/webdriver-0.8.3'
cabal: Error: some packages failed to install:
webdriver-0.8.3 failed during the building phase. The exception was:
ExitFailure 1

When install with stack, It installed successfully (not sure about run)

webdriver-0.5.3 doesn't compile with aeson-0.7.0.0

ByteString instances of FromJSON and ToJSON classes were removed in aeson-0.7.0.0 (haskell/aeson#126).

Resolving dependencies...
Configuring webdriver-0.5.3...
Building webdriver-0.5.3...
Preprocessing library webdriver-0.5.3...
[ 1 of 15] Compiling Test.WebDriver.Chrome.Extension ( src/Test/WebDriver/Chrome/Extension.hs, dist/dist-sandbox-983400fd/build/Test/WebDriver/Chrome/Extension.o )

src/Test/WebDriver/Chrome/Extension.hs:17:51:
    No instance for (ToJSON ByteString)
      arising from the 'deriving' clause of a data type declaration
    Possible fix:
      add an instance declaration for (ToJSON ByteString)
      or use a standalone 'deriving instance' declaration,
           so you can specify the instance context yourself
    When deriving the instance for (ToJSON ChromeExtension)

src/Test/WebDriver/Chrome/Extension.hs:17:59:
    No instance for (FromJSON ByteString)
      arising from the 'deriving' clause of a data type declaration
    Possible fix:
      add an instance declaration for (FromJSON ByteString)
      or use a standalone 'deriving instance' declaration,
           so you can specify the instance context yourself
    When deriving the instance for (FromJSON ChromeExtension)
Failed to install webdriver-0.5.3

phantomjs cli args not passed to Ghostdriver/PhantomJS

with the following config

myConfig = defaultConfig { wdCapabilities = defaultCaps { browser = Browser "phantomjs",
    acceptSSLCerts = Just True,
    additionalCaps = [("phantomjs.page.settings.userAgent","...")
                             ,("phantomjs.cli.args", "--webdriver-logfile=/tmp/foo.log --webdriver=11122 --ignore-ssl-errors=yes")
                             ,("phantomjs.binary.path", "/usr/local/bin/phantomjs")
                              ]} }

the selenium node does not pass the cli args to the phantomjs process:

12:12:03.125 INFO - Executing: [new session: Capabilities [{proxy={proxyType=SYSTEM}, acceptSslCerts=true, phantomjs.binary.path=/usr/local/bin/phantomjs, phant
omjs.page.settings.userAgent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:42.0) Gecko/20100101 Firefox/42.0, browserName=phantomjs, phantomjs.cli.args=--webd
river-logfile=/tmp/foo.log --webdriver=11122 --ignore-ssl-errors=yes, platform=ANY}]])
12:12:03.169 INFO - Creating a new session for Capabilities [{proxy={proxyType=SYSTEM}, acceptSslCerts=true, phantomjs.binary.path=/usr/local/bin/phantomjs, phantomjs.page.settings.userAgent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:42.0) Gecko/20100101 Firefox/42.0, browserName=phantomjs, phantomjs.cli.args=--webdriver-logfile=/tmp/foo.log --webdriver=11122 --ignore-ssl-errors=yes, platform=ANY}]
12:12:03.182 INFO - executable: /usr/local/bin/phantomjs
12:12:03.182 INFO - port: 38882
12:12:03.182 INFO - arguments: [--proxy-type=system, --webdriver=38882, --webdriver-logfile=/var/crawler/selenium/phantomjsdriver.log]
12:12:03.182 INFO - environment: {}
PhantomJS is launching GhostDriver...
[INFO  - 2015-12-08T11:12:03.864Z] GhostDriver - Main - running on port 38882
[INFO  - 2015-12-08T11:12:04.038Z] Session [82d711a0-9d9c-11e5-9a25-558c16c15c60] - page.settings - {"XSSAuditingEnabled":false,"javascriptCanCloseWindows":true
,"javascriptCanOpenWindows":true,"javascriptEnabled":true,"loadImages":true,"localToRemoteUrlAccessEnabled":false,"userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.

as can be seen in the line "12:12:03.182 INFO - arguments: " the arguments are not the ones from the haskell code.

I am using sleenium node with 'selenium-server-standalone.2.48.2.jar' and phantomjs 1.9.8,
and starting the node like this:

$JAVA -jar ./selenium-server-standalone.jar \
-role node \
-hub http://localhost:4444/grid/register \
-host localhost \
-port $PORT \
-browser "browserName=phantomjs,maxInstances=5" \
-maxSession 5 \
-timeout 30000 \
-nodePolling 5000 \
-downPollingLimit 3 \
-unregisterIfStillDownAfter 5000

Any Ideas how to pass command line args to the phantomjs browser?
Do I miss something?

thanks,
Alex.

add required capabilities support

Required capabilities need to be added to hs-webdriver. I've added some experimental code regarding this in the vinyl-capabilities branch that can be used as a reference. I'm still unsure if I want to use vinyl in release code.

more support for IO/logging ?

I imagine it is common to want to do IO in WD for troubleshooting or logging. I found these useful (especially before I found the session's browser window, which hides in the back on OSX):

p :: Show a => a -> WD ()
p = liftIO . print

printUrl :: WD ()
printUrl = getCurrentURL >>= liftIO . putStrLn

writeScreenshot :: FilePath -> WD ()
writeScreenshot f = screenshot >>= liftIO . B.writeFile f

wait :: Int -> WD ()
wait = liftIO . threadDelay

But I wonder if it would be possible to have IO actions just work in WD.

Does not build with network 2.4.*

src/Test/WebDriver/Internal.hs:52:56:
    Couldn't match expected type `Maybe b0' with actual type `URI'
    In the second argument of `($)', namely
      `relURI `relativeTo` baseURI'
    In the expression: return . fromJust $ relURI `relativeTo` baseURI
    In a case alternative:
        (Just baseURI, Just relURI)
          -> return . fromJust $ relURI `relativeTo` baseURI

Now relativeTo returns URI instead of Maybe URI (http://hackage.haskell.org/packages/archive/network/2.4.0.1/doc/html/Network-URI.html#v:relativeTo).

waitForPageLoad

Hi,

I just implemented code for making sure a new page has been loaded before returning from a wd action. See here:

liqd/thentos#114

Would you accept a PR that provides waitForPageLoad from Test.WebDriver.Commands.Wait? (I would make ackStaleException local, but do not insist either way; the *Sync seem like too much clutter for a general-purpose webdriver library and I would leave them out.)

Any suggestions welcome.

Cannot get the page opened

I try to automate tests with the help of hs-webdriver, code see below. I have a selenium-server instance started ("Started SocketListener on 0.0.0.0:4444"). Everytime I run the main function in ghci I get an

*** Exception: TimeoutTriggered

and also the given page isn't opened. Do you have any idea what I'm doing wrong?

:set -XOverloadedStrings    
:m + Test.WebDriver Control.Monad Test.WebDriver.Commands.Wait
let main :: IO() ; main = runSession defaultConfig $ do { openPage "http://stackoverflow.com/questions/ask" ; waitUntil 60 (findElem $ ByXPath ".//div") ; return () }

I also compiled the tests coming with the hs-webdriver now, but running .\dist\build\test-search-baidu\test-search-baidu.exe got me a: test-search-baidu.exe: TimeoutTriggered.

openPage always fails

The following code snippet fails at runtime with "*** Exception: connect: does not exist (Connection refused)"

import Test.WebDriver
main :: IO ()
main = runSession defaultSession defaultCaps $ do
openPage "http://www.wikipedia.org/"

Bump network dependency

Currently network >= 2.4 && < 2.6 is required.
Is it possible to bump the version to >2.6 (and maybe add network-url as advised by the network maintainers)?

This would make building darcsden easier for me.

findElem ByXPath loses with StatusCodeException

I'm trying to port a python selenium webdriver script to haskell, but I'm having trouble with ByXPath. I narrowed it down to this, which produces the huge StatusCodeException below:

{-# LANGUAGE OverloadedStrings #-}
import Test.WebDriver

main :: IO ()
main = runSession chromeConfig $ do
  openPage "http://google.com"
  x <- findElem (ByXPath "div")
  return ()

chromeConfig :: WDConfig
chromeConfig = defaultConfig { wdCapabilities = defaultCaps { browser = chrome }}

I'm using selenium-server-standalone-2.42.2.jar on Ubuntu 14.04. Other version info:

$ cabal info webdriver
...
    Versions installed: 0.6.0.1

$ apt-cache policy ghc
ghc:
  Installed: 7.6.3-10

$ /opt/google/chrome/google-chrome --version
Google Chrome 37.0.2062.94

This is the whole stderr from runghc xpathBug.hs:

xpathBug.hs: StatusCodeException (Status {statusCode = 500, statusMessage = "Internal Server Error"}) [("Date","Wed, 03 Sep 2014 18:04:49 GMT"),("Server","Jetty/5.1.x (Linux/3.13.0-35-generic amd64 java/1.7.0_51"),("Expires","Thu, 01 Jan 1970 00:00:00 GMT"),("Cache-Control","no-cache"),("Content-Length","648602"),("Expires","Thu, 01 Jan 1970 00:00:00 GMT"),("Content-Type","application/json; charset=utf-8"),("Cache-Control","no-cache"),("X-Response-Body-Start","{\"status\":7,\"sessionId\":\"3d245a45-7553-4636-937d-de421c4b98cf\",\"value\":{\"message\":\"no such element\\n  (Session info: chrome=37.0.2062.94)\\n  (Driver info: chromedriver=2.9.248304,platform=Linux 3.13.0-35-generic x86_64) (WARNING: The server did not provide any stacktrace information)\\nCommand duration or timeout: 31 milliseconds\\nFor documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html\\nBuild info: version: '2.42.2', revision: '6a6995d', time: '2014-06-03 17:42:03'\\nSystem info: host: 'pav', ip: '127.0.1.1', os.name: 'Linux', os.arch: 'amd64', os.version: '3.13.0-35-generic', java.version: '1.7.0_51'\\nSession ID: b5a6550a1ac7c1a4ac81a95bccf276f3\\nDriver info: org.openqa.selenium.chrome.ChromeDriver\\nCapabilities [{platform=LINUX, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/tmp/.com.google.Chrome.aj2IMR}, rotatable=false, locationContextEnabled=true, version=37.0.2062.94, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]\",\"screen\":\"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"),("X-Request-URL","POST http://127.0.0.1:4444/wd/hub/session/3d245a45-7553-4636-937d-de421c4b98cf/element")] (CJ {expose = []})

possible to execute commands incrementally in GHCI ?

Thanks for this great, super useful lib. (Aside: I found it much easier than the equivalent ruby or javascript libs. I did have quite a bit of trouble getting selenium working on osx. brew install selenium-server-standalone worked in the end, though it doesn't understand some things like getLogs. selenium-server-standalone245 opened the browser only. Other hurdles: getting a new enough java; finding the selenium browser window, which is backgrounded on OSX; discovering the wait* commands in the API and learning when they are needed, eg between openPage and findElem; "element detached from DOM" errors when trying to combine findElems.)

On to my question: it would be really helpful to be able to run exploratory commands one at a time in GHCI and observe the effects, keeping the session open. Is this possible ? I thought I had found a way:

*Main> :t runSession defaultConfig $ createSession def
runSession defaultConfig $ createSession def
  :: IO Test.WebDriver.Session.WDSession

..but this happens:

*Main> s <- runSession defaultConfig $ createSession def
*** Exception: ServerError "Server response session ID (Just (SessionId \"6fabed28-712d-4b48-bb45-88b5f5bf3b5f\")) does not match local session ID (Just (SessionId \"2dc93519-bcab-4588-9bce-18e4dfc82b1f\"))"

ensure W3C WebDriver support

Selenium 3 is out. I haven't been able to verify that hs-webdriver supports it due to time constraints, but I would like to make sure it does. Last I checked there was a major overhaul of the Rest API in the works.

add unimplemented commands

There are some commands in Selenium 3 that are currently not implemented in hs-webdriver.

  • get element screenshot
  • get element property
  • get element rectangle
  • window full screen

Release new version

Improvements made by #8 and #9 still weren't released on Hackage. Could you bump the version and release the package? If you prefer, I may do so in your stead as well =).

phantomjs driver with https problem

Hi,
the phantomjs driver works fine with HTTP, but fails to load sites with HTTPS.
Even with 'acceptSSLCerts = Just True' they don't load.

here is my code:

myConfig :: WDConfig
myConfig = defaultConfig { wdCapabilities = defaultCaps { browser = Browser "phantomjs",
acceptSSLCerts = Just True
]} }
printing out the WD getSource:
"<html><head></head><body></body></html>"

printing out the WD getCurrentURL (for all HTTPS pages):
"about:blank"

BTW I am running pahntomjs 1.9.8, stack lts 3.16, webdriver-0.6.3.1

Any idea how to fix it?

thanks,
Alex.

A better read me would be welcome

I think it would be good to have a better read me file. For example it could be included (for beginners like me) how to use the tool (first you have to start selenium webdriver standalone server with java -jar, then you can start your Haskell program). The list of compatible selenium versions would be also important.

Add default timeout values for explicit waits

A feature request based on conversation with @adinapoli in issue #92

Currently all wait* functions use explicit timeout parameters. Instead, include the ability to set a default timeout value as a state variable.

Variation 1: add state field directly to WDConfig and WDSession

conf = defaultConfig 
  { explicitWaitTimeout = Just 5  -- new config field. Nothing indicates indefinite waiting
  }

main = runSession conf $ do
  useWaitTimeout 10 -- can also set value via command instead of the config field 
  waitUntil foo
  useIndefiniteWait -- remove timeout. indefinite waiting
  waitUntil bar

  waitWithTimeoutUntil 10 baz -- explicit timeout value provided. function name too wordy?

Nice and simple with no additional types to work with. Easy to use in situations where test cases are heavily decoupled. However, since the timeout state is "global" to the session it can easily leak into unrelated test cases. Feels like I'm working with an imperative language instead of Haskell, but then again this library is already heavily imperative in design due to the nature of the WebDriver framework.

Variation 2: use a new state monad WDWait on top of WD that keeps track of timeout

In this variation, the wait* combinators result in a WDWait a instead of the current WD a. This new WDWait type is just a state monad on top of the existing WD monad with a simple timeout value.

main = runSession defaultConfig $ do
  withTimeout 10 $ do 
    waitUntil foo
    waitUntil bar
  withNoTimeout $ do -- no timeout. indefinite waiting
    waitUntil baz

This results in an block-structured code flow, but might be clunky when test cases are heavily split up or when many different timeouts are desired. Feels more like I'm working with Haskell.

EDIT: On further consideration I don't necessarily think isolated test cases would be clunky. In fact it has a natural-language-esque presentation:

withTimeout 10 . waitUntil $ ...

or

withNoTimeout . waitUntil $ ...

Questions and Considerations

  • Should we gut the existing functions that use mandatory timeout arguments, rename them to something else, or keep them as-is and use new names for the new functions? In any of these case, what names should we use?
  • What is the default for the default? 0? Some arbitrary number of seconds like 5 or 10? Wait indefinitely?

waitWhile retries on failure

I intended to use waitWhile to wait for the absence of an element and was puzzled that the code did not work. My understanding is that waitWhile should retry as long as the command succeeds. However, the following implementation seems to call retry if the command wd fails. Am I missing something obvious?

-- |Like 'waitUntil'', but retries the action until it either fails or
-- until the timeout is exceeded.
waitWhile' :: SessionState m => Int -> Double -> m a -> m ()
waitWhile' = wait' handler
  where
    handler retry wd = do
      b <- (wd >> return Nothing) `catches` [Handler handleFailedCommand
                                            ,Handler handleExpectFailed
                                            ]
      maybe (return ()) retry b
      where
        handleFailedCommand e@(FailedCommand NoSuchElement _) = return (Just $ show e)
        handleFailedCommand err = throwIO err

        handleExpectFailed (e :: ExpectFailed) = return (Just $ show e)

A pack of warnings while installing

[ 3 of 13] Compiling Test.WebDriver.Firefox.Profile ( src\Test\WebDriver\Firefox
\Profile.hs, dist\build\Test\WebDriver\Firefox\Profile.o )

src\Test\WebDriver\Firefox\Profile.hs:196:3:
Warning: A do-notation statement discarded a result of type SBS.ByteString.
Suppress this warning by saying "_ <- ($)
padSpaces string "user_pref
("",
or by using the flag -fno-warn-unused-do-bind

src\Test\WebDriver\Firefox\Profile.hs:198:3:
Warning: A do-notation statement discarded a result of type Char.
Suppress this warning by saying "_ <- ($) padSpaces char ','",
or by using the flag -fno-warn-unused-do-bind

src\Test\WebDriver\Firefox\Profile.hs:200:3:
Warning: A do-notation statement discarded a result of type SBS.ByteString.
Suppress this warning by saying "_ <- ($) padSpaces string ");"",
or by using the flag -fno-warn-unused-do-bind

Add the ability to extract session data from a test

A skunkworks implementation of mine, because I couldn't figure out how to extract it otherwise:

runSession' :: WDConfig -> WD a -> IO WDSession
runSession' conf test = do
 ref <- (newIORef undefined)
 runSession conf (dumpSessionHistoryWithIORef ref test)
 s <- readIORef ref
 return s

dumpSessionHistoryWithIORef :: WDSessionStateControl wd => IORef WDSession -> wd a -> wd a
dumpSessionHistoryWithIORef ref = (`finally` (getSession >>= writeIORef ref))

Example use:

> runSession' remoteConfig test >>= print . wdSessHist

waitUntil not catching the NotFound Exceptions

TL;DR: The fixes have not been released to Hackage yet. Please read the last comment and release the latest fixes on master to Hackage so that people don't continue running into this problem. Read my last comment for more info.

In cabal I have specified ==0.6.* of this library.

I have written the following condition code which I have passed to a waitUntil:

containsText "Installed and ready to go!" =<< findElem (ById "upm-plugin-status-dialog")

containsText :: (WebDriver wd) => String -> Element -> wd ()
containsText text element = do
    actualText <- getText element
    expect (text `isInfixOf` T.unpack actualText)

And when it runs I get the following back from selenium server:

12:32:10.974 INFO - Executing: [find element: By.id: upm-plugin-status-dialog])
12:32:11.741 WARN - Exception thrown
org.openqa.selenium.NoSuchElementException: no such element
  (Session info: chrome=38.0.2125.111)
  (Driver info: chromedriver=2.11.298611 (d1120fdf51badec2f7b63a96e19a58d4783de84d),platform=Mac OS X 10.9.5 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 42 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html
Build info: version: '2.43.1', revision: '5163bce', time: '2014-09-10 16:27:33'
System info: host: 'Roberts-Mac-Pro.local', ip: '192.168.1.150', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9.5', java.version: '1.7.0_60'
Session ID: 20877f4da18a7aef7a9817985b873274
Driver info: org.openqa.selenium.chrome.ChromeDriver
Capabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/var/folders/zs/16ql7n3j5bs7vb0h2bbycz080000gp/T/.org.chromium.Chromium.lsl41L}, rotatable=false, locationContextEnabled=true, mobileEmulationEnabled=false, version=38.0.2125.111, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]
    at sun.reflect.GeneratedConstructorAccessor20.newInstance(Unknown Source)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204)
    at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:156)
    at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:352)
    at org.openqa.selenium.remote.RemoteWebDriver.findElementById(RemoteWebDriver.java:393)
    at org.openqa.selenium.By$ById.findElement(By.java:214)
    at org.openqa.selenium.remote.RemoteWebDriver.findElement(RemoteWebDriver.java:344)
    at sun.reflect.GeneratedMethodAccessor22.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.openqa.selenium.support.events.EventFiringWebDriver$2.invoke(EventFiringWebDriver.java:101)
    at com.sun.proxy.$Proxy1.findElement(Unknown Source)
    at org.openqa.selenium.support.events.EventFiringWebDriver.findElement(EventFiringWebDriver.java:184)
    at org.openqa.selenium.remote.server.handler.FindElement.call(FindElement.java:47)
    at org.openqa.selenium.remote.server.handler.FindElement.call(FindElement.java:1)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at org.openqa.selenium.remote.server.DefaultSession$1.run(DefaultSession.java:169)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
12:32:11.742 WARN - Exception: no such element
  (Session info: chrome=38.0.2125.111)
  (Driver info: chromedriver=2.11.298611 (d1120fdf51badec2f7b63a96e19a58d4783de84d),platform=Mac OS X 10.9.5 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 42 milliseconds

Now, as far as I can tell that looks like a standard not found exception to me which the documentation of waitUntil (and the code itself) seems to suggest that it will catch. However, it is not until I replace that condition with:

expect . not . null =<< findElems (ById "upm-plugin-status-dialog")

that the code works as expected. What is going on here and how can I make this work all of the time? I think that this may be a bug.

P.S. Oh, and on the haskell side I am getting this:

remind-me-integration: StatusCodeException (Status {statusCode = 500, statusMessage = "Internal Server Error"}) [("Date","Sun, 09 Nov 2014 01:32:10 GMT"),("Server","Jetty/5.1.x (Mac OS X/10.9.5 x86_64 java/1.7.0_60"),("Expires","Thu, 01 Jan 1970 00:00:00 GMT"),("Cache-Control","no-cache"),("Content-Length","467018"),("Expires","Thu, 01 Jan 1970 00:00:00 GMT"),("Content-Type","application/json; charset=utf-8"),("Cache-Control","no-cache"),("X-Response-Body-Start","{\"status\":7,\"sessionId\":\"6890a609-3c81-4234-8f7d-11555d06983d\",\"value\":{\"message\":\"no such element\\n  (Session info: chrome=38.0.2125.111)\\n  (Driver info: chromedriver=2.11.298611 (d1120fdf51badec2f7b63a96e19a58d4783de84d),platform=Mac OS X 10.9.5 x86_64) (WARNING: The server did not provide any stacktrace information)\\nCommand duration or timeout: 42 milliseconds\\nFor documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html\\nBuild info: version: '2.43.1', revision: '5163bce', time: '2014-09-10 16:27:33'\\nSystem info: host: 'Roberts-Mac-Pro.local', ip: '192.168.1.150', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.9.5', java.version: '1.7.0_60'\\nSession ID: 20877f4da18a7aef7a9817985b873274\\nDriver info: org.openqa.selenium.chrome.ChromeDriver\\nCapabilities [{platform=MAC, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/var/folders/zs/16ql7n3j5bs7vb0h2bbycz080000gp/T/.org.chromium.Chromium.lsl41L}, rotatable=false, locationContextEnabled=true, mobileEmulationEnabled=false, version=38.0.2125.111, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]\",\"screen\":\"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\\n6xzyWmajnUP"),("X-Request-URL","POST http://127.0.0.1:4444/wd/hub/session/6890a609-3c81-4234-8f7d-11555d06983d/element")] (CJ {expose = []})

Build failure with GHC 7.10

Unpacking to webdriver-0.6.1/
Resolving dependencies...
Configuring webdriver-0.6.1...
Building webdriver-0.6.1...
Preprocessing library webdriver-0.6.1...
[ 1 of 17] Compiling Test.WebDriver.Chrome.Extension ( src/Test/WebDriver/Chrome/Extension.hs, dist/build/Test/WebDriver/Chrome/Extension.o )

src/Test/WebDriver/Chrome/Extension.hs:13:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()
[ 2 of 17] Compiling Test.WebDriver.Common.Profile ( src/Test/WebDriver/Common/Profile.hs, dist/build/Test/WebDriver/Common/Profile.o )

src/Test/WebDriver/Common/Profile.hs:54:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()
[ 3 of 17] Compiling Test.WebDriver.Firefox.Profile ( src/Test/WebDriver/Firefox/Profile.hs, dist/build/Test/WebDriver/Firefox/Profile.o )

src/Test/WebDriver/Firefox/Profile.hs:32:1: Warning:
    Module ‘Data.Attoparsec.Char8’ is deprecated:
      This module will be removed in the next major release.
[ 4 of 17] Compiling Test.WebDriver.Utils ( src/Test/WebDriver/Utils.hs, dist/build/Test/WebDriver/Utils.o )
[ 5 of 17] Compiling Test.WebDriver.JSON ( src/Test/WebDriver/JSON.hs, dist/build/Test/WebDriver/JSON.o )

src/Test/WebDriver/JSON.hs:41:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()
[ 6 of 17] Compiling Test.WebDriver.Capabilities ( src/Test/WebDriver/Capabilities.hs, dist/build/Test/WebDriver/Capabilities.o )

src/Test/WebDriver/Capabilities.hs:19:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()
[ 7 of 17] Compiling Test.WebDriver.Session ( src/Test/WebDriver/Session.hs, dist/build/Test/WebDriver/Session.o )

src/Test/WebDriver/Session.hs:21:1: Warning:
    Module ‘Control.Monad.Error’ is deprecated:
      Use Control.Monad.Except instead

src/Test/WebDriver/Session.hs:23:1: Warning:
    The import of ‘Control.Monad.Writer.Strict’ is redundant
      except perhaps to import instances from ‘Control.Monad.Writer.Strict’
    To import instances alone, use: import Control.Monad.Writer.Strict()

src/Test/WebDriver/Session.hs:104:11: Warning:
    In the use of type constructor or class ‘Error’
    (imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
    Deprecated: "Use Control.Monad.Trans.Except instead"

src/Test/WebDriver/Session.hs:104:57: Warning:
    In the use of type constructor or class ‘ErrorT’
    (imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
    Deprecated: "Use Control.Monad.Trans.Except instead"
[ 8 of 17] Compiling Test.WebDriver.Config ( src/Test/WebDriver/Config.hs, dist/build/Test/WebDriver/Config.o )
[ 9 of 17] Compiling Test.WebDriver.Class ( src/Test/WebDriver/Class.hs, dist/build/Test/WebDriver/Class.o )

src/Test/WebDriver/Class.hs:19:1: Warning:
    Module ‘Control.Monad.Error’ is deprecated:
      Use Control.Monad.Except instead

src/Test/WebDriver/Class.hs:21:1: Warning:
    The import of ‘Control.Monad.Writer.Strict’ is redundant
      except perhaps to import instances from ‘Control.Monad.Writer.Strict’
    To import instances alone, use: import Control.Monad.Writer.Strict()

src/Test/WebDriver/Class.hs:68:11: Warning:
    In the use of type constructor or class ‘Error’
    (imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
    Deprecated: "Use Control.Monad.Trans.Except instead"

src/Test/WebDriver/Class.hs:68:48: Warning:
    In the use of type constructor or class ‘ErrorT’
    (imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
    Deprecated: "Use Control.Monad.Trans.Except instead"
[10 of 17] Compiling Test.WebDriver.Internal ( src/Test/WebDriver/Internal.hs, dist/build/Test/WebDriver/Internal.o )

src/Test/WebDriver/Internal.hs:39:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()

src/Test/WebDriver/Internal.hs:46:1: Warning:
    The import of ‘Word’ from module ‘Data.Word’ is redundant
[11 of 17] Compiling Test.WebDriver.Commands.Internal ( src/Test/WebDriver/Commands/Internal.hs, dist/build/Test/WebDriver/Commands/Internal.o )

src/Test/WebDriver/Commands/Internal.hs:30:1: Warning:
    The import of ‘Control.Applicative’ is redundant
      except perhaps to import instances from ‘Control.Applicative’
    To import instances alone, use: import Control.Applicative()
[12 of 17] Compiling Test.WebDriver.Exceptions ( src/Test/WebDriver/Exceptions.hs, dist/build/Test/WebDriver/Exceptions.o )
[13 of 17] Compiling Test.WebDriver.Commands.Wait ( src/Test/WebDriver/Commands/Wait.hs, dist/build/Test/WebDriver/Commands/Wait.o )
[14 of 17] Compiling Test.WebDriver.Commands ( src/Test/WebDriver/Commands.hs, dist/build/Test/WebDriver/Commands.o )

src/Test/WebDriver/Commands.hs:221:15:
    Could not deduce (L.Exception e0) arising from a use of ‘handle’
    from the context (WebDriver wd, FromJSON a)
      bound by the type signature for
                 asyncJS :: (WebDriver wd, FromJSON a) =>
                            [JSArg] -> Text -> wd (Maybe a)
      at src/Test/WebDriver/Commands.hs:220:12-72
    The type variable ‘e0’ is ambiguous
    Note: there are several potential instances:
      instance L.Exception L.NestedAtomically
        -- Defined in ‘Control.Exception.Base’
      instance L.Exception L.NoMethodError
        -- Defined in ‘Control.Exception.Base’
      instance L.Exception L.NonTermination
        -- Defined in ‘Control.Exception.Base’
      ...plus 31 others
    In the expression: handle timeout
    In the expression:
      handle timeout $ Just <$> (fromJSON' =<< getResult)
    In an equation for ‘asyncJS’:
        asyncJS a s
          = handle timeout $ Just <$> (fromJSON' =<< getResult)
          where
              getResult
                = doSessCommand methodPost "/execute_async"
                  . pair ("args", "script")
                  $ (a, s)
              timeout (FailedCommand Timeout _) = return Nothing
              timeout (FailedCommand ScriptTimeout _) = return Nothing
              timeout err = throwIO err

src/Test/WebDriver/Commands.hs:225:5:
    Non type-variable argument in the constraint: MonadBase IO m
    (Use FlexibleContexts to permit this)
    When checking that ‘timeout’ has the inferred type
      timeout :: forall (m :: * -> *) a.
                 MonadBase IO m =>
                 FailedCommand -> m (Maybe a)
    In an equation for ‘asyncJS’:
        asyncJS a s
          = handle timeout $ Just <$> (fromJSON' =<< getResult)
          where
              getResult
                = doSessCommand methodPost "/execute_async"
                  . pair ("args", "script")
                  $ (a, s)
              timeout (FailedCommand Timeout _) = return Nothing
              timeout (FailedCommand ScriptTimeout _) = return Nothing
              timeout err = throwIO err

PhantomJS Support

What would be necessary? Anything to keep in mind?

If I decided to try and add this, would I be able to just model the Chrome module? Upon looking at the Chrome module, it looks like not much is in there.

Any direction is appreciated.

FindElems and FindElemsFrom

In commit b11eba5, the findElems and findElemsFrom functions no longer return lists of elements, but a single element. What is the motivation for this change, and is there another way to go about getting lists of elements off a page?

`rspStatus` is Word8 but can be set to 405?

I've seen this warning when building the library: Literal 405 is out of the Word8 range 0..255. I believe 405 is an HTTP status code. Is it possible to be in the JSON body as well?

add WDJavascript monad for complex Javascript injection

It's a common task in testing large web applications with Selenium to inject Javascript code. However, the current mechanism for doing so is very low-level and could use big improvements.

Firstly, we want to support named arguments for javascript injection. To do that we change the JSArg function to the following:

data JSArg = ToJSON a => JSArg Text a

The new Text argument to the constructor is a variable name, and the variable will be automatically defined at the beginning of the script.

But we can also provide more advanced capabilities for large, complex scripts by implementing a state-writer monad. The idea is to change executeJS and asyncJS to the following type

(ToJavascript script, Foldable f, FromJSON result, WebDriver wd) =>f JSArg -> script -> wd a

with ToJavascript being a class defined as:

class ToJavascript script where
  addJSArg :: JSArg -> script -> script
  getJavascript :: script -> Text

This class would have a Text instance, allowing the new executeJS to be mostly backwards compatible. However, now it is possible to define a WDJavascript monad that implements a DSL for Javascript construction. An example of usage would be:

myScript :: Text -> Float -> HashMap String String -> [Int] -> WDJavascript ()
myScript arg1 arg2 arg3 arg4 = do
  --declare two named variables
  var "message" arg1
  var "timer" arg2
  
  --write raw JS
  writeJS "console.log(message, timer);"

  --retrieve all defined variables  
  varMap <- getVars
  
  --delete the previous variables
  deleteVar "message"
  deleteVar "timer"
  
  --define multiple variables as a assoc list
  vars [("properties", JSArg arg3), ("vector", JSArg arg4)] 

  --delete multiple variables
  deleteVars ["properties", "vector" -- delete multiple variables

This provides an easy framework for others to add Javascript injection facilities of their own. See https://github.com/zerobuzz/webtest/blob/84fed8a494872eeafb475eca6dcb79d43eb0cad0/src/Test/WebApp/WebDriver.hs for ideas on functions that could be implemented for AngularJS support etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.