From harness-claude
Provides patterns for unit and integration testing Redux slices, thunks, selectors, React components, and RTK Query endpoints using real stores, renderWithProviders, and MSW.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Test Redux slices, thunks, selectors, and connected components with focused, maintainable test strategies
Guides Redux and Redux Toolkit for global state management: slices, stores, actions, reducers, hooks, selectors, middleware, async thunks.
Guides testing React components, hooks (renderHook), context providers, forms, and advanced patterns with React Testing Library; covers anti-patterns, excludes E2E.
Organizes Redux state into self-contained slices using createSlice for co-located reducers, actions, and selectors. Use when creating new state domains, refactoring legacy code, or adding CRUD operations.
Share bugs, ideas, or general feedback.
Test Redux slices, thunks, selectors, and connected components with focused, maintainable test strategies
renderWithProviders utility for Redux-connected component testsslice.reducer(initialState, action). No store needed.RootState objects.configureStore and dispatching the thunk. Assert on the resulting state, not on dispatched actions.renderWithProviders wrapper that creates a real store with preloaded state. Prefer this over mock stores.// test-utils.tsx — renderWithProviders
import { render, RenderOptions } from '@testing-library/react';
import { configureStore, PreloadedState } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import { RootState } from './store';
import todosReducer from './features/todos/todos.slice';
function setupStore(preloadedState?: PreloadedState<RootState>) {
return configureStore({
reducer: { todos: todosReducer },
preloadedState,
});
}
type AppStore = ReturnType<typeof setupStore>;
interface ExtendedRenderOptions extends Omit<RenderOptions, 'queries'> {
preloadedState?: PreloadedState<RootState>;
store?: AppStore;
}
export function renderWithProviders(
ui: React.ReactElement,
{
preloadedState,
store = setupStore(preloadedState),
...renderOptions
}: ExtendedRenderOptions = {}
) {
function Wrapper({ children }: { children: React.ReactNode }) {
return <Provider store={store}>{children}</Provider>;
}
return { store, ...render(ui, { wrapper: Wrapper, ...renderOptions }) };
}
// features/todos/todos.slice.test.ts
import todosReducer, { addTodo, toggleTodo } from './todos.slice';
describe('todosSlice', () => {
it('adds a todo', () => {
const state = todosReducer(undefined, addTodo('Write tests'));
expect(state.items).toHaveLength(1);
expect(state.items[0].title).toBe('Write tests');
expect(state.items[0].completed).toBe(false);
});
it('toggles a todo', () => {
const initial = todosReducer(undefined, addTodo('Write tests'));
const id = initial.items[0].id;
const state = todosReducer(initial, toggleTodo(id));
expect(state.items[0].completed).toBe(true);
});
});
Reducer tests are the simplest — they are pure functions. Pass state and action, assert on the returned state. No mocking needed.
Selector tests: Create minimal RootState objects. Only populate the fields the selector reads:
it('filters active todos', () => {
const state = {
todos: { items: [{ id: '1', title: 'A', completed: false }], filter: 'active' },
} as RootState;
expect(selectFilteredTodos(state)).toHaveLength(1);
});
Thunk tests: Use a real store, not redux-mock-store. Dispatch the thunk and assert on the resulting state:
it('fetches users', async () => {
// MSW intercepts the /api/users request
const store = setupStore();
await store.dispatch(fetchUsers());
expect(selectAllUsers(store.getState())).toHaveLength(3);
});
RTK Query tests: Use MSW to intercept requests. Render the component that uses the query hook with renderWithProviders. Wait for the loading state to resolve:
it('displays users from API', async () => {
const { getByText } = renderWithProviders(<UserList />);
expect(await screen.findByText('Alice')).toBeInTheDocument();
});
Anti-patterns:
redux-mock-store — it cannot run reducers, so you cannot assert on statehttps://redux.js.org/usage/writing-tests