Testing proves integrity and provides the ability to:
- Verify intent by exercising code it in various ways
- Provide confidence that is existing functionality still works when refactoring or adding new requirements
Adopt two mindsets
- End User Experience - Input and Expected Output
- Developer Experience - Function
Don't be obsessed with code coverage. Safe guard the user from taking the unhappy path
|1. High value/risk features||E2E||Signup, Login, Payment, etc.|
|2. Edge Cases in high value features||Integration/Unit|
|3. Things that are easy to break||Integration/Unit|
|4. Component interaction testing||Integration/Unit|
Being DRY in tests is bad for your
Mocking should be avoided if at all possible. It is better to combine two or more components in an integration test and interact with the components as the user would.
Use Mock Service Worker to mock APIs at the network level rather than excessively mocking at the component or service layer
- Loading a database with a specific, known set of data
- Erasing a hard disk and installing a known clean operating system installation
- Copying a specific known set of files
- Preparation of input data and set-up/creation of fake or mock objects
The more your tests resemble the way your software is used, the more confidence they can give you.
Design: Business logic exists in pure functions not than UI components. For example, a Shopping Cart UI component should not compute the cart total. As much possible push business logic to the Backend API.
Use Component Driven Development to save time and money.
Start from the most nested component, then come back to the root writing down interactions and expected outcomes.
📚 Isolate components using Storybook. Write test cases where each state is reproduced using props and mock data. ✅ Catch visual bugs and verify composition using Chromatic. 🐙 Verify interactions with Jest and Testing Library. ♿️ Audit accessibility of your components using Axe. 🔄 Verify user flows by writing end-to-end tests with Cypress. 🚥 Catch regressions by automatically running tests with GitHub Actions.
|1. User interactions|
|2. Conditional rendering|
Setting up a test environment.
Snapshot vs traditional unit testing: Snapshot tests lack the expression of this intent. So for anything beyond the simplest of components, prefer traditional unit tests.
Difference between queryBy, getBy and findBy queries Checking for existence of an element Waiting for removal of an element Waiting for something to happen fireEvent() vs userEvent Mocking an event handler Avoid mocking by using Mock Service Worker Overriding MSW handlers Testing page navigation Suppressing console errors
Liberal on what you accept; mean on what you let pass
Testing is of critical importance to blockchain development.
Heavily test type predicates. That will increase your confidence in the predicates, which will allow you to trust the type system as a whole.
Test function overloads to ensure the body is returning expected types. It's probably best to avoid them unless they solve a serious problem in your system.
|Cypress||Signup, Login, Payment, etc.|
|React Testing Library|
|Mock Service Worker||Mock API|
|React Testing Crash Course|
|Testing & Error Handling with Next.js|
|Best strategy with a supabase connection with NX/Next.js?|