1module Testable exposing
9 , LayoutExpectation(..)
15 , compareFormattedColor
19 , formatColorWithAlpha
22 , getSpacingFromAttributes
35import Dict exposing (Dict)
36import Element exposing (Color)
37import Html exposing (Html)
39import Internal.Model as Internal
40import Test exposing (Test)
44 = El (List (Attr msg)) (Element msg)
45 | Row (List (Attr msg)) (List (Element msg))
46 | Column (List (Attr msg)) (List (Element msg))
47 | TextColumn (List (Attr msg)) (List (Element msg))
48 | Paragraph (List (Attr msg)) (List (Element msg))
63elementTypeToString : ElementType -> String
64elementTypeToString elem =
88toElementType : Element msg -> ElementType
113{-| We have an attribute id in order to remove tests when an overriding attribtue is assigned.
115Basically, we want to implictly test for height/width shrink.
117But we want to skip this test if width/height is already set.
119This allows us to do that by comparing identities.
129 = Attr (Element.Attribute msg)
131 { test : Surroundings msg -> List LayoutExpectation
135 | Batch (List (Attr msg))
138 { location : Location
139 , element : Element msg
140 , test : Surroundings msg -> List LayoutExpectation
144 { test : Surroundings msg -> List LayoutExpectation
146 , attr : Element.Attribute msg
170type alias Surroundings msg =
171 { siblings : List Found
173 , children : List Found
175 , selfElement : Element msg
177 -- These values are needed to perform some types of tests.
178 , parentLayout : LayoutContext
179 , parentSpacing : Int
187 , textMetrics : List TextMetrics
191type alias TextMetrics =
192 { actualBoundingBoxAscent : Float
193 , actualBoundingBoxDescent : Float
194 , actualBoundingBoxLeft : Float
195 , actualBoundingBoxRight : Float
200{-| The font metrics we currently have are `actual`, meaning for the text actually rendered, not the font as a whole.
202We also know the font size is 20, so we're just going to return 20.
204TODO: improve font metric collection using something like opentype.js
210 metrics.actualBoundingBoxAscent
211 + metrics.actualBoundingBoxDescent
222type alias BoundingBox =
238type LayoutExpectation
240 { description : String
246type alias LayoutTest =
247 { elementDomId : String
248 , elementType : ElementType
250 , expectations : List LayoutExpectation
258floatToString : Float -> String
260 String.fromFloat (toFloat (round (x * 100)) / 100)
263lessThanOrEqual : String -> Float -> Float -> LayoutExpectation
264lessThanOrEqual label one two =
266 { description = label ++ " " ++ floatToString one ++ " <= " ++ floatToString two
267 , result = one <= two
271rounded : String -> { expected : Float, found : Float } -> LayoutExpectation
272rounded label { expected, found } =
274 (label ++ "| expected " ++ floatToString expected ++ ", found " ++ floatToString found)
275 (abs (expected - found) < 1)
278equal : a -> a -> LayoutExpectation
281 { description = "Are equal"
282 , result = one == two
286true : String -> Bool -> LayoutExpectation
289 { description = label
294todo : String -> LayoutExpectation
303getIds : Element msg -> List String
305 "se-0" :: getElementId [ 0, 0 ] el
308getElementId : List Int -> Element msg -> List String
309getElementId level el =
314 attrID attrIndex attr =
317 getElementId (attrIndex :: -1 :: level) nearby.element
324 |> List.indexedMap attrID
327 childrenIDs children =
328 List.concat <| List.indexedMap (\i -> getElementId (i :: level)) children
332 id :: getElementId (0 :: level) child ++ attributeIDs attrs
334 Row attrs children ->
335 id :: childrenIDs children ++ attributeIDs attrs
337 Column attrs children ->
338 id :: childrenIDs children ++ attributeIDs attrs
340 TextColumn attrs children ->
341 id :: childrenIDs children ++ attributeIDs attrs
343 Paragraph attrs children ->
344 id :: childrenIDs children ++ attributeIDs attrs
357toElement : Element msg -> Element.Element msg
359 renderElement [ 0, 0 ] el
362toHtml : Element msg -> Html msg
366 , Element.width (Element.px 1000)
367 , Element.height (Element.px 1000)
370 renderElement [ 0, 0 ] el
373idAttr : String -> Element.Attribute msg
375 Element.htmlAttribute (Html.Attributes.id ("se-" ++ id))
378renderElement : List Int -> Element msg -> Element.Element msg
379renderElement level el =
383 |> List.map String.fromInt
387 makeAttributes attrs =
389 |> List.indexedMap (renderAttribute level)
395 (id :: makeAttributes attrs)
396 (renderElement (0 :: level) child)
398 Row attrs children ->
400 (id :: makeAttributes attrs)
401 (List.indexedMap (\i -> renderElement (i :: level)) children)
403 Column attrs children ->
405 (id :: makeAttributes attrs)
406 (List.indexedMap (\i -> renderElement (i :: level)) children)
408 TextColumn attrs children ->
410 (id :: makeAttributes attrs)
411 (List.indexedMap (\i -> renderElement (i :: level)) children)
413 Paragraph attrs children ->
415 (id :: makeAttributes attrs)
416 (List.indexedMap (\i -> renderElement (i :: level)) children)
425renderAttribute : List Int -> Int -> Attr msg -> List (Element.Attribute msg)
426renderAttribute level attrIndex attr =
437 Nearby { location, element } ->
440 [ Element.above (renderElement (attrIndex :: -1 :: level) element) ]
443 [ Element.below (renderElement (attrIndex :: -1 :: level) element) ]
446 [ Element.onRight (renderElement (attrIndex :: -1 :: level) element) ]
449 [ Element.onLeft (renderElement (attrIndex :: -1 :: level) element) ]
452 [ Element.inFront (renderElement (attrIndex :: -1 :: level) element) ]
455 [ Element.behindContent (renderElement (attrIndex :: -1 :: level) element) ]
458 List.indexedMap (renderAttribute (attrIndex :: level)) batch
461 LabeledTest tested ->
469runTests : Dict String Found -> Element msg -> List LayoutTest
470runTests harvested el =
473 Dict.get "se-0" harvested
477 [ { elementDomId = "se-0"
478 , elementType = EmptyType
479 , label = "Finding root element"
482 { description = "Locating root element for rendering tests"
501levelToString : List Int -> String
504 |> List.map String.fromInt
506 |> (\x -> "se-" ++ x)
510 { siblings : List Found
512 , cache : Dict String Found
514 , element : Element msg
515 , location : LayoutContext
516 , parentSpacing : Int
519createTest { siblings, parent, cache, level, element, location, parentSpacing } =
523 |> Maybe.withDefault 0
528 testChildren : Found -> List (Element msg) -> List LayoutTest
529 testChildren found children =
532 -- Should check that this lookup doesn't fail.
533 -- Thoug if it does, it'll fail when the element itself is tested
536 Dict.get (levelToString (x :: level)) cache
538 (List.range 0 (List.length children))
540 List.foldl (applyChildTest found)
542 , upcoming = childrenFound
555 , previous : List Found
556 , tests : List LayoutTest
557 , upcoming : List Found
561 , previous : List Found
562 , tests : List LayoutTest
563 , upcoming : List Found
565 applyChildTest found child childTest =
566 -- { index, upcoming, previous, tests }
568 surroundingChildren =
569 case childTest.upcoming of
574 remaining ++ childTest.previous
578 { siblings = surroundingChildren
581 , level = childTest.index :: level
583 , parentSpacing = spacing
608 { index = childTest.index + 1
609 , tests = childTest.tests ++ childrenTests
611 case childTest.upcoming of
616 x :: childTest.previous
618 case childTest.upcoming of
626 tests : Found -> List (Attr msg) -> List (Element msg) -> List LayoutTest
627 tests self attributes children =
629 findBBox elem ( i, gathered ) =
642 case Dict.get (levelToString (i :: level)) cache of
646 Debug.log "el failed to find" elem
649 Debug.log "Failed to find child" (levelToString (i :: level))
661 List.foldl findBBox ( 0, [] ) children
667 -- Found -> Dict String Found -> List Int -> Int -> Surroundings -> Attr msg -> List Test
669 createAttributeTest self
673 { siblings = siblings
676 , selfElement = element
677 , children = childrenFoundData
678 , parentLayout = location
679 , parentSpacing = parentSpacing
686 ++ testChildren self children
688 case Dict.get id cache of
698 [ { elementDomId = id
699 , elementType = EmptyType
700 , label = "Finding element in DOM"
703 { description = "Locating element for rendering test"
713 tests self attrs [ child ]
715 Row attrs children ->
716 tests self attrs children
718 Column attrs children ->
719 tests self attrs children
721 TextColumn attrs children ->
722 tests self attrs children
724 Paragraph attrs children ->
725 tests self attrs children
742createAttributeTest parent cache level attrIndex surroundings attr =
745 "#" ++ levelToString level
755 [ { elementDomId = domId
757 toElementType surroundings.selfElement
758 , label = details.label
759 , expectations = details.test surroundings
769 , level = attrIndex :: -1 :: level
770 , location = IsNearby nearby.location
774 { label = nearby.label
785 |> List.indexedMap (\i attribute -> createAttributeTest parent cache level i surroundings attribute)
788 LabeledTest { label, test } ->
789 [ { elementDomId = domId
790 , elementType = toElementType surroundings.selfElement
792 , expectations = test surroundings
797addAttribute : Attr msg -> Element msg -> Element msg
798addAttribute attr el =
801 El (attr :: attrs) child
803 Row attrs children ->
804 Row (attr :: attrs) children
806 Column attrs children ->
807 Column (attr :: attrs) children
809 TextColumn attrs children ->
810 TextColumn (attr :: attrs) children
812 Paragraph attrs children ->
813 Paragraph (attr :: attrs) children
822compareFormattedColor : Color -> String -> Bool
823compareFormattedColor color expected =
824 formatColor color == expected || formatColorWithAlpha color == expected
827formatColorWithAlpha : Color -> String
828formatColorWithAlpha (Internal.Rgba red green blue alpha) =
830 ("rgba(" ++ String.fromInt (round (red * 255)))
831 ++ (", " ++ String.fromInt (round (green * 255)))
832 ++ (", " ++ String.fromInt (round (blue * 255)))
837 ("rgba(" ++ String.fromInt (round (red * 255)))
838 ++ (", " ++ String.fromInt (round (green * 255)))
839 ++ (", " ++ String.fromInt (round (blue * 255)))
840 ++ (", " ++ String.fromFloat alpha ++ ")")
843formatColor : Color -> String
844formatColor (Internal.Rgba red green blue alpha) =
846 ("rgb(" ++ String.fromInt (round (red * 255)))
847 ++ (", " ++ String.fromInt (round (green * 255)))
848 ++ (", " ++ String.fromInt (round (blue * 255)))
852 ("rgb(" ++ String.fromInt (round (red * 255)))
853 ++ (", " ++ String.fromInt (round (green * 255)))
854 ++ (", " ++ String.fromInt (round (blue * 255)))
858getSpacingFromAttributes attrs =
863 (Spacing i) :: remain ->
866 (Batch batched) :: remain ->
867 getSpacingFromAttributes (batched ++ remain)
870 getSpacingFromAttributes remain
873getSpacing : Element msg -> Maybe Int
876 getSpacingAttr attr found =
877 if found /= Nothing then
886 List.foldr getSpacingAttr Nothing attrs
892 List.foldr getSpacingAttr Nothing attrs
904 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