Here is my attempt at finding all inputs of type "text" on a webpage. I have since figured out I could use xpath, but I'd like to know how to make the way I attempted work. I'm most interested in how I would lifft my [Element] into the [WD Element] and make this program valid.
However if my approach is just wrong or unidiomatic, feel free to totally rewrite it. Here is the code:
{-# LANGUAGE OverloadedStrings #-}
import Control.Monad
import Control.Monad.IO.Class
import Test.WebDriver
import Test.WebDriver.Classes (WebDriver (..))
import Test.WebDriver.Commands
import Test.WebDriver.Commands.Wait
main = do
runSession defaultSession capabilities $ do
openPage "http://www.appnitro.com/demo/view.php?id=1"
inputs <- findElems $ ByTag "input"
textElems <- filterM (liftM $ ((==) "text" . (`attr` "type"))) inputs
-- wait 20 seconds
waitUntil 20 (getText <=< findElem $ ByCSS ".doesnotexist")
`onTimeout` return ""
liftIO $ putStrLn "done"
where
capabilities = allCaps { browser=firefox }
-- [1 of 1] Compiling Main ( src/Main.hs, interpreted )
-- src/Main.hs:168:70:
-- Couldn't match type `Element' with `WD Element'
-- Expected type: [WD Element]
-- Actual type: [Element]
-- In the second argument of `filterM', namely `inputs'
-- In a stmt of a 'do' block:
-- textElems <- filterM
-- (liftM $ ((==) "text" . (`attr` "type"))) inputs
-- In the second argument of `($)', namely
-- `do { openPage "http://www.appnitro.com/demo/view.php?id=1";
-- inputs <- findElems $ ByTag "input";
-- textElems <- filterM
-- (liftM $ ((==) "text" . (`attr` "type"))) inputs;
-- waitUntil 20 (getText <=< findElem $ ByCSS ".doesnotexist")
-- `onTimeout` return "" }'
-- Failed, modules loaded: none.
This might not be the answer you were looking for, but I find it best to express these kinds of constraints on elements directly in the locators, in order not to clutter the haskell sources. As you mention using XPath is one possibility:
textElems <- findElems $ ByXPath "//input[@type='text']"
but I often prefer CSS selectors, which tend to be briefer (alas a bit less powerful - e.g. you cannot traverse from given element to its parent etc.) and work just as well in these simple cases
textElems <- findElems $ ByCSS "input[type='text']"
Replace your text elem filtering with this piece:
textElems <- filterM textElem inputs
And then add this where:
textElem e = (== Just "text") `fmap` (e `attr` "type")
But then you will still have the line with waitUntil that doesn't compile. That seems unrelated though as it has nothing to do with the filtering.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With