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
167type alias Surroundings msg =
168 { siblings : List Found
170 , children : List Found
172 , selfElement : Element msg
174 -- These values are needed to perform some types of tests.
175 , parentLayout : LayoutContext
176 , parentSpacing : Int
184 , textMetrics : List TextMetrics
188type alias TextMetrics =
189 { actualBoundingBoxAscent : Float
190 , actualBoundingBoxDescent : Float
191 , actualBoundingBoxLeft : Float
192 , actualBoundingBoxRight : Float
197{-| The font metrics we currently have are `actual`, meaning for the text actually rendered, not the font as a whole.
199We also know the font size is 20, so we're just going to return 20.
201TODO: improve font metric collection using something like opentype.js
207 metrics.actualBoundingBoxAscent
208 + metrics.actualBoundingBoxDescent
219type alias BoundingBox =
235type LayoutExpectation
237 { description : String
243type alias LayoutTest =
244 { elementDomId : String
245 , elementType : ElementType
247 , expectations : List LayoutExpectation
255floatToString : Float -> String
257 String.fromFloat (toFloat (round (x * 100)) / 100)
260lessThanOrEqual : String -> Float -> Float -> LayoutExpectation
261lessThanOrEqual label one two =
263 { description = label ++ " " ++ floatToString one ++ " <= " ++ floatToString two
264 , result = one <= two
268rounded : String -> { expected : Float, found : Float } -> LayoutExpectation
269rounded label { expected, found } =
271 (label ++ "| expected " ++ floatToString expected ++ ", found " ++ floatToString found)
272 (abs (expected - found) < 1)
275equal : a -> a -> LayoutExpectation
278 { description = "Are equal"
279 , result = one == two
283true : String -> Bool -> LayoutExpectation
286 { description = label
291todo : String -> LayoutExpectation
300getIds : Element msg -> List String
302 "se-0" :: getElementId [ 0, 0 ] el
305getElementId : List Int -> Element msg -> List String
306getElementId level el =
311 attrID attrIndex attr =
314 getElementId (attrIndex :: -1 :: level) nearby.element
321 |> List.indexedMap attrID
324 childrenIDs children =
325 List.concat <| List.indexedMap (\i -> getElementId (i :: level)) children
329 id :: getElementId (0 :: level) child ++ attributeIDs attrs
331 Row attrs children ->
332 id :: childrenIDs children ++ attributeIDs attrs
334 Column attrs children ->
335 id :: childrenIDs children ++ attributeIDs attrs
337 TextColumn attrs children ->
338 id :: childrenIDs children ++ attributeIDs attrs
340 Paragraph attrs children ->
341 id :: childrenIDs children ++ attributeIDs attrs
354toElement : Element msg -> Element.Element msg
356 renderElement [ 0, 0 ] el
359toHtml : Element msg -> Html msg
363 , Element.width (Element.px 1000)
364 , Element.height (Element.px 1000)
367 renderElement [ 0, 0 ] el
370idAttr : String -> Element.Attribute msg
372 Element.htmlAttribute (Html.Attributes.id ("se-" ++ id))
375renderElement : List Int -> Element msg -> Element.Element msg
376renderElement level el =
380 |> List.map String.fromInt
384 makeAttributes attrs =
386 |> List.indexedMap (renderAttribute level)
392 (id :: makeAttributes attrs)
393 (renderElement (0 :: level) child)
395 Row attrs children ->
397 (id :: makeAttributes attrs)
398 (List.indexedMap (\i -> renderElement (i :: level)) children)
400 Column attrs children ->
402 (id :: makeAttributes attrs)
403 (List.indexedMap (\i -> renderElement (i :: level)) children)
405 TextColumn attrs children ->
407 (id :: makeAttributes attrs)
408 (List.indexedMap (\i -> renderElement (i :: level)) children)
410 Paragraph attrs children ->
412 (id :: makeAttributes attrs)
413 (List.indexedMap (\i -> renderElement (i :: level)) children)
422renderAttribute : List Int -> Int -> Attr msg -> List (Element.Attribute msg)
423renderAttribute level attrIndex attr =
434 Nearby { location, element } ->
437 [ Element.above (renderElement (attrIndex :: -1 :: level) element) ]
440 [ Element.below (renderElement (attrIndex :: -1 :: level) element) ]
443 [ Element.onRight (renderElement (attrIndex :: -1 :: level) element) ]
446 [ Element.onLeft (renderElement (attrIndex :: -1 :: level) element) ]
449 [ Element.inFront (renderElement (attrIndex :: -1 :: level) element) ]
452 [ Element.behindContent (renderElement (attrIndex :: -1 :: level) element) ]
455 List.indexedMap (renderAttribute (attrIndex :: level)) batch
458 LabeledTest tested ->
466runTests : Dict String Found -> Element msg -> List LayoutTest
467runTests harvested el =
470 Dict.get "se-0" harvested
474 [ { elementDomId = "se-0"
475 , elementType = EmptyType
476 , label = "Finding root element"
479 { description = "Locating root element for rendering tests"
498levelToString : List Int -> String
501 |> List.map String.fromInt
503 |> (\x -> "se-" ++ x)
507 { siblings : List Found
509 , cache : Dict String Found
511 , element : Element msg
512 , location : LayoutContext
513 , parentSpacing : Int
516createTest { siblings, parent, cache, level, element, location, parentSpacing } =
520 |> Maybe.withDefault 0
525 testChildren : Found -> List (Element msg) -> List LayoutTest
526 testChildren found children =
529 -- Should check that this lookup doesn't fail.
530 -- Thoug if it does, it'll fail when the element itself is tested
533 Dict.get (levelToString (x :: level)) cache
535 (List.range 0 (List.length children))
537 List.foldl (applyChildTest found)
539 , upcoming = childrenFound
552 , previous : List Found
553 , tests : List LayoutTest
554 , upcoming : List Found
558 , previous : List Found
559 , tests : List LayoutTest
560 , upcoming : List Found
562 applyChildTest found child childTest =
563 -- { index, upcoming, previous, tests }
565 surroundingChildren =
566 case childTest.upcoming of
571 remaining ++ childTest.previous
575 { siblings = surroundingChildren
578 , level = childTest.index :: level
580 , parentSpacing = spacing
605 { index = childTest.index + 1
606 , tests = childTest.tests ++ childrenTests
608 case childTest.upcoming of
613 x :: childTest.previous
615 case childTest.upcoming of
623 tests : Found -> List (Attr msg) -> List (Element msg) -> List LayoutTest
624 tests self attributes children =
626 findBBox elem ( i, gathered ) =
639 case Dict.get (levelToString (i :: level)) cache of
643 Debug.log "el failed to find" elem
646 Debug.log "Failed to find child" (levelToString (i :: level))
658 List.foldl findBBox ( 0, [] ) children
664 -- Found -> Dict String Found -> List Int -> Int -> Surroundings -> Attr msg -> List Test
666 createAttributeTest self
670 { siblings = siblings
673 , selfElement = element
674 , children = childrenFoundData
675 , parentLayout = location
676 , parentSpacing = parentSpacing
683 ++ testChildren self children
685 case Dict.get id cache of
695 [ { elementDomId = id
696 , elementType = EmptyType
697 , label = "Finding element in DOM"
700 { description = "Locating element for rendering test"
710 tests self attrs [ child ]
712 Row attrs children ->
713 tests self attrs children
715 Column attrs children ->
716 tests self attrs children
718 TextColumn attrs children ->
719 tests self attrs children
721 Paragraph attrs children ->
722 tests self attrs children
739createAttributeTest parent cache level attrIndex surroundings attr =
742 "#" ++ levelToString level
752 [ { elementDomId = domId
754 toElementType surroundings.selfElement
755 , label = details.label
756 , expectations = details.test surroundings
766 , level = attrIndex :: -1 :: level
767 , location = IsNearby nearby.location
771 { label = nearby.label
782 |> List.indexedMap (\i attribute -> createAttributeTest parent cache level i surroundings attribute)
785 LabeledTest { label, test } ->
786 [ { elementDomId = domId
787 , elementType = toElementType surroundings.selfElement
789 , expectations = test surroundings
794addAttribute : Attr msg -> Element msg -> Element msg
795addAttribute attr el =
798 El (attr :: attrs) child
800 Row attrs children ->
801 Row (attr :: attrs) children
803 Column attrs children ->
804 Column (attr :: attrs) children
806 TextColumn attrs children ->
807 TextColumn (attr :: attrs) children
809 Paragraph attrs children ->
810 Paragraph (attr :: attrs) children
819compareFormattedColor : Color -> String -> Bool
820compareFormattedColor color expected =
821 formatColor color == expected || formatColorWithAlpha color == expected
824formatColorWithAlpha : Color -> String
825formatColorWithAlpha (Internal.Rgba red green blue alpha) =
827 ("rgba(" ++ String.fromInt (round (red * 255)))
828 ++ (", " ++ String.fromInt (round (green * 255)))
829 ++ (", " ++ String.fromInt (round (blue * 255)))
834 ("rgba(" ++ String.fromInt (round (red * 255)))
835 ++ (", " ++ String.fromInt (round (green * 255)))
836 ++ (", " ++ String.fromInt (round (blue * 255)))
837 ++ (", " ++ String.fromFloat alpha ++ ")")
840formatColor : Color -> String
841formatColor (Internal.Rgba red green blue alpha) =
843 ("rgb(" ++ String.fromInt (round (red * 255)))
844 ++ (", " ++ String.fromInt (round (green * 255)))
845 ++ (", " ++ String.fromInt (round (blue * 255)))
849 ("rgb(" ++ String.fromInt (round (red * 255)))
850 ++ (", " ++ String.fromInt (round (green * 255)))
851 ++ (", " ++ String.fromInt (round (blue * 255)))
855getSpacingFromAttributes attrs =
860 (Spacing i) :: remain ->
863 (Batch batched) :: remain ->
864 getSpacingFromAttributes (batched ++ remain)
867 getSpacingFromAttributes remain
870getSpacing : Element msg -> Maybe Int
873 getSpacingAttr attr found =
874 if found /= Nothing then
883 List.foldr getSpacingAttr Nothing attrs
889 List.foldr getSpacingAttr Nothing attrs
901 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