The problem that testing-library
aims to solve is that when we write tests for our components, we rely upon the implementation details of said component, which in turn make our tests fragile, and not refactor proof. This goal is an admirable one and something which could help every developer to ship reliable and maintainable code.
The problem with this is not a conceptual one, but an execution one.
I was testing a custom input component because I found a bug. In a specific situation, the user could not type in it. Yes, it was a bug I introduced but thought before fixing it, I'll write tests to cover this. TDD, right? It turns out you cannot cover this scenario with react-testing-library
and jest
, because how it only partially implements a DOM.
What I needed was to test if, in the given situation, the user focuses the input and starts typing, the value of the input changes accordingly. The test has failed as it should have. So I began fixing the issue. It was quick and easy and could confirm the fix in my browser. When I went back to check up on my tests, they still failed.
My test consisted of using keyDown
events to emulate typing. Because this is the user does, right? Well, it turns out that according to testing-library
, the user is not pressing buttons, but fires change
events! AS we all do when we do a Google search. We hit it up, and fire change
event left and right and boom, here comes the search result.
My issue with this concept is that there are cases when firing a change event works, but pressing keys does not. And I could not find a solution for this since.
This issue is similar to not being able to query innerText
because you'd need a layout engine for that. As if the user would be using your components without one. But worry not, there is data-test-id
. Which is a way of saying, do not test implementation details, but implement details to test the thing.
I think while the concept is excellent, the tools are not in place to deliver yet. You still need puppeteer
, playwright
or selenium
to get into the shoes of your end-user. If you know of any ways to run my existing testing-library
specs in a browser a way that allows for querying elements by input text, like an xPath
selector or something, and has a complete chain of events, please let me know.
Thank you, rant over
Top comments (8)
In theory, if you use a test runner that can be used in a browser (mocha and tape comes to mind), you could use a bundler to gather all your tests together and run them in a real browser. I did this experiment in
2018
with tape and dom-testing-library, at that time it worked great (just had to make sure to add{ node: fs: 'empty' }
on my webpack config).If jest is the real problem then you could try one of these testing library wrapper
Thanks for your reply!
We already use
Puppeteer
for E2E testing, but currently transitioning toPlaywright
. TriedCypress
, which is awesome, but lacked the cross-domain support, which we still need for the time being. I have not familiarized myself withTestCafe
tho.But to sum up, you say we should bundle
jest
and all test files, open in a browser, and it should work withreact-testing-library
as long as it's bundled with it?Do you reckon, from the top of your head, that it would be easy to support file watching as well?
Oh no. Heavens no! That's not what I'm saying. Jest is a monster of a framework, I don't think you can make it run in a browser. I'm just trying to defend the
testing-library
family here.Do you use pptr-testing-library with puppeteer?
Nope, we created a test suite with
cucumber-js
and a lot of custom steps to support Gherkin for our PMs and non-technical staff.Does it allow to run
@testing-library/react
based tests inPuppeteer
?Because I'm under the impression, they won't work together like that, and that's where I may be wrong.
No. pptr-testing-library was made to control puppeteer. So, technically puppeteer will render your app, then you use
pptr-testing-library
to query and manipulate the DOM (just like you would withreact-testing-library
).Thanks! That's what I thought. What I would like ultimately, is my unit-tests to run in an actual browser.
To sum up, serious projects need unit testing (React Testing Library, Jest — TDD) but also end-to-end testing (Cypress/WebdriverIO — BDD). That's just two different testing angles. Running Cypress on a component, to test prop is overkill. That's what RTL is for. On the same way, user interactions like you described with user typing is typical Cypress area. Using RTL for that is cumbersome if not impossible like you noted.
PS. let's fix typo "rent over" to "rant over"
Thanks for noting the typo, fixed it.
On the matter of RTL, I'm not sure if it's unavoidable. If you maintain a Storybook, you could do a lot of your unit tests there, with puppeteer, you need to assert your expectations in your E2E framework.
There are cases where I cannot imagine using a browser with current tooling but could imagine tooling that would allow. Like mocking global variables like location and etc.
So in short TDD does not say anything about the environment you run it in IMHO.