wasp/waspc/test/AnalyzerTest.hs

180 lines
6.4 KiB
Haskell
Raw Normal View History

{-# LANGUAGE TypeApplications #-}
2021-08-22 20:25:55 +03:00
module AnalyzerTest where
import Data.Either (isRight)
2021-08-22 20:25:55 +03:00
import Test.Tasty.Hspec
import Wasp.Analyzer
import qualified Wasp.Analyzer.TypeChecker as TC
2021-11-25 14:36:42 +03:00
import Wasp.AppSpec.Action (Action)
import qualified Wasp.AppSpec.Action as Action
import Wasp.AppSpec.App (App)
import qualified Wasp.AppSpec.App as App
import qualified Wasp.AppSpec.App.Auth as Auth
import qualified Wasp.AppSpec.App.Db as Db
import qualified Wasp.AppSpec.App.Server as Server
import Wasp.AppSpec.Core.Ref (Ref (..))
import Wasp.AppSpec.Entity (Entity)
import qualified Wasp.AppSpec.Entity as Entity
import Wasp.AppSpec.ExtImport (ExtImport (..), ExtImportName (..))
import Wasp.AppSpec.JSON (JSON (..))
import Wasp.AppSpec.Page (Page)
import qualified Wasp.AppSpec.Page as Page
2021-11-25 14:26:48 +03:00
import Wasp.AppSpec.Query (Query)
import qualified Wasp.AppSpec.Query as Query
2021-11-25 14:02:02 +03:00
import Wasp.AppSpec.Route (Route)
import qualified Wasp.AppSpec.Route as Route
2021-08-22 20:25:55 +03:00
spec_Analyzer :: Spec
spec_Analyzer = do
describe "Analyzer" $ do
it "Analyzes a well-typed example" $ do
let source =
unlines
[ "app Todo {",
" title: \"Todo App\",",
" head: [\"foo\", \"bar\"],",
" auth: {",
" userEntity: User,",
" methods: [EmailAndPassword],",
" },",
" dependencies: {=json",
" \"redux\": \"^4.0.5\"",
" json=},",
" server: {",
" setupFn: import { setupServer } from \"@ext/bar.js\"",
" },",
" db: {",
" system: PostgreSQL",
" }",
"}",
"",
"entity User {=psl test psl=}",
"",
"page HomePage {",
" component: import Home from \"@ext/pages/Main\"",
"}",
"",
"page ProfilePage {",
" component: import { profilePage } from \"@ext/pages/Profile\",",
" authRequired: true",
2021-11-25 14:02:02 +03:00
"}",
"",
2021-11-25 14:26:48 +03:00
"route HomeRoute { path: \"/\", page: HomePage }",
"",
"query getUsers {",
" fn: import { getAllUsers } from \"@ext/foo.js\",",
" entities: [User]",
2021-11-25 14:36:42 +03:00
"}",
"",
"action updateUser {",
" fn: import { updateUser } from \"@ext/foo.js\",",
" entities: [User],",
" auth: true",
2021-11-25 14:26:48 +03:00
"}"
]
2021-11-25 14:26:48 +03:00
let decls = analyze source
2021-11-25 14:26:48 +03:00
let expectedApps =
[ ( "Todo",
App.App
{ App.title = "Todo App",
App.head = Just ["foo", "bar"],
App.auth =
Just
Auth.Auth
{ Auth.userEntity = Ref "User" :: Ref Entity,
Auth.methods = [Auth.EmailAndPassword],
Auth.onAuthFailedRedirectTo = Nothing
},
App.dependencies = Just $ JSON "\n \"redux\": \"^4.0.5\"\n ",
App.server =
Just
Server.Server
{ Server.setupFn = Just $ ExtImport (ExtImportField "setupServer") "@ext/bar.js"
},
App.db = Just Db.Db {Db.system = Just Db.PostgreSQL}
}
)
]
takeDecls @App <$> decls `shouldBe` Right expectedApps
2021-11-25 14:26:48 +03:00
let expectedPages =
[ ( "HomePage",
Page.Page
{ Page.component = ExtImport (ExtImportModule "Home") "@ext/pages/Main",
Page.authRequired = Nothing
}
),
( "ProfilePage",
Page.Page
{ Page.component = ExtImport (ExtImportField "profilePage") "@ext/pages/Profile",
Page.authRequired = Just True
}
)
]
takeDecls @Page <$> decls `shouldBe` Right expectedPages
2021-11-25 14:26:48 +03:00
let expectedEntities =
[ ( "User",
Entity.Entity (Entity.PSL " test ")
)
]
takeDecls @Entity <$> decls `shouldBe` Right expectedEntities
2021-11-25 14:02:02 +03:00
let expectedRoutes =
[ ( "HomeRoute",
Route.Route {Route.path = "/", Route.page = Ref "HomePage"}
)
]
takeDecls @Route <$> decls `shouldBe` Right expectedRoutes
2021-11-25 14:26:48 +03:00
let expectedQueries =
[ ( "getUsers",
Query.Query
{ Query.fn = ExtImport (ExtImportField "getAllUsers") "@ext/foo.js",
2021-11-25 14:36:42 +03:00
Query.entities = Just [Ref "User"],
Query.auth = Nothing
2021-11-25 14:26:48 +03:00
}
)
]
takeDecls @Query <$> decls `shouldBe` Right expectedQueries
2021-11-25 14:36:42 +03:00
let expectedAction =
[ ( "updateUser",
Action.Action
{ Action.fn = ExtImport (ExtImportField "updateUser") "@ext/foo.js",
Action.entities = Just [Ref "User"],
Action.auth = Just True
}
)
]
takeDecls @Action <$> decls `shouldBe` Right expectedAction
it "Returns a type error if unexisting declaration is referenced" $ do
let source =
unlines
2021-11-25 14:02:02 +03:00
[ "route HomeRoute { path: \"/\", page: NonExistentPage }"
2021-08-22 20:25:55 +03:00
]
2021-11-25 14:02:02 +03:00
takeDecls @Route <$> analyze source `shouldBe` Left (TypeError $ TC.UndefinedIdentifier "NonExistentPage")
it "Returns a type error if referenced declaration is of wrong type" $ do
let source =
unlines
2021-11-25 14:02:02 +03:00
[ "route HomeRoute { path: \"/\", page: HomeRoute }"
]
2021-11-25 14:02:02 +03:00
takeDecls @Route <$> analyze source `shouldSatisfy` isAnalyzerOutputTypeError
it "Works when referenced declaration is declared after the reference." $ do
let source =
unlines
2021-11-25 14:02:02 +03:00
[ "route HomeRoute { path: \"/\", page: HomePage }",
"page HomePage { component: import Home from \"@ext/HomePage.js\" }"
]
isRight (analyze source) `shouldBe` True
isAnalyzerOutputTypeError :: Either AnalyzeError a -> Bool
isAnalyzerOutputTypeError (Left (TypeError _)) = True
isAnalyzerOutputTypeError _ = False