Skip to main content

Testing

Testing proves integrity and provides the ability to:

  1. Verify intent by exercising code it in various ways
  2. Provide confidence that is existing functionality still works when refactoring or adding new requirements
tip

Write tests, not too many, mostly integration - Kent Dodds

Leverage best possible tools for testing stack to deliver quality products.

Strategy

Adopt two mindsets

  1. End User Experience - Input and Expected Output
  2. Developer Experience - Function
tip

Don't be obsessed with code coverage. Safe guard the user from taking the unhappy path

PriorityTypeNotes
1. High value/risk featuresE2ESignup, Login, Payment, etc.
2. Edge Cases in high value featuresIntegration/Unit
3. Things that are easy to breakIntegration/Unit
4. Component interaction testingIntegration/Unit

Concepts

Being DRY in tests is bad for your

Integration Testing

Integration Tests

Mocking

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

Test Fixtures

  • 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

Frontend

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.

Flow

Use Component Driven Development to save time and money.

UI Testing Handbook

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.

FlowNotes
1. User interactions
2. Conditional rendering
3. Utils/Hooks

Foundations

Setting up a test environment.

Approach

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.

Procedure

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

Backend

Liberal on what you accept; mean on what you let pass

Blockchain

Testing is of critical importance to blockchain development.

Typescript Code

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.