elm-explorations / test

Write unit and fuzz tests for Elm code.
https://package.elm-lang.org/packages/elm-explorations/test/latest
BSD 3-Clause "New" or "Revised" License
237 stars 39 forks source link

Simulate event bubbling? #60

Open rtfeldman opened 5 years ago

rtfeldman commented 5 years ago

Someone suggested simulating event bubbling in html tests.

The basic idea would be:

In this world, presumably stopPropagation would need to be processed and handled properly.

Thoughts?

mgold commented 5 years ago

It sounds like this proposal is to make something like enzyme or react-testing-library for Elm. Judging by the size of those libraries, this is a massive undertaking.

Here's how I imagine this playing out:

  1. See if we have 2-4 people willing to take on this project.
  2. Learn about the implementation of Elm's virtual DOM enough to see if it's possible and feasible to simulate onClick.
  3. Study prior art and people's testing needs to see what problem needs to be solved. What are people trying to test: menus, forms, something else entirely?
  4. Come up with an initial API proposal and present to the larger elm-test, and maybe Elm, community
  5. Iterate on that API
  6. Implement, likely in a separate repo (like project fuzzball).

I'm not available to help, but it seems like a potentially useful feature.

rtfeldman commented 5 years ago

It sounds like this proposal is to make something like enzyme or react-testing-library for Elm.

I don't have an personal experience with those, but at least for this issue, the scope is only bubbling.

We already simulate onClick at the level of the individual element, but it's very basic. We don't do things like:

The latter seems like a perpetual nonstarter for elm-test - good luck ever realistically simulating node dimensions in the event object without involving a real browser - but bubbling seems plausible, and Elm doesn't support enabling capture, and that seems like a reasonably narrow scope.

I wasn't thinking there would actually be any API changes here. My thinking was:

  1. You use Test.Html.Event.simulate on an element.
  2. That element has no handler for that event, but it does have an ancestor with a handler for that event.
  3. Today, the simulated event ignores the ancestor and fails the test. The idea of this change would be that instead it'd simulate the bubbling and the test would actually work.

I'm confident Elm's vdom has enough info to pull that off, and it doesn't seem like it would be a big enough project to necessitate multiple people working on it...but maybe I'm missing something!

mgold commented 5 years ago

No, I totally missed that we had event simulations already. This probably is much simpler than I imagined.

So would this look like simulateAt : List Selector -> (String, Value) -> Single msg -> Event msg, failing if no child node was found at the selectors?

mgold commented 5 years ago

So I looked through src/Test/Html/Event.elm and thought about this some more, and I don't think simulating or testing event bubbling is worthwhile. That's because the event being bubbled is fake to begin with, and un-faking it is a "perpetual nonstarter", so it doesn't really matter how it arrives at the handling node.

I wasn't thinking there would actually be any API changes here. My thinking was... That element has no handler for that event, but it does have an ancestor with a handler for that event.

The problem here is that you supply one node in the current API, and it has no reference to its parent. That's what simulateAt was going for -- a reference to the parent and selectors to find the child -- but I don't think that's very useful. Why not fake your own event directly to the handling node?

Instead, what I think is missing is a way to expect an event handler to (not?) stop propagation. We might as well add expectations for (not?) preventing default while we're at it.

mgold commented 5 years ago

I added expectations for stop propagation and prevent default in #80.

rtfeldman commented 5 years ago

Instead, what I think is missing is a way to expect an event handler to (not?) stop propagation.

One of the use cases I heard about was this:

  1. I have a button with some text in it.
  2. The button is inside a div which also contains some images.
  3. Clicking anywhere in the div (the images or the button) should do the same thing. This is why the div (quite reasonably) has the onClick handler.
  4. The div doesn't have any markers that make it easy to select in the dom, but the button does (its text).

So really the goal of the test is "clicking this button causes the expected event to fire," not "clicking this button doesn't propagate."

The tester could of course add a marker to the production dom to make the div easier to select in a test, but anytime someone has to do that it's worth questioning whether the testing system should have a better way to write that test!