-- |
-- Module:
--   Reflex.Test.Monad.Host
-- Description:
--   This module contains a monad for testing reflex networks

module Reflex.Test.Monad.Host
  ( TestGuestT
  , TestGuestConstraints
  , ReflexTriggerRef

  , MonadReflexTest(..)
  , AppState(..)
  , ReflexTestT(..)
  , runReflexTestT
  , ReflexTestApp(..)
  , runReflexTestApp
  )
where



import           Prelude


import           Control.Concurrent.Chan
import           Control.Monad.IO.Class

import           Control.Monad.Fix
import           Control.Monad.Primitive
import           Control.Monad.Reader
import           Control.Monad.Ref
import           Control.Monad.State.Strict
import           Data.Dependent.Sum
import           Data.Functor.Identity
import           Data.Kind

import           Reflex
import           Reflex.Class               ()
import           Reflex.Host.Class


type TestGuestT t (m :: Type -> Type)
  = TriggerEventT t (PostBuildT t (PerformEventT t m))

type TestGuestConstraints t (m :: Type -> Type)
  = ( MonadReflexHost t m
    , MonadHold t m
    , MonadSample t m
    , Ref m ~ Ref IO
    , MonadRef m
    , MonadRef (HostFrame t)
    , Ref (HostFrame t) ~ Ref IO
    , MonadIO (HostFrame t)
    , PrimMonad (HostFrame t)
    , MonadIO m
    , MonadFix m
    )

-- | since we work with this type directly a lot, it helps to wrap it around a type synonym
type ReflexTriggerRef t (m :: Type -> Type) a = Ref m (Maybe (EventTrigger t a))

-- |
class MonadReflexTest t m | m -> t  where
  -- | since event subscriptions also happen within the monad, input triggers created via 'newEventWithTriggerRef' may be stuck in the 'Nothing' state as there are no listeners yet
  -- therefore it's necessary to pass in IORefs to the EventTriggers, thus the name of this type
  -- in practice, this will likely be a record containing many trigger refs and the monad user must deref them all
  type InputTriggerRefs m :: Type
  -- | in practice, this will likely be a record containing events and behaviors for the monad user to build a 'ReadPhase' that is passed into 'fireQueuedEventsAndRead'
  type OutputEvents m :: Type
  -- | the inner monad that reflex is running in
  -- likely 'SpiderHost Global'
  type InnerMonad m :: Type -> Type
  -- | see comments for 'InputTriggerRefs'
  inputTriggerRefs :: m (InputTriggerRefs m)
  -- | all queued triggers will fire simultaneous on the next execution of 'fireQueuedEventsAndRead'
  queueEventTrigger :: DSum (EventTrigger t) Identity -> m ()
  -- | same as 'queueEventTrigger' except works with trigger refs
  -- if the trigger ref derefs to 'Nothing', the event does not get queued
  queueEventTriggerRef :: Ref (InnerMonad m) (Maybe (EventTrigger t a)) -> a -> m ()
  -- | see comments for 'OutputEvents'
  outputs :: m (OutputEvents m)
  -- | fire all queued events and run a ReadPhase to produce results from the execution frames
  -- readphase takes place in the inner monad
  fireQueuedEventsAndRead :: ReadPhase (InnerMonad m) a -> m [a]
  -- | same as above with no ReadPhase
  fireQueuedEvents :: (Monad (ReadPhase (InnerMonad m))) => m [()]
  fireQueuedEvents = forall t (m :: * -> *) a.
