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
439 Testable.Row rowAttrs _ ->
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 Testable.getSpacingFromAttributes rowAttrs
459 toFloat spacingAmount * (toFloat (List.length context.children) - 1)
461 [ expectRoundedEquality
462 { expected = totalChildren + horizontalPadding + totalSpacing
463 , found = context.self.bbox.width
467 Testable.Column _ _ ->
468 -- The width of the column is the width of the widest child.
472 + context.self.bbox.padding.left
473 + context.self.bbox.padding.right
479 + context.self.bbox.padding.left
480 + context.self.bbox.padding.right
482 context.self.textMetrics
486 |> List.map childWidth
487 |> List.append textChildren
489 [ expectRoundedEquality
490 { expected = Maybe.withDefault 0 (List.maximum allChildren)
491 , found = context.self.bbox.width
495 Testable.TextColumn _ _ ->
498 Testable.Paragraph _ _ ->
499 -- This should be the size it's text,
500 -- unless it takes up all available space, in which case it should wrap.
507 |> List.map childWidth
508 |> List.append (List.map .width context.self.textMetrics)
512 context.self.bbox.padding.left + context.self.bbox.padding.right
514 [ expectRoundedEquality
515 { expected = totalChildren + horizontalPadding
516 , found = context.self.bbox.width
528heightHelper maybeMin maybeMax len =
536 l |> Element.minimum minPx
544 l |> Element.maximum maxPx
552 " min:" ++ String.fromInt i
560 " max:" ++ String.fromInt i
562 minMaxTest actualheight =
563 case ( maybeMin, maybeMax ) of
564 ( Nothing, Nothing ) ->
567 ( Just lower, Nothing ) ->
568 lower <= actualheight
570 ( Just lower, Just higher ) ->
571 lower <= actualheight && actualheight <= higher
573 ( Nothing, Just higher ) ->
574 actualheight <= higher
578 heightHelper (Just m) maybeMax newLen
581 heightHelper maybeMin (Just m) newLen
584 -- Pixel values should ignore min and max?
586 { label = "height " ++ String.fromInt val ++ "px" ++ minLabel ++ maxLabel
593 , id = Testable.IsHeight
596 [ Testable.true ("exact height is exact: " ++ String.fromInt (floor found.self.bbox.height) ++ "," ++ String.fromInt val)
597 (floor found.self.bbox.height == val)
598 , Testable.true "min/max holds true"
599 (minMaxTest (floor found.self.bbox.height))
605 { label = "height fill-" ++ String.fromInt portion ++ minLabel ++ maxLabel
608 (Element.fillPortion portion
612 , id = Testable.IsHeight
615 [ if List.member context.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
616 Testable.true "height fill doesn't apply to above/below elements" True
620 parentAvailableHeight =
621 context.parent.bbox.height - (context.self.bbox.padding.top + context.self.bbox.padding.bottom)
623 case context.parentLayout of
624 Testable.IsNearby _ ->
625 Testable.true "Nearby Element has fill height"
626 ((floor context.parent.bbox.height == floor context.self.bbox.height)
627 || minMaxTest (floor context.self.bbox.height)
631 Testable.true "Element within column has fill height"
632 ((floor parentAvailableHeight == floor context.self.bbox.height)
633 || minMaxTest (floor context.self.bbox.height)
637 Testable.true "Element within el has fill height" <|
638 (floor parentAvailableHeight == floor context.self.bbox.height)
639 || minMaxTest (floor context.self.bbox.height)
644 parentAvailableHeight / toFloat (List.length context.siblings + 1)
646 Testable.true "el has fill height" <|
647 (floor spacePerPortion == floor context.self.bbox.height)
648 || minMaxTest (floor context.self.bbox.height)
654 { label = "height shrink" ++ minLabel ++ maxLabel
661 , id = Testable.IsHeight
664 case context.selfElement of
668 -- TODO: add margin values to heights
673 |> List.map childHeight
674 |> List.append (List.map Testable.textHeight context.self.textMetrics)
678 context.self.bbox.padding.top + context.self.bbox.padding.bottom
681 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
683 [ expectRoundedEquality
684 { expected = totalChildren + verticalPadding + spacingValue
685 , found = context.self.bbox.height
696 |> List.map childHeight
697 |> List.append (List.map Testable.textHeight context.self.textMetrics)
699 |> Maybe.withDefault 0
702 context.self.bbox.padding.top + context.self.bbox.padding.bottom
704 [ expectRoundedEquality
705 { expected = totalChildren + verticalPadding
706 , found = context.self.bbox.height
710 Testable.Column _ _ ->
717 |> List.map childHeight
718 |> List.append (List.map Testable.textHeight context.self.textMetrics)
722 context.self.bbox.padding.top + context.self.bbox.padding.bottom
725 toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
727 [ expectRoundedEquality
728 { expected = totalChildren + verticalPadding + spacingValue
729 , found = context.self.bbox.height
733 Testable.TextColumn _ _ ->
736 Testable.Paragraph _ _ ->
747width : Length -> Testable.Attr msg
749 widthHelper Nothing Nothing len
752height : Length -> Testable.Attr msg
754 heightHelper Nothing Nothing len
757spacing : Int -> Testable.Attr msg
760 [ Testable.Spacing space
761 , Testable.LabeledTest
762 { label = "spacing: " ++ String.fromInt space
763 , attr = Element.spacing space
768 findDistance child total =
775 - otherChild.bbox.right
780 - otherChild.bbox.bottom
782 [ if horizontal > 0 then
787 , if vertical > 0 then
798 List.foldl findDistance [] found.children
803 if not (x >= space) then
813 ("All children are at least "
814 ++ String.fromInt space
816 ++ Debug.toString allAreSpaced
825{-| alignLeft needs to account for
828 - elements to the left
831in order to calculate the expected result.
833Also need parent rendering context if this is to work with wrapped rows in the future.
838alignLeft : Testable.Attr msg
841 { label = "alignLeft"
842 , attr = Element.alignLeft
846 [ if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
847 Testable.true "alignLeft doesn't apply to elements that are onLeft or onRight" True
850 List.member found.parentLayout
851 [ Testable.IsNearby Testable.InFront
852 , Testable.IsNearby Testable.Behind
853 , Testable.IsNearby Testable.Above
854 , Testable.IsNearby Testable.Below
857 expectRoundedEquality
858 { found = found.self.bbox.left
859 , expected = found.parent.bbox.left
862 else if List.length found.siblings == 0 then
863 expectRoundedEquality
864 { found = found.self.bbox.left
865 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
869 case found.parentLayout of
873 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
876 toFloat (List.length siblingsOnLeft * found.parentSpacing)
880 |> List.map (.width << .bbox)
883 expectRoundedEquality
884 { found = found.self.bbox.left
885 , expected = found.parent.bbox.left + (found.parent.bbox.padding.left + widthsOnLeft + spacings)
889 expectRoundedEquality
890 { found = found.self.bbox.left
891 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
898centerX : Testable.Attr msg
902 , attr = Element.centerX
909 found.self.bbox.left + (found.self.bbox.width / 2)
913 found.parent.bbox.left + (found.parent.bbox.width / 2)
915 if List.member found.parentLayout [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
916 [ Testable.true "centerX doesn't apply to elements that are onLeft or onRight" True ]
918 else if List.length found.siblings == 0 then
919 [ expectRoundedEquality
921 , expected = parentCenter
926 case found.parentLayout of
930 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
933 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
938 |> List.map (.width << .bbox)
940 |> (\x -> x + (toFloat (List.length siblingsOnLeft) * toFloat found.parentSpacing))
944 |> List.map (.width << .bbox)
946 |> (\x -> x + (toFloat (List.length siblingsOnRight) * toFloat found.parentSpacing))
948 expectedCenter : Float
950 found.parent.bbox.left
952 + ((found.parent.bbox.width - (widthsOnRight + widthsOnLeft))
956 [ expectRoundedEquality
958 , expected = expectedCenter
963 [ expectRoundedEquality
965 , expected = parentCenter
972alignRight : Testable.Attr msg
975 { label = "alignRight"
976 , attr = Element.alignRight
980 if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
981 [ Testable.true "alignRight doesn't apply to elements that are onLeft or onRight" True ]
984 List.member found.parentLayout
985 [ Testable.IsNearby Testable.InFront
986 , Testable.IsNearby Testable.Behind
987 , Testable.IsNearby Testable.Above
988 , Testable.IsNearby Testable.Below
991 [ expectRoundedEquality
992 { found = found.self.bbox.right
993 , expected = found.parent.bbox.right
997 else if List.length found.siblings == 0 then
998 [ expectRoundedEquality
999 { found = found.self.bbox.right
1000 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1005 case found.parentLayout of
1009 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
1012 toFloat (List.length siblingsOnRight * found.parentSpacing)
1016 |> List.map (.width << .bbox)
1019 [ expectRoundedEquality
1020 { found = found.self.bbox.right
1021 , expected = found.parent.bbox.right - (found.parent.bbox.padding.right + widthsOnRight + spacings)
1026 [ expectRoundedEquality
1027 { found = found.self.bbox.right
1028 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1035alignTop : Testable.Attr msg
1037 Testable.LabeledTest
1038 { label = "alignTop"
1039 , attr = Element.alignTop
1040 , id = Testable.NoId
1043 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1044 [ Testable.true "alignTop doesn't apply to elements that are above or below" True ]
1047 List.member found.parentLayout
1048 [ Testable.IsNearby Testable.InFront
1049 , Testable.IsNearby Testable.Behind
1050 , Testable.IsNearby Testable.OnRight
1051 , Testable.IsNearby Testable.OnLeft
1054 [ expectRoundedEquality
1055 { found = found.self.bbox.top
1056 , expected = found.parent.bbox.top
1060 else if List.length found.siblings == 0 then
1061 [ expectRoundedEquality
1062 { found = found.self.bbox.top
1063 , expected = found.parent.bbox.top + found.parent.bbox.padding.top
1068 case found.parentLayout of
1069 Testable.InColumn ->
1072 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1075 toFloat (List.length siblingsAbove * found.parentSpacing)
1079 |> List.map (.height << .bbox)
1082 [ expectRoundedEquality
1083 { found = found.self.bbox.top
1084 , expected = found.parent.bbox.top + (found.parent.bbox.padding.top + heightsAbove + spacings)
1089 [ expectRoundedEquality
1090 { found = found.self.bbox.top
1091 , expected = found.parent.bbox.top
1098alignBottom : Testable.Attr msg
1100 Testable.LabeledTest
1101 { label = "alignBottom"
1102 , attr = Element.alignBottom
1103 , id = Testable.NoId
1106 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1107 [ Testable.true "alignBottom doesn't apply to elements that are above or below" True ]
1110 List.member found.parentLayout
1111 [ Testable.IsNearby Testable.InFront
1112 , Testable.IsNearby Testable.Behind
1113 , Testable.IsNearby Testable.OnRight
1114 , Testable.IsNearby Testable.OnLeft
1117 [ expectRoundedEquality
1118 { found = found.self.bbox.bottom
1119 , expected = found.parent.bbox.bottom
1123 else if List.length found.siblings == 0 then
1124 [ expectRoundedEquality
1125 { found = found.self.bbox.bottom
1126 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1131 case found.parentLayout of
1132 Testable.InColumn ->
1135 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1138 toFloat (List.length siblingsBelow * found.parentSpacing)
1142 |> List.map (.height << .bbox)
1145 [ expectRoundedEquality
1146 { found = found.self.bbox.bottom
1147 , expected = found.parent.bbox.bottom - (found.parent.bbox.padding.bottom + heightsBelow + spacings)
1152 [ expectRoundedEquality
1153 { found = found.self.bbox.bottom
1154 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1160expectRoundedEquality : { expected : Float, found : Float } -> Testable.LayoutExpectation
1161expectRoundedEquality { expected, found } =
1163 ("expected " ++ floatToString expected ++ ", found " ++ floatToString found)
1164 (abs (expected - found) < 1)
1167floatToString : Float -> String
1169 String.fromFloat (toFloat (round (x * 100)) / 100)
1173centerY : Testable.Attr msg
1175 Testable.LabeledTest
1177 , attr = Element.centerY
1178 , id = Testable.NoId
1183 found.self.bbox.top + (found.self.bbox.height / 2)
1186 found.parent.bbox.top + (found.parent.bbox.height / 2)
1188 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1189 [ Testable.true "centerY doesn't apply to elements that are above or below" True ]
1191 else if List.length found.siblings == 0 then
1192 [ expectRoundedEquality
1193 { found = selfCenter
1194 , expected = parentCenter
1199 case found.parentLayout of
1200 Testable.InColumn ->
1203 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1206 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1208 heightsAbove : Float
1211 |> List.map (.height << .bbox)
1213 |> (\x -> x + (toFloat (List.length siblingsOnTop) * toFloat found.parentSpacing))
1217 |> List.map (.height << .bbox)
1219 |> (\x -> x + (toFloat (List.length siblingsBelow) * toFloat found.parentSpacing))
1221 expectedCenter : Float
1223 found.parent.bbox.top
1225 + ((found.parent.bbox.height - (heightsBelow + heightsAbove))
1229 [ expectRoundedEquality
1230 { found = selfCenter
1231 , expected = expectedCenter
1236 [ expectRoundedEquality
1237 { found = selfCenter
1238 , expected = parentCenter
1245above : Testable.Element msg -> Testable.Attr msg
1248 { location = Testable.Above
1253 [ expectRoundedEquality
1254 { found = found.self.bbox.bottom
1255 , expected = found.parent.bbox.top
1262below : Testable.Element msg -> Testable.Attr msg
1265 { location = Testable.Below
1270 [ expectRoundedEquality
1271 { found = found.self.bbox.top
1272 , expected = found.parent.bbox.bottom
1279onRight : Testable.Element msg -> Testable.Attr msg
1282 { location = Testable.OnRight
1287 [ expectRoundedEquality
1288 { found = found.self.bbox.left
1289 , expected = found.parent.bbox.right
1296onLeft : Testable.Element msg -> Testable.Attr msg
1299 { location = Testable.OnLeft
1304 [ expectRoundedEquality
1305 { found = found.self.bbox.right
1306 , expected = found.parent.bbox.left
1313 vs (round x) (round y) || vs (floor x) (floor y)
1317inFront : Testable.Element msg -> Testable.Attr msg
1320 { location = Testable.InFront
1325 [ withinHelper found ]
1332 if found.self.bbox.width > found.parent.bbox.width then
1333 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1334 || compare found.self.bbox.left (>=) found.parent.bbox.left
1338 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1339 , compare found.self.bbox.left (>=) found.parent.bbox.left
1343 if found.self.bbox.width > found.parent.bbox.width then
1344 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1345 || compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1349 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1350 , compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1353 Testable.true "within the confines of the parent"
1354 (List.all ((==) True)
1364behindContent : Testable.Element msg -> Testable.Attr msg
1365behindContent element =
1367 { location = Testable.Behind
1369 , label = "behindContent"
1372 [ withinHelper found ]
1377{- Implicit width/height calcualtions -}
1380implicitWidthHeightShrink attrs =
1383 implicitTest (widthHelper Nothing Nothing Shrink)
1384 :: implicitTest (heightHelper Nothing Nothing Shrink)
1387 skipOverridden withImplicits
1392 Testable.LabeledTest details ->
1395 Testable.AttrTest details ->
1404 (\attr ( found, caught ) ->
1414 , hasHeight = found.hasHeight
1418 Testable.IsHeight ->
1420 , { hasWidth = found.hasWidth
1433 ( { hasWidth = False
1443{-| This is taking a normal test and rmoving its ability to attach a real `Element` attribute.
1447 Testable.LabeledTest details ->
1449 { test = details.test
1450 , 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