Testing
Introduction
Testing is one of the best things in Hyper Fetch. With our architecture and focus on global singleton structure, tests can be largely based on the application’s configuration. This means tests are no longer sensitive to micro-changes (like changing endpoints or types). Everything reacts and adapts to tests or shows the appropriate error – making tests easier to maintain and faster to write.
Benefits
- Our setup is always up-to-date with the production solution.
- No configuration or setup duplication.
- Easy test maintenance.
- Faster test builds.
Isolation
The Client
can become a global module, which will cause it to get mixed between test cases from different files if we
run them in many workers. Thus, we need to isolate it. This takes two steps:
- Clear the Client
Use the built-in method .clear()
to ensure client submodules are initialized and clear of any changes.
- Clear the node / runner cache
As you would with Jest, use the built-in method .resetModules()
to clean the client global module and reinitialize it.
Depending on the libraries used, you can check out your environment runner methods or try libraries like decache.
Example
In this example, we’re using the great mocking libraries msw and testing-library, but this solution works with other libraries like Cypress. This allows us to simulate real requests and make our tests as close to the production environment as possible. We can thus create a really powerful flow that allows us to easily develop tests.
You can build a utilities set that takes a request and uses its method, endpoint and types to create functions that allow you to intercept requests.
import { client } from "../api/client";
import { getUsers } from "../api";
// 'createInterceptor' is some custom method for handling intercepting in the tests we write
// In our internal test we used MSW as main intercepting layer
const getUsersInterceptor = createInterceptor(getUsers, {
data: [
{ name: "John", age: 18 },
{ name: "Matthew", age: 27 },
],
});
beforeEach(() => {
// We need to reset modules cache as client is globally exported module
// This way it will not get mixed-up with other test cases running in parallel
jest.resetModules();
// Clean the environment to make sure it's isolated
client.clear();
});
it("My test", async () => {
// Start interceptor listener
const mock = getUsersInterceptor();
// Handle test
renderApp();
expect(await screen.findByText(mock.data[0])).toBeVisible();
});