@@ -220,113 +220,217 @@ main = hspec $ parallel $ do
220220 pure ()
221221
222222 describe "inputElement" $ parallel $ do
223− it "doesn't wipe user input when switching over" $ do
224− inputRef <- newIORef ""
225− testWidget'
226− (do
227− e <- WD.findElem $ WD.ByTag "input"
228− WD.sendKeys "hello world" e
229− pure e)
230− (\e -> do
231− t <- WD.attr e "value"
232− liftIO $ t `shouldBe` Just "hello world"
233− WD.click <=< WD.findElem $ WD.ByTag "button"
234− input <- liftIO $ readIORef inputRef
235− liftIO $ input `shouldBe` "hello world"
236− ) $ do
237− e <- inputElement def
238− click <- button "save"
239− performEvent_ $ liftIO . writeIORef inputRef <$> tag (current (value e)) click
240− it "captures user input after switchover" $ do
241− inputRef <- newIORef ""
242− let checkValue = do
243− WD.sendKeys "hello world" <=< WD.findElem $ WD.ByTag "input"
223+ describe "hydration" $ do
224+ it "doesn't wipe user input when switching over" $ do
225+ inputRef <- newIORef ""
226+ testWidget'
227+ (do
228+ e <- WD.findElem $ WD.ByTag "input"
229+ WD.sendKeys "hello world" e
230+ pure e)
231+ (\e -> do
232+ t <- WD.attr e "value"
233+ liftIO $ t `shouldBe` Just "hello world"
244234 WD.click <=< WD.findElem $ WD.ByTag "button"
245235 input <- liftIO $ readIORef inputRef
246236 liftIO $ input `shouldBe` "hello world"
247− testWidget (pure ()) checkValue $ do
248− e <- inputElement def
249− click <- button "save"
250− performEvent_ $ liftIO . writeIORef inputRef <$> tag (current (value e)) click
251− it "sets focus appropriately" $ do
252− focusRef <- newIORef False
253− let checkValue = do
254− liftIO $ readIORef focusRef >>= flip shouldBe False
255− e <- WD.findElem $ WD.ByTag "input"
256− WD.moveToCenter e
257− WD.click e
258− liftIO $ threadDelay 100000
259− liftIO $ readIORef focusRef >>= flip shouldBe True
260− testWidget (pure ()) checkValue $ do
261− e <- inputElement def
262− performEvent_ $ liftIO . writeIORef focusRef <$> updated (_inputElement_hasFocus e)
263− it "sets value appropriately" $ do
264− valueByUIRef <- newIORef ""
265− valueRef <- newIORef ""
266− setValueChan :: Chan Text <- newChan
267− let checkValue = do
268− liftIO $ readIORef valueByUIRef >>= flip shouldBe ""
269− liftIO $ readIORef valueRef >>= flip shouldBe ""
270− e <- WD.findElem $ WD.ByTag "input"
271− WD.sendKeys "hello" e
272− liftIO $ do
273− threadDelay 100000
274− readIORef valueByUIRef >>= flip shouldBe "hello"
275− readIORef valueRef >>= flip shouldBe "hello"
276− writeChan setValueChan "world"
277− threadDelay 100000
278− readIORef valueByUIRef >>= flip shouldBe "hello"
279− readIORef valueRef >>= flip shouldBe "world"
280− testWidget (pure ()) checkValue $ do
281− (setValue, triggerSetValue) <- newTriggerEvent
282− prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
283− triggerSetValue =<< readChan setValueChan
284− e <- inputElement $ def & inputElementConfig_setValue .~ setValue
285− performEvent_ $ liftIO . writeIORef valueByUIRef <$> _inputElement_input e
286− performEvent_ $ liftIO . writeIORef valueRef <$> updated (value e)
287− it "sets checked appropriately" $ do
288− checkedByUIRef <- newIORef False
289− checkedRef <- newIORef False
290− setCheckedChan <- newChan
291− let checkValue = do
292− liftIO $ readIORef checkedByUIRef >>= flip shouldBe False
293− liftIO $ readIORef checkedRef >>= flip shouldBe False
294− e <- WD.findElem $ WD.ByTag "input"
295− WD.moveToCenter e
296− WD.click e
297− liftIO $ do
298− threadDelay 100000
299− readIORef checkedByUIRef >>= flip shouldBe True
300− readIORef checkedRef >>= flip shouldBe True
301− writeChan setCheckedChan False
302− threadDelay 100000
303− readIORef checkedByUIRef >>= flip shouldBe True
304− readIORef checkedRef >>= flip shouldBe False
305− testWidget (pure ()) checkValue $ do
306− (setChecked, triggerSetChecked) <- newTriggerEvent
307− prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
308− triggerSetChecked =<< readChan setCheckedChan
309− e <- inputElement $ def
310− & initialAttributes .~ "type" =: "checkbox"
311− & inputElementConfig_setChecked .~ setChecked
312− performEvent_ $ liftIO . writeIORef checkedByUIRef <$> _inputElement_checkedChange e
313− performEvent_ $ liftIO . writeIORef checkedRef <$> updated (_inputElement_checked e)
314− it "captures file uploads" $ do
315− filesRef :: IORef [Text] <- newIORef []
316− let uploadFile = do
317− e <- WD.findElem $ WD.ByTag "input"
318− path <- liftIO $ writeSystemTempFile "testFile" "file contents"
319− WD.sendKeys (T.pack path) e
320− WD.click <=< WD.findElem $ WD.ByTag "button"
321− liftIO $ removeFile path
322− input <- liftIO $ readIORef filesRef
323− liftIO $ input `shouldBe` [T.pack $ FilePath.takeFileName path]
324− testWidget (pure ()) uploadFile $ do
325− e <- inputElement $ def & initialAttributes .~ "type" =: "file"
326− click <- button "save"
327− prerender (pure ()) $ performEvent_ $ ffor (tag (current (_inputElement_files e)) click) $ \fs -> do
328− names <- liftJSM $ traverse File.getName fs
329− liftIO $ writeIORef filesRef names
237+ ) $ do
238+ e <- inputElement def
239+ click <- button "save"
240+ performEvent_ $ liftIO . writeIORef inputRef <$> tag (current (value e)) click
241+ it "captures user input after switchover" $ do
242+ inputRef <- newIORef ""
243+ let checkValue = do
244+ WD.sendKeys "hello world" <=< WD.findElem $ WD.ByTag "input"
245+ WD.click <=< WD.findElem $ WD.ByTag "button"
246+ input <- liftIO $ readIORef inputRef
247+ liftIO $ input `shouldBe` "hello world"
248+ testWidget (pure ()) checkValue $ do
249+ e <- inputElement def
250+ click <- button "save"
251+ performEvent_ $ liftIO . writeIORef inputRef <$> tag (current (value e)) click
252+ it "sets focus appropriately" $ do
253+ focusRef <- newIORef False
254+ let checkValue = do
255+ liftIO $ readIORef focusRef >>= flip shouldBe False
256+ e <- WD.findElem $ WD.ByTag "input"
257+ WD.click e
258+ liftIO $ threadDelay 100000
259+ liftIO $ readIORef focusRef >>= flip shouldBe True
260+ testWidget (pure ()) checkValue $ do
261+ e <- inputElement def
262+ performEvent_ $ liftIO . writeIORef focusRef <$> updated (_inputElement_hasFocus e)
263+ it "sets focus when focus occurs before hydration" $ do
264+ focusRef <- newIORef False
265+ let setup = do
266+ e <- WD.findElem $ WD.ByTag "input"
267+ WD.click e
268+ hasFocus <- (== e) <$> WD.activeElem
269+ liftIO $ do
270+ hasFocus `shouldBe` True
271+ readIORef focusRef >>= flip shouldBe False
272+ check = liftIO $ readIORef focusRef >>= flip shouldBe True
273+ testWidget setup check $ do
274+ e <- inputElement def
275+ performEvent_ $ liftIO . writeIORef focusRef <$> updated (_inputElement_hasFocus e)
276+ it "sets value appropriately" $ do
277+ valueByUIRef <- newIORef ""
278+ valueRef <- newIORef ""
279+ setValueChan :: Chan Text <- newChan
280+ let checkValue = do
281+ liftIO $ readIORef valueByUIRef >>= flip shouldBe ""
282+ liftIO $ readIORef valueRef >>= flip shouldBe ""
283+ e <- WD.findElem $ WD.ByTag "input"
284+ WD.sendKeys "hello" e
285+ liftIO $ do
286+ threadDelay 100000
287+ readIORef valueByUIRef >>= flip shouldBe "hello"
288+ readIORef valueRef >>= flip shouldBe "hello"
289+ writeChan setValueChan "world"
290+ threadDelay 100000
291+ readIORef valueByUIRef >>= flip shouldBe "hello"
292+ readIORef valueRef >>= flip shouldBe "world"
293+ testWidget (pure ()) checkValue $ do
294+ (setValue, triggerSetValue) <- newTriggerEvent
295+ prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
296+ triggerSetValue =<< readChan setValueChan
297+ e <- inputElement $ def & inputElementConfig_setValue .~ setValue
298+ performEvent_ $ liftIO . writeIORef valueByUIRef <$> _inputElement_input e
299+ performEvent_ $ liftIO . writeIORef valueRef <$> updated (value e)
300+ it "sets checked appropriately" $ do
301+ checkedByUIRef <- newIORef False
302+ checkedRef <- newIORef False
303+ setCheckedChan <- newChan
304+ let checkValue = do
305+ liftIO $ readIORef checkedByUIRef >>= flip shouldBe False
306+ liftIO $ readIORef checkedRef >>= flip shouldBe False
307+ e <- WD.findElem $ WD.ByTag "input"
308+ WD.moveToCenter e
309+ WD.click e
310+ liftIO $ do
311+ threadDelay 100000
312+ readIORef checkedByUIRef >>= flip shouldBe True
313+ readIORef checkedRef >>= flip shouldBe True
314+ writeChan setCheckedChan False
315+ threadDelay 100000
316+ readIORef checkedByUIRef >>= flip shouldBe True
317+ readIORef checkedRef >>= flip shouldBe False
318+ testWidget (pure ()) checkValue $ do
319+ (setChecked, triggerSetChecked) <- newTriggerEvent
320+ prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
321+ triggerSetChecked =<< readChan setCheckedChan
322+ e <- inputElement $ def
323+ & initialAttributes .~ "type" =: "checkbox"
324+ & inputElementConfig_setChecked .~ setChecked
325+ performEvent_ $ liftIO . writeIORef checkedByUIRef <$> _inputElement_checkedChange e
326+ performEvent_ $ liftIO . writeIORef checkedRef <$> updated (_inputElement_checked e)
327+ it "captures file uploads" $ do
328+ filesRef :: IORef [Text] <- newIORef []
329+ let uploadFile = do
330+ e <- WD.findElem $ WD.ByTag "input"
331+ path <- liftIO $ writeSystemTempFile "testFile" "file contents"
332+ WD.sendKeys (T.pack path) e
333+ WD.click <=< WD.findElem $ WD.ByTag "button"
334+ liftIO $ removeFile path
335+ input <- liftIO $ readIORef filesRef
336+ liftIO $ input `shouldBe` [T.pack $ FilePath.takeFileName path]
337+ testWidget (pure ()) uploadFile $ do
338+ e <- inputElement $ def & initialAttributes .~ "type" =: "file"
339+ click <- button "save"
340+ prerender (pure ()) $ performEvent_ $ ffor (tag (current (_inputElement_files e)) click) $ \fs -> do
341+ names <- liftJSM $ traverse File.getName fs
342+ liftIO $ writeIORef filesRef names
343+
344+ describe "hydration/immediate" $ do
345+ it "captures user input after switchover" $ do
346+ inputRef :: IORef Text <- newIORef ""
347+ let checkValue = do
348+ WD.sendKeys "hello world" <=< WD.findElem $ WD.ByTag "input"
349+ WD.click <=< WD.findElem $ WD.ByTag "button"
350+ input <- liftIO $ readIORef inputRef
351+ liftIO $ input `shouldBe` "hello world"
352+ testWidget (pure ()) checkValue $ prerender (pure ()) $ do
353+ e <- inputElement def
354+ click <- button "save"
355+ performEvent_ $ liftIO . writeIORef inputRef <$> tag (current (value e)) click
356+ it "sets focus appropriately" $ do
357+ focusRef <- newIORef False
358+ let checkValue = do
359+ liftIO $ readIORef focusRef >>= flip shouldBe False
360+ e <- WD.findElem $ WD.ByTag "input"
361+ WD.click e
362+ liftIO $ threadDelay 100000
363+ liftIO $ readIORef focusRef >>= flip shouldBe True
364+ testWidget (pure ()) checkValue $ prerender (pure ()) $ do
365+ e <- inputElement def
366+ performEvent_ $ liftIO . writeIORef focusRef <$> updated (_inputElement_hasFocus e)
367+ it "sets value appropriately" $ do
368+ valueByUIRef :: IORef Text <- newIORef ""
369+ valueRef :: IORef Text <- newIORef ""
370+ setValueChan :: Chan Text <- newChan
371+ let checkValue = do
372+ liftIO $ readIORef valueByUIRef >>= flip shouldBe ""
373+ liftIO $ readIORef valueRef >>= flip shouldBe ""
374+ e <- WD.findElem $ WD.ByTag "input"
375+ WD.sendKeys "hello" e
376+ liftIO $ do
377+ threadDelay 100000
378+ readIORef valueByUIRef >>= flip shouldBe "hello"
379+ readIORef valueRef >>= flip shouldBe "hello"
380+ writeChan setValueChan "world"
381+ threadDelay 100000
382+ readIORef valueByUIRef >>= flip shouldBe "hello"
383+ readIORef valueRef >>= flip shouldBe "world"
384+ testWidget (pure ()) checkValue $ prerender (pure ()) $ do
385+ (setValue, triggerSetValue) <- newTriggerEvent
386+ prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
387+ triggerSetValue =<< readChan setValueChan
388+ e <- inputElement $ def & inputElementConfig_setValue .~ setValue
389+ performEvent_ $ liftIO . writeIORef valueByUIRef <$> _inputElement_input e
390+ performEvent_ $ liftIO . writeIORef valueRef <$> updated (value e)
391+ it "sets checked appropriately" $ do
392+ checkedByUIRef <- newIORef False
393+ checkedRef <- newIORef False
394+ setCheckedChan <- newChan
395+ let checkValue = do
396+ liftIO $ readIORef checkedByUIRef >>= flip shouldBe False
397+ liftIO $ readIORef checkedRef >>= flip shouldBe False
398+ e <- WD.findElem $ WD.ByTag "input"
399+ WD.moveToCenter e
400+ WD.click e
401+ liftIO $ do
402+ threadDelay 100000
403+ readIORef checkedByUIRef >>= flip shouldBe True
404+ readIORef checkedRef >>= flip shouldBe True
405+ writeChan setCheckedChan False
406+ threadDelay 100000
407+ readIORef checkedByUIRef >>= flip shouldBe True
408+ readIORef checkedRef >>= flip shouldBe False
409+ testWidget (pure ()) checkValue $ prerender (pure ()) $ do
410+ (setChecked, triggerSetChecked) <- newTriggerEvent
411+ prerender (pure ()) $ liftIO $ void $ forkIO $ forever $ do
412+ triggerSetChecked =<< readChan setCheckedChan
413+ e <- inputElement $ def
414+ & initialAttributes .~ "type" =: "checkbox"
415+ & inputElementConfig_setChecked .~ setChecked
416+ performEvent_ $ liftIO . writeIORef checkedByUIRef <$> _inputElement_checkedChange e
417+ performEvent_ $ liftIO . writeIORef checkedRef <$> updated (_inputElement_checked e)
418+ it "captures file uploads" $ do
419+ filesRef :: IORef [Text] <- newIORef []
420+ let uploadFile = do
421+ e <- WD.findElem $ WD.ByTag "input"
422+ path <- liftIO $ writeSystemTempFile "testFile" "file contents"
423+ WD.sendKeys (T.pack path) e
424+ WD.click <=< WD.findElem $ WD.ByTag "button"
425+ liftIO $ removeFile path
426+ input <- liftIO $ readIORef filesRef
427+ liftIO $ input `shouldBe` [T.pack $ FilePath.takeFileName path]
428+ testWidget (pure ()) uploadFile $ prerender (pure ()) $ do
429+ e <- inputElement $ def & initialAttributes .~ "type" =: "file"
430+ click <- button "save"
431+ prerender (pure ()) $ performEvent_ $ ffor (tag (current (_inputElement_files e)) click) $ \fs -> do
432+ names <- liftJSM $ traverse File.getName fs
433+ liftIO $ writeIORef filesRef names
330434
331435 describe "prerender" $ parallel $ do
332436 it "works in simple case" $ do
@@ -444,4 +548,5 @@ testWidget' beforeJS afterSwitchover bodyWidget = maybe (error "test timed out")
444548 a <- beforeJS
445549 liftIO $ putMVar waitBeforeJS ()
446550 liftIO $ takeMVar waitUntilSwitchover
551+ liftIO $ threadDelay 100000 -- wait a bit
447552 afterSwitchover a