elm-pages-v3-beta/tests/RouteTests.elm
2021-06-03 18:10:06 -07:00

177 lines
4.7 KiB
Elm

module RouteTests exposing (all)
import Expect
import List.Extra
import Regex
import Test exposing (Test, describe, test)
all : Test
all =
describe "routes"
[ test "test 1" <|
\() ->
"/cats/larry"
|> tryMatch
{ pattern = "^cats(?:\\/([^/]+))?$"
, toRoute =
\matches ->
case matches of
[ name ] ->
Cats__Name__ { name = name } |> Just
_ ->
Nothing
}
|> Expect.equal (Cats__Name__ { name = Just "larry" } |> Just)
, test "test 2" <|
\() ->
"/cats"
|> tryMatch
{ pattern = "^cats(?:\\/([^/]+))?$"
, toRoute =
\matches ->
case matches of
[ name ] ->
Cats__Name__ { name = name } |> Just
_ ->
Nothing
}
|> Expect.equal (Cats__Name__ { name = Nothing } |> Just)
, test "multiple matchers" <|
\() ->
"/slide/123"
|> firstMatch exampleMatchers
|> Expect.equal (Slide__Number_ { number = "123" } |> Just)
, test "hardcoded routes have precedence over dynamic segments" <|
\() ->
"/post/create"
|> firstMatch postPrecedenceExample
|> Expect.equal (Post__Create {} |> Just)
, test "dynamic segments match when they are not overshadowed by a hardcoded route" <|
\() ->
"/post/update"
|> firstMatch postPrecedenceExample
|> Expect.equal (Post__Slug_ { slug = "update" } |> Just)
]
exampleMatchers : List (Matcher Route)
exampleMatchers =
[ { pattern = "^cats(?:\\/([^/]+))?$"
, toRoute =
\matches ->
case matches of
[ name ] ->
Cats__Name__ { name = name } |> Just
_ ->
Nothing
}
, { pattern = "^slide\\/(?:([^/]+))$"
, toRoute =
\matches ->
case matches of
[ Just number ] ->
Slide__Number_ { number = number } |> Just
_ ->
Nothing
}
]
postPrecedenceExample : List (Matcher Route)
postPrecedenceExample =
[ { pattern = "^post\\/create$"
, toRoute =
\_ ->
Just (Post__Create {})
}
, { pattern = "^post\\/(?:([^/]+))$"
, toRoute =
\matches ->
case matches of
[ Just slug ] ->
Post__Slug_ { slug = slug } |> Just
_ ->
Nothing
}
]
firstMatch : List (Matcher Route) -> String -> Maybe Route
firstMatch matchers path =
List.Extra.findMap
(\matcher ->
if Regex.contains (matcher.pattern |> toRegex) (normalizePath path) then
tryMatch matcher path
else
Nothing
)
matchers
toRegex : String -> Regex.Regex
toRegex pattern =
Regex.fromString pattern
|> Maybe.withDefault Regex.never
type alias Matcher route =
{ pattern : String, toRoute : List (Maybe String) -> Maybe route }
tryMatch : { pattern : String, toRoute : List (Maybe String) -> Maybe Route } -> String -> Maybe Route
tryMatch { pattern, toRoute } path =
path
|> normalizePath
|> submatches pattern
|> toRoute
submatches : String -> String -> List (Maybe String)
submatches pattern path =
Regex.find
(Regex.fromString pattern
|> Maybe.withDefault Regex.never
)
path
|> List.concatMap .submatches
normalizePath : String -> String
normalizePath path =
path
|> stripLeadingSlash
|> stripTrailingSlash
stripLeadingSlash : String -> String
stripLeadingSlash path =
if path |> String.startsWith "/" then
String.dropLeft 1 path
else
path
stripTrailingSlash : String -> String
stripTrailingSlash path =
if path |> String.endsWith "/" then
String.dropRight 1 path
else
path
type Route
= Slide {}
| Cats__Name__ { name : Maybe String }
| Slide__Number_ { number : String }
| Post__Create {}
| Post__Slug_ { slug : String }