3

我正在尝试使用webdriverpolysemy在 Haskell 中构建一个自动化功能测试套件。我已经定义了适当的效果并将它们解释为 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

它确实有效,但它似乎为每个命令启动了一个新的浏览器会话,而不是只启动一次,在内部完成所有操作并关闭。

我有一种直觉,它必须与资源获取和释放有关,但我无法理解这一点,以便能够将它们放在一起。

4

1 回答 1

3

请记住,每次执行效果的动作时都会执行每个解释器BrowserMaster。所以每次它运行runWebDriver解释器时,它解释了它为什么创建、运行和关闭会话。

我认为您想要做的是创建/删除一次会话,并在此会话中执行您的整个代码。另外,由于WD已经是 wrapper 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

于 2020-06-06T13:48:51.833 回答