我正在使用Haskell WebDriver selenium软件包进行测试,here。
我有这个例子:
import Test.WebDriver
firefoxConfig :: WDConfig
firefoxConfig = defaultConfig
main :: IO ()
main = runSession firefoxConfig $ do
openPage "http://google.com"
searchInput <- findElem ( ByCSS "input[type='text']" )
sendKeys "Hello, World!" searchInput
submit searchInput
closeSession
getting started section表明selenium客户端需要selenium服务器与
进行通信java -jar selenium-server-standalone-*.jar
如果没有它运行,你会得到这个:
ghci λ> main
*** Exception: FailedConnectionException2 "127.0.0.1" 4444 False connect: does not exist (Connection refused)
我希望将我的整个测试脚本包装在一个函数中,该函数初始化selenium-server,记录其pid,并在运行会话后kill(pid)。也就是说,在我现有的main的持续时间内,我想调用java selenium-server,但我希望它在调用完成后立即停止存在。
在python中我通过定义__enter__()
和__exit__()
以及其他拆解内容subprocess.Popen
,记录id,杀死它,然后执行此操作调用
with Browser() as b:
do_stuff
我理解runSession实体是我需要复制以包装启动和拆卸这样的事情,因为它将firefoxConfig $ do
块作为参数并且我想这样做,太
但是,我无法理解来自询问runSession的类型,如何做出这样的事情:
ghci λ> :t runSession
runSession
:: Test.WebDriver.Config.WebDriverConfig conf =>
conf -> WD a -> IO a
我想我正在寻找某种withMonad我可以应用于do
。我认为语法会是某种......
import Test.WebDriver
import System.Process
firefoxConfig :: WDConfig
firefoxConfig = defaultConfig
withBrowser :: Monad a -> Monad a -- maybe this type?
withBrowser = do
r <- createProcess (proc "java -jar selenium-server-standalone-*.jar" [])
-- other magic here?
main :: IO ()
main = withBrowser $ runSession firefoxConfig $ do
openPage "http://google.com"
searchInput <- findElem ( ByCSS "input[type='text']" )
sendKeys "Hello, World!" searchInput
submit searchInput
closeSession
我将如何实现这一目标? monad是否正确?是否有更多的Haskell习惯用法或策略?
答案 0 :(得分:1)
你基本上只想要来自https://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Exception.html#v:bracket的bracket
。
它允许您指定设置和拆卸IO操作以围绕第三个操作运行。它会自动处理将设置动作的输出输入主动作和拆卸动作,你的设置动作应该只给出PID的结果,这样拆解动作就会被告知要杀死什么PID。
类似的东西:
withBrowser browserAction
= bracket startSelenium killSelenium (const browserAction)
(我假设您不希望主要操作必须为pid采用参数,因此我使用const
忽略它)