Bring back tests

This commit is contained in:
Filip Graliński 2018-09-20 13:02:07 +02:00
parent 5ade94b225
commit ef6e892680
5 changed files with 99 additions and 34 deletions

View File

@ -5,6 +5,7 @@ module Application
, appSelfContainedMain , appSelfContainedMain
, develMain , develMain
, makeFoundation , makeFoundation
, makeLogWare
-- * for DevelMain -- * for DevelMain
, getApplicationRepl , getApplicationRepl
, shutdownApp , shutdownApp
@ -22,6 +23,7 @@ import Network.Wai.Handler.Warp (Settings, defaultSettings,
defaultShouldDisplayException, defaultShouldDisplayException,
runSettings, setHost, runSettings, setHost,
setOnException, setPort, getPort) setOnException, setPort, getPort)
import Network.Wai (Middleware)
import Network.Wai.Middleware.RequestLogger (Destination (Logger), import Network.Wai.Middleware.RequestLogger (Destination (Logger),
IPAddrSource (..), IPAddrSource (..),
OutputFormat (..), destination, OutputFormat (..), destination,
@ -142,6 +144,19 @@ makeApplication foundation = do
appPlain <- toWaiAppPlain foundation appPlain <- toWaiAppPlain foundation
return $ logWare $ defaultMiddlewaresNoLogging appPlain return $ logWare $ defaultMiddlewaresNoLogging appPlain
makeLogWare :: App -> IO Middleware
makeLogWare foundation =
mkRequestLogger def
{ outputFormat =
if appDetailedRequestLogging $ appSettings foundation
then Detailed True
else Apache
(if appIpFromHeader $ appSettings foundation
then FromFallback
else FromSocket)
, destination = Logger $ loggerSet $ appLogger foundation
}
-- | Warp settings for the given foundation value. -- | Warp settings for the given foundation value.
warpSettings :: App -> Settings warpSettings :: App -> Settings
warpSettings foundation = warpSettings foundation =

View File

@ -8,6 +8,8 @@ import Text.Hamlet (hamletFile)
import Yesod.Auth.HashDB (HashDBUser(..), authHashDBWithForm) import Yesod.Auth.HashDB (HashDBUser(..), authHashDBWithForm)
import qualified Yesod.Core.Unsafe as Unsafe import qualified Yesod.Core.Unsafe as Unsafe
import Yesod.Core.Types (Logger) import Yesod.Core.Types (Logger)
import qualified Data.CaseInsensitive as CI
import qualified Data.Text.Encoding as TE
import Yesod.Default.Util (addStaticContentExternal) import Yesod.Default.Util (addStaticContentExternal)
instance HashDBUser User where instance HashDBUser User where
@ -49,6 +51,10 @@ mkMessage "App" "messages" "en"
-- | A convenient synonym for creating forms. -- | A convenient synonym for creating forms.
type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget) type Form x = Html -> MForm (HandlerT App IO) (FormResult x, Widget)
-- | A convenient synonym for database access functions.
type DB a = forall (m :: * -> *).
(MonadIO m) => ReaderT SqlBackend m a
isTrustedAuthorized :: (AuthEntity (HandlerSite m) ~ User, AuthId (HandlerSite m) ~ Key User, MonadHandler m, YesodAuthPersist (HandlerSite m)) => m AuthResult isTrustedAuthorized :: (AuthEntity (HandlerSite m) ~ User, AuthId (HandlerSite m) ~ Key User, MonadHandler m, YesodAuthPersist (HandlerSite m)) => m AuthResult
isTrustedAuthorized = do isTrustedAuthorized = do
mauth <- maybeAuth mauth <- maybeAuth
@ -92,6 +98,16 @@ instance Yesod App where
120 -- timeout in minutes 120 -- timeout in minutes
((appVarDir $ appSettings app) </> "config/client_session_key.aes") ((appVarDir $ appSettings app) </> "config/client_session_key.aes")
-- Yesod Middleware allows you to run code before and after each handler function.
-- The defaultYesodMiddleware adds the response header "Vary: Accept, Accept-Language" and performs authorization checks.
-- Some users may also want to add the defaultCsrfMiddleware, which:
-- a) Sets a cookie with a CSRF token in it.
-- b) Validates that incoming write requests include that token in either a header or POST parameter.
-- To add it, chain it together with the defaultMiddleware: yesodMiddleware = defaultYesodMiddleware . defaultCsrfMiddleware
-- For details, see the CSRF documentation in the Yesod.Core.Handler module of the yesod-core package.
yesodMiddleware :: ToTypedContent res => Handler res -> Handler res
yesodMiddleware = defaultYesodMiddleware
defaultLayout widget = do defaultLayout widget = do
master <- getYesod master <- getYesod
mmsg <- getMessage mmsg <- getMessage

