-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Behavioural unit tests for navigation and reference #5085
Conversation
438044f
to
8cc73f0
Compare
8cc73f0
to
0528cd7
Compare
Note: Updated base to make diff easier to read. |
075a647
to
799e43b
Compare
0528cd7
to
bb35372
Compare
@@ -0,0 +1,719 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think large snapshots are not a good thing. It makes it difficult to review and understand diffs, which can hide regressions, and in particular exposes rather technical details like classnames to the diff. I think snapshots, if used, should be kept as small as semantically reasonable. Alternatively, the snapshot assertion could be replaced with a manully defined assertion (about the order, for example for this test).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These snapshots are real lifesavers some times (e.g. unexpected change in snapshot). Snapshots are used only as additions and functionality should be tested separately. That being said, it's nice to know what are the changes in DOM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think large snapshots have more costs than benefits and I wouldn't approve this PR with these.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't like that snapshot based testing locks in the DOM, I think that the user doesn't care at all about it and more cares about the text then if an extra <div>
is added somewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again: Reasoning for snapshots is different. Snapshots are very important for detecting unexpected changes in UI caused by some change in somewhere else.
Please, provide more than you opinions. Concreate examples how you would solve the issue described here and in slack. Snapshots provide easy solution without minimal downsides (if any).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't agree that this should be a requirement for testing. We want tests for UI components to test from a "user perspective", not asserting a specific DOM structure. If we have a good test coverage of unit tests of UI components we can be confident that the UI components work correctly, making snapshots unnecessary. I think that it's a rare edge case where these snapshots would be actionable for developers, thus making the downsides exceed the benefits.
The downsides of large snapshots are
a) difficult to review snapshot diffs, making them mostly useless
b) creating noise to diffs
c) having to update the snapshots when DOM changes
d) creating an incentive for developers to rely on a snapshot for asserting a semantic meaning of the DOM tree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have a good test coverage of unit tests
We don't have. And we won't have in near future. And we won't have ever, as long as whole team doesn't write code in TDD.
--
a) Large snapshot diffs are not supposed to be reviewed. That doesn't mean they are useless.
b) Read a)
c) It's not downside that you get instant feedback from unit tests that something has changed. Current situation in code base is that components are re-used in so many places that unexpected places need to be caught. And this doesn't affect only components, even though components are the ones that are rendered. How many bugs we have seen caused by some change in somewhere else? I can answer that: too many. If there is a way to give instant feedback to developer, we should definitely use it.
d) This is where PR review comes to place. No functionality should be tested with snapshots.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the goal is to have good coverage.
The downside is having to do a manual step to update the snapshots (even if that step is pretty small).
799e43b
to
0835fa6
Compare
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
bb35372
to
9427de6
Compare
Conflicts have been resolved. A maintainer will review the pull request shortly. |
9427de6
to
b3f5ae6
Compare
1a767e8
to
da94d9d
Compare
9352219
to
3c86646
Compare
da94d9d
to
3ccf237
Compare
df2e171
to
104ce24
Compare
0d39b23
to
21e5ab9
Compare
89d8a3b
to
4a3ef18
Compare
22838a7
to
6083077
Compare
0c72746
to
7915e04
Compare
6083077
to
adbe73c
Compare
adbe73c
to
63434bb
Compare
|
||
describe("when changing page parameters", () => { | ||
beforeEach(() => { | ||
const button = rendered.getByTestId("button-to-change-page-parameters"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think getByTestId should be avoided and getByText etc. should be preferred.
See best practice in the official docs: https://testing-library.com/docs/queries/bytestid/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Read the post linked in the page you provided. https://kentcdodds.com/blog/making-your-ui-tests-resilient-to-change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read it, and it agrees with my review comment..
To be more specific: using test ids is okay if other queries are not reliable / possible.
Quote from the post:
"Sometimes you can't reliably select an element by any of the other queries. For those, it's recommended to use data-testid"
Longer quote from the post:
"This is why Testing Library has the queries that it does. The queries help you to find elements in the same way that users will find them. These queries allow you to find elements by their role, label, placeholder, text contents, display value, alt text, title, test ID.
That's actually in the order of recommendation."
The priority is even documented here:
https://testing-library.com/docs/queries/about/#priority
That's why I said that others should be preferred.
I'm fine with using test ids if others are not possible / practical for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no way to reliably select an element using title
, label
, role
, placeholder
, text contents
, display value
or alt text
. Role is only one of those that is not changed too often. But role alone isn't enough. Therefore, only option is to select with test ID
. I would even use plain old data-attributes if testing-library
wouldn't limit us.
Needs to be said again, I'm not interested in the tools and how we use them. Tool (here. testing-library) doesn't affect my mind in anyway. If the tool is not solving the problem, then we change the tool. I'm more interested about the problem that we are trying to solve. In this case it is:
How do we test something that user can act with, in a way that:
- we can minimize amount of unit tests that need to adapt for unrelated change
- we can change our mind in the content
- we can even change our mind on the element (e.g. could be button now, but in the future we decide that it's a link)
- we can be sure enough that user find's the element (doesn't have to be same way, since it's just a burden. As long as abstraction levels are correct in the unit tests, we should be fine)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clearly it's possible to reliably select an element using title, label, role, placeholder, text contents, display value or alt text.
Usually it's good to follow library's best practises.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How? Could you elaborate how you would solve the problem that I introduced in previous message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could argue that changing the title is not an unrelated change. I wouldn't find it unreasonable to have to update the test if the title changed. I'd even expect to have to change the test if the element changed. The title and element shouldn't be changing that often that it is a huge burden to have to update the test too. In fact, having to update tests in this situation has the advantage of keeping you aware of them, their implementations, and how they drive development...
src/behaviours/add-cluster/navigation-using-application-menu.test.ts
Outdated
Show resolved
Hide resolved
expect(actual).toBeNull(); | ||
}); | ||
|
||
describe("when navigating to add cluster using application menu", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do the two describes here both match the same snapshot? How do they get different results when looking for "add-cluster-page"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First snapshot test in this suite is snapshot that will match to "front page" of the application. However, currently it's just component that doesn't render any page component. Second snapshot matches to "add-cluster-page".
it("shows add cluster page", () => {
tests that we are actually on that page andit("renders", () => {
tests how it's rendered at the moment. Covers a lot, since all of the sub components are rendered too and if there is change, it will break the snapshot and make sure you are attempting to change functionality in this page.
This is just a behaviour for navigating to that page. In future, there will be a lot more behaviours for "add-cluster-page" which will cover all of the functionalities. Most of these will be covered in other behaviours that actually do some action.
Examples of behaviours:
- Add single cluster
- Add multiple clusters
- Cancel
- Navigate using application menu
- Navigate from catalog (most likely covered with all other behaviours)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, sorry, missed that there are two snapshots in the snap file.
This reverts commit ecd881c25df219b511d7efd43dac59e748b21cc7. Signed-off-by: Iku-turso <mikko.aspiala@gmail.com> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
f5594fe
to
bb1be0a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly much careful hard work has gone into this and I'm confident that it can lead to a more stable and robust product. Although I still have some things to figure out before I'm comfortable with this di-based test framework. Lots to work by example from.
I think test names are suitable as documentation written as a user story...for users. I don't find the test implementations themselves that well documented, or easy to understand (I assume it comes with time). Also, test names are susceptible to staleness like code comments, they don't always get changed when the code changes.
Good work @jansav and @Iku-turso!
expect(actual).toBeNull(); | ||
}); | ||
|
||
describe("when navigating to add cluster using application menu", () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah, sorry, missed that there are two snapshots in the snap file.
|
||
describe("when changing page parameters", () => { | ||
beforeEach(() => { | ||
const button = rendered.getByTestId("button-to-change-page-parameters"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could argue that changing the title is not an unrelated change. I wouldn't find it unreasonable to have to update the test if the title changed. I'd even expect to have to change the test if the element changed. The title and element shouldn't be changing that often that it is a huge burden to have to update the test too. In fact, having to update tests in this situation has the advantage of keeping you aware of them, their implementations, and how they drive development...
As motivation, behavioural unit tests:
See conversation for more info.
Not to be merged before #5084.