Writing a unit test in Elm

Series: Snake in Elm, Elm makes me happy, Elm Basics, Elm Unit Test

I’ve been having fun with Elm programming recently. Elm is a replacement for JavaScript that is pure functional and highly practical.

Here’s how to go from nothing installed at all to writing a unit test that passes, in just over 10 minutes.

The source code is here: github.com/andybalaam/elm-unit-test-example

Mousedown events delayed or sluggish on mobile

I am learning about Elm and web apps by writing a little game called sootl.

It’s all SVGs animated with requestAnimationFrame(), and you control your player by clicking or touch the screen.

Everything seemed good on desktop browsers, but on mobile it took an age for the mousedown event to trigger when you touched.

Update: Thanks to @zatnosk on mastodon.social for letting me know there is a better way: 300ms tap delay, gone away. Short answer: add a <meta name="viewport" content="width=device-width"> tag inside your <head> tag.

It turns out that under certain circumstances, some mobile devices wait after the first touch happens to see whether you are going to swipe before they emit the mousedown event.

So, the short answer was to listen for touchstart events as well as mousedown ones. In Elm that looked like this change: e77e055e470c38489657ecaf5edc54a4e5f85782.

Elm resizeable SVG canvas filling the screen

I am toying with writing an SVG-based game in (exciting-looking JavaScript-replacement) Elm, and I wanted an SVG that filled the whole screen and resized when the screen resized. I found it harder than I expected, so here is what I came up with for your information and comment.

Try the demo.

Because I was using Html.App.programWithFlags I was not able to shortcut the process and use just elm-reactor – I needed to create an HTML file and compile my code with elm-make.

index.html sets up a full-screen app and passes in the window size:

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8"/>
    <title>Sootl</title>
    <script src="sootl.js"></script>
    <style>
        html, body, svg
        {
            margin: 0px;
            padding: 0px;
            border: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>
</body>
<script>
var app = Elm.Main.fullscreen(
    {
        width:  window.innerWidth,
        height: window.innerHeight
    }
);
</script>
</html>

elm-package.json requires the Html, Svg and Window packages:

{
    "version": "1.0.0",
    "summary": "Stay out of the light!",
    "repository": "https://github.com/andybalaam/sootl.git",
    "license": "GPL2",
    "source-directories": [
        "."
    ],
    "exposed-modules": [],
    "dependencies": {
        "elm-lang/core": "4.0.5 <= v < 5.0.0",
        "elm-lang/html": "1.1.0 <= v < 2.0.0",
        "elm-lang/svg": "1.1.1 <= v < 2.0.0",
        "elm-lang/window": "1.0.0 <= v < 2.0.0"
    },
    "elm-version": "0.17.1 <= v < 0.18.0"
}

Main.elm contains the Elm code, which starts off with the window size from JavaScript, and then listens to resize events using the Window module.

import Html exposing (Html)
import Html.App exposing (programWithFlags)
import Svg exposing (..)
import Svg.Attributes exposing (..)
import Window


type alias Flags =
    { width : Int
    , height : Int
    }


type Msg = Resize Int Int


type alias Model =
    { screen :
        { width : Int
        , height : Int
        }
    }


init : Flags -> (Model, Cmd Msg)
init flags =
    (
        { screen =
            { width = flags.width
            , height = flags.height
            }
        }
    , Cmd.none
    )



view : Model -> Html Msg
view model =
    let
        sw = model.screen.width  - 0
        sh = model.screen.height - 0
    in
        svg
        [ width  <| toString sw
        , height <| toString sh
        ]
        [ rect
            [ x "0"
            , y "0"
            , width (toString model.screen.width)
            , height (toString model.screen.height)
            , fill "#eeffee"
            ]
            []
        , text'
            [ x <| toString <| sw / 2
            , y <| toString <| sh / 2
            , fontSize <| toString <| sh / 10
            , textAnchor "middle"
            ]
            [ text
                ((toString model.screen.width)
                ++ ", "
                ++ (toString model.screen.height))
            ]
        ]


update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
    let m =
        case msg of
            Resize w h -> {model | screen = {width = w, height = h}}
    in
        (m, Cmd.none)


subscriptions : Model -> Sub Msg
subscriptions model =
    Window.resizes (\size -> Resize size.width size.height)


main =
   programWithFlags
     { init = init
     , view = view
     , update = update
     , subscriptions = subscriptions
     }

I installed all the packages with:

elm-package install

Then I compiled the code with:

elm-make --output=sootl.js Main.elm

Now I launched elm-reactor:

elm-reactor

And navigated my browser to http://localhost:8000/index.html to see it working.

Elm Basics Video

Series: Snake in Elm, Elm makes me happy, Elm Basics, Elm Unit Test

A lot of the documentation about the new language I am really excited about, Elm focusses on the Elm Architecture and the ideas of Functional Reactive Programming, and while those are the fundamental reasons I am interested in Elm, I found myself stuck on the syntax quite often.

So, in this video I review almost all the syntax and basic ideas you need to be able to read and write Elm code, treating it as a general programming language.

Update: forgot to add the slides – here they are:
Slides: Elm Basics

Elm makes me happy

Series: Snake in Elm, Elm makes me happy, Elm Basics, Elm Unit Test

Elm lets you write interactive web sites in a really clean and safe-feeling way, which is a contrast to the feeling I get when using JavaScript and HTML. It’s functional, but instead of that making everything seem hard, it makes me happy.

Slides: Elm makes me happy