Search code examples
reactjsinputjestjsreact-testing-library

I cannot pass the test to dynamically change the value of the input tag when i clicked the button


My App Code

export function App() {
    const [inputValue, setInputValue] = React.useState("");
    const inputRef = React.useRef<HTMLInputElement>(null);

    const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
        e.preventDefault();
        if (inputRef.current) {
            inputRef.current.value = inputRef.current.value + "1";
            setInputValue(inputRef.current.value);
        }
    };

    return (
        <form>
            <label htmlFor="password-input" >
                비밀번호
            </label>
            <input
                ref={inputRef}
                type="password"
                id="password-input"
                name="password-input"
                value={inputValue}
            />
            <button
                className="insert"
                data-testId={1}
                onClick={(e) => { handleClick(e) }}>
                입력
            </button>
        </form>)
}

My test code

test("Does clicking the button change the input value?", async () => {
        render(<App />);

        userEvent.click(await screen.findByTestId(1));
        userEvent.click(await screen.findByTestId(1));

        expect((await screen.findByLabelText<HTMLInputElement>(`비밀번호`)).value).toHaveLength(2);

        userEvent.click(await screen.findByTestId(1));
        userEvent.click(await screen.findByTestId(1));
        userEvent.click(await screen.findByTestId(1));
        userEvent.click(await screen.findByTestId(1));

        expect((await screen.findByLabelText<HTMLInputElement>(`비밀번호`)).value).toHaveLength(6);
    })

As a result of running the test code is

    expect(received).toHaveLength(expected)

    Expected length: 2
    Received length: 1
    Received string: "1"

      37 |         userEvent.click(await screen.findByTestId(1));
      38 |
    > 39 |         expect((await screen.findByLabelText<HTMLInputElement>(`비밀번호`)).value).toHaveLength(2);
         |                                                                                ^
      40 |
      41 |         userEvent.click(await screen.findByTestId(1));
      42 |         userEvent.click(await screen.findByTestId(1));

      at Object.toHaveLength (src/test/my.spec.tsx:39:80)

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total

Every time I clicked on a button, i expected the input value to be "1", "11" and "111" from "", but it seems to work on dev server, but when i ran the test code, the input value continued to be less than the number of clicks. How can i fix thi error and pass the test? Please help me...


Solution

    • It should be data-testid, not data-testId.

    • click() API returns a promise, so you need to use it like await useEvent.click().

    • There is no need to use data-testid, you can find the button element by its accessible role('button') with accessible name('입력')

    e.g.

    index.tsx:

    import React from 'react';
    
    export function App() {
        const [inputValue, setInputValue] = React.useState('');
        const inputRef = React.useRef<HTMLInputElement>(null);
    
        const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
            e.preventDefault();
            if (inputRef.current) {
                inputRef.current.value = inputRef.current.value + '1';
                setInputValue(inputRef.current.value);
            }
        };
    
        return (
            <form>
                <label htmlFor='password-input'>비밀번호</label>
                <input ref={inputRef} type='password' id='password-input' name='password-input' value={inputValue} />
                <button
                    className='insert'
                    onClick={(e) => {
                        handleClick(e);
                    }}
                >
                    입력
                </button>
            </form>
        );
    }
    

    index.test.tsx:

    import React from 'react';
    import { render, screen } from '@testing-library/react';
    import { App } from '.';
    import userEvent from '@testing-library/user-event';
    
    test('Does clicking the button change the input value?', async () => {
        render(<App />);
    
        const $button = screen.getByRole('button', { name: '입력' });
    
        await userEvent.click($button);
        await userEvent.click($button);
    
        let $passwordInput = (await screen.findByLabelText(`비밀번호`)) as HTMLInputElement;
    
        expect($passwordInput.value).toHaveLength(2);
    
        await userEvent.click($button);
        await userEvent.click($button);
        await userEvent.click($button);
        await userEvent.click($button);
    
        expect($passwordInput.value).toHaveLength(6);
        expect($passwordInput.value).toBe('111111');
    });
    

    Test result:

      console.error
        Warning: Failed prop type: You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`.
            in input (created by App)
            in form (created by App)
            in App
    
          at printWarning (node_modules/prop-types/checkPropTypes.js:20:15)
    
     PASS  stackoverflow/76865066/index.test.tsx (6.41 s)
      ✓ Does clicking the button change the input value? (116 ms)
    
    -----------|---------|----------|---------|---------|-------------------
    File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
    -----------|---------|----------|---------|---------|-------------------
    All files  |     100 |       50 |     100 |     100 |                   
     index.tsx |     100 |       50 |     100 |     100 | 9                 
    -----------|---------|----------|---------|---------|-------------------
    Test Suites: 1 passed, 1 total
    Tests:       1 passed, 1 total
    Snapshots:   0 total
    Time:        6.619 s, estimated 7 s
    Ran all test suites related to changed files.
    

    package versions:

    "@testing-library/react": "^11.2.7",
    "@testing-library/user-event": "^14.4.3",
    "jest": "^26.6.3",