View File

@ -89,6 +89,7 @@ library
, classy-prelude-conduit >= 0.10.2 , classy-prelude-conduit >= 0.10.2
, classy-prelude-yesod >= 0.10.2 , classy-prelude-yesod >= 0.10.2
, bytestring >= 0.9 && < 0.11 , bytestring >= 0.9 && < 0.11
, case-insensitive
, text >= 0.11 && < 2.0 , text >= 0.11 && < 2.0
, persistent >= 2.0 && < 2.9 , persistent >= 2.0 && < 2.9
, persistent-postgresql >= 2.1.1 && < 2.9 , persistent-postgresql >= 2.1.1 && < 2.9
@ -140,6 +141,7 @@ library
, extra , extra
, attoparsec , attoparsec
, random-strings , random-strings
, wai
executable gonito executable gonito
if flag(library-only) if flag(library-only)
@ -187,8 +189,9 @@ test-suite test
build-depends: base build-depends: base
, gonito , gonito
, yesod-test >= 1.4.3 && < 1.5 , yesod-test >= 1.6 && < 1.7
, yesod-core , yesod-core
, yesod-auth >= 1.6 && < 1.7
, yesod , yesod
, persistent , persistent
, persistent-postgresql , persistent-postgresql
@ -200,3 +203,4 @@ test-suite test
, classy-prelude , classy-prelude
, classy-prelude-yesod , classy-prelude-yesod
, wai-handler-fastcgi , wai-handler-fastcgi
, wai

View File

@ -1,26 +1,17 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Handler.HomeSpec (spec) where module Handler.HomeSpec (spec) where
import TestImport import TestImport
spec :: Spec spec :: Spec
spec = withApp $ do spec = withApp $ do
describe "Homepage" $ do
it "loads the index and checks it looks right" $ do it "loads the index and checks it looks right" $ do
get HomeR get HomeR
statusIs 200 statusIs 200
htmlAllContain "h1" "Welcome to Yesod" htmlAnyContain "h1" "Welcome to Gonito.net!"
request $ do
setMethod "POST"
setUrl HomeR
addToken
fileByLabel "Choose a file" "test/Spec.hs" "text/plain" -- talk about self-reference
byLabel "What's on the file?" "Some Content"
statusIs 200
-- more debugging printBody
htmlCount ".message" 1
htmlAllContain ".message" "Some Content"
htmlAllContain ".message" "text/plain"
-- This is a simple example of using a database access in a test. The -- This is a simple example of using a database access in a test. The
-- test will succeed for a fresh scaffolded site with an empty database, -- test will succeed for a fresh scaffolded site with an empty database,
@ -29,4 +20,4 @@ spec = withApp $ do
get HomeR get HomeR
statusIs 200 statusIs 200
users <- runDB $ selectList ([] :: [Filter User]) [] users <- runDB $ selectList ([] :: [Filter User]) []
assertEqual "user table empty" 0 $ length users assertEq "user table empty" 0 $ length users

View File

