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
100 Testable.Paragraph (implicitWidthHeightShrink attrs)
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.parentLayout [ 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.parentLayout 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
418 case context.selfElement of
426 |> List.map childWidth
427 |> List.append (List.map .width context.self.textMetrics)
431 context.self.bbox.padding.left + context.self.bbox.padding.right
433 [ expectRoundedEquality
434 { expected = totalChildren + horizontalPadding
435 , found = context.self.bbox.width
440 -- width of row is the sum of all children widths
441 -- both text elements and others.
448 |> List.map childWidth
449 |> List.append (List.map .width context.self.textMetrics)
453 context.self.bbox.padding.left + context.self.bbox.padding.right
456 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
458 [ expectRoundedEquality
459 { expected = totalChildren + horizontalPadding + spacingValue
460 , found = context.self.bbox.width
464 Testable.Column _ _ ->
465 -- The width of the column is the width of the widest child.
469 + context.self.bbox.padding.left
470 + context.self.bbox.padding.right
476 + context.self.bbox.padding.left
477 + context.self.bbox.padding.right
479 context.self.textMetrics
483 |> List.map childWidth
484 |> List.append textChildren
486 [ expectRoundedEquality
487 { expected = Maybe.withDefault 0 (List.maximum allChildren)
488 , found = context.self.bbox.width
492 Testable.TextColumn _ _ ->
495 Testable.Paragraph _ _ ->
496 -- This should be the size it's text,
497 -- unless it takes up all available space, in which case it should wrap.
504 |> List.map childWidth
505 |> List.append (List.map .width context.self.textMetrics)
509 context.self.bbox.padding.left + context.self.bbox.padding.right
511 [ expectRoundedEquality
512 { expected = totalChildren + horizontalPadding
513 , found = context.self.bbox.width
525heightHelper maybeMin maybeMax len =
533 l |> Element.minimum minPx
541 l |> Element.maximum maxPx
549 " min:" ++ String.fromInt i
557 " max:" ++ String.fromInt i
559 minMaxTest actualheight =
560 case ( maybeMin, maybeMax ) of
561 ( Nothing, Nothing ) ->
564 ( Just lower, Nothing ) ->
565 lower <= actualheight
567 ( Just lower, Just higher ) ->
568 lower <= actualheight && actualheight <= higher
570 ( Nothing, Just higher ) ->
571 actualheight <= higher
575 heightHelper (Just m) maybeMax newLen
578 heightHelper maybeMin (Just m) newLen
581 -- Pixel values should ignore min and max?
583 { label = "height " ++ String.fromInt val ++ "px" ++ minLabel ++ maxLabel
590 , id = Testable.IsHeight
593 [ Testable.true ("exact height is exact: " ++ String.fromInt (floor found.self.bbox.height) ++ "," ++ String.fromInt val)
594 (floor found.self.bbox.height == val)
595 , Testable.true "min/max holds true"
596 (minMaxTest (floor found.self.bbox.height))
602 { label = "height fill-" ++ String.fromInt portion ++ minLabel ++ maxLabel
605 (Element.fillPortion portion
609 , id = Testable.IsHeight
612 [ if List.member context.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
613 Testable.true "height fill doesn't apply to above/below elements" True
617 parentAvailableHeight =
618 context.parent.bbox.height - (context.self.bbox.padding.top + context.self.bbox.padding.bottom)
620 case context.parentLayout of
621 Testable.IsNearby _ ->
622 Testable.true "Nearby Element has fill height"
623 ((floor context.parent.bbox.height == floor context.self.bbox.height)
624 || minMaxTest (floor context.self.bbox.height)
628 Testable.true "Element within column has fill height"
629 ((floor parentAvailableHeight == floor context.self.bbox.height)
630 || minMaxTest (floor context.self.bbox.height)
634 Testable.true "Element within el has fill height" <|
635 (floor parentAvailableHeight == floor context.self.bbox.height)
636 || minMaxTest (floor context.self.bbox.height)
641 parentAvailableHeight / toFloat (List.length context.siblings + 1)
643 Testable.true "el has fill height" <|
644 (floor spacePerPortion == floor context.self.bbox.height)
645 || minMaxTest (floor context.self.bbox.height)
651 { label = "height shrink" ++ minLabel ++ maxLabel
658 , id = Testable.IsHeight
661 case context.selfElement of
665 -- TODO: add margin values to heights
670 |> List.map childHeight
671 |> List.append (List.map Testable.textHeight context.self.textMetrics)
675 context.self.bbox.padding.top + context.self.bbox.padding.bottom
678 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
680 [ expectRoundedEquality
681 { expected = totalChildren + verticalPadding + spacingValue
682 , found = context.self.bbox.height
693 |> List.map childHeight
694 |> List.append (List.map Testable.textHeight context.self.textMetrics)
696 |> Maybe.withDefault 0
699 context.self.bbox.padding.top + context.self.bbox.padding.bottom
701 [ expectRoundedEquality
702 { expected = totalChildren + verticalPadding
703 , found = context.self.bbox.height
707 Testable.Column _ _ ->
714 |> List.map childHeight
715 |> List.append (List.map Testable.textHeight context.self.textMetrics)
719 context.self.bbox.padding.top + context.self.bbox.padding.bottom
722 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
724 [ expectRoundedEquality
725 { expected = totalChildren + verticalPadding + spacingValue
726 , found = context.self.bbox.height
730 Testable.TextColumn _ _ ->
733 Testable.Paragraph _ _ ->
744width : Length -> Testable.Attr msg
746 widthHelper Nothing Nothing len
749height : Length -> Testable.Attr msg
751 heightHelper Nothing Nothing len
754spacing : Int -> Testable.Attr msg
757 [ Testable.Spacing space
758 , Testable.LabeledTest
759 { label = "spacing: " ++ String.fromInt space
760 , attr = Element.spacing space
765 findDistance child total =
772 - otherChild.bbox.right
777 - otherChild.bbox.bottom
779 [ if horizontal > 0 then
784 , if vertical > 0 then
795 List.foldl findDistance [] found.children
800 if not (x >= space) then
810 ("All children are at least "
811 ++ String.fromInt space
813 ++ Debug.toString allAreSpaced
822{-| alignLeft needs to account for
825 - elements to the left
828in order to calculate the expected result.
830Also need parent rendering context if this is to work with wrapped rows in the future.
835alignLeft : Testable.Attr msg
838 { label = "alignLeft"
839 , attr = Element.alignLeft
843 [ if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
844 Testable.true "alignLeft doesn't apply to elements that are onLeft or onRight" True
847 List.member found.parentLayout
848 [ Testable.IsNearby Testable.InFront
849 , Testable.IsNearby Testable.Behind
850 , Testable.IsNearby Testable.Above
851 , Testable.IsNearby Testable.Below
854 expectRoundedEquality
855 { found = found.self.bbox.left
856 , expected = found.parent.bbox.left
859 else if List.length found.siblings == 0 then
860 expectRoundedEquality
861 { found = found.self.bbox.left
862 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
866 case found.parentLayout of
870 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
873 toFloat (List.length siblingsOnLeft * found.parentSpacing)
877 |> List.map (.width << .bbox)
880 expectRoundedEquality
881 { found = found.self.bbox.left
882 , expected = found.parent.bbox.left + (found.parent.bbox.padding.left + widthsOnLeft + spacings)
886 expectRoundedEquality
887 { found = found.self.bbox.left
888 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
895centerX : Testable.Attr msg
899 , attr = Element.centerX
906 found.self.bbox.left + (found.self.bbox.width / 2)
910 found.parent.bbox.left + (found.parent.bbox.width / 2)
912 if List.member found.parentLayout [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
913 [ Testable.true "centerX doesn't apply to elements that are onLeft or onRight" True ]
915 else if List.length found.siblings == 0 then
916 [ expectRoundedEquality
918 , expected = parentCenter
923 case found.parentLayout of
927 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
930 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
935 |> List.map (.width << .bbox)
937 |> (\x -> x + (toFloat (List.length siblingsOnLeft) * toFloat found.parentSpacing))
941 |> List.map (.width << .bbox)
943 |> (\x -> x + (toFloat (List.length siblingsOnRight) * toFloat found.parentSpacing))
945 expectedCenter : Float
947 found.parent.bbox.left
949 + ((found.parent.bbox.width - (widthsOnRight + widthsOnLeft))
953 [ expectRoundedEquality
955 , expected = expectedCenter
960 [ expectRoundedEquality
962 , expected = parentCenter
969alignRight : Testable.Attr msg
972 { label = "alignRight"
973 , attr = Element.alignRight
977 if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
978 [ Testable.true "alignRight doesn't apply to elements that are onLeft or onRight" True ]
981 List.member found.parentLayout
982 [ Testable.IsNearby Testable.InFront
983 , Testable.IsNearby Testable.Behind
984 , Testable.IsNearby Testable.Above
985 , Testable.IsNearby Testable.Below
988 [ expectRoundedEquality
989 { found = found.self.bbox.right
990 , expected = found.parent.bbox.right
994 else if List.length found.siblings == 0 then
995 [ expectRoundedEquality
996 { found = found.self.bbox.right
997 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1002 case found.parentLayout of
1006 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
1009 toFloat (List.length siblingsOnRight * found.parentSpacing)
1013 |> List.map (.width << .bbox)
1016 [ expectRoundedEquality
1017 { found = found.self.bbox.right
1018 , expected = found.parent.bbox.right - (found.parent.bbox.padding.right + widthsOnRight + spacings)
1023 [ expectRoundedEquality
1024 { found = found.self.bbox.right
1025 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1032alignTop : Testable.Attr msg
1034 Testable.LabeledTest
1035 { label = "alignTop"
1036 , attr = Element.alignTop
1037 , id = Testable.NoId
1040 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1041 [ Testable.true "alignTop doesn't apply to elements that are above or below" True ]
1044 List.member found.parentLayout
1045 [ Testable.IsNearby Testable.InFront
1046 , Testable.IsNearby Testable.Behind
1047 , Testable.IsNearby Testable.OnRight
1048 , Testable.IsNearby Testable.OnLeft
1051 [ expectRoundedEquality
1052 { found = found.self.bbox.top
1053 , expected = found.parent.bbox.top
1057 else if List.length found.siblings == 0 then
1058 [ expectRoundedEquality
1059 { found = found.self.bbox.top
1060 , expected = found.parent.bbox.top + found.parent.bbox.padding.top
1065 case found.parentLayout of
1066 Testable.InColumn ->
1069 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1072 toFloat (List.length siblingsAbove * found.parentSpacing)
1076 |> List.map (.height << .bbox)
1079 [ expectRoundedEquality
1080 { found = found.self.bbox.top
1081 , expected = found.parent.bbox.top + (found.parent.bbox.padding.top + heightsAbove + spacings)
1086 [ expectRoundedEquality
1087 { found = found.self.bbox.top
1088 , expected = found.parent.bbox.top
1095alignBottom : Testable.Attr msg
1097 Testable.LabeledTest
1098 { label = "alignBottom"
1099 , attr = Element.alignBottom
1100 , id = Testable.NoId
1103 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1104 [ Testable.true "alignBottom doesn't apply to elements that are above or below" True ]
1107 List.member found.parentLayout
1108 [ Testable.IsNearby Testable.InFront
1109 , Testable.IsNearby Testable.Behind
1110 , Testable.IsNearby Testable.OnRight
1111 , Testable.IsNearby Testable.OnLeft
1114 [ expectRoundedEquality
1115 { found = found.self.bbox.bottom
1116 , expected = found.parent.bbox.bottom
1120 else if List.length found.siblings == 0 then
1121 [ expectRoundedEquality
1122 { found = found.self.bbox.bottom
1123 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1128 case found.parentLayout of
1129 Testable.InColumn ->
1132 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1135 toFloat (List.length siblingsBelow * found.parentSpacing)
1139 |> List.map (.height << .bbox)
1142 [ expectRoundedEquality
1143 { found = found.self.bbox.bottom
1144 , expected = found.parent.bbox.bottom - (found.parent.bbox.padding.bottom + heightsBelow + spacings)
1149 [ expectRoundedEquality
1150 { found = found.self.bbox.bottom
1151 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1157expectRoundedEquality : { expected : Float, found : Float } -> Testable.LayoutExpectation
1158expectRoundedEquality { expected, found } =
1160 ("expected " ++ floatToString expected ++ ", found " ++ floatToString found)
1161 (abs (expected - found) < 1)
1164floatToString : Float -> String
1166 String.fromFloat (toFloat (round (x * 100)) / 100)
1170centerY : Testable.Attr msg
1172 Testable.LabeledTest
1174 , attr = Element.centerY
1175 , id = Testable.NoId
1180 found.self.bbox.top + (found.self.bbox.height / 2)
1183 found.parent.bbox.top + (found.parent.bbox.height / 2)
1185 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1186 [ Testable.true "centerY doesn't apply to elements that are above or below" True ]
1188 else if List.length found.siblings == 0 then
1189 [ expectRoundedEquality
1190 { found = selfCenter
1191 , expected = parentCenter
1196 case found.parentLayout of
1197 Testable.InColumn ->
1200 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1203 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1205 heightsAbove : Float
1208 |> List.map (.height << .bbox)
1210 |> (\x -> x + (toFloat (List.length siblingsOnTop) * toFloat found.parentSpacing))
1214 |> List.map (.height << .bbox)
1216 |> (\x -> x + (toFloat (List.length siblingsBelow) * toFloat found.parentSpacing))
1218 expectedCenter : Float
1220 found.parent.bbox.top
1222 + ((found.parent.bbox.height - (heightsBelow + heightsAbove))
1226 [ expectRoundedEquality
1227 { found = selfCenter
1228 , expected = expectedCenter
1233 [ expectRoundedEquality
1234 { found = selfCenter
1235 , expected = parentCenter
1242above : Testable.Element msg -> Testable.Attr msg
1245 { location = Testable.Above
1250 [ expectRoundedEquality
1251 { found = found.self.bbox.bottom
1252 , expected = found.parent.bbox.top
1259below : Testable.Element msg -> Testable.Attr msg
1262 { location = Testable.Below
1267 [ expectRoundedEquality
1268 { found = found.self.bbox.top
1269 , expected = found.parent.bbox.bottom
1276onRight : Testable.Element msg -> Testable.Attr msg
1279 { location = Testable.OnRight
1284 [ expectRoundedEquality
1285 { found = found.self.bbox.left
1286 , expected = found.parent.bbox.right
1293onLeft : Testable.Element msg -> Testable.Attr msg
1296 { location = Testable.OnLeft
1301 [ expectRoundedEquality
1302 { found = found.self.bbox.right
1303 , expected = found.parent.bbox.left
1310 vs (round x) (round y) || vs (floor x) (floor y)
1314inFront : Testable.Element msg -> Testable.Attr msg
1317 { location = Testable.InFront
1322 [ withinHelper found ]
1329 if found.self.bbox.width > found.parent.bbox.width then
1330 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1331 || compare found.self.bbox.left (>=) found.parent.bbox.left
1335 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1336 , compare found.self.bbox.left (>=) found.parent.bbox.left
1340 if found.self.bbox.width > found.parent.bbox.width then
1341 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1342 || compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1346 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1347 , compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1350 Testable.true "within the confines of the parent"
1351 (List.all ((==) True)
1361behindContent : Testable.Element msg -> Testable.Attr msg
1362behindContent element =
1364 { location = Testable.Behind
1366 , label = "behindContent"
1369 [ withinHelper found ]
1374{- Implicit width/height calcualtions -}
1377implicitWidthHeightShrink attrs =
1380 implicitTest (widthHelper Nothing Nothing Shrink)
1381 :: implicitTest (heightHelper Nothing Nothing Shrink)
1384 skipOverridden withImplicits
1389 Testable.LabeledTest details ->
1392 Testable.AttrTest details ->
1401 (\attr ( found, caught ) ->
1411 , hasHeight = found.hasHeight
1415 Testable.IsHeight ->
1417 , { hasWidth = found.hasWidth
1430 ( { hasWidth = False
1440{-| This is taking a normal test and rmoving its ability to attach a real `Element` attribute.
1444 Testable.LabeledTest details ->
1446 { test = details.test
1447 , 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