Coder Social home page Coder Social logo

Comments (34)

artooras avatar artooras commented on June 30, 2024 5

I would back using user-events as the new default. The philosophy of dom-testing-library is to test "the way a user would". A user certainly doesn't trigger separate DOM events, of which the user is usually even unaware (think a simple "hover" vs. all the mouseIn, mouseOver and their chains). Instead, if a user clicks on an input field, he would expect the input field to become active, along with any side effects that normally take place in the browser. So, I would replace the "old" way with this.

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024 4

Hey @weyert, your test is firing change events at a button, not the input field. I believe that's the problem.

from dom-testing-library.

Gpx avatar Gpx commented on June 30, 2024 3

Just for me to understand, would this "user" library work somehow like this?

import React from "react";
import { render, fireEvent } from "react-testing-library";
import "jest-dom/extend-expect";

function App() {
  return (
    <React.Fragment>
      <input data-testid="A" />
      <input data-testid="B" />
    </React.Fragment>
  );
}

const userEvent = {
  click(element) {
    /* This is what really happens in my browser
     * when I click on an element.
     *
     * Chrome 69.0.3497.92 (Official Build) (64-bit)
     * OS X 10.11.6 (15G22010)
     *
     * mouseenter
     * mouseover
     * mousemove (a bunch of them)
     * mousedown
     * focus
     * mouseup
     * click
     *
     * If we fire the same events with fireEvent
     * in the same exact order it doesn't work.
     *
     * This is because:
     *
     * 1. fireEvent.mouseOver also fires mouseenter
     *    although in the wrong order
     * 2. fireEvent.focus does not set
     *    document.activeElement. I had to use
     *    element.focus()
     *
     * This is the best I could come up with
     * to simulate the browser as closely as possible.
     */

    const focusedElement = document.activeElement;
    const wasAnotherElementFocused =
      focusedElement !== document.body && focusedElement !== element;
    if (wasAnotherElementFocused) {
      fireEvent.mouseMove(focusedElement);
      fireEvent.mouseLeave(focusedElement);
    }

    fireEvent.mouseOver(element);
    fireEvent.mouseMove(element);
    fireEvent.mouseDown(element);
    element.focus();
    fireEvent.mouseUp(element);
    fireEvent.click(element);

    wasAnotherElementFocused && focusedElement.blur();
  }
};

test("events", () => {
  const { getByTestId } = render(<App />);
  userEvent.click(getByTestId("A"));
  expect(getByTestId("A")).toHaveFocus();
  userEvent.click(getByTestId("B"));
  expect(getByTestId("B")).toHaveFocus();
  expect(getByTestId("A")).not.toHaveFocus();
});

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024 3

@alexkrolick, I'm going to be building a monorepo project at work (because I can't use semantic-release there) so we'll see how I enjoy it. My biggest hesitance for using monorepos is the semantic-release solution for monorepos seems slightly unmaintained and I'm worried about things that could come up. Dropping semantic-release from my workflow is kinda out of the question. I wouldn't have time to maintain the packages I do without semantic-release.

That said, I'll let you know what I think of my experience using a monorepo. If it's positive, then I'll see about trying to get semantic-release to work for a monorepo.

@Gpx, yes, I think that's exactly the kind of thing we're looking for ๐Ÿ‘

from dom-testing-library.

Gpx avatar Gpx commented on June 30, 2024 3

@sompylasar yep you're right there are going to be many edge cases. As you suggested I intend to start by reviewing what other projects do and what browsers do.

Next, I'll take the new user events I create and put them in my test suite to see how it goes.

We'll probably need to sacrifice some events (I'm thinking of mousemove for example) but I'll try to be as accurate as possible.

I'll keep you posted and I'm happy if somebody wants to contribute.

from dom-testing-library.

Gpx avatar Gpx commented on June 30, 2024 3

Hi everyone, a little update. I've started working on a library called user-event. At the moment it supports only click, dblClick and type but I've been testing it in my day to day job, and it seems quite useful.

I would much appreciate any feedback and especially bug reports. I believe many edge cases are not covered yet and at the moment I'm focusing only on the issues I find while working on my other projects.

Let me know what you think, and if you want to contribute you're more than welcome!

from dom-testing-library.

alexkrolick avatar alexkrolick commented on June 30, 2024 3

