Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: prototype unit testing #712

Merged
merged 13 commits into from Nov 14, 2020
Merged

Feat: prototype unit testing #712

merged 13 commits into from Nov 14, 2020

Conversation

mmiask
Copy link
Contributor

@mmiask mmiask commented Nov 9, 2020

Closes: #660

  • Setup of react-testing-library and its utilities
  • Configuration of jest config file to handle node modules mappings
  • Added data-testid attributes
  • Wrote unit tests for Try It Out header component
  • Configured CircleCI job to run tests and clear jest cache beforehand (due to recurring errors in loading test files; solution: ts-jest 26.1.2 - "cannot find source file" kulshekhar/ts-jest#1506)

@netlify
Copy link

netlify bot commented Nov 9, 2020

Deploy preview for stoplight-elements ready!

Built with commit 0f43b92

https://deploy-preview-712--stoplight-elements.netlify.app

@mmiask mmiask self-assigned this Nov 10, 2020
@mmiask mmiask requested a review from a team November 10, 2020 14:35
@mmiask mmiask marked this pull request as ready for review November 10, 2020 14:35
Copy link
Contributor

@marcelltoth marcelltoth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setup is nice, it works great!

I'm not so much a fan of the tests however. I know they are just some examples, but they are not really good examples right now IMO. Let's tidy them up together!

As they stand now, both the selectors and the assertions use a lot of artificial artifacts such as the copy, data-* attributes or test ids. These should be used as the last resort and when you use them you should question whether the thing is worth testing in the first place. We should always keep testing goals & pain/reward ratios in mind.

I offered you some tips on how I would make that one test nicer, but you can apply the same principles to most of the other selectors and assertions, too.

But it really is very difficult to come up with a good testing approach in regards to this component. And as I said, when encountering this, one should stop and rethink. So digging further down I think I found what the real problem is here: The component you picked doesn't have much behavior to test. If you open its source code you can see that's its completely static, does nothing - except for that popup that may very well be the only valid thing to test here. It's almost static HTML.

I don't think these static components are worth testing at all, because what can you assert? That it renders what's written into the source code? That doesn't offer any added value, does it? I think in general we are looking to test behavior and very little presentation, so maybe it all only has to do with the component choice. That's one of the reasons I suggested to do an overall test of API.

Having said that, if you can clean this one up - even if you only keep a single test - that's perfectly good enough as well to complete the connected issue. The issue says you can test anything, what I would not like however, is to merge an example of doing the wrong thing. Having a single very simple but nicely written example is much much better.

@@ -17,6 +17,7 @@ jobs:
- run: yarn --frozen-lockfile
- run: yarn type-check
- run: yarn lint
- run: yarn test.clear
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to kulshekhar/ts-jest#1506 - I encountered an error when trying to run tests with jest a couple of times and clearing cache helped. We could get rid of for now and see if it breaks in CircleCI frequently, but it only adds about 2 seconds to a job.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It cannot affect CircleCI because it's a new container each time, with an empty cache - that's also why it takes 2s.
This justifies having the yarn command however, if it is useful for you locally.

The issue you linked to is closed however ("v26.1.4 is out, I will close this issue"), so you could try upgrading ts-jest (by upgrading jest itself) and that should fix your local problems as well.

Comment on lines 13 to 14
expect(elem.innerHTML).toContain('data-icon="magic"');
expect(elem.innerHTML).toContain('data-icon="question-circle"');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implementation-dependent and unimportant

Comment on lines 25 to 27
await screen.findByText(
"Send HTTP requests to your API, or one of our mock servers, to see how it's going to respond. View the docs",
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing the copy is rarely a good idea either. The only thing it does is makes it more annoying to change it down the road, without providing any real safety.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But testing whether the popover works is a good one!

Now on how to select it? One really underrated and underutilized way of selecting things is by accessibility attributes (ARIA).

You may be familiar already that HTML5 includes many new "semantic" tags that behave the same as a regular div, but mean a slightly different thing. section, main, article, etc. Since HTML5, the official goal of HTML is to describe semantics, not to prescribe appearance or behavior. (We have CSS and JS for those, respectively.) We should utilize this semantic part of HTML more than we do right now, but that's another matter.

In addition to these, a more in-depth way to describe a web-page is using the HTML accessibility attributes: https://www.w3.org/TR/wai-aria-1.1/ & https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics

While these are mainly designed to provide accessibility to websites - help screen readers and such - they implicitly let you describe the semantics of your site really well, the very semantics that you want to test. I tend to think of these as tools aiding testability and comprehension, and think of the accessibility improvement as a nice side-effect.

In this case using the tooltip role would be a perfect fit, then you could use the screen.findByRole selector to find the element and instead of asserting on the contents you could assert e.g. toBeVisible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Testing the copy is rarely a good idea either. The only thing it does is makes it more annoying to change it down the road, without providing any real safety.

I agree and will get rid of it

@mmiask
Copy link
Contributor Author

mmiask commented Nov 13, 2020

@marcelltoth

I don't think these static components are worth testing at all, because what can you assert?

I agree, let's drop the checking of displayed text

That's one of the reasons I suggested to do an overall test of API.

I wanted to test that as well, but ran into a situation when react-testing-library was asserting elements in empty skeleton of API component, before the data was loaded. It seemed too much of a hustle ATM comparing to just testing a simple component like Try It header, and that's why I decided to switch.

@marcelltoth
Copy link
Contributor

I wanted to test that as well, but ran into a situation when react-testing-library was asserting elements in empty skeleton of API component, before the data was loaded. It seemed too much of a hustle ATM comparing to just testing a simple component like Try It header, and that's why I decided to switch.

Understood. 👍 Then let's just narrow this down to as much as we can, I'm fine with only having that single test that asserts that the tooltip is visible on hover. I don't think there's any more behavior in this component at all, but if you think so, sure, let's add that, too.

@mmiask
Copy link
Contributor Author

mmiask commented Nov 13, 2020

@marcelltoth bear in mind that there's still a need to add a data-testid attribute to question-icon since its role is not unique in the component

@marcelltoth
Copy link
Contributor

@marcelltoth bear in mind that there's still a need to add a data-testid attribute to question-icon since its role is not unique in the component

I guess it's fine for now. It's an example afterall, we won't be testing Popups like this much anymore

removed unused data-testid attribute
Copy link
Contributor

@marcelltoth marcelltoth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test looks quite pretty and concise now, I love it! 🎉

You could remove all the --clearCache-related lines, they shouldn't be needed anymore. If someone really wants to run it they can always run yarn test --clearCache or yarn jest --clearCache or yarn workspace run jest --clearCache if you want to run it everywhere. We shouldn't create yarn commands for everything we might need to do, only the most frequent.

Other than that, good to go! 🚀

@mmiask mmiask merged commit 26440d3 into beta Nov 14, 2020
@mmiask mmiask deleted the feat/prototype-unit-testing branch November 14, 2020 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Prototype unit testing
2 participants