MonadReflexTest t m =>
ReadPhase (InnerMonad m) a -> m [a]
fireQueuedEventsAndRead (forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- m is 'InnerMonad' from above
data AppState t m = AppState
    { forall t (m :: * -> *).
AppState t m -> [DSum (EventTrigger t) Identity]
_appState_queuedEvents :: [DSum (EventTrigger t) Identity] -- ^ events to fire in next 'FireCommand'
    -- ^ 'FireCommand' to fire events and run next frame
    , forall t (m :: * -> *). AppState t m -> FireCommand t m
_appState_fire         :: FireCommand t m -- ^ 'FireCommand' to fire events and run next frame
    }

-- | implementation of 'MonadReflexTest'
newtype ReflexTestT t intref out m a = ReflexTestT { forall t intref out (m :: * -> *) a.
ReflexTestT t intref out m a
-> ReaderT (intref, out) (StateT (AppState t m) m) a
unReflexTestM :: ReaderT (intref, out) (StateT (AppState t m) m) a }
  deriving
    ( forall a b.
a -> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
forall a b.
(a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
forall t intref out (m :: * -> *) a b.
Functor m =>
a -> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
forall t intref out (m :: * -> *) a b.
Functor m =>
(a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b.
a -> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
$c<$ :: forall t intref out (m :: * -> *) a b.
Functor m =>
a -> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
fmap :: forall a b.
(a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
$cfmap :: forall t intref out (m :: * -> *) a b.
Functor m =>
(a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
Functor
    , forall a. a -> ReflexTestT t intref out m a
forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
forall a b.
ReflexTestT t intref out m (a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
forall a b c.
(a -> b -> c)
-> ReflexTestT t intref out m a
-> ReflexTestT t intref out m b
-> ReflexTestT t intref out m c
forall {t} {intref} {out} {m :: * -> *}.
Monad m =>
Functor (ReflexTestT t intref out m)
forall t intref out (m :: * -> *) a.
Monad m =>
a -> ReflexTestT t intref out m a
forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m (a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
forall t intref out (m :: * -> *) a b c.
Monad m =>
(a -> b -> c)
-> ReflexTestT t intref out m a
-> ReflexTestT t intref out m b
-> ReflexTestT t intref out m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
$c<* :: forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m a
*> :: forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
$c*> :: forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
liftA2 :: forall a b c.
(a -> b -> c)
-> ReflexTestT t intref out m a
-> ReflexTestT t intref out m b
-> ReflexTestT t intref out m c
$cliftA2 :: forall t intref out (m :: * -> *) a b c.
Monad m =>
(a -> b -> c)
-> ReflexTestT t intref out m a
-> ReflexTestT t intref out m b
-> ReflexTestT t intref out m c
<*> :: forall a b.
ReflexTestT t intref out m (a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
$c<*> :: forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m (a -> b)
-> ReflexTestT t intref out m a -> ReflexTestT t intref out m b
pure :: forall a. a -> ReflexTestT t intref out m a
$cpure :: forall t intref out (m :: * -> *) a.
Monad m =>
a -> ReflexTestT t intref out m a
Applicative
    , forall a. a -> ReflexTestT t intref out m a
forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
forall a b.
ReflexTestT t intref out m a
-> (a -> ReflexTestT t intref out m b)
-> ReflexTestT t intref out m b
forall t intref out (m :: * -> *).
Monad m =>
Applicative (ReflexTestT t intref out m)
forall t intref out (m :: * -> *) a.
Monad m =>
a -> ReflexTestT t intref out m a
forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> (a -> ReflexTestT t intref out m b)
-> ReflexTestT t intref out m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> ReflexTestT t intref out m a
$creturn :: forall t intref out (m :: * -> *) a.
Monad m =>
a -> ReflexTestT t intref out m a
>> :: forall a b.
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
$c>> :: forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> ReflexTestT t intref out m b -> ReflexTestT t intref out m b
>>= :: forall a b.
ReflexTestT t intref out m a
-> (a -> ReflexTestT t intref out m b)
-> ReflexTestT t intref out m b
$c>>= :: forall t intref out (m :: * -> *) a b.
Monad m =>
ReflexTestT t intref out m a
-> (a -> ReflexTestT t intref out m b)
-> ReflexTestT t intref out m b
Monad
    , forall a. IO a -> ReflexTestT t intref out m a
forall {t} {intref} {out} {m :: * -> *}.
MonadIO m =>
Monad (ReflexTestT t intref out m)
forall t intref out (m :: * -> *) a.
MonadIO m =>
IO a -> ReflexTestT t intref out m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> ReflexTestT t intref out m a
$cliftIO :: forall t intref out (m :: * -> *) a.
MonadIO m =>
IO a -> ReflexTestT t intref out m a
MonadIO
    , forall a.
(a -> ReflexTestT t intref out m a) -> ReflexTestT t intref out m a
forall {t} {intref} {out} {m :: * -> *}.
MonadFix m =>
Monad (ReflexTestT t intref out m)
forall t intref out (m :: * -> *) a.
MonadFix m =>
(a -> ReflexTestT t intref out m a) -> ReflexTestT t intref out m a
forall (m :: * -> *).
Monad m -> (forall a. (a -> m a) -> m a) -> MonadFix m
mfix :: forall a.
(a -> ReflexTestT t intref out m a) -> ReflexTestT t intref out m a
$cmfix :: forall t intref out (m :: * -> *) a.
MonadFix m =>
(a -> ReflexTestT t intref out m a) -> ReflexTestT t intref out m a
MonadFix
    , MonadReader (intref, out)
    , MonadState (AppState t m))

deriving instance MonadSample t m => MonadSample t (ReflexTestT t intref out m)
deriving instance MonadHold t m => MonadHold t (ReflexTestT t intref out m)
deriving instance MonadReflexCreateTrigger t m => MonadReflexCreateTrigger t (ReflexTestT t intref out m)

instance MonadTrans (ReflexTestT t intref out) where
  lift :: forall (m :: * -> *) a.
Monad m =>
m a -> ReflexTestT t intref out m a
lift = forall t intref out (m :: * -> *) a.
ReaderT (intref, out) (StateT (AppState t m) m) a
-> ReflexTestT t intref out m a
ReflexTestT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

instance (MonadSubscribeEvent t m) => MonadSubscribeEvent t (ReflexTestT t intref out m) where
  subscribeEvent :: forall a. Event t a -> ReflexTestT t intref out m (EventHandle t a)
subscribeEvent = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t (m :: * -> *) a.
MonadSubscribeEvent t m =>
Event t a -> m (EventHandle t a)
subscribeEvent

instance (MonadRef m) => MonadReflexTest t (ReflexTestT t intref out m) where
  type InputTriggerRefs (ReflexTestT t intref out m) = intref
  type OutputEvents (ReflexTestT t intref out m) = out
  type InnerMonad (ReflexTestT t intref out m) = m
  inputTriggerRefs :: ReflexTestT
  t intref out m (InputTriggerRefs (ReflexTestT t intref out m))
inputTriggerRefs = do
    (intref
intref,out
_) <- forall r (m :: * -> *). MonadReader r m => m r
ask
    forall (m :: * -> *) a. Monad m => a -> m a
return intref
intref
  queueEventTrigger :: DSum (EventTrigger t) Identity -> ReflexTestT t intref out m ()
queueEventTrigger DSum (EventTrigger t) Identity
evt = do
    AppState t m
as <- forall s (m :: * -> *). MonadState s m => m s
get
    forall s (m :: * -> *). MonadState s m => s -> m ()
put forall a b. (a -> b) -> a -> b
$ AppState t m
as { _appState_queuedEvents :: [DSum (EventTrigger t) Identity]
_appState_queuedEvents = DSum (EventTrigger t) Identity
evt forall a. a -> [a] -> [a]
: forall t (m :: * -> *).
AppState t m -> [DSum (EventTrigger t) Identity]
_appState_queuedEvents AppState t m
as }
  queueEventTriggerRef :: forall a.
Ref
  (InnerMonad (ReflexTestT t intref out m))
  (Maybe (EventTrigger t a))
-> a -> ReflexTestT t intref out m ()
queueEventTriggerRef Ref
  (InnerMonad (ReflexTestT t intref out m))
  (Maybe (EventTrigger t a))
ref a
a = do
    Maybe (EventTrigger t a)
mpulse <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. MonadRef m => Ref m a -> m a
readRef Ref
  (InnerMonad (ReflexTestT t intref out m))
  (Maybe (EventTrigger t a))
ref
    case Maybe (EventTrigger t a)
mpulse of
      Maybe (EventTrigger t a)
Nothing    -> forall (m :: * -> *) a. Monad m => a -> m a
return ()
      Just EventTrigger t a
pulse -> do
        AppState t m
as <- forall s (m :: * -> *). MonadState s m => m s
get
        forall s (m :: * -> *). MonadState s m => s -> m ()
put forall a b. (a -> b) -> a -> b
$ AppState t m
as { _appState_queuedEvents :: [DSum (EventTrigger t) Identity]
_appState_queuedEvents = (EventTrigger t a
pulse forall {k} (tag :: k -> *) (f :: k -> *) (a :: k).
tag a -> f a -> DSum tag f
:=> forall a. a -> Identity a
Identity a
a) forall a. a -> [a] -> [a]
: forall t (m :: * -> *).
AppState t m -> [DSum (EventTrigger t) Identity]
_appState_queuedEvents AppState t m
as }
  outputs :: ReflexTestT
  t intref out m (OutputEvents (ReflexTestT t intref out m))
outputs = do
    (intref
_,out
out) <- forall r (m :: * -> *). MonadReader r m => m r
ask
    forall (m :: * -> *) a. Monad m => a -> m a
return out
out
  fireQueuedEventsAndRead :: forall a.
ReadPhase (InnerMonad (ReflexTestT t intref out m)) a
-> ReflexTestT t intref out m [a]
fireQueuedEventsAndRead ReadPhase (InnerMonad (ReflexTestT t intref out m)) a
rp = do
    AppState t m
as <- forall s (m :: * -> *). MonadState s m => m s
get
    forall s (m :: * -> *). MonadState s m => s -> m ()
put forall a b. (a -> b) -> a -> b
$ AppState t m
as { _appState_queuedEvents :: [DSum (EventTrigger t) Identity]
_appState_queuedEvents = [] }
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ (forall t (m :: * -> *).
FireCommand t m
-> forall a.
   [DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a]
runFireCommand forall a b. (a -> b) -> a -> b
$ forall t (m :: * -> *). AppState t m -> FireCommand t m
_appState_fire AppState t m
as) (forall t (m :: * -> *).
AppState t m -> [DSum (EventTrigger t) Identity]
_appState_queuedEvents AppState t m
as) ReadPhase (InnerMonad (ReflexTestT t intref out m)) a
rp

runReflexTestT
  :: forall intref inev out t m a
   . (TestGuestConstraints t m)
  => (inev, intref) -- ^ make sure intref match inev, i.e. return values of newEventWithTriggerRef
  -> (inev -> TestGuestT t m out) -- ^ network to test
  -> ReflexTestT t intref out m a -- ^ test monad to run
  -> m ()
runReflexTestT :: forall intref inev out t (m :: * -> *) a.
TestGuestConstraints t m =>
(inev, intref)
-> (inev -> TestGuestT t m out)
-> ReflexTestT t intref out m a
-> m ()
runReflexTestT (inev
input, intref
inputTRefs) inev -> TestGuestT t m out
app ReflexTestT t intref out m a
rtm = do
  (Event t ()
postBuild, IORef (Maybe (EventTrigger t ()))
postBuildTriggerRef) <- forall t (m :: * -> *) a.
(MonadReflexCreateTrigger t m, MonadRef m, Ref m ~ Ref IO) =>
m (Event t a, Ref m (Maybe (EventTrigger t a)))
newEventWithTriggerRef

  Chan [DSum (EventTriggerRef t) TriggerInvocation]
events                           <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a. IO (Chan a)
newChan
  (out
output, fc :: FireCommand t m
fc@(FireCommand forall a.
[DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a]
fire))  <- do
    forall t (m :: * -> *) a.
(Monad m, MonadSubscribeEvent t m, MonadReflexHost t m, MonadRef m,
 Ref m ~ Ref IO) =>
PerformEventT t m a -> m (a, FireCommand t m)
hostPerformEventT
      forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> b -> a -> c
flip forall t (m :: * -> *) a. PostBuildT t m a -> Event t () -> m a
runPostBuildT    Event t ()
postBuild
      forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> b -> a -> c
flip forall t (m :: * -> *) a.
TriggerEventT t m a
-> Chan [DSum (EventTriggerRef t) TriggerInvocation] -> m a
runTriggerEventT Chan [DSum (EventTriggerRef t) TriggerInvocation]
events
      forall a b. (a -> b) -> a -> b
$ inev -> TestGuestT t m out
app inev
input

  -- handle post build
  -- TODO consider adding some way to test 'PostBuild' results
  Maybe (EventTrigger t ())
mPostBuildTrigger <- forall (m :: * -> *) a. MonadRef m => Ref m a -> m a
readRef IORef (Maybe (EventTrigger t ()))
postBuildTriggerRef
  [()]
_                 <- case Maybe (EventTrigger t ())
mPostBuildTrigger of
    Maybe (EventTrigger t ())
Nothing -> forall (m :: * -> *) a. Monad m => a -> m a
return [()] -- no subscribers
    Just EventTrigger t ()
postBuildTrigger ->
      forall a.
[DSum (EventTrigger t) Identity] -> ReadPhase m a -> m [a]
fire [EventTrigger t ()
postBuildTrigger forall {k} (tag :: k -> *) (f :: k -> *) (a :: k).
tag a -> f a -> DSum tag f
:=> forall a. a -> Identity a
Identity ()] forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ()

  -- TODO maybe find a way to handle trigger events
  -- one solution is to implement non-blocking variant of TriggerEventT
  -- and then pass as part of AppState such that each call to readPhase will fire any trigger events
  -- another option is just to start a thread and output warnings anytime triggerEvs are created
  --triggerEvs <- liftIO $ readChan events

  -- run the test monad
  forall a b c. (a -> b -> c) -> b -> a -> c
flip forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (forall t (m :: * -> *).
[DSum (EventTrigger t) Identity] -> FireCommand t m -> AppState t m
AppState [] FireCommand t m
fc)
    forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> b -> a -> c
flip forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (intref
inputTRefs, out
output)
      forall a b. (a -> b) -> a -> b
$ forall t intref out (m :: * -> *) a.
ReflexTestT t intref out m a
-> ReaderT (intref, out) (StateT (AppState t m) m) a
unReflexTestM ReflexTestT t intref out m a
rtm

  return ()



-- | class to help bind network and types to a 'ReflexTestT'
-- see test/Reflex/Test/Monad/HostSpec.hs for usage example
class ReflexTestApp app t m | app -> t m where
  data AppInputTriggerRefs app :: Type
  data AppInputEvents app :: Type
  data AppOutput app :: Type
  getApp :: AppInputEvents app -> TestGuestT t m (AppOutput app)
  makeInputs :: m (AppInputEvents app, AppInputTriggerRefs app)

runReflexTestApp
  :: (ReflexTestApp app t m, TestGuestConstraints t m)
  => ReflexTestT t (AppInputTriggerRefs app) (AppOutput app) m ()
  -> m ()
runReflexTestApp :: forall app t (m :: * -> *).
(ReflexTestApp app t m, TestGuestConstraints t m) =>
ReflexTestT t (AppInputTriggerRefs app) (AppOutput app) m ()
-> m ()
runReflexTestApp ReflexTestT t (AppInputTriggerRefs app) (AppOutput app) m ()
rtm = do
  (AppInputEvents app, AppInputTriggerRefs app)
i <- forall app t (m :: * -> *).
ReflexTestApp app t m =>
m (AppInputEvents app, AppInputTriggerRefs app)
makeInputs
  forall intref inev out t (m :: * -> *) a.
TestGuestConstraints t m =>
(inev, intref)
-> (inev -> TestGuestT t m out)
-> ReflexTestT t intref out m a
-> m ()
runReflexTestT (AppInputEvents app, AppInputTriggerRefs app)
i forall app t (m :: * -> *).
ReflexTestApp app t m =>
AppInputEvents app -> TestGuestT t m (AppOutput app)
getApp ReflexTestT t (AppInputTriggerRefs app) (AppOutput app) m ()
rtm