eeue56 / elm-html-test

Test elm-html in Elm!
http://package.elm-lang.org/packages/eeue56/elm-html-test/latest
BSD 3-Clause "New" or "Revised" License
67 stars 15 forks source link

Things needed to support high-level UI tests #32

Closed avh4 closed 6 years ago

avh4 commented 7 years ago

We want to start using elm-html-test in some of our higher-level tests, and would like to be able to have something like clickOn similar to in capybara, which would be able to find a button with the given text.

Here are some thoughts on the kinds of things I think we'd need to be able to write something like clickOn and similar functions.

Basic:

Advanced:

eeue56 commented 7 years ago

can you make some examples with input html and expected output? if I'm understanding correctly these should all be pretty easy

avh4 commented 7 years ago

some way to find the "Click me" button. Currently, Query.find [ tag "button", text "Click me" ] finds no matches (possibly related to https://github.com/eeue56/elm-html-test/issues/13?):

div []
    [ button [] [ text "Click me" ]
    , button [] [ text "Don't click me" ]
    ]

some way to write a query that will find the button when given a, and the input when given b:

a = div [] [ button [] [ text "Click me" ] ]
b = div [] [ input [ type_ "button", value "Click me" ] ]

Possible API:

Query.find
    [ Selector.oneOf
        [ [ tag "button", text "Click me" ]
        , [ tag "input", attribute "type" "button", attribute "value" "Click me" ]
        ]
    ]

Another possible API:

case Query.toResult <| Query.find [ tag "button", text "Click me" ] of
    Err _ ->
        Query.find [ tag "input", attribute "type" "button", attribute "value" "Click me" ]
    Ok single ->
        single

some way to find the input that's associated with a label that matched another selector. In this example, find the input associated with the "A" label, and not the other input (this should also work in cases where the input and the label aren't siblings):

div []
    [ label [ for "input-1" ] [ text "A" ]
    , label [ for "input-2" ] [ text "B" ]
    , input [ id "input-1" ] []
    , input [ id "input-2" ] []
    ]

Possible low-level API:

dom
    |> Query.find [ tag "label", text "A" ]
    |> Query.getAttribute "for"
    |> (\labelFor -> Query.find [ tag "input", id labelFor ] dom)

(I guess Query.getAttribute would probably have to return Result _ String or even Result _ (Maybe String) instead of String.)

Possible high-level API:

Query.find
    [ tag "input"
    , labelledBy [ tag "label", text "A" ]
    ]

some way to find an element in relation to another element. In this example, find the button in "Section A" (and ignore the button in "Section B"):

div []
    [ section []
        [ h3 [] [ text "Section A" ]
        , button [] [ text "Submit" ]
        ]
    , section []
        [ h3 [] [ text "Section B" ]
        , button [] [ text "Submit" ]
        ]
    ]

Possible API:

Query.find
    [ tag "section"
    , havingChild [ tag "h3", text "Section A" ]
    ]
    |> Query.find [ tag "button", text "Submit" ]

Another possible API:

Query.find
    [ tag "button"
    , text "Submit"
    , havingAncestor [ tag "section", text "Section A" ]
    ]

some way to select only elements that have a particular event handler. In this example, find the div with the onClick handler, and ignore the other divs:

div []
    [ div []
        [ div [ onClick MyMsg ]
            [ div [] [ text "Click me" ] ]
        , div [] []
        ]
    , div [] []
    ]

Possible API:

Query.find [ tag "div", withHandler "click" ]
rtfeldman commented 6 years ago

This issue covers some fairly unrelated features, which makes it tricky to discuss things on it. I'd like to split this up into separate issues, so we can discuss them separately.

a way to find an element that contains particular text.

Now tracking in https://github.com/eeue56/elm-html-test/pull/47

a ways to combine multiple queries: either Selector.oneOf, or having a way to destructure a Query.Single or turn a Query.Single into a Result

Now tracking in https://github.com/eeue56/elm-html-test/issues/49

a way to extract the for attribute from a found label tag and then use that value to find the input with the matching id. currently, there's no way to extract the attribute value

I understand what this would do, but I'm not sure if we want a general solution for this or if this is something that's particular to the way label and input elements interact. (Put another way: do we want to introduce full-blown monadic attribute chaining, or do we really just want to add labelledBy to the API directly?)

@gurdiga I noticed you ran into this with https://github.com/gurdiga/xo.elm/commit/34f50cafadd1ef22a335824c13a472ed3af94da4 - but I'm not sure if you were looking to do this with aria-labelledby or something else. 😄 Would you mind opening an issue on this repo describing your use case?

a way to do something like the following: find the button with the given text in the tr that contains a h3 with some other given text (alternatively, find the h3 with given text, then find the tr that contains it, ...)

I didn't quite understand this example. @avh4 could you open a separate issue describing the use case here?

a selector that only matches elements that have a given event handler type (something like find [ tag "div", withHandler "onClick" ]), or alternatively a way to find the nearest parent to a given node that handles a given event type.

This doesn't seem tricky to implement, but I'm curious how it would be used. @avh4 would you mind opening a separate issue describing what we'd use this for that can't already be done in other ways?

avh4 commented 6 years ago

a way to do something like the following: find the button with the given text in the tr that contains a h3 with some other given text (alternatively, find the h3 with given text, then find the tr that contains it, ...)

I didn't quite understand this example. @avh4 could you open a separate issue describing the use case here?

a selector that only matches elements that have a given event handler type (something like find [ tag "div", withHandler "onClick" ]), or alternatively a way to find the nearest parent to a given node that handles a given event type.

This doesn't seem tricky to implement, but I'm curious how it would be used. @avh4 would you mind opening a separate issue describing what we'd use this for that can't already be done in other ways?

Examples of both were given in https://github.com/eeue56/elm-html-test/issues/32#issuecomment-306840487. I've created #52, #53, #54.