Testing Patterns (@data-client/test)
Hook Testing with renderDataHook()
typescriptimport { renderDataHook } from '@data-client/test'; it('useSuspense() should render the response', async () => { const { result, waitFor } = renderDataHook( () => useSuspense(ArticleResource.get, { id: 5 }), { initialFixtures: [ { endpoint: ArticleResource.get, args: [{ id: 5 }], response: { id: 5, title: 'hi ho', content: 'whatever' }, }, ], }, ); expect(result.current.title).toBe('hi ho'); });
Options:
initialFixtures- Set up initial state of the storeresolverFixtures- Add interceptors for subsequent requestsgetInitialInterceptorData- Simulate changing server state
Return values:
- Inherits all
renderHook()return values from@testing-library/react controller- Controller instance for manual actionsallSettled()- Wait for all async operations to complete
Cleanup is automatic -- an afterEach hook is registered at module load time that drains all active cleanups. No manual renderDataHook.cleanup() calls are needed.
Fixtures and Interceptors
Success Fixture:
typescriptinterface SuccessFixture { endpoint; args; response; error?; delay?; }
Response Interceptor:
typescriptinterface ResponseInterceptor { endpoint; response(...args); delay?; delayCollapse?; }
Testing Mutations
Create operations:
typescriptit('should create a new todo', async () => { const { result } = renderDataHook( () => useController(), { initialFixtures: [ { endpoint: TodoResource.getList, args: [], response: [], }, ], resolverFixtures: [ { endpoint: TodoResource.getList.push, response: (newTodo) => ({ ...newTodo, id: 1 }), }, ], }, ); const newTodo = { title: 'Test Todo', completed: false }; const createdTodo = await result.current.fetch(TodoResource.getList.push, newTodo); expect(createdTodo.id).toBe(1); });
Testing Error States
typescriptit('should handle fetch errors', async () => { const { result, waitFor } = renderDataHook( () => useSuspense(TodoResource.get, { id: 1 }), { initialFixtures: [ { endpoint: TodoResource.get, args: [{ id: 1 }], response: null, error: new Error('Not found'), }, ], }, ); await waitFor(() => { expect(result.current).toBeUndefined(); }); });
Testing Components
Use MockResolver to provide fixture data when rendering components with DataProvider:
typescriptimport { render } from '@testing-library/react'; import { DataProvider } from '@data-client/react'; import { MockResolver } from '@data-client/test'; it('should render todo list', async () => { const fixtures = [ { endpoint: TodoResource.getList, args: [], response: [{ id: 1, title: 'Test Todo', completed: false }], }, ]; const { getByText } = render( <DataProvider> <MockResolver fixtures={fixtures}> <TodoList /> </MockResolver> </DataProvider>, ); expect(getByText('Test Todo')).toBeInTheDocument(); });
Testing with nock (HTTP Endpoint Testing)
typescriptimport nock from 'nock'; it('should fetch data from API', async () => { const scope = nock('https://jsonplaceholder.typicode.com') .get('/todos/1') .reply(200, { id: 1, title: 'Test', completed: false }); const result = await TodoResource.get({ id: 1 }); expect(result.title).toBe('Test'); scope.done(); });
Testing Managers
typescriptit('should handle manager middleware', async () => { const mockManager = { middleware: (controller) => (next) => async (action) => { if (action.type === 'FETCH') { console.log('Fetch action:', action); } return next(action); }, cleanup: jest.fn(), }; const { controller } = renderDataHook( () => useController(), { managers: [mockManager] }, ); await controller.fetch(TodoResource.get, { id: 1 }); expect(mockManager.cleanup).not.toHaveBeenCalled(); });
Test File Organization
Keep tests under packages/*/src/**/__tests__:
packages/react/src/hooks/__tests__/useSuspense.test.ts packages/react/src/components/__tests__/DataProvider.test.tsx
Test naming:
- Node-only:
*.node.test.ts[x] - React Native:
*.native.test.ts[x] - Regular:
*.test.ts[x]
Best Practices
- Use
renderDataHook()for testing hooks that use @data-client/react hooks - Use fixtures or interceptors when testing hooks or components
- Use
nockwhen testing networking definitions - Test both success and error scenarios
- Test mutations and their side effects
- Don't mock @data-client internals directly
- Don't use raw fetch in tests when fixtures are available
- Don't manually call
renderDataHook.cleanup()inafterEach-- cleanup is automatic
References
For detailed API documentation, see the references directory:
- renderDataHook - Hook testing utility
- makeRenderDataHook - Custom hook renderer
- Fixtures - Fixture format reference
- MockResolver - Component testing wrapper
- mockInitialState - Create initial state
- unit-testing-hooks - Hook testing guide
- unit-testing-components - Component testing guide


