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 colAttrs _ ->
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 Testable.getSpacingFromAttributes colAttrs
728 toFloat spacingAmount * (toFloat (List.length context.children) - 1)
730 [ expectRoundedEquality
731 { expected = totalChildren + verticalPadding + totalSpacing
732 , found = context.self.bbox.height
736 Testable.TextColumn _ _ ->
739 Testable.Paragraph _ _ ->
750width : Length -> Testable.Attr msg
752 widthHelper Nothing Nothing len
755height : Length -> Testable.Attr msg
757 heightHelper Nothing Nothing len
760spacing : Int -> Testable.Attr msg
763 [ Testable.Spacing space
764 , Testable.LabeledTest
765 { label = "spacing: " ++ String.fromInt space
766 , attr = Element.spacing space
771 findDistance child total =
778 - otherChild.bbox.right
783 - otherChild.bbox.bottom
785 [ if horizontal > 0 then
790 , if vertical > 0 then
801 List.foldl findDistance [] found.children
806 if not (x >= space) then
816 ("All children are at least "
817 ++ String.fromInt space
819 ++ Debug.toString allAreSpaced
828{-| alignLeft needs to account for
831 - elements to the left
834in order to calculate the expected result.
836Also need parent rendering context if this is to work with wrapped rows in the future.
841alignLeft : Testable.Attr msg
844 { label = "alignLeft"
845 , attr = Element.alignLeft
849 [ if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
850 Testable.true "alignLeft doesn't apply to elements that are onLeft or onRight" True
853 List.member found.parentLayout
854 [ Testable.IsNearby Testable.InFront
855 , Testable.IsNearby Testable.Behind
856 , Testable.IsNearby Testable.Above
857 , Testable.IsNearby Testable.Below
860 expectRoundedEquality
861 { found = found.self.bbox.left
862 , expected = found.parent.bbox.left
865 else if List.length found.siblings == 0 then
866 expectRoundedEquality
867 { found = found.self.bbox.left
868 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
872 case found.parentLayout of
876 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
879 toFloat (List.length siblingsOnLeft * found.parentSpacing)
883 |> List.map (.width << .bbox)
886 expectRoundedEquality
887 { found = found.self.bbox.left
888 , expected = found.parent.bbox.left + (found.parent.bbox.padding.left + widthsOnLeft + spacings)
892 expectRoundedEquality
893 { found = found.self.bbox.left
894 , expected = found.parent.bbox.left + found.parent.bbox.padding.left
901centerX : Testable.Attr msg
905 , attr = Element.centerX
912 found.self.bbox.left + (found.self.bbox.width / 2)
916 found.parent.bbox.left + (found.parent.bbox.width / 2)
918 if List.member found.parentLayout [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
919 [ Testable.true "centerX doesn't apply to elements that are onLeft or onRight" True ]
921 else if List.length found.siblings == 0 then
922 [ expectRoundedEquality
924 , expected = parentCenter
929 case found.parentLayout of
933 List.filter (\x -> x.bbox.right < found.self.bbox.left) found.siblings
936 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
941 |> List.map (.width << .bbox)
943 |> (\x -> x + (toFloat (List.length siblingsOnLeft) * toFloat found.parentSpacing))
947 |> List.map (.width << .bbox)
949 |> (\x -> x + (toFloat (List.length siblingsOnRight) * toFloat found.parentSpacing))
951 expectedCenter : Float
953 found.parent.bbox.left
955 + ((found.parent.bbox.width - (widthsOnRight + widthsOnLeft))
959 [ expectRoundedEquality
961 , expected = expectedCenter
966 [ expectRoundedEquality
968 , expected = parentCenter
975alignRight : Testable.Attr msg
978 { label = "alignRight"
979 , attr = Element.alignRight
983 if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
984 [ Testable.true "alignRight doesn't apply to elements that are onLeft or onRight" True ]
987 List.member found.parentLayout
988 [ Testable.IsNearby Testable.InFront
989 , Testable.IsNearby Testable.Behind
990 , Testable.IsNearby Testable.Above
991 , Testable.IsNearby Testable.Below
994 [ expectRoundedEquality
995 { found = found.self.bbox.right
996 , expected = found.parent.bbox.right
1000 else if List.length found.siblings == 0 then
1001 [ expectRoundedEquality
1002 { found = found.self.bbox.right
1003 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1008 case found.parentLayout of
1012 List.filter (\x -> x.bbox.left > found.self.bbox.right) found.siblings
1015 toFloat (List.length siblingsOnRight * found.parentSpacing)
1019 |> List.map (.width << .bbox)
1022 [ expectRoundedEquality
1023 { found = found.self.bbox.right
1024 , expected = found.parent.bbox.right - (found.parent.bbox.padding.right + widthsOnRight + spacings)
1029 [ expectRoundedEquality
1030 { found = found.self.bbox.right
1031 , expected = found.parent.bbox.right + found.parent.bbox.padding.right
1038alignTop : Testable.Attr msg
1040 Testable.LabeledTest
1041 { label = "alignTop"
1042 , attr = Element.alignTop
1043 , id = Testable.NoId
1046 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1047 [ Testable.true "alignTop doesn't apply to elements that are above or below" True ]
1050 List.member found.parentLayout
1051 [ Testable.IsNearby Testable.InFront
1052 , Testable.IsNearby Testable.Behind
1053 , Testable.IsNearby Testable.OnRight
1054 , Testable.IsNearby Testable.OnLeft
1057 [ expectRoundedEquality
1058 { found = found.self.bbox.top
1059 , expected = found.parent.bbox.top
1063 else if List.length found.siblings == 0 then
1064 [ expectRoundedEquality
1065 { found = found.self.bbox.top
1066 , expected = found.parent.bbox.top + found.parent.bbox.padding.top
1071 case found.parentLayout of
1072 Testable.InColumn ->
1075 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1078 toFloat (List.length siblingsAbove * found.parentSpacing)
1082 |> List.map (.height << .bbox)
1085 [ expectRoundedEquality
1086 { found = found.self.bbox.top
1087 , expected = found.parent.bbox.top + (found.parent.bbox.padding.top + heightsAbove + spacings)
1092 [ expectRoundedEquality
1093 { found = found.self.bbox.top
1094 , expected = found.parent.bbox.top
1101alignBottom : Testable.Attr msg
1103 Testable.LabeledTest
1104 { label = "alignBottom"
1105 , attr = Element.alignBottom
1106 , id = Testable.NoId
1109 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1110 [ Testable.true "alignBottom doesn't apply to elements that are above or below" True ]
1113 List.member found.parentLayout
1114 [ Testable.IsNearby Testable.InFront
1115 , Testable.IsNearby Testable.Behind
1116 , Testable.IsNearby Testable.OnRight
1117 , Testable.IsNearby Testable.OnLeft
1120 [ expectRoundedEquality
1121 { found = found.self.bbox.bottom
1122 , expected = found.parent.bbox.bottom
1126 else if List.length found.siblings == 0 then
1127 [ expectRoundedEquality
1128 { found = found.self.bbox.bottom
1129 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1134 case found.parentLayout of
1135 Testable.InColumn ->
1138 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1141 toFloat (List.length siblingsBelow * found.parentSpacing)
1145 |> List.map (.height << .bbox)
1148 [ expectRoundedEquality
1149 { found = found.self.bbox.bottom
1150 , expected = found.parent.bbox.bottom - (found.parent.bbox.padding.bottom + heightsBelow + spacings)
1155 [ expectRoundedEquality
1156 { found = found.self.bbox.bottom
1157 , expected = found.parent.bbox.bottom + found.parent.bbox.padding.bottom
1163expectRoundedEquality : { expected : Float, found : Float } -> Testable.LayoutExpectation
1164expectRoundedEquality { expected, found } =
1166 ("expected " ++ floatToString expected ++ ", found " ++ floatToString found)
1167 (abs (expected - found) < 1)
1170floatToString : Float -> String
1172 String.fromFloat (toFloat (round (x * 100)) / 100)
1176centerY : Testable.Attr msg
1178 Testable.LabeledTest
1180 , attr = Element.centerY
1181 , id = Testable.NoId
1186 found.self.bbox.top + (found.self.bbox.height / 2)
1189 found.parent.bbox.top + (found.parent.bbox.height / 2)
1191 if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
1192 [ Testable.true "centerY doesn't apply to elements that are above or below" True ]
1194 else if List.length found.siblings == 0 then
1195 [ expectRoundedEquality
1196 { found = selfCenter
1197 , expected = parentCenter
1202 case found.parentLayout of
1203 Testable.InColumn ->
1206 List.filter (\x -> x.bbox.bottom < found.self.bbox.top) found.siblings
1209 List.filter (\x -> x.bbox.top > found.self.bbox.bottom) found.siblings
1211 heightsAbove : Float
1214 |> List.map (.height << .bbox)
1216 |> (\x -> x + (toFloat (List.length siblingsOnTop) * toFloat found.parentSpacing))
1220 |> List.map (.height << .bbox)
1222 |> (\x -> x + (toFloat (List.length siblingsBelow) * toFloat found.parentSpacing))
1224 expectedCenter : Float
1226 found.parent.bbox.top
1228 + ((found.parent.bbox.height - (heightsBelow + heightsAbove))
1232 [ expectRoundedEquality
1233 { found = selfCenter
1234 , expected = expectedCenter
1239 [ expectRoundedEquality
1240 { found = selfCenter
1241 , expected = parentCenter
1248above : Testable.Element msg -> Testable.Attr msg
1251 { location = Testable.Above
1256 [ expectRoundedEquality
1257 { found = found.self.bbox.bottom
1258 , expected = found.parent.bbox.top
1265below : Testable.Element msg -> Testable.Attr msg
1268 { location = Testable.Below
1273 [ expectRoundedEquality
1274 { found = found.self.bbox.top
1275 , expected = found.parent.bbox.bottom
1282onRight : Testable.Element msg -> Testable.Attr msg
1285 { location = Testable.OnRight
1290 [ expectRoundedEquality
1291 { found = found.self.bbox.left
1292 , expected = found.parent.bbox.right
1299onLeft : Testable.Element msg -> Testable.Attr msg
1302 { location = Testable.OnLeft
1307 [ expectRoundedEquality
1308 { found = found.self.bbox.right
1309 , expected = found.parent.bbox.left
1316 vs (round x) (round y) || vs (floor x) (floor y)
1320inFront : Testable.Element msg -> Testable.Attr msg
1323 { location = Testable.InFront
1328 [ withinHelper found ]
1335 if found.self.bbox.width > found.parent.bbox.width then
1336 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1337 || compare found.self.bbox.left (>=) found.parent.bbox.left
1341 [ compare found.self.bbox.right (<=) found.parent.bbox.right
1342 , compare found.self.bbox.left (>=) found.parent.bbox.left
1346 if found.self.bbox.width > found.parent.bbox.width then
1347 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1348 || compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1352 [ compare found.self.bbox.top (>=) found.parent.bbox.top
1353 , compare found.self.bbox.bottom (<=) found.parent.bbox.bottom
1356 Testable.true "within the confines of the parent"
1357 (List.all ((==) True)
1367behindContent : Testable.Element msg -> Testable.Attr msg
1368behindContent element =
1370 { location = Testable.Behind
1372 , label = "behindContent"
1375 [ withinHelper found ]
1380{- Implicit width/height calcualtions -}
1383implicitWidthHeightShrink attrs =
1386 implicitTest (widthHelper Nothing Nothing Shrink)
1387 :: implicitTest (heightHelper Nothing Nothing Shrink)
1390 skipOverridden withImplicits
1395 Testable.LabeledTest details ->
1398 Testable.AttrTest details ->
1407 (\attr ( found, caught ) ->
1417 , hasHeight = found.hasHeight
1421 Testable.IsHeight ->
1423 , { hasWidth = found.hasWidth
1436 ( { hasWidth = False
1446{-| This is taking a normal test and rmoving its ability to attach a real `Element` attribute.
1450 Testable.LabeledTest details ->
1452 { test = details.test
1453 , 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