https://github.com/bigtestjs/interactor - an interesting library for simulating interactions, plus some Cypress like "interactability" detectors like isHidden, etc. Might be possible to get it to work with dom-testing-library somehow.

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024 3

I'm happy to discuss this further, but let's open a new issue on user-event.

from dom-testing-library.

nickmccurdy avatar nickmccurdy commented on June 30, 2024 3

We're now working on merging user-event back into dom-testing-library in #616

from dom-testing-library.

matchai avatar matchai commented on June 30, 2024 2

Skimming over the Cypress API, these seem to be some of the most useful APIs provided and an idea of how they would act:

check
Focus, toggle-on
clear
Focus, select all, backspace
click
Click, focus
dblclick
Click, focus, 10ms delayed click
hover
As hover is a trusted event, it wouldn't be possible to activate the pseudo-class state of the element programmatically.
To address testing-library/jest-dom#53, you would need to programmatically apply the CSS of the hover pseudo-class to the element. Sounds challenging to do correctly.
select
Opening a select is a trusted event, so it wouldn't be possible programmatically.
Focus select, set option to selected
uncheck
Focus, toggle-off
type
Focus, add one character every 10ms

from dom-testing-library.

sompylasar avatar sompylasar commented on June 30, 2024 2

@Gpx Not to discourage you from doing what you're going to do, but there's a lot of corner cases, so please reuse the experience Cypress has collected over time in how this should work. Also puppeteer has an extensive user-simulating API to look at.

From my perspective the most accurate representation of user interactions with the UI is described in terms of the tools available to the user: 1) analyze the output: eyes or screenreaders to observe elements and move pointers on the screen, 2) produce the input: pointers, fingers, keyboards to interact with the screen. The input tools have state: the current coordinates and pressed/released for every button. The "click" action is actually a pointer click so it will be just optional focus of the element under the current coordinates and then click of the element under the current coordinates (also something may rerender on focus so click may hit a different element). Cypress has had a different approach last time I looked: to make as many shortcuts as possible (sacrificing the accuracy of representation), but still they try to emulate all events they can via the DOM.

from dom-testing-library.

Gpx avatar Gpx commented on June 30, 2024 2

I agree with @kentcdodds user-event is not mature enough. It still lacks some basic actions and more real-world testing.

As for including it in dom-testing-library, I'm not sure either. I think it shoudโ€”at least in the beginningโ€”be an external library that offers an alternative to fireEvent.

from dom-testing-library.

weyert avatar weyert commented on June 30, 2024 1

Amazing, thank you @kentcdodds. Clearly you are having a pair of fresh eyes!!

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024 1

Closing this as we now have user-event

from dom-testing-library.

sompylasar avatar sompylasar commented on June 30, 2024

Also have a look at https://github.com/getgauge/taiko whose goal is to provide such a high-level API on top of a browser and a REPL to test it and record scripts.

I wish the very similar efforts dom-testing-library and cousins, Cypress, and now Taiko all put into making human-emulating APIs for webapp testing and automation could be united, but unfortunately Cypress is a not-so-modular-and-importable pile of CoffeeScript.

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

Yeah, I think that someone should develop a package separate from dom-testing-library that's intended to do this. Then dom-testing-library can just re-export that library (like we do with wait-for-element).

Anyone want to do that? It'd probably be a lot of fun and I bet would get a lot of use. I just don't have time for it at the moment.

from dom-testing-library.

sompylasar avatar sompylasar commented on June 30, 2024

The very part that I wish could be reuse from Cypress is all the funky and often-simply-impossible-without-devtools-protocol but still useful emulation of the browser default behavior via just the DOM APIs (what dom-testing-library does as an infant compared to Cypress).

