Stop huge error output from testing-library
Asked Answered
R

3

22

I love testing-library, have used it a lot in a React project, and I'm trying to use it in an Angular project now - but I've always struggled with the enormous error output, including the HTML text of the render. Not only is this not usually helpful (I couldn't find an element, here's the HTML where it isn't); but it gets truncated, often before the interesting line if you're running in debug mode.

I simply added it as a library alongside the standard Angular Karma+Jasmine setup.

I'm sure you could say the components I'm testing are too large if the HTML output causes my console window to spool for ages, but I have a lot of integration tests in Protractor, and they are SO SLOW :(.

Rialto answered 24/9, 2020 at 11:48 Comment(0)
D
22

I would say the best solution would be to use the configure method and pass a custom function for getElementError which does what you want.

You can read about configuration here: https://testing-library.com/docs/dom-testing-library/api-configuration

An example of this might look like:

configure({
  getElementError: (message: string, container) => {
    const error = new Error(message);
    error.name = 'TestingLibraryElementError';
    error.stack = null;
    return error;
  },
});

You can then put this in any single test file or use Jest's setupFiles or setupFilesAfterEnv config options to have it run globally.

Dasyure answered 1/10, 2020 at 12:31 Comment(3)
My example above is TypeScript, BTW - you might not want : string if you're using Jest with React in a non-TS project!Rialto
After a recent update to webpack (5.61.0), this seems to not be working anymore. Can anyone else confirm that this is still working (with or even without webpack in the equation)?Cenacle
Set the configuration in setupFiles would be break the feature of cleanup automatically, so it is better to set the config in setupFilesAfterEnv. Please see Cleanup not happening when using configure from @testing-library/reactOvercapitalize
E
15

I am assuming you running jest with rtl in your project.

I personally wouldn't turn it off as it's there to help us, but everyone has a way so if you have your reasons, then fair enough.

1. If you want to disable errors for a specific test, you can mock the console.error.

    it('disable error example', () => {

  const errorObject = console.error; //store the state of the object
  console.error = jest.fn(); // mock the object

  // code

  //assertion (expect)

  console.error = errorObject; // assign it back so you can use it in the next test
});

2. If you want to silence it for all the test, you could use the jest --silent CLI option. Check the docs

The above might even disable the DOM printing that is done by rtl, I am not sure as I haven't tried this, but if you look at the docs I linked, it says

"Prevent tests from printing messages through the console."

Now you almost certainly have everything disabled except the DOM recommendations if the above doesn't work. On that case you might look into react-testing-library's source code and find out what is used for those print statements. Is it a console.log? is it a console.warn? When you got that, just mock it out like option 1 above.

UPDATE

After some digging, I found out that all testing-library DOM printing is built on prettyDOM();

While prettyDOM() can't be disabled you can limit the number of lines to 0, and that would just give you the error message and three dots ... below the message.

Here is an example printout, I messed around with:

    TestingLibraryElementError: Unable to find an element with the text: Hello ther. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

...

All you need to do is to pass in an environment variable before executing your test suite, so for example with an npm script it would look like:

DEBUG_PRINT_LIMIT=0 npm run test

Here is the doc

UPDATE 2:

As per the OP's FR on github this can also be achieved without injecting in a global variable to limit the PrettyDOM line output (in case if it's used elsewhere). The getElementError config option need to be changed:

dom-testing-library/src/config.js

     // called when getBy* queries fail. (message, container) => Error 
 getElementError(message, container) { 
   const error = new Error( 
     [message, prettyDOM(container)].filter(Boolean).join('\n\n'), 
   ) 
   error.name = 'TestingLibraryElementError' 
   return error 
 }, 

The callstack can also be removed

Elaineelam answered 24/9, 2020 at 12:55 Comment(12)
Oh no! Thank you so much for your reply and I'm SO sorry I forgot to say I'm not using jest! I'm just using Karma (with jasmine, as per normal for Angular). SORRY! :(Rialto
Ah I see, sorry I am not that literate with the Angular ecosystem. Regardless of the testing framework console.error console.warn etc is the same everywhere. Wouldn't it work by mocking it out with the tools you have?Elaineelam
removing console would make life very difficult. I want to stop it spooling a load of HTML onto the commandline pointlessley when there's a failure.Rialto
@IanGrainger I updated my answer, I might have a solution for you. Good luck.Elaineelam
Thanks - though I normally use prettyDOM for my own debugging :(Rialto
I tried this after reading: testing-library.com/docs/dom-testing-library/api-helpers 'Note: Since the DOM can get very large'.... Why is that OK!? 😆 and it didn't work, because I'm running via Karma I guess 🙄Rialto
I never used Karma but it's a test runner. PrettyDOM is not part of Jest, so theoretically it should be used with any kind of Test runner and package manager(s). At this point, maybe it's worth raising a feature request on testing-library's github to be able to limit the length of the DOM on a test by test basis?Elaineelam
the problem is that Karma ignores env vars set on the commandline, because it runs Chrome (which runs the test) in an other process. The first place that testing library point you is here, to SO - so that's why this is here first!Rialto
I think this is done by the DOM testing library, so I've created a FR here: github.com/testing-library/dom-testing-library/issues/773Rialto
Yepp, that's correct - react testing library as an abstraction of the dom testing library is inheriting the feature, I noticed when I was looking into PrettyDOM. I also see you received an answer, that's great. I would complete wyze's answer by: the config.js code snippet states: // called when getBy* queries fail. (message, container) => Error - this won't cover the queryBy queries, so you need to cover that as well, I believe.Elaineelam
Oops, didn't see you'd updated. I'd added a copy of wyze's answer here. But seeing as I presumably don't get points for my own answer - I may as well take yours! :)Rialto
Sorry, bro. The guy that answered on GH has come over here - so I've moved the points. Thanks for your help, too! 🤜Rialto
R
2

You can change how the message is built by setting the DOM testing library message building function with config. In my Angular project I added this to test.js:

configure({
  getElementError: (message: string, container) => {
    const error = new Error(message);
    error.name = 'TestingLibraryElementError';
    error.stack = null;
    return error;
  },
});

This was answered here: https://github.com/testing-library/dom-testing-library/issues/773 by https://github.com/wyze.

Rialto answered 1/10, 2020 at 4:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.