要約
Browser.Navigation.Key
は自分で生成できなくてテストなどで困るので以下のような型を作ってます
type WithKey m
= WithKey Key m
以上です。ありがとうございました
問題提起
Elm0.19になって起動Program
周りが整理されてBrowser
packageに集約されました
この中のBrouwser.application
ではルーティングを行う際、Key
が必要になります
このKey
型の値はinit
関数に渡されるのでそこでよしなに自分のModel
に含めることになります
type alias Model = { key : Browser.Navigation.Key, ... }
init : () -> Url -> Key -> ( Model, Cmd Msg )
init _ url key =
( { key = key
, ...
}
, Cmd.none
)
さて、何も問題はありませんね
Modelを引数にとる関数のテストをしたい
あなたの手元にはModelを引数に取る関数があり、これをあなたはテストしたいはずです
updateの中身を切り出した関数とか、Page用のviewとかですね
update msg model =
case msg of
ComplicatedMsg data ->
complicatedUpdate data model
...
view model =
case route of
ListRoute ->
listView model
...
わたしの場合はviewでKeyが問題になりました(コード)。わたしは自分で作ったBibliopolaというStorybook的なのでviewを見ながら開発してるのでModelが生成できないと使えなくなって困るんです
解決策1
問題を解決するのは難しいことではありません
引数にKey
が入ってるとはいえ別に使ってるわけではないので適切に引数の型を狭めればいいです
type alias Model =
{ key : Key
, ham : Ham
, egg : Egg
}
-- view : Model -> Html Msg
view : { a | ham :Ham, egg : Egg } -> Html Msg
view model =
...
こんな感じ。構造的部分型とかいうのかな、まあ詳しくないので呼び方はなんでもいいのですがこれでこのview関数をテストするのにKey
は不要になりました
ついでにaliasしときましょう
type alias SubModel a =
{ a | ham : Ham, egg : Egg }
view : SubModel a -> Html Msg
view model =
...
よしこれでOkですね🎉
解決策2
SubModel a
の型変数がうざい
解決策3も出てきますが型いじってるだけで大差ないのでお好きなものがあれば採用ください
アプリケーションの都合で型変数を持たされてしまった型を引数に取るのはなんかうざいのでちょっと逆転させます
type alias Model =
{ ham : Ham, egg : Egg }
type alias WithKey m =
{ m | key : Key }
view : Model -> Html Msg
view = ...
main : Program () (WithKey Model) Msg
main = ...
よしよしこれでProgramの都合はBrowser.application
が直接依存する関数だけにとどまるぞ🎉
解決策3
Model
の詰め替えがつらい
WithKey Model -> Model
の処理は自動でやってくれないので中身を取り出して詰め替えしないだめです。Model
にフィールド増えたときも増やさないといけないです
まあめんどいです
とうことで今日仕事中に唐突に思いついたんですけどこれでどうでしょうか?
type WithKey m
= WithKey Key m
これなら要素の詰め替えもしなくてよい
解決策2と比べて代わりにupdateの返り値を必ずWithKeyで包まなくてはならなくなったのですが、updateの内で対処するのは理にかなってるので今はこれでやってみてます
おわり
[feldmanがこの件に関して対処するようです]
(https://github.com/elm-explorations/test/issues/24#issuecomment-444143745)
Cmd
のテストとかできるようになるんですかねー、たのしみー