1module Testable.Element exposing
15 , expectRoundedEquality
47{-| This module should mirror the top level `Element` api, with one important distinction.
49The resulting `Element msg` structure can either be rendered to Html or transformed into a test suite that can be run.
51In order to run the test:
54 - gather information from the browser
66layout : List (Testable.Attr msg) -> Testable.Element Testable.Runner.Msg -> Testable.Runner.TestableProgram
68 Testable.Runner.program
69 [ ( "Tests Run", elem )
73text : String -> Testable.Element msg
78el : List (Testable.Attr msg) -> Testable.Element msg -> Testable.Element msg
80 Testable.El (implicitWidthHeightShrink attrs)
83row : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
85 Testable.Row (implicitWidthHeightShrink attrs)
88column : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
90 Testable.Column (implicitWidthHeightShrink attrs)
93none : Testable.Element msg
98paragraph : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
103textColumn : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
105 Testable.TextColumn (implicitWidthHeightShrink attrs)
108{-| Old labeling mechanism that i removed to hastily
115 Testable.Attr (Element.moveUp x)
119 Testable.Attr (Element.moveDown x)
123 Testable.Attr (Element.moveRight x)
127 Testable.Attr (Element.moveLeft x)
169fillPortion : Int -> Length
174transparent : Bool -> Testable.Attr msg
183 , attr = Element.transparent on
190 |> Dict.get "opacity"
191 |> Maybe.withDefault "notfound"
200 [ Testable.equal value selfTransparency ]
205isVisible : Testable.Attr msg
208 { label = "is-visible"
212 [ Testable.equal context.self.isVisible True ]
217alpha : Float -> Testable.Attr msg
220 { label = "alpha-" ++ String.fromFloat a
221 , attr = Element.alpha a
228 |> Dict.get "opacity"
229 |> Maybe.withDefault "notfound"
231 [ Testable.equal (String.fromFloat a) selfTransparency ]
236padding : Int -> Testable.Attr msg
239 { label = "padding " ++ String.fromInt pad
240 , attr = Element.padding pad
244 [ Testable.true ("Padding " ++ String.fromInt pad ++ " is present")
246 [ floor found.self.bbox.padding.left
247 , floor found.self.bbox.padding.right
248 , floor found.self.bbox.padding.top
249 , floor found.self.bbox.padding.bottom
257paddingXY : Int -> Int -> Testable.Attr msg
260 { label = "paddingXY " ++ String.fromInt x ++ ", " ++ String.fromInt y
261 , attr = Element.paddingXY x y
265 [ Testable.true ("PaddingXY (" ++ String.fromInt x ++ ", " ++ String.fromInt y ++ ") is present")
267 [ floor found.self.bbox.padding.left
268 , floor found.self.bbox.padding.right
271 [ floor found.self.bbox.padding.top
272 , floor found.self.bbox.padding.bottom
279widthHelper maybeMin maybeMax len =
287 l |> Element.minimum minPx
295 l |> Element.maximum maxPx
303 " min:" ++ String.fromInt i
311 " max:" ++ String.fromInt i
313 minMaxTest actualWidth =
314 case ( maybeMin, maybeMax ) of
315 ( Nothing, Nothing ) ->
318 ( Just lower, Nothing ) ->
321 ( Just lower, Just higher ) ->
322 lower <= actualWidth && actualWidth <= higher
324 ( Nothing, Just higher ) ->
325 actualWidth <= higher
329 widthHelper (Just m) maybeMax newLen
332 widthHelper maybeMin (Just m) newLen
335 -- Pixel values should ignore min and max?
337 { label = "width " ++ String.fromInt val ++ "px" ++ minLabel ++ maxLabel
338 , id = Testable.IsWidth
347 [ Testable.true "exact width is exact" (floor found.self.bbox.width == val)
348 , Testable.true "min/max is upheld" (minMaxTest (floor found.self.bbox.width))
356 "width fill" ++ minLabel ++ maxLabel
359 "width fill-" ++ String.fromInt portion ++ minLabel ++ maxLabel
360 , id = Testable.IsWidth
363 (Element.fillPortion portion
369 if List.member context.location [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
370 [ Testable.true "width fill doesn't apply to onright/onleft elements" True ]
374 parentAvailableWidth =
375 context.parent.bbox.width - (context.self.bbox.padding.left + context.self.bbox.padding.right)
377 [ case context.location of
378 Testable.IsNearby _ ->
379 Testable.true "Nearby Element has fill width"
380 ((floor context.parent.bbox.width == floor context.self.bbox.width)
381 || minMaxTest (floor context.self.bbox.width)
385 Testable.true "Element within column has fill width"
386 ((floor parentAvailableWidth == floor context.self.bbox.width)
387 || minMaxTest (floor context.self.bbox.width)
391 Testable.true "Element within element has fill width" <|
392 (floor parentAvailableWidth == floor context.self.bbox.width)
393 || minMaxTest (floor context.self.bbox.width)
398 parentAvailableWidth / toFloat (List.length context.siblings + 1)
400 Testable.true "element has fill width" <|
401 (floor spacePerPortion == floor context.self.bbox.width)
402 || minMaxTest (floor context.self.bbox.width)
408 { label = "width shrink" ++ minLabel ++ maxLabel
415 , id = Testable.IsWidth
420 -- TODO: add margin values to widths
425 |> List.map childWidth
429 context.self.bbox.padding.left + context.self.bbox.padding.right
432 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
434 if totalChildren == 0 then
435 -- TODO: The issue is that we have a hard time measuring `text` elements
436 -- So if a element has a text child, then it's width isn't going to show up in the system.
437 [ Testable.Todo "Calculate text size for width-shrink calculation"
441 -- This fails if this element is actually a column
442 -- So we need to capture what this element is in order to do this calculation.
443 [ expectRoundedEquality
444 { expected = totalChildren + horizontalPadding + spacingValue
445 , found = context.self.bbox.width
451heightHelper maybeMin maybeMax len =
459 l |> Element.minimum minPx
467 l |> Element.maximum maxPx
475 " min:" ++ String.fromInt i
483 " max:" ++ String.fromInt i
485 minMaxTest actualheight =
486 case ( maybeMin, maybeMax ) of
487 ( Nothing, Nothing ) ->
490 ( Just lower, Nothing ) ->
491 lower <= actualheight
493 ( Just lower, Just higher ) ->
494 lower <= actualheight && actualheight <= higher
496 ( Nothing, Just higher ) ->
497 actualheight <= higher
501 heightHelper (Just m) maybeMax newLen
504 heightHelper maybeMin (Just m) newLen
507 -- Pixel values should ignore min and max?
509 { label = "height " ++ String.fromInt val ++ "px" ++ minLabel ++ maxLabel
516 , id = Testable.IsHeight
519 [ Testable.true ("exact height is exact: " ++ String.fromInt (floor found.self.bbox.height) ++ "," ++ String.fromInt val)
520 (floor found.self.bbox.height == val)
521 , Testable.true "min/max holds true"
522 (minMaxTest (floor found.self.bbox.height))
528 { label = "height fill-" ++ String.fromInt portion ++ minLabel ++ maxLabel
531 (Element.fillPortion portion
535 , id = Testable.IsHeight
538 [ if List.member context.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
539 Testable.true "height fill doesn't apply to above/below elements" True
543 parentAvailableHeight =
544 context.parent.bbox.height - (context.self.bbox.padding.top + context.self.bbox.padding.bottom)
546 case context.location of
547 Testable.IsNearby _ ->
548 Testable.true "Nearby Element has fill height"
549 ((floor context.parent.bbox.height == floor context.self.bbox.height)
550 || minMaxTest (floor context.self.bbox.height)
554 Testable.true "Element within column has fill height"
555 ((floor parentAvailableHeight == floor context.self.bbox.height)
556 || minMaxTest (floor context.self.bbox.height)
560 Testable.true "Element within el has fill height" <|
561 (floor parentAvailableHeight == floor context.self.bbox.height)
562 || minMaxTest (floor context.self.bbox.height)
567 parentAvailableHeight / toFloat (List.length context.siblings + 1)
569 Testable.true "el has fill height" <|
570 (floor spacePerPortion == floor context.self.bbox.height)
571 || minMaxTest (floor context.self.bbox.height)
577 { label = "height shrink" ++ minLabel ++ maxLabel
584 , id = Testable.IsHeight
589 -- TODO: add margin values to heights
594 |> List.map childHeight
598 context.self.bbox.padding.top + context.self.bbox.padding.bottom
601 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
603 if totalChildren == 0 then
604 -- TODO: The issue is that we have a hard time measuring `text` elements
605 -- So if a element has a text child, then it's height isn't going to show up in the system.
606 [ Testable.Todo "Calculate expected height shrink"
610 -- This fails if this element is actually a column
611 -- So we need to capture what this element is in order to do this calculation.
612 [ expectRoundedEquality
613 { expected = totalChildren + verticalPadding + spacingValue
614 , found = context.self.bbox.height
620width : Length -> Testable.Attr msg
622 widthHelper Nothing Nothing len
625height : Length -> Testable.Attr msg
627 heightHelper Nothing Nothing len
630spacing : Int -> Testable.Attr msg
633 [ Testable.Spacing space
634 , Testable.LabeledTest
635 { label = "spacing: " ++ String.fromInt space
636 , attr = Element.spacing space
641 findDistance child total =
648 - otherChild.bbox.right
653 - otherChild.bbox.bottom
655 [ if horizontal > 0 then
660 , if vertical > 0 then
671 List.foldl findDistance [] found.children
676 if not (x >= space) then
686 ("All children are at least "
687 ++ String.fromInt space
689 ++ Debug.toString allAreSpaced
698{-| alignLeft needs to account for
701 - elements to the left
704in order to calculate the expected result.
706Also need parent rendering context if this is to work with wrapped rows in the future.
711alignLeft : Testable.Attr msg
714 { label = "alignLeft"
715 , attr = Element.alignLeft
719 [ if List.member found.location [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
720 Testable.true "alignLeft doesn't apply to elements that are onLeft or onRight" True
723 List.member found.location
724 [ Testable.IsNearby Testable.InFront
725 , Testable.IsNearby Testable.Behind
726 , Testable.IsNearby Testable.Above
727 , Testable.IsNearby Testable.Below
730 expectRoundedEquality
731 { found = found.self.bbox.left
732 , expected = found.parent.bbox.left
735 else if List.length found.siblings == 0 then
736 expectRoundedEquality
737 { found = found.self.bbox.left
738 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
742 case found.location of
746 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
749 toFloat (List.length siblingsOnLeft * found.parentSpacing)
753 |> List.map (.width << .bbox)
756 expectRoundedEquality
757 { found = found.self.bbox.left
758 , expected = found.parent.bbox.left + (found.parent.bbox.padding.left + widthsOnLeft + spacings)
762 expectRoundedEquality
763 { found = found.self.bbox.left
764 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
771centerX : Testable.Attr msg
775 , attr = Element.centerX
782 found.self.bbox.left + (found.self.bbox.width / 2)
786 found.parent.bbox.left + (found.parent.bbox.width / 2)
788 if List.member found.location [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
789 [ Testable.true "centerX doesn't apply to elements that are onLeft or onRight" True ]
791 else if List.length found.siblings == 0 then
792 [ expectRoundedEquality
794 , expected = parentCenter
799 case found.location of
803 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
806 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
811 |> List.map (.width << .bbox)
813 |> (\x -> x + (toFloat (List.length siblingsOnLeft) * toFloat found.parentSpacing))
817 |> List.map (.width << .bbox)
819 |> (\x -> x + (toFloat (List.length siblingsOnRight) * toFloat found.parentSpacing))
821 expectedCenter : Float
823 found.parent.bbox.left
825 + ((found.parent.bbox.width - (widthsOnRight + widthsOnLeft))
829 [ expectRoundedEquality
831 , expected = expectedCenter
836 [ expectRoundedEquality
838 , expected = parentCenter
845alignRight : Testable.Attr msg
848 { label = "alignRight"
849 , attr = Element.alignRight
853 if List.member found.location [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
854 [ Testable.true "alignRight doesn't apply to elements that are onLeft or onRight" True ]
857 List.member found.location
858 [ Testable.IsNearby Testable.InFront
859 , Testable.IsNearby Testable.Behind
860 , Testable.IsNearby Testable.Above
861 , Testable.IsNearby Testable.Below
864 [ expectRoundedEquality
865 { found = found.self.bbox.right
866 , expected = found.parent.bbox.right
870 else if List.length found.siblings == 0 then
871 [ expectRoundedEquality
872 { found = found.self.bbox.right
873 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
878 case found.location of
882 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
885 toFloat (List.length siblingsOnRight * found.parentSpacing)
889 |> List.map (.width << .bbox)
892 [ expectRoundedEquality
893 { found = found.self.bbox.right
894 , expected = found.parent.bbox.right - (found.parent.bbox.padding.right + widthsOnRight + spacings)
899 [ expectRoundedEquality
900 { found = found.self.bbox.right
901 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
908alignTop : Testable.Attr msg
912 , attr = Element.alignTop
916 if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
917 [ Testable.true "alignTop doesn't apply to elements that are above or below" True ]
920 List.member found.location
921 [ Testable.IsNearby Testable.InFront
922 , Testable.IsNearby Testable.Behind
923 , Testable.IsNearby Testable.OnRight
924 , Testable.IsNearby Testable.OnLeft
927 [ expectRoundedEquality
928 { found = found.self.bbox.top
929 , expected = found.parent.bbox.top
933 else if List.length found.siblings == 0 then
934 [ expectRoundedEquality
935 { found = found.self.bbox.top
936 , expected = found.parent.bbox.top + found.parent.bbox.padding.top
941 case found.location of
945 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
948 toFloat (List.length siblingsAbove * found.parentSpacing)
952 |> List.map (.height << .bbox)
955 [ expectRoundedEquality
956 { found = found.self.bbox.top
957 , expected = found.parent.bbox.top + (found.parent.bbox.padding.top + heightsAbove + spacings)
962 [ expectRoundedEquality
963 { found = found.self.bbox.top
964 , expected = found.parent.bbox.top
971alignBottom : Testable.Attr msg
974 { label = "alignBottom"
975 , attr = Element.alignBottom
979 if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
980 [ Testable.true "alignBottom doesn't apply to elements that are above or below" True ]
983 List.member found.location
984 [ Testable.IsNearby Testable.InFront
985 , Testable.IsNearby Testable.Behind
986 , Testable.IsNearby Testable.OnRight
987 , Testable.IsNearby Testable.OnLeft
990 [ expectRoundedEquality
991 { found = found.self.bbox.bottom
992 , expected = found.parent.bbox.bottom
996 else if List.length found.siblings == 0 then
997 [ expectRoundedEquality
998 { found = found.self.bbox.bottom
999 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1004 case found.location of
1005 Testable.InColumn ->
1008 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1011 toFloat (List.length siblingsBelow * found.parentSpacing)
1015 |> List.map (.height << .bbox)
1018 [ expectRoundedEquality
1019 { found = found.self.bbox.bottom
1020 , expected = found.parent.bbox.bottom - (found.parent.bbox.padding.bottom + heightsBelow + spacings)
1025 [ expectRoundedEquality
1026 { found = found.self.bbox.bottom
1027 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1033expectRoundedEquality : { expected : Float, found : Float } -> Testable.LayoutExpectation
1034expectRoundedEquality { expected, found } =
1036 ("expected " ++ floatToString expected ++ ", found " ++ floatToString found)
1037 (abs (expected - found) < 1)
1040floatToString : Float -> String
1042 String.fromFloat (toFloat (round (x * 100)) / 100)
1046centerY : Testable.Attr msg
1048 Testable.LabeledTest
1050 , attr = Element.centerY
1051 , id = Testable.NoId
1056 found.self.bbox.top + (found.self.bbox.height / 2)
1059 found.parent.bbox.top + (found.parent.bbox.height / 2)
1061 if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1062 [ Testable.true "centerY doesn't apply to elements that are above or below" True ]
1064 else if List.length found.siblings == 0 then
1065 [ expectRoundedEquality
1066 { found = selfCenter
1067 , expected = parentCenter
1072 case found.location of
1073 Testable.InColumn ->
1076 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1079 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1081 heightsAbove : Float
1084 |> List.map (.height << .bbox)
1086 |> (\x -> x + (toFloat (List.length siblingsOnTop) * toFloat found.parentSpacing))
1090 |> List.map (.height << .bbox)
1092 |> (\x -> x + (toFloat (List.length siblingsBelow) * toFloat found.parentSpacing))
1094 expectedCenter : Float
1096 found.parent.bbox.top
1098 + ((found.parent.bbox.height - (heightsBelow + heightsAbove))
1102 [ expectRoundedEquality
1103 { found = selfCenter
1104 , expected = expectedCenter
1109 [ expectRoundedEquality
1110 { found = selfCenter
1111 , expected = parentCenter
1118above : Testable.Element msg -> Testable.Attr msg
1121 { location = Testable.Above
1126 [ expectRoundedEquality
1127 { found = found.self.bbox.bottom
1128 , expected = found.parent.bbox.top
1135below : Testable.Element msg -> Testable.Attr msg
1138 { location = Testable.Below
1143 [ expectRoundedEquality
1144 { found = found.self.bbox.top
1145 , expected = found.parent.bbox.bottom
1152onRight : Testable.Element msg -> Testable.Attr msg
1155 { location = Testable.OnRight
1160 [ expectRoundedEquality
1161 { found = found.self.bbox.left
1162 , expected = found.parent.bbox.right
1169onLeft : Testable.Element msg -> Testable.Attr msg
1172 { location = Testable.OnLeft
1177 [ expectRoundedEquality
1178 { found = found.self.bbox.right
1179 , expected = found.parent.bbox.left
1186 vs (round x) (round y) || vs (floor x) (floor y)
1190inFront : Testable.Element msg -> Testable.Attr msg
1193 { location = Testable.InFront
1198 [ withinHelper found ]
1205 if found.self.bbox.width > found.parent.bbox.width then
1206 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1207 || compare found.self.bbox.left (>=) found.parent.bbox.left
1211 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1212 , compare found.self.bbox.left (>=) found.parent.bbox.left
1216 if found.self.bbox.width > found.parent.bbox.width then
1217 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1218 || compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1222 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1223 , compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1226 Testable.true "within the confines of the parent"
1227 (List.all ((==) True)
1237behindContent : Testable.Element msg -> Testable.Attr msg
1238behindContent element =
1240 { location = Testable.Behind
1242 , label = "behindContent"
1245 [ withinHelper found ]
1250{- Implicit width/height calcualtions -}
1253implicitWidthHeightShrink attrs =
1256 implicitTest (widthHelper Nothing Nothing Shrink)
1257 :: implicitTest (heightHelper Nothing Nothing Shrink)
1260 skipOverridden withImplicits
1265 Testable.LabeledTest details ->
1268 Testable.AttrTest details ->
1277 (\attr ( found, caught ) ->
1287 , hasHeight = found.hasHeight
1291 Testable.IsHeight ->
1293 , { hasWidth = found.hasWidth
1306 ( { hasWidth = False
1316{-| This is taking a normal test and rmoving its ability to attach a real `Element` attribute.
1320 Testable.LabeledTest details ->
1322 { test = details.test
1323 , label = "Implicit -> " ++ details.label
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list