围绕do块的haskell"withSubprocess"构造

Mit*_*ops 6 selenium haskell

我通过哈斯克尔硒的webdriver工作包进行测试,在这里.

我有这个例子:

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                                            
Run Code Online (Sandbox Code Playgroud)

入门部分明确指出,硒客户端需要硒服务器进行通信

java -jar selenium-server-standalone-*.jar
Run Code Online (Sandbox Code Playgroud)

没有它运行,你得到这个:

ghci    ?> main
*** Exception: FailedConnectionException2 "127.0.0.1" 4444 False connect: does not exist (Connection refused)
Run Code Online (Sandbox Code Playgroud)

我想将我的整个测试脚本包装在一个函数中,该函数初始化selenium-server,记录它的pid,并在运行会话后kill(pid).也就是说,在我现有main的持续时间内,我想调用java selenium-server,但我希望它在调用完成后立即停止存在.

在python中我会通过定义一个__enter__()和一个__exit__()其他拆解的东西subprocess.Popen,记录id,杀死它,然后调用

with Browser() as b:
  do_stuff
Run Code Online (Sandbox Code Playgroud)

我理解runSession实体是我需要复制以包装启动和拆卸这样的事情,因为它将firefoxConfig $ do块作为参数,我也想这样做.

但是,我无法理解来自询问runSession的类型,如何做出这样的事情:

ghci    ?> :t runSession
runSession
  :: Test.WebDriver.Config.WebDriverConfig conf =>
     conf -> WD a -> IO a
Run Code Online (Sandbox Code Playgroud)

我想我会寻找某种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                                            
Run Code Online (Sandbox Code Playgroud)

我怎么做到这一点?monad是否正确?是否有更多的Haskell成语或策略?

Ben*_*Ben 1

您基本上只bracket需要https://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Exception.html#v:bracket

它允许您指定设置和拆卸 IO 操作以围绕第三个操作运行。它自动处理将设置操作的输出馈送到主操作和拆卸操作中,您的设置操作是否应该只给出 PID 作为结果,以便拆卸操作将被告知要杀死哪个 PID。

就像是:

withBrowser browserAction
  = bracket startSelenium killSelenium (const browserAction)
Run Code Online (Sandbox Code Playgroud)

(我假设你不希望主要操作必须为 pid 提供参数,所以我过去常常const忽略它)