home / skills / reactive / data-client / data-client-react-testing

data-client-react-testing skill

/.cursor/skills/data-client-react-testing

This skill assists testing React data-client hooks and components with renderDataHook, fixtures, and nock HTTP mocks for reliable unit and integration tests.

npx playbooks add skill reactive/data-client --skill data-client-react-testing

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
5.5 KB
---
name: data-client-react-testing
description: Test @data-client/react with renderDataHook - jest unit tests, fixtures, interceptors, mock responses, nock HTTP mocking, hook testing, component testing
license: Apache 2.0
---

# Testing Patterns (@data-client/test)

## Hook Testing with renderDataHook()

```typescript
import { 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 store
- `resolverFixtures` - Add interceptors for subsequent requests
- `getInitialInterceptorData` - Simulate changing server state

**Return values:**
- Inherits all `renderHook()` return values from `@testing-library/react`
- `controller` - Controller instance for manual actions
- `cleanup()` - Cleanup function
- `allSettled()` - Wait for all async operations to complete

## Fixtures and Interceptors

**Success Fixture:**
```typescript
interface SuccessFixture {
  endpoint;
  args;
  response;
  error?;
  delay?;
}
```

**Response Interceptor:**
```typescript
interface ResponseInterceptor {
  endpoint;
  response(...args);
  delay?;
  delayCollapse?;
}
```

## Testing Mutations

**Create operations:**
```typescript
it('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

```typescript
it('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

```typescript
import { render } from '@testing-library/react';
import { DataProvider } from '@data-client/react';

const renderWithProvider = (component, options = {}) => {
  return render(
    <DataProvider {...options}>
      {component}
    </DataProvider>
  );
};

it('should render todo list', async () => {
  const { getByText } = renderWithProvider(
    <TodoList />,
    {
      initialFixtures: [
        {
          endpoint: TodoResource.getList,
          args: [],
          response: [{ id: 1, title: 'Test Todo', completed: false }],
        },
      ],
    },
  );

  expect(getByText('Test Todo')).toBeInTheDocument();
});
```

## Testing with nock (HTTP Endpoint Testing)

```typescript
import 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

```typescript
it('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 `nock` when 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

## References

For detailed API documentation, see the [references](references/) directory:

- [renderDataHook](references/renderDataHook.md) - Hook testing utility
- [makeRenderDataHook](references/makeRenderDataHook.md) - Custom hook renderer
- [Fixtures](references/Fixtures.md) - Fixture format reference
- [MockResolver](references/MockResolver.md) - Component testing wrapper
- [mockInitialState](references/mockInitialState.md) - Create initial state
- [unit-testing-hooks](references/unit-testing-hooks.md) - Hook testing guide
- [unit-testing-components](references/unit-testing-components.md) - Component testing guide

Overview

This skill provides utilities and patterns for testing @data-client/react code with renderDataHook and related helpers. It focuses on Jest unit tests for hooks and components, offering fixture-driven state, interceptors, and optional HTTP mocking with nock. The goal is reliable, deterministic tests for REST/GraphQL/SSE hooks, mutations, and manager middleware.

How this skill works

Use renderDataHook to mount hooks that rely on @data-client/react and supply initialFixtures to populate store state synchronously. Add resolverFixtures to intercept subsequent requests and return mock responses or transforms. For full HTTP-level tests, use nock to stub network endpoints and assert request behavior. The renderer returns controller access, cleanup utilities, and wait helpers to coordinate async operations.

When to use it

  • Unit testing hooks that call resources (useSuspense, useController, etc.)
  • Component tests that need a DataProvider-backed store
  • Testing mutations and verifying created/updated entities without a real backend
  • Simulating error responses and delay conditions
  • Validating manager middleware behavior and side effects

Best practices

  • Prefer initialFixtures for predictable initial state instead of mocking internals
  • Use resolverFixtures for dynamic responses and to test mutation callbacks
  • Test both success and error paths, including delayed responses
  • Use nock only when exercising actual network request definitions
  • Keep tests organized by environment: .node.test, .native.test, or regular .test files

Example use cases

  • Render useSuspense(ArticleResource.get) with initialFixtures and assert returned data fields
  • Simulate creating a todo via controller.fetch(TodoResource.getList.push) and assert assigned id from resolverFixtures
  • Render a component inside DataProvider with initialFixtures and assert rendered list items
  • Stub a third-party API with nock and call the resource directly to validate HTTP integration
  • Attach a mock manager to renderDataHook and assert middleware is invoked during fetch

FAQ

How do I simulate server-side state changes between requests?

Provide getInitialInterceptorData or resolverFixtures that compute responses based on prior calls to mimic evolving server state.

When should I use nock instead of fixtures?

Use nock when you want to exercise the actual HTTP layer or validate request shapes; use fixtures/resolvers for faster, isolated unit tests without network I/O.