1module Testable exposing
9 , LayoutExpectation(..)
15 , compareFormattedColor
19 , formatColorWithAlpha
22 , getSpacingFromAttributes
34import Dict exposing (Dict)
35import Element exposing (Color)
36import Html exposing (Html)
38import Internal.Model as Internal
39import Test exposing (Test)
43 = El (List (Attr msg)) (Element msg)
44 | Row (List (Attr msg)) (List (Element msg))
45 | Column (List (Attr msg)) (List (Element msg))
46 | TextColumn (List (Attr msg)) (List (Element msg))
47 | Paragraph (List (Attr msg)) (List (Element msg))
62elementTypeToString : ElementType -> String
63elementTypeToString elem =
87toElementType : Element msg -> ElementType
112{-| We have an attribute id in order to remove tests when an overriding attribtue is assigned.
114Basically, we want to implictly test for height/width shrink.
116But we want to skip this test if width/height is already set.
118This allows us to do that by comparing identities.
128 = Attr (Element.Attribute msg)
130 { test : Surroundings msg -> List LayoutExpectation
134 | Batch (List (Attr msg))
137 { location : Location
138 , element : Element msg
139 , test : Surroundings msg -> List LayoutExpectation
143 { test : Surroundings msg -> List LayoutExpectation
145 , attr : Element.Attribute msg
166type alias Surroundings msg =
167 { siblings : List Found
169 , children : List Found
171 , selfElement : Element msg
173 -- These values are needed to perform some types of tests.
174 , parentLayout : LayoutContext
175 , parentSpacing : Int
183 , textMetrics : List TextMetrics
187type alias TextMetrics =
188 { actualBoundingBoxAscent : Float
189 , actualBoundingBoxDescent : Float
190 , actualBoundingBoxLeft : Float
191 , actualBoundingBoxRight : Float
196{-| The font metrics we currently have are `actual`, meaning for the text actually rendered, not the font as a whole.
198We also know the font size is 20, so we're just going to return 20.
200TODO: improve font metric collection using something like opentype.js
206 metrics.actualBoundingBoxAscent
207 + metrics.actualBoundingBoxDescent
218type alias BoundingBox =
234type LayoutExpectation
236 { description : String
242type alias LayoutTest =
243 { elementDomId : String
244 , elementType : ElementType
246 , expectations : List LayoutExpectation
254floatToString : Float -> String
256 String.fromFloat (toFloat (round (x * 100)) / 100)
259lessThanOrEqual : String -> Float -> Float -> LayoutExpectation
260lessThanOrEqual label one two =
262 { description = label ++ " " ++ floatToString one ++ " <= " ++ floatToString two
263 , result = one <= two
267equal : a -> a -> LayoutExpectation
270 { description = "Are equal"
271 , result = one == two
275true : String -> Bool -> LayoutExpectation
278 { description = label
283todo : String -> LayoutExpectation
292getIds : Element msg -> List String
294 "se-0" :: getElementId [ 0, 0 ] el
297getElementId : List Int -> Element msg -> List String
298getElementId level el =
303 attrID attrIndex attr =
306 getElementId (attrIndex :: -1 :: level) nearby.element
313 |> List.indexedMap attrID
316 childrenIDs children =
317 List.concat <| List.indexedMap (\i -> getElementId (i :: level)) children
321 id :: getElementId (0 :: level) child ++ attributeIDs attrs
323 Row attrs children ->
324 id :: childrenIDs children ++ attributeIDs attrs
326 Column attrs children ->
327 id :: childrenIDs children ++ attributeIDs attrs
329 TextColumn attrs children ->
330 id :: childrenIDs children ++ attributeIDs attrs
332 Paragraph attrs children ->
333 id :: childrenIDs children ++ attributeIDs attrs
346toElement : Element msg -> Element.Element msg
348 renderElement [ 0, 0 ] el
351toHtml : Element msg -> Html msg
355 , Element.width (Element.px 1000)
356 , Element.height (Element.px 1000)
359 renderElement [ 0, 0 ] el
362idAttr : String -> Element.Attribute msg
364 Element.htmlAttribute (Html.Attributes.id ("se-" ++ id))
367renderElement : List Int -> Element msg -> Element.Element msg
368renderElement level el =
372 |> List.map String.fromInt
376 makeAttributes attrs =
378 |> List.indexedMap (renderAttribute level)
384 (id :: makeAttributes attrs)
385 (renderElement (0 :: level) child)
387 Row attrs children ->
389 (id :: makeAttributes attrs)
390 (List.indexedMap (\i -> renderElement (i :: level)) children)
392 Column attrs children ->
394 (id :: makeAttributes attrs)
395 (List.indexedMap (\i -> renderElement (i :: level)) children)
397 TextColumn attrs children ->
399 (id :: makeAttributes attrs)
400 (List.indexedMap (\i -> renderElement (i :: level)) children)
402 Paragraph attrs children ->
404 (id :: makeAttributes attrs)
405 (List.indexedMap (\i -> renderElement (i :: level)) children)
414renderAttribute : List Int -> Int -> Attr msg -> List (Element.Attribute msg)
415renderAttribute level attrIndex attr =
426 Nearby { location, element } ->
429 [ Element.above (renderElement (attrIndex :: -1 :: level) element) ]
432 [ Element.below (renderElement (attrIndex :: -1 :: level) element) ]
435 [ Element.onRight (renderElement (attrIndex :: -1 :: level) element) ]
438 [ Element.onLeft (renderElement (attrIndex :: -1 :: level) element) ]
441 [ Element.inFront (renderElement (attrIndex :: -1 :: level) element) ]
444 [ Element.behindContent (renderElement (attrIndex :: -1 :: level) element) ]
447 List.indexedMap (renderAttribute (attrIndex :: level)) batch
450 LabeledTest tested ->
458runTests : Dict String Found -> Element msg -> List LayoutTest
459runTests harvested el =
462 Dict.get "se-0" harvested
466 [ { elementDomId = "se-0"
467 , elementType = EmptyType
468 , label = "Finding root element"
471 { description = "Locating root element for rendering tests"
490levelToString : List Int -> String
493 |> List.map String.fromInt
495 |> (\x -> "se-" ++ x)
499 { siblings : List Found
501 , cache : Dict String Found
503 , element : Element msg
504 , location : LayoutContext
505 , parentSpacing : Int
508createTest { siblings, parent, cache, level, element, location, parentSpacing } =
512 |> Maybe.withDefault 0
517 testChildren : Found -> List (Element msg) -> List LayoutTest
518 testChildren found children =
521 -- Should check that this lookup doesn't fail.
522 -- Thoug if it does, it'll fail when the element itself is tested
525 Dict.get (levelToString (x :: level)) cache
527 (List.range 0 (List.length children))
529 List.foldl (applyChildTest found)
531 , upcoming = childrenFound
544 , previous : List Found
545 , tests : List LayoutTest
546 , upcoming : List Found
550 , previous : List Found
551 , tests : List LayoutTest
552 , upcoming : List Found
554 applyChildTest found child childTest =
555 -- { index, upcoming, previous, tests }
557 surroundingChildren =
558 case childTest.upcoming of
563 remaining ++ childTest.previous
567 { siblings = surroundingChildren
570 , level = childTest.index :: level
572 , parentSpacing = spacing
597 { index = childTest.index + 1
598 , tests = childTest.tests ++ childrenTests
600 case childTest.upcoming of
605 x :: childTest.previous
607 case childTest.upcoming of
615 tests : Found -> List (Attr msg) -> List (Element msg) -> List LayoutTest
616 tests self attributes children =
618 findBBox elem ( i, gathered ) =
631 case Dict.get (levelToString (i :: level)) cache of
635 Debug.log "el failed to find" elem
638 Debug.log "Failed to find child" (levelToString (i :: level))
650 List.foldl findBBox ( 0, [] ) children
656 -- Found -> Dict String Found -> List Int -> Int -> Surroundings -> Attr msg -> List Test
658 createAttributeTest self
662 { siblings = siblings
665 , selfElement = element
666 , children = childrenFoundData
667 , parentLayout = location
668 , parentSpacing = parentSpacing
675 ++ testChildren self children
677 case Dict.get id cache of
687 [ { elementDomId = id
688 , elementType = EmptyType
689 , label = "Finding element in DOM"
692 { description = "Locating element for rendering test"
702 tests self attrs [ child ]
704 Row attrs children ->
705 tests self attrs children
707 Column attrs children ->
708 tests self attrs children
710 TextColumn attrs children ->
711 tests self attrs children
713 Paragraph attrs children ->
714 tests self attrs children
731createAttributeTest parent cache level attrIndex surroundings attr =
734 "#" ++ levelToString level
744 [ { elementDomId = domId
746 toElementType surroundings.selfElement
747 , label = details.label
748 , expectations = details.test surroundings
758 , level = attrIndex :: -1 :: level
759 , location = IsNearby nearby.location
763 { label = nearby.label
774 |> List.indexedMap (\i attribute -> createAttributeTest parent cache level i surroundings attribute)
777 LabeledTest { label, test } ->
778 [ { elementDomId = domId
779 , elementType = toElementType surroundings.selfElement
781 , expectations = test surroundings
786addAttribute : Attr msg -> Element msg -> Element msg
787addAttribute attr el =
790 El (attr :: attrs) child
792 Row attrs children ->
793 Row (attr :: attrs) children
795 Column attrs children ->
796 Column (attr :: attrs) children
798 TextColumn attrs children ->
799 TextColumn (attr :: attrs) children
801 Paragraph attrs children ->
802 Paragraph (attr :: attrs) children
811compareFormattedColor : Color -> String -> Bool
812compareFormattedColor color expected =
813 formatColor color == expected || formatColorWithAlpha color == expected
816formatColorWithAlpha : Color -> String
817formatColorWithAlpha (Internal.Rgba red green blue alpha) =
819 ("rgba(" ++ String.fromInt (round (red * 255)))
820 ++ (", " ++ String.fromInt (round (green * 255)))
821 ++ (", " ++ String.fromInt (round (blue * 255)))
826 ("rgba(" ++ String.fromInt (round (red * 255)))
827 ++ (", " ++ String.fromInt (round (green * 255)))
828 ++ (", " ++ String.fromInt (round (blue * 255)))
829 ++ (", " ++ String.fromFloat alpha ++ ")")
832formatColor : Color -> String
833formatColor (Internal.Rgba red green blue alpha) =
835 ("rgb(" ++ String.fromInt (round (red * 255)))
836 ++ (", " ++ String.fromInt (round (green * 255)))
837 ++ (", " ++ String.fromInt (round (blue * 255)))
841 ("rgb(" ++ String.fromInt (round (red * 255)))
842 ++ (", " ++ String.fromInt (round (green * 255)))
843 ++ (", " ++ String.fromInt (round (blue * 255)))
847getSpacingFromAttributes attrs =
852 (Spacing i) :: remain ->
855 (Batch batched) :: remain ->
856 getSpacingFromAttributes (batched ++ remain)
859 getSpacingFromAttributes remain
862getSpacing : Element msg -> Maybe Int
865 getSpacingAttr attr found =
866 if found /= Nothing then
875 List.foldr getSpacingAttr Nothing attrs
881 List.foldr getSpacingAttr Nothing attrs
893 TextColumn attrs _ ->
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