Should you unit-test React components?

I am someone who takes unit testing very seriously. I believe it has huge positives and is a discipline which should be followed. However I have recently come across a common belief which is the following:
“UI itself is trivial and expensive to test so it’s not worth the effort. All the actual logic is in separate utility modules, which are tested” — I personally firmly do not agree with this and here is why.
1. Business Logic
Imagine the following scenario..Function X inside an external module is responsible for a lot of logic, which is unit tested. React component Y calls Function X inside a condition and if true renders component A or if false renders nothing.
Now, the decision to render nothing instead of a broken component A is probably something the business deems as important aka Business Logic. Business Logic is most definitely something that should be covered in unit tests, the last thing anybody wants is the website to show a broken component.
2. Functional React
React is very functional library. Views are functions and Elements are plain old javascript objects (POJO’s). We can chain them together, iterate over them, do all sorts of things which we would normally do to a function because that is what they are. If the above is true then why treat them any different to a normal Javascript module? There is no reason at all. As modules, you want them to be isolated/extendable/reusable. Unit tests assist that massively.
Really there is no UI anymore. Your component “represents” UI but really its just taking input, transforming it, and returning. We deal with data trees and let React handle the DOM.
3. Snapshot tests are not a replacement
Snapshot tests are something which have gained popularity in recent times. I am not opposed to them at all, but I strongly feel they are for Regression Testing and should “compliment” not “replace” unit tests. Here is my thoughts:
- They can’t test the same level of detail as a unit test. If I change some of the code of Component A, the test looking for logic might fail even though it is unrelated.
- SRP — each test should isolate one behaviour and if it fails should be obvious why
- Errors are found as a a side-effects from a snapshot, they might not be related to its spec.
- The details of the tested behaviour are obfuscated, hidden inside the snapshot.
- If they fail (being fragile) they can just be re-generated. Not actually fixed.
- Easy to have snapshot and test fall out-of-sync. Then it becomes useless.
- Very hard to confirm test. Reviewer has to read the generated file to know if test spec is honest, rather than reading an assertion.
- Depending on the test, its easy to generate superfluous amounts of markup/code.
These are just my personal thoughts on why they make bad Unit Test replacements.
4. We don’t need 100% coverage anyway
This is a common misconception and excuse for missing out unit tests.
Actually the truth is that 0–50% is the hardest part. Its where the setup/time/effort and cost are. The next 50–80% does not take that long once you are at that stage. I often aim for 50% and end up adding more as it takes only a couple of minutes to really make a big increase at that point.
5. This UI changes frequently
I have no problems with throwaway code, but really it is something people need to have already agreed on. If something is going to be worked on again and again then it clearly is not throwaway and it should be protected with a unit test. Which will give confidence and help enforce good design patterns inside this new code.
6. We have higher-level tests covering them
E2E/behaviour etc tests are not designed to cover all branches in the same way unit tests are. If a user interaction triggers a lot of logic, other types of tests will struggle to capture this.
I know that these are not all the reasons and there are undoubtedly more out there but I sincerely hope not too many.
Thanks for reading and I would love to hear your thoughts and experiences.