expand width and height testing to be informed by what the element is that's being tested

This commit is contained in:
Elm UI Automation 2020-05-06 23:19:50 -04:00
parent 4ea86ab0d8
commit 5f880a7981
4 changed files with 328 additions and 136 deletions

View File

@ -7,13 +7,23 @@ import Testable.Element.Background as Background
main =
layout [] <|
-- row [] [ el [] (text "Example with centerX:") ]
column []
[ text "Example with centerX:"
, row
[ width fill ]
[ row [ centerX, Background.color <| rgb 0 1 0 ]
[ paragraph [ width shrink ] [ text "Hello world" ]
, paragraph [ width shrink ] [ text "Hello world" ]
[ row
[ centerX
, Background.color <| rgb 0 1 0
]
[ paragraph
[ width shrink
]
[ text "Hello world" ]
, paragraph
[ width shrink
]
[ text "Hello world" ]
]
]
, text "Example without centerX:"

View File

@ -3,6 +3,7 @@ module Testable exposing
, AttributeId(..)
, BoundingBox
, Element(..)
, ElementType(..)
, Found
, LayoutContext(..)
, LayoutExpectation(..)
@ -10,13 +11,16 @@ module Testable exposing
, Location(..)
, Style
, Surroundings
, TextMetrics
, compareFormattedColor
, elementTypeToString
, equal
, formatColor
, formatColorWithAlpha
, getIds
, getSpacing
, runTests
, textHeight
, toElement
, toHtml
, todo
@ -43,6 +47,66 @@ type Element msg
| Empty
type ElementType
= ElType
| RowType
| ColumnType
| TextColumnType
| ParagraphType
| TextType
| EmptyType
elementTypeToString : ElementType -> String
elementTypeToString elem =
case elem of
ElType ->
"El"
RowType ->
"Row"
ColumnType ->
"Column"
TextColumnType ->
"TextColumn"
ParagraphType ->
"Paragraph"
TextType ->
"Text"
EmptyType ->
"Empty"
toElementType : Element msg -> ElementType
toElementType elem =
case elem of
El _ _ ->
ElType
Row _ _ ->
RowType
Column _ _ ->
ColumnType
TextColumn _ _ ->
TextColumnType
Paragraph _ _ ->
ParagraphType
Text _ ->
TextType
Empty ->
EmptyType
{-| We have an attribute id in order to remove tests when an overriding attribtue is assigned.
Basically, we want to implictly test for height/width shrink.
@ -61,7 +125,7 @@ type AttributeId
type Attr msg
= Attr (Element.Attribute msg)
| AttrTest
{ test : Surroundings -> List LayoutExpectation
{ test : Surroundings msg -> List LayoutExpectation
, label : String
, id : AttributeId
}
@ -70,11 +134,11 @@ type Attr msg
| Nearby
{ location : Location
, element : Element msg
, test : Surroundings -> List LayoutExpectation
, test : Surroundings msg -> List LayoutExpectation
, label : String
}
| LabeledTest
{ test : Surroundings -> List LayoutExpectation
{ test : Surroundings msg -> List LayoutExpectation
, label : String
, attr : Element.Attribute msg
, id : AttributeId
@ -97,14 +161,15 @@ type LayoutContext
| InColumn
type alias Surroundings =
type alias Surroundings msg =
{ siblings : List Found
, parent : Found
, children : List Found
, self : Found
, selfElement : Element msg
-- These values are needed to perform some types of tests.
, location : LayoutContext
, parentLayout : LayoutContext
, parentSpacing : Int
}
@ -113,9 +178,24 @@ type alias Found =
{ bbox : BoundingBox
, style : Style
, isVisible : Bool
, textMetrics : List TextMetrics
}
type alias TextMetrics =
{ actualBoundingBoxAscent : Float
, actualBoundingBoxDescent : Float
, actualBoundingBoxLeft : Float
, actualBoundingBoxRight : Float
, width : Float
}
textHeight metrics =
metrics.actualBoundingBoxAscent
+ metrics.actualBoundingBoxDescent
{-| -}
type alias Style =
Dict String String
@ -147,6 +227,7 @@ type LayoutExpectation
type alias LayoutTest =
{ elementDomId : String
, elementType : ElementType
, label : String
, expectations : List LayoutExpectation
}
@ -351,6 +432,7 @@ runTests harvested el =
case maybeFound of
Nothing ->
[ { elementDomId = "se-0"
, elementType = EmptyType
, label = "Finding root element"
, expectations =
[ Expect
@ -548,8 +630,9 @@ createTest { siblings, parent, cache, level, element, location, parentSpacing }
{ siblings = siblings
, parent = parent
, self = self
, selfElement = element
, children = childrenFoundData
, location = location
, parentLayout = location
, parentSpacing = parentSpacing
}
attr
@ -570,6 +653,7 @@ createTest { siblings, parent, cache, level, element, location, parentSpacing }
_ ->
[ { elementDomId = id
, elementType = EmptyType
, label = "Finding element in DOM"
, expectations =
[ Expect
@ -609,7 +693,7 @@ createAttributeTest :
-> Dict String Found
-> List Int
-> Int
-> Surroundings
-> Surroundings msg
-> Attr msg
-> List LayoutTest
createAttributeTest parent cache level attrIndex surroundings attr =
@ -626,6 +710,8 @@ createAttributeTest parent cache level attrIndex surroundings attr =
AttrTest details ->
[ { elementDomId = domId
, elementType =
toElementType surroundings.selfElement
, label = details.label
, expectations = details.test surroundings
}
@ -658,6 +744,7 @@ createAttributeTest parent cache level attrIndex surroundings attr =
LabeledTest { label, test } ->
[ { elementDomId = domId
, elementType = toElementType surroundings.selfElement
, label = label
, expectations = test surroundings
}
@ -689,45 +776,6 @@ addAttribute attr el =
Text str
-- runTests :
-- Random.Seed
-- -> Test
-- ->
-- List
-- ( String
-- , Maybe
-- { given : Maybe String
-- , description : String
-- , reason : Test.Runner.Failure.Reason
-- }
-- )
-- runTests seed tests =
-- let
-- run runner =
-- let
-- ran =
-- List.map Test.Runner.getFailureReason (runner.run ())
-- in
-- List.map2 Tuple.pair runner.labels ran
-- results =
-- case Test.Runner.fromTest 100 seed tests of
-- Test.Runner.Plain rnrs ->
-- List.map run rnrs
-- Test.Runner.Only rnrs ->
-- List.map run rnrs
-- Test.Runner.Skipping rnrs ->
-- List.map run rnrs
-- Test.Runner.Invalid invalid ->
-- let
-- _ =
-- Debug.log "Invalid tests" invalid
-- in
-- []
-- in
-- List.concat results
compareFormattedColor : Color -> String -> Bool
compareFormattedColor color expected =
formatColor color == expected || formatColorWithAlpha color == expected

View File

@ -96,8 +96,8 @@ none =
paragraph : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
paragraph =
Testable.Paragraph
paragraph attrs =
Testable.Paragraph (implicitWidthHeightShrink attrs)
textColumn : List (Testable.Attr msg) -> List (Testable.Element msg) -> Testable.Element msg
@ -366,7 +366,7 @@ widthHelper maybeMin maybeMax len =
)
, test =
\context ->
if List.member context.location [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
if List.member context.parentLayout [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
[ Testable.true "width fill doesn't apply to onright/onleft elements" True ]
else
@ -374,7 +374,7 @@ widthHelper maybeMin maybeMax len =
parentAvailableWidth =
context.parent.bbox.width - (context.self.bbox.padding.left + context.self.bbox.padding.right)
in
[ case context.location of
[ case context.parentLayout of
Testable.IsNearby _ ->
Testable.true "Nearby Element has fill width"
((floor context.parent.bbox.width == floor context.self.bbox.width)
@ -415,36 +415,110 @@ widthHelper maybeMin maybeMax len =
, id = Testable.IsWidth
, test =
\context ->
let
childWidth child =
-- TODO: add margin values to widths
child.bbox.width
case context.selfElement of
Testable.El _ _ ->
let
childWidth child =
child.bbox.width
totalChildren =
context.children
|> List.map childWidth
|> List.sum
totalChildren =
context.children
|> List.map childWidth
|> List.append (List.map .width context.self.textMetrics)
|> List.sum
horizontalPadding =
context.self.bbox.padding.left + context.self.bbox.padding.right
horizontalPadding =
context.self.bbox.padding.left + context.self.bbox.padding.right
in
[ expectRoundedEquality
{ expected = totalChildren + horizontalPadding
, found = context.self.bbox.width
}
]
spacingValue =
toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
in
if totalChildren == 0 then
-- TODO: The issue is that we have a hard time measuring `text` elements
-- So if a element has a text child, then it's width isn't going to show up in the system.
[ Testable.Todo "Calculate text size for width-shrink calculation"
]
Testable.Row _ _ ->
-- width of row is the sum of all children widths
-- both text elements and others.
let
childWidth child =
child.bbox.width
else
-- This fails if this element is actually a column
-- So we need to capture what this element is in order to do this calculation.
[ expectRoundedEquality
{ expected = totalChildren + horizontalPadding + spacingValue
, found = context.self.bbox.width
}
]
totalChildren =
context.children
|> List.map childWidth
|> List.append (List.map .width context.self.textMetrics)
|> List.sum
horizontalPadding =
context.self.bbox.padding.left + context.self.bbox.padding.right
spacingValue =
toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
in
[ expectRoundedEquality
{ expected = totalChildren + horizontalPadding + spacingValue
, found = context.self.bbox.width
}
]
Testable.Column _ _ ->
-- The width of the column is the width of the widest child.
let
childWidth child =
child.bbox.width
+ context.self.bbox.padding.left
+ context.self.bbox.padding.right
textChildren =
List.map
(\txt ->
txt.width
+ context.self.bbox.padding.left
+ context.self.bbox.padding.right
)
context.self.textMetrics
allChildren =
context.children
|> List.map childWidth
|> List.append textChildren
in
[ expectRoundedEquality
{ expected = Maybe.withDefault 0 (List.maximum allChildren)
, found = context.self.bbox.width
}
]
Testable.TextColumn _ _ ->
[]
Testable.Paragraph _ _ ->
-- This should be the size it's text,
-- unless it takes up all available space, in which case it should wrap.
let
childWidth child =
child.bbox.width
totalChildren =
context.children
|> List.map childWidth
|> List.append (List.map .width context.self.textMetrics)
|> List.sum
horizontalPadding =
context.self.bbox.padding.left + context.self.bbox.padding.right
in
[ expectRoundedEquality
{ expected = totalChildren + horizontalPadding
, found = context.self.bbox.width
}
]
Testable.Text _ ->
[]
Testable.Empty ->
[]
}
@ -535,7 +609,7 @@ heightHelper maybeMin maybeMax len =
, id = Testable.IsHeight
, test =
\context ->
[ if List.member context.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
[ if List.member context.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
Testable.true "height fill doesn't apply to above/below elements" True
else
@ -543,7 +617,7 @@ heightHelper maybeMin maybeMax len =
parentAvailableHeight =
context.parent.bbox.height - (context.self.bbox.padding.top + context.self.bbox.padding.bottom)
in
case context.location of
case context.parentLayout of
Testable.IsNearby _ ->
Testable.true "Nearby Element has fill height"
((floor context.parent.bbox.height == floor context.self.bbox.height)
@ -584,36 +658,86 @@ heightHelper maybeMin maybeMax len =
, id = Testable.IsHeight
, test =
\context ->
let
childHeight child =
-- TODO: add margin values to heights
child.bbox.height
case context.selfElement of
Testable.El _ _ ->
let
childHeight child =
-- TODO: add margin values to heights
child.bbox.height
totalChildren =
context.children
|> List.map childHeight
|> List.sum
totalChildren =
context.children
|> List.map childHeight
|> List.append (List.map Testable.textHeight context.self.textMetrics)
|> List.sum
verticalPadding =
context.self.bbox.padding.top + context.self.bbox.padding.bottom
verticalPadding =
context.self.bbox.padding.top + context.self.bbox.padding.bottom
spacingValue =
toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
in
if totalChildren == 0 then
-- TODO: The issue is that we have a hard time measuring `text` elements
-- So if a element has a text child, then it's height isn't going to show up in the system.
[ Testable.Todo "Calculate expected height shrink"
]
spacingValue =
toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
in
[ expectRoundedEquality
{ expected = totalChildren + verticalPadding + spacingValue
, found = context.self.bbox.height
}
]
else
-- This fails if this element is actually a column
-- So we need to capture what this element is in order to do this calculation.
[ expectRoundedEquality
{ expected = totalChildren + verticalPadding + spacingValue
, found = context.self.bbox.height
}
]
Testable.Row _ _ ->
let
childHeight child =
child.bbox.height
totalChildren =
context.children
|> List.map childHeight
|> List.append (List.map Testable.textHeight context.self.textMetrics)
|> List.maximum
|> Maybe.withDefault 0
verticalPadding =
context.self.bbox.padding.top + context.self.bbox.padding.bottom
in
[ expectRoundedEquality
{ expected = totalChildren + verticalPadding
, found = context.self.bbox.height
}
]
Testable.Column _ _ ->
let
childHeight child =
child.bbox.height
totalChildren =
context.children
|> List.map childHeight
|> List.append (List.map Testable.textHeight context.self.textMetrics)
|> List.sum
verticalPadding =
context.self.bbox.padding.top + context.self.bbox.padding.bottom
spacingValue =
toFloat context.parentSpacing * (toFloat (List.length context.children) - 1)
in
[ expectRoundedEquality
{ expected = totalChildren + verticalPadding + spacingValue
, found = context.self.bbox.height
}
]
Testable.TextColumn _ _ ->
[]
Testable.Paragraph _ _ ->
[]
Testable.Text _ ->
[]
Testable.Empty ->
[]
}
@ -716,11 +840,11 @@ alignLeft =
, id = Testable.NoId
, test =
\found ->
[ if List.member found.location [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
[ if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
Testable.true "alignLeft doesn't apply to elements that are onLeft or onRight" True
else if
List.member found.location
List.member found.parentLayout
[ Testable.IsNearby Testable.InFront
, Testable.IsNearby Testable.Behind
, Testable.IsNearby Testable.Above
@ -739,7 +863,7 @@ alignLeft =
}
else
case found.location of
case found.parentLayout of
Testable.InRow ->
let
siblingsOnLeft =
@ -785,7 +909,7 @@ centerX =
parentCenter =
found.parent.bbox.left + (found.parent.bbox.width / 2)
in
if List.member found.location [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
if List.member found.parentLayout [ Testable.IsNearby Testable.OnRight, Testable.IsNearby Testable.OnLeft ] then
[ Testable.true "centerX doesn't apply to elements that are onLeft or onRight" True ]
else if List.length found.siblings == 0 then
@ -796,7 +920,7 @@ centerX =
]
else
case found.location of
case found.parentLayout of
Testable.InRow ->
let
siblingsOnLeft =
@ -850,11 +974,11 @@ alignRight =
, id = Testable.NoId
, test =
\found ->
if List.member found.location [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
if List.member found.parentLayout [ Testable.IsNearby Testable.OnLeft, Testable.IsNearby Testable.OnRight ] then
[ Testable.true "alignRight doesn't apply to elements that are onLeft or onRight" True ]
else if
List.member found.location
List.member found.parentLayout
[ Testable.IsNearby Testable.InFront
, Testable.IsNearby Testable.Behind
, Testable.IsNearby Testable.Above
@ -875,7 +999,7 @@ alignRight =
]
else
case found.location of
case found.parentLayout of
Testable.InRow ->
let
siblingsOnRight =
@ -913,11 +1037,11 @@ alignTop =
, id = Testable.NoId
, test =
\found ->
if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
[ Testable.true "alignTop doesn't apply to elements that are above or below" True ]
else if
List.member found.location
List.member found.parentLayout
[ Testable.IsNearby Testable.InFront
, Testable.IsNearby Testable.Behind
, Testable.IsNearby Testable.OnRight
@ -938,7 +1062,7 @@ alignTop =
]
else
case found.location of
case found.parentLayout of
Testable.InColumn ->
let
siblingsAbove =
@ -976,11 +1100,11 @@ alignBottom =
, id = Testable.NoId
, test =
\found ->
if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
[ Testable.true "alignBottom doesn't apply to elements that are above or below" True ]
else if
List.member found.location
List.member found.parentLayout
[ Testable.IsNearby Testable.InFront
, Testable.IsNearby Testable.Behind
, Testable.IsNearby Testable.OnRight
@ -1001,7 +1125,7 @@ alignBottom =
]
else
case found.location of
case found.parentLayout of
Testable.InColumn ->
let
siblingsBelow =
@ -1058,7 +1182,7 @@ centerY =
parentCenter =
found.parent.bbox.top + (found.parent.bbox.height / 2)
in
if List.member found.location [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
if List.member found.parentLayout [ Testable.IsNearby Testable.Above, Testable.IsNearby Testable.Below ] then
[ Testable.true "centerY doesn't apply to elements that are above or below" True ]
else if List.length found.siblings == 0 then
@ -1069,7 +1193,7 @@ centerY =
]
else
case found.location of
case found.parentLayout of
Testable.InColumn ->
let
siblingsOnTop =

View File

@ -138,7 +138,7 @@ type Msg
, bbox : Testable.BoundingBox
, style : List ( String, String )
, isVisible : Bool
, textMetrics : List TextMetrics
, textMetrics : List Testable.TextMetrics
}
)
@ -180,6 +180,7 @@ update msg model =
, { style = Dict.fromList box.style
, bbox = box.bbox
, isVisible = box.isVisible
, textMetrics = box.textMetrics
}
)
@ -339,11 +340,26 @@ viewResult testable =
[ Element.alignLeft, Element.spacing 16 ]
(testable.results
|> groupBy .elementDomId
|> List.map viewLayoutTestGroup
|> List.map (expandDetails >> viewLayoutTestGroup)
)
]
expandDetails group =
case group.members of
[] ->
{ id = group.id
, elementType = Testable.EmptyType
, members = group.members
}
top :: _ ->
{ id = group.id
, elementType = top.elementType
, members = group.members
}
groupBy fn list =
groupWhile (\one two -> fn one == fn two) list
|> List.map
@ -387,7 +403,10 @@ viewLayoutTestGroup group =
, Events.onMouseLeave (HighlightDomID Nothing)
, Element.htmlAttribute (Html.Attributes.style "user-select" "none")
]
[ Element.el [ Font.color palette.lightGrey ] (Element.text group.id)
[ Element.row [ Element.spacing 16 ]
[ Element.el [] (Element.text (Testable.elementTypeToString group.elementType))
, Element.el [ Font.color palette.lightGrey ] (Element.text group.id)
]
, Element.column
[ Element.spacing 8
, Element.paddingXY 32 0
@ -484,17 +503,8 @@ port styles :
, bbox : Testable.BoundingBox
, style : List ( String, String )
, isVisible : Bool
, textMetrics : List TextMetrics
, textMetrics : List Testable.TextMetrics
}
-> msg
)
-> Sub msg
type alias TextMetrics =
{ actualBoundingBoxAscent : Float
, actualBoundingBoxDescent : Float
, actualBoundingBoxLeft : Float
, actualBoundingBoxRight : Float
, width : Float
}