brian-watkins / elm-spec

Describe the behavior of Elm programs
https://package.elm-lang.org/packages/brian-watkins/elm-spec/latest/
MIT License
29 stars 4 forks source link

Implementing Spec.Time.tick #74

Closed dotnetspec closed 7 months ago

dotnetspec commented 8 months ago

I'm attempting to pass the following scenario and it appears that Spec.Time.tick is exactly what I need:

scenario "4. Re-load the availability if the clicked timeslot is less than 2 hours into the future i.e. user left the page and came back"
            (given
                (Setup.init (Sched.init testFlags)
                    |> Spec.Time.withTime 1709042943000 -- Date and time (GMT): Tuesday, February 27, 2024 2:09:03 PM
                    |> Setup.withUpdate Sched.update
                    |> Setup.withView Sched.view
                    |> Stub.serve
                        [ successfulAccessTokenStub
                        , successfulTimeSlotsStub27_Feb_2024_14_09
                        ]
                ) 
                |> when "2 hours pass"
                    [ Spec.Time.tick 7200000
                    ]
                |> when "we click on the first available timeslot (5 PM) - still there after 2 hours with no user activity"
                    [ Markup.target
                   -- NOTE: It appears that the test ONLY matches on the first element that matches the selector. Should be 5PM in this test.
                        << by [ id "timeSlot" ]
                    -- NOTE: Click the first element that matches the selector
                    -- this should trigger update ChosenDateTime
                    , Event.click
                    ]
                |> Spec.when "log the requests the app is making to the server"
                    [ -- NOTE: These are the requests the app is making. If they match a stub above, the stubbed response will be returned.
                      Spec.Http.logRequests
                    ]
                |> Spec.observeThat
                    [ it "we do not proceed to booking and the UI displays 7 PM as the first available timeslot"
                        (Markup.observeElement
                            |> Markup.query
                            -- NOTE: It appears that the test ONLY matches on the first element that matches the selector
                            << by [ id "timeSlot" ]
                            |> Spec.expect
                                (Claim.isSomethingWhere <|
                                    Markup.text <|
                                        -- NOTE: 7 PM is the first expected remaining timeslot
                                        Claim.isStringContaining 1 "7 PM"

                                )
                        )
                    ]
            )

However, the console log indicates that the first timeslot is 'clicked', but that the datetime in the model, that represents 'current time', is still the same as at the beginning of the test i.e. |> Spec.Time.withTime 1709042943000 -- Date and time (GMT): Tuesday, February 27, 2024 2:09:03 PM.

It therefore appears that

|> when "2 hours pass"
    [ Spec.Time.tick 7200000
    ]

hasn't effectively moved the time on by 2 hours in my app.

This is how Tick is defined in the update function:

Tick newTime ->
            let
                _ =
                    Debug.log "newTime" newTime

                dateTimeOnlyUpdatedIfNotSelected =
                    case model.datetimeFromMain of
                        Just (CurrentDateTime _ zone) ->
                            Just
                                (CurrentDateTime
                                    newTime
                                    zone
                                )

                        Just (SelectedDateTime dt zone) ->
                            Just (SelectedDateTime dt zone)

                        Nothing ->
                            Just
                                (CurrentDateTime newTime Time.utc)
            in
            ( { model | datetimeFromMain = dateTimeOnlyUpdatedIfNotSelected }, Cmd.none )

What else should I be looking into to simulate the passage of 2 hours in the app before clicking on a redundant timeslot?

Thanks ...

brian-watkins commented 7 months ago

If you're using Time.every in your subscriptions function to update your model as the time changes, you'll need to update the setup of your spec to provide your subscriptions function -- I don't currently see that in the example code you provided.

So you would do something like:

(given
    (Setup.init (Sched.init testFlags)
        |> Spec.Time.withTime 1709042943000 -- Date and time (GMT): Tuesday, February 27, 2024 2:09:03 PM
        |> Setup.withUpdate Sched.update
        |> Setup.withSubscriptions Sched.subscriptions   --  <-- ***THIS PART IS NEW***
        |> Setup.withView Sched.view
        |> Stub.serve
            [ successfulAccessTokenStub
            , successfulTimeSlotsStub27_Feb_2024_14_09
            ]
    )
)

I've updated the example repo with a spec that uses Spec.Time.tick to illustrate what I mean:

https://github.com/brian-watkins/elm-spec-example/blob/main/specs/src/TimeSpec.elm

I looked at the documentation and noticed that the example provided on the docs for Spec.Time is actually missing the line that provides the subscriptions function during the setup. Apologies for that. Maybe I can correct that and publish a new version so others won't be tripped up by this.

dotnetspec commented 7 months ago

Thanks, that fixed it ...