Akashii
Akashii

Reputation: 2281

Test component use custom hook react-testing-library

I'm using react-testing-library for test my component using custom hook. But I can't make it pass. Here is my code

function useInput<T>(): Return<T> {
    const [input, setInput] = useState<T>({} as T);
    const [isDirty, setDirty] = useState({} as Record<keyof T, boolean>);

    const handleInputChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
        setInput({
            ...input,
            [e.target.name]: e.target.value
        });
        setDirty({
            ...isDirty,
            [e.target.name]: true
        });
    };

    const resetInput = () => {
        Object.keys(input).map((v) => (input[v as keyof T] as unknown as string) = '');
        Object.keys(isDirty).map((v) => (isDirty[v as keyof T] as unknown as string) = '');
        setInput({...input});
        setDirty({...isDirty});
    };

    return [input, handleInputChange, isDirty, resetInput, setInput]
}

const Login: React.FC = () => {
    const [input, handleChangeInput, isDirty, resetInput] = useInput<IInput>();

    return (
                <input
                    value={input.username}
                    onChange={handleChangeInput}
                    name={'username'}
                    className={classNames(`shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline`)}
                    id={'username'} type={'text'} placeholder={'Username'}/>

    )
}

test

import React from "react";
import {render, unmountComponentAtNode} from "react-dom";
import Login from './index'
import {renderHook, act as actHook} from '@testing-library/react-hooks'
import {MemoryRouter} from "react-router-dom";
import {useInput} from '../hooks';
import { fireEvent } from '@testing-library/react';


describe('test login', () => {
  it('to match snapshot', () => {
    render(
      <MemoryRouter>
        <Login/>
      </MemoryRouter>
      ,
      container);
    expect(container).toMatchSnapshot()
  });

  it('input correct when change username',  () => { //can't pass
     render(
      <MemoryRouter>
        <Login/>
      </MemoryRouter>
      ,
      container);

    const {result} = renderHook(() => useInput());
    const [input, handleChangeInput] = result.current;
    const inputName = container.querySelector('#username');
    fireEvent.change(inputName, {target: {value: 'test'}});

    actHook(() => {
      handleChangeInput({target: {name: 'username', value: 'test'}});
    });
    expect(input).toBe({
      username: 'test'
    })

  })
});

My script test is. When input fireEvent call, input change value and value in hook useInput have same value. But I can make it pass. Where is my wrong? Please help

Upvotes: 0

Views: 864

Answers (1)

Emzaw
Emzaw

Reputation: 758

React hooks testing library was created to test hooks without having to mount it on test component. You have to decide to either test the hook itself (without use of your Login component) or your component as whole - then you don't need hooks testing library at all - react-testing-library should be enough. Your fireEvent actually "fire" your hook without the part below

const {result} = renderHook(() => useInput());
const [input, handleChangeInput] = result.current;

Upvotes: 1

Related Questions