Skip to main content

Hooks

The @archibald/testing package provides renderHook function to test hooks. It is a wrapper of renderHook function from React Hooks Testing Library which provides specifically prepared context necessary for testing hooks in Archibald projects.

import { renderHook } from '@archibald/testing';

const { result } = renderHook(() => useSomeHook());

When using renderHook function a set of options can be provided. An options object as described here or as described in following table can be used.

Interface TestingOptionPropsHooks<P = any> is used to type the options object.

OptionTypeDescription
contextTestingContext An options object as described here.
initialPropsPInitial props that should be passed to a hook.
customWrapperCustomWrapperA custom wrapper component.

Example

Let's have a look at the following example.

// Imports

export function useTestHook(initialState: string) {
const [someValue, setSomeValue] = useState(initialState);

const translate = useTranslate();
const testTranslation = translate('test.translation.key');

function changeSomeValue(value: string) {
setSomeValue(value);
}

return { exampleData, testTranslation, someValue, changeSomeValue };
}

In this example following is done:

  1. useState hook is used to manage some state. The state is exported and can be changed with changeSomeValue function.
  2. A translation key test.translation.key is translated and exported.

A test for this hook could look like following:

// Import renderHook function
import { renderHook } from '@archibald/testing';

const tkValue = 'Test translation key';

describe('useTestHook hook', () => {
const dataClient = new DataClient();

beforeEach(()=> {
dataClient.set([MESSAGES_KEY, 'en'], {
hasBeenLoaded: true,
status: 'prefetched',
response: {
'test.translation.key': 'Test translation key'
}
});
});

afterEach(()=> {
dataClient.clearAll();
});

it('should render', () => {
const { result } = renderHook(() => useTestHook(''));

expect(result.current.someValue).toBe(defaultValue);
expect(result.current.testTranslation).toBe(tkValue);
expect(typeof result.current.changeSomeValue).toBe('function');
});
});

This test will fail because not all values that we expect are provided. Let's fix it.

Provide initial value

The first expect check can be fixed by providing the correct initial value to the hook.

const { result } = renderHook(() => useTestHook(defaultValue));

Test state change

The example hook exposes changeSomeValue function to manipulate state. The function call has to be wrapped with act function.

// Import act function
import { render, type TestingContext, act } from '@archibald/testing';

act(() => {
result.current.changeSomeValue(newDefaultValue);
});

expect(result.current.someValue).toBe(newDefaultValue);

Full example

// Other imports
import { renderHook, TestingContext, act } from '@archibald/testing';
import { DataClient, MESSAGES_KEY } from '@archibald/core';

const defaultValue = 'Default value';
const newDefaultValue = 'New default value';
const tkValue = 'Test translation key';

describe('useTestHook hook', () => {
const dataClient = new DataClient();

beforeEach(()=> {
dataClient.set([MESSAGES_KEY, 'en'], {
hasBeenLoaded: true,
status: 'prefetched',
response: {
'test.translation.key': 'Test translation key'
}
});
});

afterEach(()=> {
dataClient.clearAll();
});

it('should render', () => {
const { result } = renderHook(() => useTestHook(defaultValue), { dataClient });

expect(result.current.someValue).toBe(defaultValue);
expect(result.current.exampleData).toBe(true);
expect(result.current.testTranslation).toBe(tkValue);
expect(typeof result.current.changeSomeValue).toBe('function');

act(() => {
result.current.changeSomeValue(newDefaultValue);
});

expect(result.current.someValue).toBe(newDefaultValue);
});
});