{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase #-} module EventHandlingSpec where import Prelude hiding (div) import Control.Concurrent.STM.TChan import Control.Monad.STM (atomically) import Control.Monad.IO.Class import Test.Hspec.QuickCheck import Test.Hspec import Test.QuickCheck import Data.Aeson import Data.Aeson.TH import TreeGenerator import Component import EventHandling import Events import PrepareTree import Rendering type Id a = a -> a data TestAction = Up | Down $(deriveJSON defaultOptions ''TestAction) data SingleConstructor = SingleConstructor $(deriveJSON (defaultOptions{tagSingleConstructors=True}) ''SingleConstructor) {- Just to clean up tests a bit. I dunno if this approach would work to clean up the main event loop as well, since it calls "runEvent" (re: applying the event) in a non-forked fashioned. If you try void . forkIO you end up back in m a -> IO a hell. -} apply :: MonadIO m => TChan Event -> Event -> Purview parentAction action m -> m (Purview parentAction action m) apply eventBus newStateEvent@StateChangeEvent {} component = pure $ applyNewState newStateEvent component apply eventBus fromEvent@Event {event=eventKind} component = case eventKind of "newState" -> pure $ applyNewState fromEvent component _ -> do events <- runEvent fromEvent component liftIO $ mapM_ (atomically . writeTChan eventBus) events pure component spec :: SpecWith () spec = parallel $ do describe "apply" $ do it "changes state" $ do let actionHandler :: String -> Int -> Int actionHandler "up" _ = 1 actionHandler _ _ = 0 handler :: Purview () a IO handler = simpleHandler (0 :: Int) actionHandler (Text . show) render handler `shouldBe` "