@ -1,18 +1,23 @@
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module TestImport module TestImport
( module TestImport ( module TestImport
, module X , module X
) where ) where
import Application (makeFoundation) import Application (makeFoundation, makeLogWare)
import ClassyPrelude as X import ClassyPrelude as X hiding (delete, deleteBy, Handler)
import Database.Persist as X hiding (get) import Database.Persist as X hiding (get)
import Database.Persist.Sql (SqlPersistM, SqlBackend, runSqlPersistMPool, rawExecute, rawSql, unSingle, connEscapeName) import Database.Persist.Sql (SqlPersistM, runSqlPersistMPool, rawExecute, rawSql, unSingle, connEscapeName)
import Foundation as X import Foundation as X
import Model as X import Model as X
import Test.Hspec as X import Test.Hspec as X
import Text.Shakespeare.Text (st) import Text.Shakespeare.Text (st)
import Yesod.Default.Config2 (ignoreEnv, loadAppSettings) import Yesod.Default.Config2 (useEnv, loadYamlSettings)
import Yesod.Auth as X
import Yesod.Test as X import Yesod.Test as X
import Yesod.Core.Unsafe (fakeHandlerGetLogger)
runDB :: SqlPersistM a -> YesodExample App a runDB :: SqlPersistM a -> YesodExample App a
runDB query = do runDB query = do
@ -22,16 +27,22 @@ runDB query = do
runDBWithApp :: App -> SqlPersistM a -> IO a runDBWithApp :: App -> SqlPersistM a -> IO a
runDBWithApp app query = runSqlPersistMPool query (appConnPool app) runDBWithApp app query = runSqlPersistMPool query (appConnPool app)
runHandler :: Handler a -> YesodExample App a
runHandler handler = do
app <- getTestYesod
fakeHandlerGetLogger appLogger app handler
withApp :: SpecWith App -> Spec
withApp :: SpecWith (TestApp App) -> Spec
withApp = before $ do withApp = before $ do
settings <- loadAppSettings settings <- loadYamlSettings
["config/test-settings.yml", "config/settings.yml"] ["config/test-settings.yml", "config/settings.yml"]
[] []
ignoreEnv useEnv
foundation <- makeFoundation settings foundation <- makeFoundation settings
wipeDB foundation wipeDB foundation
return foundation logWare <- liftIO $ makeLogWare foundation
return (foundation, logWare)
-- This function will truncate all of the tables in your database. -- This function will truncate all of the tables in your database.
-- 'withApp' calls it before each test, creating a clean environment for each -- 'withApp' calls it before each test, creating a clean environment for each
@ -45,7 +56,7 @@ wipeDB app = runDBWithApp app $ do
query = "TRUNCATE TABLE " ++ intercalate ", " escapedTables query = "TRUNCATE TABLE " ++ intercalate ", " escapedTables
rawExecute query [] rawExecute query []
getTables :: MonadIO m => ReaderT SqlBackend m [Text] getTables :: DB [Text]
getTables = do getTables = do
tables <- rawSql [st| tables <- rawSql [st|
SELECT table_name SELECT table_name
@ -54,3 +65,31 @@ getTables = do
|] [] |] []
return $ map unSingle tables return $ map unSingle tables
-- | Authenticate as a user. This relies on the `auth-dummy-login: true` flag
-- being set in test-settings.yaml, which enables dummy authentication in
-- Foundation.hs
authenticateAs :: Entity User -> YesodExample App ()
authenticateAs (Entity _ u) = do
request $ do
setMethod "POST"
addPostParam "ident" $ userIdent u
setUrl $ AuthR $ PluginR "dummy" []
-- | Create a user. The dummy email entry helps to confirm that foreign-key
-- checking is switched off in wipeDB for those database backends which need it.
createUser :: Text -> YesodExample App (Entity User)
createUser ident = runDB $ do
user <- insertEntity User
{ userIdent = ident
, userPassword = Nothing
, userName = Nothing
, userIsAdmin = False
, userLocalId = Nothing
, userIsAnonymous = False
, userAvatar = Nothing
, userVerificationKey = Nothing
, userKeyExpirationDate = Nothing
, userTriggerToken = Nothing
}
return user