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.
| Option | Type | Description |
|---|---|---|
| context | TestingContext | An options object as described here. |
| initialProps | P | Initial props that should be passed to a hook. |
| customWrapper | CustomWrapper | A 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:
useStatehook is used to manage some state. The state is exported and can be changed withchangeSomeValuefunction.- A translation key
test.translation.keyis 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);
});
});