Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all text inputs on webpage with Haskell webdriver package

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.
like image 265
codygman Avatar asked Mar 19 '23 02:03

codygman


2 Answers

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']"
like image 185
Jan Hrcek Avatar answered Mar 21 '23 15:03

Jan Hrcek


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.

like image 44
rethab Avatar answered Mar 21 '23 16:03

rethab