The part I wish could be reused from Taiko (although I read the code and it's not very robust yet) is the visually relative selectors by text (dom-testing-library kinda does by text, but not visually relative). I mean near, above, below, I would also add alongVector(minDistance, maxDistance).

I agree with Kent that it should be a separate library.

from dom-testing-library.

lgandecki avatar lgandecki commented on June 30, 2024

@sompylasar Taiko looks amazing, but if I understand correctly since jsdom doesn't support "getBoundingClientRects", or "the ability to calculate where elements will be visually laid out as a result of CSS", we won't be able to do things like near/above/below. :-( Is there something that I'm missing?
It would be fantastic to have it in terms of testing the app like the user would. My team could possibly spend some time building a library like that, but if implementing layout in jsdom is prerequisite, that seems like way beyond our availability. :-(

from dom-testing-library.

alexkrolick avatar alexkrolick commented on June 30, 2024

a package separate from dom-testing-library

Are you sure you don't want to pursue the monorepo idea in #98? The cross-dependency between these packages is a bit hairy and some of the wrappers are undoubtedly already falling behind, depending on implementation.

from dom-testing-library.

Gpx avatar Gpx commented on June 30, 2024

I think that someone should develop a package separate from dom-testing-library that's intended to do this

Can I give it a shot?

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

Go for it!

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

Fantastic! That's a great start ๐Ÿ‘ once we get more user actions in there, then we can pull that in and re-export it ๐Ÿ’ฏ

Circular dependencies are fun ๐Ÿ˜… I'm pretty sure it works though.

from dom-testing-library.

weyert avatar weyert commented on June 30, 2024

I have had a look at the library and even when using that I am struggling to make onChange event handlers be called or the keydown events. I am not sure if something is broken or not. I have been able to make a reproducible sandbox which can be found at the link below. I have added some logs in my onChange and onKeyDown event handlers in my component MyField when using it in the preview I am correctly receiving things like MyField.onFieldChange() etc but not when running the tests.

I am a bit worried that my testing approach is wrong. I am trying to test things which I should test?

Sandbox URL: https://codesandbox.io/s/ol4qnvy669

from dom-testing-library.

weyert avatar weyert commented on June 30, 2024

I have created a PR for @Gpx library so that it will dispatch onKeyDown/onKeyUp and change correctly when you are using preventDefault() in your code to block the entry of a character, you can find it here: testing-library/user-event#27

If this change is against the intended use of react-testing-library let me know. I think when you a user types 1.5a and your component does event.preventDefault() on the a then the type() should accordingly trigger 1.5 and not 1.5a

from dom-testing-library.

alexkrolick avatar alexkrolick commented on June 30, 2024

@kentcdodds do you think user-event is mature enough to include in the next release?

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

I'm not sure. I'm actually a bit concerned about this. One of the things I didn't like about enzyme was that there were a million ways to do things. If we include this in dom-testing-library then we have two ways to do things and I feel like it could get confusing. What do you all think?

from dom-testing-library.

sompylasar avatar sompylasar commented on June 30, 2024

I think there are inherently at least two ways to simulate user-originated events in the browser: 1) imitate them with variable precision via browser DOM API from within JS runtime (not all possible to implement, many shortcuts and hacks); 2) inject into browser user input queue as if an input device generated them, let the browser translate to DOM events (precise but requires browser automation API which either not available or is async).

from dom-testing-library.

matchai avatar matchai commented on June 30, 2024

I was under the impression that this would be the new default behavior, and that if someone would want to fire events the old way, they would just do it manually. That seems consistent with how dom-testing-library handles selection - if you want to select a class, use DOM methods directly.

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

I would like to see it support more typical user events (drag and drop, hover, etc), then I'd like to see it used in real codebases for a while to see how it works in practice and work out any issues/common questions. I'm a little hesitant, particularly when someone changes from fireEvent.change to user.type. Their change handler will get called once for every character typed rather than once for the event which is correct, but I think could lead to confusion.

from dom-testing-library.

weyert avatar weyert commented on June 30, 2024

Yes, I think it would be a good idea to mention the availability in the React and Dom testing library README that this helper library exists for some common user events :)

from dom-testing-library.

kentcdodds avatar kentcdodds commented on June 30, 2024

Yes, I agree @weyert. Will help with adoption. I would like to suggest that we refer to it as experimental until it gets more features and is more proven.

from dom-testing-library.

nickmccurdy avatar nickmccurdy commented on June 30, 2024

I think it would be great to expand on user-event enough for it to be worth replacing fireEvent. Are there any specific events we'd want to add (maybe all the ones from Cypress)? Since this initial discussion, selectOptions has been added.

from dom-testing-library.

JimmyLv avatar JimmyLv commented on June 30, 2024

Where is the new issue? :D we are looking forward to it.

from dom-testing-library.

nickmccurdy avatar nickmccurdy commented on June 30, 2024

testing-library/user-event#183

from dom-testing-library.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.