Triggering ArrowUp in elm-spc

Hello,

I’m trying to trigger an “ArrowUp” event from elm-spec in a spec test.

Using an example from the spec tests for elm-spec, I found this helper function:

keyPressEvent : String -> Step.Context model -> Step.Command msg
keyPressEvent char =
  Encode.object
    [ ( "key", Encode.string char )
    ]
    |> Event.trigger "keypress"

Making this a bit more verbose I get

upArrowPressed =
    Json.Encode.object [ ( "key", Json.Encode.string "ArrowUp") ]
    |> Event.trigger "keypress"

In the spec test I’m using it like:

...
Spec.when "ArrowUp is pressed"
    [ Markup.target << document
    , upArrowPressed
    ]
...

In Main I’m subscribing to these events with

subscriptions model =
    Sub.batch
        [ ...
        , onKeyDown (Decode.succeed ArrowUp)
        ]

I have tried changing “key” to “keyCode” and encoding the int code (38), “Keypress” to “keydown”. Also tried running the tests in the browser rather than JSDOM to no avail. Could I get a point in the right direction?

Here’s a gist with a sample spec that describes an app that listens for a keydown event; I hope it’s helpful. Note that you should make sure to set up your scenario to use the subscriptions function with Spec.Setup.withSubscriptions (I often forget this myself).

SampleSpec.elm

I’m happy to hear that someone is trying out elm-spec, and welcome any feedback!

1 Like

Thanks Brian!

Wow, I didn’t expect the author to reply :grinning:

I was so happy I found it! I was contemplating using selenium and python, which introduces a whole other set of dependencies/configuration/setup that I was trying to avoid.

Thanks for the gist!

UPDATE

Using the gist example I was able to get my code working in the original post, however when I included considerKeyboardEvent in my subscription I broke it. The issue is due to this package expecting JSON with all the fields of a:

type alias KeyboardEvent =
        { altKey : Bool
        , ctrlKey : Bool
        , key : Maybe String
        , keyCode : Key
        , metaKey : Bool
        , repeat : Bool
        , shiftKey : Bool
        }

Which doesn’t seems to be the case with elm-spec events. I have raised an issue here as well

Glad to hear you were able to get your original code working!

The example I provided used Spec.Markup.Event.trigger to dispatch a custom DOM event with the name and any properties that you specify. In my example I just added the key property because that’s all my program cared about.

In the real world, pressing down a key would generate a KeyboardEvent, which would always have many more properties, so I think it’s reasonable for a library like elm-keyboard-event to expect those properties to be there.

To address this, you could write a helper function for your specs that triggers an event with all (or more of) the properties found in a standard KeyboardEvent:

triggerKeyboardEventWithKey key =
  Spec.Markup.Event.trigger "keydown" <|
    Json.Encode.object
    [ ("altKey", Encode.bool False)
    , ("ctrlKey", Encode.bool False)
    , ("key", Encode.string key)
    , ("keyCode", Encode.int 0) -- probably not the right keycode
    , ("metaKey", Encode.bool False)
    , ("repeat", Encode.bool False)
    , ("shiftKey", Encode.bool False)
    }]

This function would generate a custom DOM event with all the properties expected by the decoder in elm-keyboard-event (I think – haven’t tried it). And then you could modify this to make sure you’re able to set the values of those properties that your program cares about. So, if your program doesn’t ever care about whether the shift key is pressed, just leave it as false.

So, Spec.Markup.Event.trigger gives you lots of freedom to dispatch whatever kind of DOM event the scenario might need. Sounds like here you might be able to satisfy the library you’d like to use by triggering an event with a few more properties.

1 Like

Thanks for all the input!

That is a nice feature for sure, I hadn’t fully grasped the flexibility of Spec.Markup.Event.trigger. Don’t know why but I hadn’t made the connection that what is encoded is exactly what is attached to the event. I feel stupid, however happy I understand :laughing:

Update

Not sure if this is the best approach (time will tell) but I decided to write my own helper function to replace the considerKeyboardEvent dependency

arrowUp =
    maybeKeyEvent "ArrowUp"


arrowDown =
    maybeKeyEvent "ArrowDown"


enter =
    maybeKeyEvent "Enter"


maybeKeyEvent : String -> msg -> Decoder msg
maybeKeyEvent str msg =
    andThen
        (\result ->
            case result == str of
                True ->
                    succeed msg

                False ->
                    fail "Ignoring keyboard event"
        )
        (field "key" string)

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.