Colocation of test files is the hands down winner and encourages the writing of tests. When you're making a change to a code file, you probably won't think to scour the codebase for relevant tests. If you see the test file right next to source file in your editor, you probably will.
That said, I'm not 100% sold on the value of testing React components, outside of some very specific cases (eg. a very complex component with lots of internal state). I prefer to write integration / e2e tests that check views/pages/flows as a whole. And so for those, since they aren't connected to specific components, I do have a separate `/tests` folder.
1. Sometimes you want to do some experimental refactor in your application. This might break a lot of tests (cause them to not compile). But you first want to play around with the new change before committing to it and updating all your tests. If your test code is in the same project then the compiler errors will prevent you from doing this.
2. Your test code and application code usually need different dependencies. You don't want your test code to accidentally call functions from some helper library, and you don't want your application code accidentally calling functions from some test framework. If you have a shared list of dependencies and a large team then this will inevitably happen.
3. You don't want your application code to accidentally call helper functions from your test files. If you mix them in the same project then with a large team this will inevitably happen.
4. For code navigation and things like IDE "find usages", it is better to not be flooded with results from test code, in order to be able to focus on discovering how the code works. (Sometimes you do want to be taken to the test code which is why good IDEs allow you to choose to toggle on/off cross-project navigation).
5. Bonus: Sometimes you may want to write your test code in a different programming language then your application. This is uncommon but does happen. For example a C library with a test suite written in C++. Or a webapp backend with tests written in a scripting language using selenium. In these cases you have to have a separate project, and so for consistency you do it as well also for tests that use the same programming language.
I think the last point is actually the most important: it helps formulate the understanding that your test suite should be viewed as its own separate and independent program, not inherently tied to the library code that you are developing. This leads to two insights: 1) there's no reason why you couldn't have more than one test suite to test your library (possibly developed by different teams). 2) more interestingly: you should be able to take your test suite, and run it against a different implementation of your library. This makes sense for something like a test suite for a filesystem or SQL database. But even for your custom library, if you ever need to do a rewrite, or port to a different platform/language, then being able to take your existing test suite with you will be invaluable.
Some people also like to go further the bad way and group code by type rather than feature.
src/
components/
componentA.tsx
componentB.tsx
hooks/
hookA.ts
hookB.ts
tests/
componentA.test.tsx
componentB.test.tsx
Angular pre 1.5 liked this a lot. Must be a Java thing.Another one I despise is the page object pattern for E2E tests. Basically introducing a pseudo-DSL tied to something that is ever changing. I like the Cypress approach of using app actions instead:
https://www.cypress.io/blog/2019/01/03/stop-using-page-objec...
I utilize this in my playwright tests since I found it very useful when writing cypress tests previously.
Checkout talk about Mouseless Driven Development by Hadi Hariri[1]
One thing I am reluctant about is having a project dictated by your IDE/editor. I think this is an antipattern. Not everyone uses JetBrains products, I myself use vim. It just makes me sad that some people prefer to have their linting, testing, and other automated checks handled by their IDE rather than using proper git hooks or scripting in general.
I'm mostly a web developer so maybe other types of projects this makes sense.
Will check out the video, always happy to be exposed to new ways of doing things!
Yes, you are right
> It just makes me sad that some people prefer to have their linting, testing, and other automated checks handled by their IDE rather than using proper git hooks or scripting in general.
I agree with you things like linting, testing should check in CI.
there is actually benefit of co-locating whether you use JetBrains IDE or not like easier to explore the code base when you diving into existing project.
Kinda curious to learn how they enforced directory structures. I know now they co-locate tests, but IIRC CRA always used jest and with jest you just set the globs you want to use in the config file. Hardly hardcoded or strictly enforced, but I could be wrong.
The default templates are just a single folder, with tests located adjacent to their source files.
CRA configures jest to look for test files in arc/, but let's users override that.
https://github.com/facebook/create-react-app/tree/main/packa...
https://github.com/facebook/create-react-app/tree/main/packa...
The oddest part is that some staff and principle engineers are very adamant about this structure. It's just additional boilerplate that doesn't help and makes it hard to understand what components have tests (especially when you get in the weeds of not having a flat component directory, where child components have nested directories often several layers deep). I have no idea where this pattern permeates but it should be discouraged in most frontend projects.
Co-location of files should absolutely be encouraged, the alternative is just a jumble of directories that make it hard to grok what is actually happening.
IDK, just ranting now at this point.