Skip to content

Commit 4b125bb

Browse files
authored
Merge pull request #684 from auslavs/feliz_v3.0
Add Elmish Subscription Support and Tests to Feliz.UseElmish
2 parents e5b13c4 + 07c568a commit 4b125bb

2 files changed

Lines changed: 99 additions & 0 deletions

File tree

src/Feliz.UseElmish/UseElmish.fs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,18 @@ type React =
133133

134134
static member inline useElmish(init: 'Model * Cmd<'Msg>, update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>, ?dependencies: obj array) =
135135
React.useElmish((fun () -> Program.mkProgram (fun () -> init) update (fun _ _ -> ())), ?dependencies=dependencies)
136+
137+
static member inline useElmish(init: 'Arg -> 'Model * Cmd<'Msg>, update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>, subscribe: 'Model -> Sub<'Msg>, arg: 'Arg, ?dependencies: obj array) =
138+
React.useElmish((fun () ->
139+
Program.mkProgram init update (fun _ _ -> ())
140+
|> Program.withSubscription subscribe), arg, ?dependencies=dependencies)
141+
142+
static member inline useElmish(init: unit -> 'Model * Cmd<'Msg>, update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>, subscribe: 'Model -> Sub<'Msg>, ?dependencies: obj array) =
143+
React.useElmish((fun () ->
144+
Program.mkProgram init update (fun _ _ -> ())
145+
|> Program.withSubscription subscribe), ?dependencies=dependencies)
146+
147+
static member inline useElmish(init: 'Model * Cmd<'Msg>, update: 'Msg -> 'Model -> 'Model * Cmd<'Msg>, subscribe: 'Model -> Sub<'Msg>, ?dependencies: obj array) =
148+
React.useElmish((fun () ->
149+
Program.mkProgram (fun () -> init) update (fun _ _ -> ())
150+
|> Program.withSubscription subscribe), ?dependencies=dependencies)

tests/Feliz.UseElmish/Main.test.fs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,87 @@ describe "UseElmish" <| fun () ->
146146
expect(render.getByTestId("count")).toHaveTextContent "0" //"State should have been reset because dependency has changed"
147147
)
148148
}
149+
150+
module Subscriber =
151+
open Elmish
152+
open Fable.Core.JS
153+
154+
type Model = {
155+
Count: int
156+
SubscriberTicks: int
157+
}
158+
159+
type Msg =
160+
| Increment
161+
| SubscriberTick
162+
163+
let init initialValue =
164+
{
165+
Count = initialValue
166+
SubscriberTicks = 0
167+
},
168+
Cmd.none
169+
170+
let update msg (model: Model) =
171+
match msg with
172+
| Increment ->
173+
{ model with Count = model.Count + 1 }, Cmd.none
174+
| SubscriberTick ->
175+
{ model with SubscriberTicks = model.SubscriberTicks + 1 }, Cmd.none
176+
177+
let subscribeToTimer dispatch =
178+
let subscriptionId =
179+
setInterval
180+
(fun _ -> dispatch SubscriberTick)
181+
100
182+
{ new System.IDisposable with member _.Dispose() = clearInterval subscriptionId }
183+
184+
let subscribe _model =
185+
[ ["timer"], subscribeToTimer ]
186+
187+
[<ReactComponent>]
188+
let render (props: {| initialValue: int |}) =
189+
let model, dispatch = React.useElmish((fun () -> init props.initialValue), update, subscribe, [||])
190+
191+
Html.div [
192+
Html.h1 [
193+
prop.testId "count"
194+
prop.text model.Count
195+
]
196+
197+
Html.h1 [
198+
prop.testId "subscriber-ticks"
199+
prop.text model.SubscriberTicks
200+
]
201+
202+
Html.button [
203+
prop.text "Increment"
204+
prop.onClick (fun _ -> dispatch Increment)
205+
prop.testId "increment"
206+
]
207+
]
208+
209+
describe "UseElmish with subscriptions" <| fun () ->
210+
testPromise "Elmish subscriptions work correctly" <| fun () -> promise {
211+
let render = RTL.render(Subscriber.render {| initialValue = 0 |})
212+
213+
expect(render.getByTestId("count")).toHaveTextContent "0" //"Should start with initial count"
214+
expect(render.getByTestId("subscriber-ticks")).toHaveTextContent "0" //"Should start with 0 subscriber ticks"
215+
216+
// Wait for subscriber to tick a few times
217+
do! Promise.sleep 350
218+
219+
do!
220+
RTL.waitFor (fun () ->
221+
let ticks = render.getByTestId("subscriber-ticks").textContent |> int
222+
expect(ticks >= 3).toBeTruthy() //"Subscriber should have ticked at least 3 times"
223+
)
224+
225+
// Click increment button
226+
render.getByTestId("increment").click()
227+
228+
do!
229+
RTL.waitFor (fun () ->
230+
expect(render.getByTestId("count")).toHaveTextContent "1" //"Count should have been incremented"
231+
)
232+
}

0 commit comments

Comments
 (0)