on develop help sign in
Add file upload test
3a8590fTom Smalley
reflex-dom-core/reflex-dom-core.cabal+2
@@ -156,6 +156,8 @@ test-suite hydration
156 , aeson
156 , aeson
157 , bytestring
157 , bytestring
158 , containers
158 , containers
159+ , directory
160+ , filepath
159 , exceptions
161 , exceptions
160 , ghcjs-dom
162 , ghcjs-dom
161 , hspec
163 , hspec
reflex-dom-core/src/Reflex/Dom/Builder/Hydration.hs+12−6
@@ -657,6 +657,8 @@ instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT
657 (checkedChangedByUI, triggerCheckedChangedByUI) <- newTriggerEvent
657 (checkedChangedByUI, triggerCheckedChangedByUI) <- newTriggerEvent
658 (checkedChangedBySetChecked, triggerCheckedChangedBySetChecked) <- newTriggerEvent
658 (checkedChangedBySetChecked, triggerCheckedChangedBySetChecked) <- newTriggerEvent
659
659
660+ (fileChange, triggerFileChange) <- newTriggerEvent
661+
660 -- Expected initial value from config
662 -- Expected initial value from config
661 let v0 = _inputElementConfig_initialValue cfg
663 let v0 = _inputElementConfig_initialValue cfg
662
664
@@ -697,10 +699,12 @@ instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT
697 Input.setChecked domInputElement newChecked
699 Input.setChecked domInputElement newChecked
698 when (newChecked /= oldChecked) $ liftIO $ triggerCheckedChangedBySetChecked newChecked
700 when (newChecked /= oldChecked) $ liftIO $ triggerCheckedChangedBySetChecked newChecked
699
701
700−-- files <- holdDyn mempty <=< wrapDomEvent domInputElement (`on` Events.change) $ do
702+ liftJSM $ domInputElement `on` Events.change $ do
701−-- mfiles <- Input.getFiles domInputElement
703+ mfiles <- Input.getFiles domInputElement
702−-- let getMyFiles xs = fmap catMaybes . mapM (FileList.item xs) . flip take [0..] . fromIntegral =<< FileList.getLength xs
704+ let getMyFiles xs = fmap catMaybes . mapM (FileList.item xs) . flip take [0..] . fromIntegral =<< FileList.getLength xs
703−-- maybe (return []) getMyFiles mfiles
705+ liftIO . triggerFileChange =<< maybe (return []) getMyFiles mfiles
706+
707+ return ()
704
708
705 checked' <- holdDyn (_inputElementConfig_initialChecked cfg) $ leftmost
709 checked' <- holdDyn (_inputElementConfig_initialChecked cfg) $ leftmost
706 [ checkedChangedBySetChecked
710 [ checkedChangedBySetChecked
@@ -716,6 +720,8 @@ instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT
716 , valueChangedByUI
720 , valueChangedByUI
717 ]
721 ]
718
722
723+ files <- holdDyn mempty fileChange
724+
719 return $ InputElement
725 return $ InputElement
720 { _inputElement_value = v
726 { _inputElement_value = v
721 , _inputElement_checked = checked
727 , _inputElement_checked = checked
@@ -723,8 +729,8 @@ instance (SupportsHydrationDomBuilder t m) => DomBuilder t (HydrationDomBuilderT
723 , _inputElement_input = valueChangedByUI
729 , _inputElement_input = valueChangedByUI
724 , _inputElement_hasFocus = hasFocus
730 , _inputElement_hasFocus = hasFocus
725 , _inputElement_element = e
731 , _inputElement_element = e
726− , _inputElement_raw = undefined -- domInputElement
732+ , _inputElement_raw = undefined -- TODO domInputElement
727− , _inputElement_files = undefined -- files
733+ , _inputElement_files = files
728 }
734 }
729
735
730 {-# INLINABLE textAreaElement #-}
736 {-# INLINABLE textAreaElement #-}
reflex-dom-core/test/hydration.hs+21−3
@@ -19,7 +19,7 @@ import Data.IORef
19import Data.Maybe (fromMaybe)
19import Data.Maybe (fromMaybe)
20import Data.Proxy
20import Data.Proxy
21import Data.Text (Text)
21import Data.Text (Text)
22−import Language.Javascript.JSaddle (JSException(..), syncPoint)
22+import Language.Javascript.JSaddle (JSException(..), syncPoint, liftJSM)
23import Language.Javascript.JSaddle.Warp
23import Language.Javascript.JSaddle.Warp
24import Network.HTTP.Types (status200)
24import Network.HTTP.Types (status200)
25import Network.Wai
25import Network.Wai
@@ -31,11 +31,13 @@ import System.Timeout
31import Test.Hspec
31import Test.Hspec
32import Test.HUnit
32import Test.HUnit
33import Test.WebDriver (WD)
33import Test.WebDriver (WD)
34+import qualified GHCJS.DOM.Types as DOM (File)
35+import qualified GHCJS.DOM.File as File
34
36
35--import System.IO.Silently
37--import System.IO.Silently
36import System.IO.Temp
38import System.IO.Temp
37−import System.IO
39+import System.Directory
38−import GHC.IO.Handle (hDuplicate, hDuplicateTo)
40+import qualified System.FilePath as FilePath
39
41
40import qualified Data.ByteString.Lazy as LBS
42import qualified Data.ByteString.Lazy as LBS
41import qualified Data.Text as T
43import qualified Data.Text as T
@@ -265,6 +267,22 @@ main = hspec $ parallel $ do
265 & inputElementConfig_setChecked .~ setChecked
267 & inputElementConfig_setChecked .~ setChecked
266 performEvent_ $ liftIO . writeIORef checkedByUIRef <$> _inputElement_checkedChange e
268 performEvent_ $ liftIO . writeIORef checkedByUIRef <$> _inputElement_checkedChange e
267 performEvent_ $ liftIO . writeIORef checkedRef <$> updated (_inputElement_checked e)
269 performEvent_ $ liftIO . writeIORef checkedRef <$> updated (_inputElement_checked e)
270+ it "captures file uploads" $ do
271+ filesRef :: IORef [Text] <- newIORef []
272+ let uploadFile = do
273+ e <- WD.findElem $ WD.ByTag "input"
274+ path <- liftIO $ writeSystemTempFile "testFile" "file contents"
275+ WD.sendKeys (T.pack path) e
276+ WD.click <=< WD.findElem $ WD.ByTag "button"
277+ liftIO $ removeFile path
278+ input <- liftIO $ readIORef filesRef
279+ liftIO $ input `shouldBe` [T.pack $ FilePath.takeFileName path]
280+ testWidget (pure ()) uploadFile $ do
281+ e <- inputElement $ def & initialAttributes .~ "type" =: "file"
282+ click <- button "save"
283+ prerender (pure ()) $ performEvent_ $ ffor (tag (current (_inputElement_files e)) click) $ \fs -> do
284+ names <- liftJSM $ traverse File.getName fs
285+ liftIO $ writeIORef filesRef names
268
286
269 describe "prerender" $ parallel $ do
287 describe "prerender" $ parallel $ do
270 it "works in simple case" $ do
288 it "works in simple case" $ do