我正在尝试在Haskell中使用webdriver和polysemy构建一个自动化的特性测试套件。我已经定义了适当的效果,并将它们解释为webdriver WD monad,但现在我被卡住了。
我有一个Member BrowserMaster r => Sem r ()类型的值,其中BrowserMaster是我的自定义功能。
这是解释器:
runBrowserMaster :: Members [Embed WD.WD, Embed IO] r => Sem (BrowserMaster ': r) a -> Sem r a
runBrowserMaster = interpret $ \case
ClickElement bmSelector ->
let action = (WD.findElem (bmSelectoToSelector bmSelector) >>= WD.click :: WD.WD ())
in embed action
{- ... -}现在我想知道如何将Embed WD.WD效果转换为Embed IO,这样我最终只得到一个效果。
我试着设计了一个解释器:
runWebDriver :: Member (Embed IO) r => Sem (Embed WD.WD ': r) a -> Sem r a
runWebDriver = interpret $
\a -> embed $ runSession chromeConfig . finallyClose $ do
setImplicitWait 60000
setWindowSize (1024, 768)
unEmbed a(这里的runSession chromeConfig . finallyClose是一个WD a -> IO a)
它确实可以工作,但它似乎为每个命令启动了一个新的浏览器会话,而不是只启动一次,在里面做所有的事情,然后关闭。
我有一种直觉,它必须做一些与资源获取和释放有关的事情,但我就是想不通,才能把它们放在一起。
发布于 2020-06-06 21:48:52
请记住,每次执行BrowserMaster效果的操作时,都会执行每个解释器。所以每次它运行runWebDriver解释器,这解释了为什么它创建,运行和关闭会话。
我认为你想要做的是创建/删除一次会话,然后在这个会话中执行你的全部代码。此外,由于WD已经是IO的包装器,我认为没有必要同时嵌入这两种效果。
我既不熟悉您的代码,也不熟悉webdriver库,但我假设这应该是这样的:
main :: IO ()
main = runSession chromeConfig . finallyClose $ do
setImplicitWait 60000
setWindowSize (1024, 768)
runM . runBrowserMaster $ myBusinessCode
runBrowserMaster :: Member (Embed WD.WD) r => Sem (BrowserMaster ': r) a -> Sem r a
runBrowserMaster = interpret $ \case
ClickElement bmSelector ->
let action = (WD.findElem (bmSelectoToSelector bmSelector) >>= WD.click :: WD.WD ())
in embed action
{- ... -}注意:如果您需要在解释器中运行一些IO代码,请使用liftIO将其转换为WD操作,例如liftIO $ putStrLn "Hello world"。
PS:我建议将runBrowserMaster解释器重命名为类似browserMasterToWD的名称,因为它更好地代表了它的功能:根据BrowserMaster操作解释WD效果。
https://stackoverflow.com/questions/62231245
复制相似问题