Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 30, 2022 09:10 am GMT

Frontend test smells

Introduction

This article aims to help you find common problems in frontend testing.

Our frontend applications grows very fast, along with the addition of (more and more thoughtful ) features, which should be tested automatically.

I strongly encourage you to critique and also review the additional materials at the end of this article, that formed the basis for this list of "test smell's"

List of the most common problems in testing, that I have noticed in projects and libraries that I maintain in my regular job:

Test smells

  • using fireEvent - if you using a React Testing Library in your tests I would suggest to switch for userEvent.

UserEvent is way better at simulating the user behaviour, fireEvent just dispatches the DOM event, when the userEvent simulates full interactions - similarly like it is in real browser.

  • lack of using setup for userEvent - it is recommended to invoke setup method before the actual component render in test.

The UserEvent authors encourage to invoke setup always before the render. Personally I'm sticking with helper createWrapper function.

export const createTestWrapper = ({ children }: React.PropsWithChildren<unknown>) => {  return {    user: userEvent.setup(),    ...render(<SomeProvider>{children}</SomeProvider>),  }}
  • lack of await for user events
const { user } = createTestWrapper({ children: <Checkbox /> })const checkbox = screen.getByRole('checkbox')user.click(checkbox) await user.click(checkbox) expect(screen.getByRole('checkbox')).toBeChecked()

The only expection from it is .type according to the docs:

"To be clear, userEvent.type always returns a promise, but you only need to await the promise it returns if you're using the delay option. Otherwise everything runs synchronously and you can ignore the promise".

  • Huge test cases - on the whole it is quite logical, it is definitely better to break up into several smaller cases - than to test everything in one.

There is absolutely no point in artificially limiting the number of cases.

  • Too many assertions in one test case - it will be problematic to find what exactly failed, while you have a lot of assertions that checks totally different things.

Some people like to have only 1 assertion per test. I think it might be problematic, since checking one behavior might need more than just one assertion. As long as you testing one thing - you should be fine.

Here it can be helpful to use the techniques:

  • given => when => then or
  • prepare => act => assert
  • Lack of any assertions - or assertion which are useless - like expect(true).toBe(true) or expect(MightyComponent).toBeDefined()
  • Lack of strongly typed response mocks - in case you are using msw I think it is best to aim to be 100% up to date in terms of api responses structure. By typing it all, the TypeScript compiler makes sure that these mocks are always up to date as to type
  • Badly described test cases - I see it always should render a component or method should return true

I found that, it is best to show our descriptions to someone else and give that person very short time to read it and then ask what this test is actually checking ? If it is not obvious, then most likely our descriptions are misleading.

It is crucial to think, up front - what exactly I need to test. What user interaction should I check, the more our description is for humans not the better test is.

  • tests that sometimes passes, sometimes not - if it happens to your unit tests, then most likely it will be caused by some side effects. I often see the problems with time. If there is not time for such a debugging I would suggest to just delete those problematic tests
  • logic in your tests - even "simple" if statements. It is hard to determine if your logic in test failed or something is wrong with the thing that you are testing.

When someone claims, that if/else logic in test can be removed for some reason, I would try to check if it can be split into two or more cases

  • it is hard to write any tests - this usually indicates a complicated code, functions that do everything ? React Context that oversees the entire state ?
  • tests duplication - sometimes it is enough to write only integration test to check user interaction and not necessarily additionally unit-test a component / function that has already been tested in the integration test
  • very high coverage (90% +) - most often points to implementation testing, or worse, jacking up coverage at all costs, and no longer necessarily focusing on quality and behavioral coverage.
  • very slow tests - especially the typical unit ones, we want developers to get in the habit of running tests often, if they are slow, no one will let them go - happily there is always CICD at the end but it is rather poor consolation when we want to popularize testing
  • mocking everything - such a test does not work much, in addition, having in our projects setup msw - mocking axios is in my opinion an average idea - when we have fantastic tools like msw to deal with your api calls easily
  • tests initially are always passes - it is quite important to check whether for bad data or for reversal of the studied behavior - the test will correctly fail. Then we are sure that we do not fall into the so-called false positive. Here I refer to the article by Vlad Khorikov
  • tests don't act as living documentation

tests do not behave as living documentation - good tests should be easy for the person reading them, below I cite some of the most important features developed by Gerard Meszaros

The guiding principle, of course, is to write tests for people not robots A good test:

describes the context, starting point or preconditions that must be metillustrates how the code is calledvariables or names in the test are trivial for the recipient to understanddescribes exactly the expected result or the secondary conditions it verifies
  • Lack of any test - the biggest red flag that I can think of . It is best to start by testing the simplest utils or even (it might be controversial) write empty test casses with detailed business descriptions of the functionality. When the time is right, someone can help with writing such tests, or you can learn it yourself

Material that helped me a lot preparing this article:


Original Link: https://dev.to/verthon/frontend-test-smells-137h

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To