Skip to content

Instantly share code, notes, and snippets.

@cryogenian
Created April 24, 2018 14:50
Show Gist options
  • Save cryogenian/037c23df672737f367a200cea04b094e to your computer and use it in GitHub Desktop.
Save cryogenian/037c23df672737f367a200cea04b094e to your computer and use it in GitHub Desktop.
module Main where
import Prelude
import Control.Monad.Aff (launchAff, delay, forkAff)
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Ref (REF, newRef, writeRef, readRef)
import Control.Monad.Eff.Console (CONSOLE, log)
import CSS (fromString)
import Data.Array as A
import Data.Argonaut as J
import Data.Either (Either(..))
import Data.Newtype (un)
import Data.Symbol (SProxy(..))
import Data.Time.Duration (Milliseconds)
import Data.Traversable as T
import Data.Exists (mkExists, runExists, Exists)
import Data.String as Str
import Text.Chalky as TC
import Run as R
import Run.Except as RE
import Lunapark.Utils (catch, throwLeft)
import Lunapark.Types as LT
import Lunapark as LP
--import Unsafe.Coerce (unsafeCoerce)
--import Debug.Trace as DT
data LogF r a
= Section String (R.Run r a)
derive instance functorLogFFunctor (LogF r)
_log = SProxySProxy "log"
type LOG r = R.FProxy (LogF r)
type WithLog r a = R.Run (logLOG r|r) a
liftLog r. LogF r ~> WithLog r
liftLog = R.lift _log
section r. String R.Run r ~> WithLog r
section str action = liftLog $ Section str action
interpret
e r
. WithLog (effR.EFF (consoleCONSOLE|e)|r)
~> R.Run (effR.EFF (consoleCONSOLE|e)|r)
interpret = loop
where
handle = R.on _log Left Right
bar = "========================================"
loop r = case R.peel r of
Left a → case handle a of
Left logF → case logF of
Section ann others → do
R.liftEff do
log ""
log $ TC.magenta bar
log $ TC.magenta ann
log $ TC.magenta bar
log ""
result ← loop =<< others
R.liftEff do
log ""
log $ TC.magenta bar
log $ TC.green $ "OK: " <> ann <> " passed"
log $ TC.magenta bar
log ""
pure result
Right others → loop =<< R.send others
Right a → pure a
data BindE m a b = BindE (m b) (b m a)
newtype BindF m a = BindF (Exists (BindE m a))
mkBindF m a b. m b (b m a) BindF m a
mkBindF mb bma = BindF $ mkExists (BindE mb bma)
runBindF a m. Monad m BindF m a m a
runBindF (BindF st) = runExists (\(BindE mb bma) → bma =<< mb) st
instance functorBindFFunctor m Functor (BindF m) where
map f (BindF st) = runExists (\(BindE mb bma) → mkBindF mb $ map f <<< bma) st
data FlowF m a
= Await (BindF m a)
| AwaitNot (BindF m a) a
| Expect (BindF m a)
derive instance functorFlowFFunctor m Functor (FlowF m)
_flow = SProxySProxy "flow"
type FLOW m = R.FProxy (FlowF m)
type WithFlow r a = R.Run (flowFLOW (R.Run r)|r) a
liftFlow r. FlowF (R.Run r) ~> WithFlow r
liftFlow = R.lift _flow
await r a b. R.Run r a (a R.Run r b) WithFlow r b
await ra arb = liftFlow $ Await $ mkBindF ra arb
awaitNot r a b. R.Run r a (a R.Run r b) WithFlow r Unit
awaitNot ra arb = liftFlow $ AwaitNot (mkBindF ra (arb >>> void)) unit
expect r a b. R.Run r a (a R.Run r b) WithFlow r b
expect ra arb = liftFlow $ Expect $ mkBindF ra arb
runFlow
r eff lval
. RetryInput
lval
WithFlow (effR.EFF (refREF|eff), affR.AFF (refREF|eff), exceptRE.EXCEPT lval|r)
~> R.Run (effR.EFF (refREF|eff), affR.AFF (refREF|eff), exceptRE.EXCEPT lval|r)
runFlow rt awaitNotError = loop
where
lrRun = R.on _flow Left Right
loop r = case R.peel r of
Right a → pure a
Left cont → runFlow rt awaitNotError =<< case lrRun cont of
Right others → R.send others
Left f → case f of
Await bind → retry rt (runBindF bind)
AwaitNot (BindF bind) next →
runExists (\(BindE ma amb) → catch ((ma >>= amb) *> RE.throw awaitNotError) (\_ → pure next)) bind
Expect (BindF bind) →
runExists (\(BindE ma amb) → retry rt ma >>= amb) bind
type RetryInput =
{ step Milliseconds
, total Milliseconds
}
data MoonshineF el r a
= WithLabel String (el a)
| WithTitle String (el a)
| WithText String (el a)
| Before el (WithMoonshine el r a)
| After el (WithMoonshine el r a)
derive instance functorMoonshineFFunctor (MoonshineF el r)
_moonshine = SProxySProxy "moonshine"
type MOONSHINE el r = R.FProxy (MoonshineF el r)
type WithMoonshine el r a = R.Run (moonshineMOONSHINE el r|r) a
liftMoonshine el r. MoonshineF el r ~> WithMoonshine el r
liftMoonshine = R.lift _moonshine
withLabel el r. String WithMoonshine el r el
withLabel txt = liftMoonshine $ WithLabel txt id
withTitle el r. String WithMoonshine el r el
withTitle txt = liftMoonshine $ WithTitle txt id
withText el r. String WithMoonshine el r el
withText txt = liftMoonshine $ WithText txt id
before el r. el WithMoonshine el r ~> WithMoonshine el r
before el a = liftMoonshine $ Before el a
after el r. el WithMoonshine el r ~> WithMoonshine el r
after el a = liftMoonshine $ After el a
before_ el r. WithMoonshine el r el WithMoonshine el r el WithMoonshine el r el
before_ b s = b >>= \a → before a s
after_ el r. WithMoonshine el r el WithMoonshine el r el WithMoonshine el r el
after_ b s = b >>= \a → after a s
runMoonshine r. WithMoonshine LT.Element (lunapark LP.LUNAPARK|r) ~> R.Run (lunapark LP.LUNAPARK|r)
runMoonshine = loop
where
handleMoonshine = R.on _moonshine Left Right
loop r = case R.peel r of
Right a → pure a
Left rr → case handleMoonshine rr of
Right others → loop =<< R.send others
Left mf → case mf of
WithLabel txt cont →
loop =<< (map cont $ LP.findElement $ LT.ByCss $ fromString "*")
WithTitle txt cont →
loop =<< (map cont $ LP.findElement $ LT.ByCss $ fromString "*")
WithText txt cont →
loop =<< (map cont $ LP.findElement $ LT.ByCss $ fromString "*")
Before el moon → do
loop $ join moon
After el moon →
loop $ join moon
newtype TableDescription = TableDescription Void
data ExpectationF el a
= Exists el a
| IsChecked el a
| IsEnabled el a
| HasSelection String el a
| Table TableDescription el a
derive instance functorExpectationFFunctor (ExpectationF el)
_expectation = SProxySProxy "expectation"
type EXPECTATION el = R.FProxy (ExpectationF el)
type WithExpectation el r a = R.Run (expectationEXPECTATION el|r) a
liftExpectation el r. ExpectationF el ~> WithExpectation el r
liftExpectation = R.lift _expectation
exists el r. el WithExpectation el r Unit
exists el = liftExpectation $ Exists el unit
isChecked el r. el WithExpectation el r Unit
isChecked el = liftExpectation $ IsChecked el unit
isEnabled el r. el WithExpectation el r Unit
isEnabled el = liftExpectation $ IsEnabled el unit
hasSelection el r. String el WithExpectation el r Unit
hasSelection txt el = liftExpectation $ HasSelection txt el unit
table el r. TableDescription el WithExpectation el r Unit
table descr el = liftExpectation $ Table descr el unit
runExpectation
r
. WithExpectation LT.Element (lunaparkLP.LUNAPARK, exceptRE.EXCEPT LP.Error|r)
~> R.Run (lunaparkLP.LUNAPARK, exceptRE.EXCEPT LP.Error |r)
runExpectation = R.interpretRec (R.on _expectation handleExpectation R.send)
where
handleExpectation ExpectationF LT.Element ~> R.Run (lunapark LP.LUNAPARK, except RE.EXCEPT LP.Error |r)
handleExpectation = case _ of
Exists el next → do
j ← LP.executeScript { script: "var el = arguments[0]; return !!el", args: [LT.encodeElement el ] }
res ← throwLeft $ J.decodeJson j
unless res $ RE.throw
{ error: LP.StaleElementReference
, message: "The element " <> un LT.Element el <> " doesn't exist"
, stacktrace: ""
}
pure next
IsChecked el next → do
res ← LP.isSelected el
unless res $ RE.throw
{ error: LP.UnknownError
, message: "The element " <> un LT.Element el <> " is not selected"
, stacktrace: ""
}
pure next
IsEnabled el next → do
res ← LP.isEnabled el
unless res $ RE.throw
{ error: LP.UnknownError
, message: "The element " <> un LT.Element el <> " is not enabled"
, stacktrace: ""
}
pure next
HasSelection txt el next → do
opts ← LP.childElements el $ LT.ByCss $ fromString $ "option[text='" <> txt <> "']"
inputs ← LP.childElements el $ LT.ByCss $ fromString "input"
values ← T.for inputs $ flip LP.getProperty "value"
let compatibles = flip T.foldMap values \j → case J.decodeJson j of
Left _ → [ ]
Right c → if Str.contains (Str.Pattern txt) c then [c] else [ ]
unless (A.length compatibles + A.length opts > 0) $ RE.throw
{ error: LP.UnknownError
, message: "The element " <> un LT.Element el <> " has now " <> txt <> " selection"
, stacktrace: ""
}
pure next
Table _ _ next → pure next
retry
e a lval r
. RetryInput
R.Run (effR.EFF (refREF|e), affR.AFF (refREF|e), exceptRE.EXCEPT lval|r) a
R.Run (effR.EFF (refREF|e), affR.AFF (refREF|e), exceptRE.EXCEPT lval|r) a
retry { step, total } action = do
elapsed ← R.liftEff $ newRef false
_ ← R.liftAff $ forkAff do
delay total
liftEff $ writeRef elapsed true
let attempt = action `catch` \err → do
shouldRethrow ← R.liftEff $ readRef elapsed
if shouldRethrow
then RE.throw err
else do
R.liftAff $ delay step
attempt
attempt
main e. Eff (console CONSOLE|e) Unit
main = void $ launchAff do
R.runBaseAff' $ interpret do
section "section" do
R.liftEff $ log "ZZZ"
tst _
tst = section "foo" do
await (withText "foo") isEnabled
await (before_ (withText "foo") (withLabel "bar")) $ hasSelection "baz"
awaitNot (withText "booz") exists
expect (withText "quux") exists
-- _ ← await (pure 2) \x → pure $ x + 2
-- void $ await (pure "") \x → pure $ x <> ""
-- awaitNot (pure 1.0) \x → pure $ x + 1.0
-- expect (pure 1.0) \x → pure $ x * 2.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment