/
Combinators.purs
86 lines (75 loc) · 2.66 KB
/
Combinators.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
module Elmish.Test.Combinators where
import Prelude
import Control.Monad.Reader (local)
import Data.Traversable (traverse, traverse_)
import Elmish.Test.Discover (find)
import Elmish.Test.State (class Testable, TestState(..))
import Web.DOM (Element)
-- | Finds an element by the given selector and runs the given computation in
-- | the context of that element.
-- |
-- | Example:
-- |
-- | describe "My component" $
-- | it "should work" $
-- | testComponent { init, view, update } do
-- |
-- | within "section:nth-child(1)" do
-- | find "h2" >> text >>= shouldEqual "First Section"
-- | clickOn "button"
-- |
-- | within "section:nth-child(2)" do
-- | find "h2" >> text >>= shouldEqual "Second Section"
-- | find "input[type=text]" >> change "Some Text"
-- |
within :: ∀ m a. Testable m => String -> m a -> m a
within selector f = do
el <- find selector
within' el f
infixl 8 within' as ##
-- | A more general version of `within` that accepts an `Element` instead of a
-- | CSS selector.
-- |
-- | In its operator form `##` this function can be used similarly to postfix
-- | function application, for example:
-- |
-- | button <- find "button"
-- | button ## click
-- |
within' :: ∀ m a. Testable m => Element -> m a -> m a
within' el = local \(TestState s) -> TestState s { current = el }
infixl 8 chainM as >>
-- | Used in its operator form `>>`, this function chains two DOM operations
-- | together, taking the output of the first operation and making it context of
-- | the second one. For example:
-- |
-- | buttonInsideDiv <- find "div" >> find "button"
-- | inputValue <- find "input" >> attr "value"
-- |
chainM :: ∀ m a. Testable m => m Element -> m a -> m a
chainM getEl f = do
el <- getEl
within' el f
infixl 8 chain as $$
-- | A flipped version of `within'`. In its operator form `$$` this function can
-- | be used similarly to function application, for example:
-- |
-- | button <- find "button"
-- | click $$ button
-- |
chain :: ∀ m a. Testable m => m a -> Element -> m a
chain = flip within'
-- | Runs the given computation multiple times, in the context of each of the
-- | given `Element`s.
-- |
-- | findAll "button" >> forEach click
-- |
forEach :: ∀ m. Testable m => m Unit -> Array Element -> m Unit
forEach f = traverse_ \el -> f $$ el
-- | Runs the given computation multiple times, in the context of each of the
-- | given `Element`s, and returns their results as an array.
-- |
-- | values <- findAll "input" >> mapEach (prop P.value)
-- |
mapEach :: ∀ m a. Testable m => m a -> Array Element -> m (Array a)
mapEach f = traverse \el -> f $$ el