首页 > 解决方案 > 反应waitforelement不适用于异步调用

问题描述

我目前正在尝试使用 TypeScript 和类在 React 中进行异步调用的简单登录表单。我的组件如下所示:

import * as React from 'react';
import { LoginService } from './services/LoginService';

interface CredentialsState {
    userName: string,
    password: string,
    isLoggedIn: boolean,
    loginAttempted: boolean
}

interface CustomEvent {
    target: HTMLInputElement
}

export class Login extends React.Component<{}, CredentialsState> {

    state: CredentialsState = {
        password: "",
        userName: "",
        isLoggedIn: false,
        loginAttempted: false
    };

    private loginService: LoginService = new LoginService();

    private async handleSubmit(event: React.SyntheticEvent) {
        event.preventDefault();
        const loginResponse = await this.loginService.login(
            this.state.userName,
            this.state.password
        );
        console.log('Login result ' + loginResponse);
        this.setState({
            loginAttempted: true,
            isLoggedIn: loginResponse
        });
    }

    private setPassword(event: CustomEvent) {
        this.setState({ password: event.target.value });
    }
    private setUserName(event: CustomEvent) {
        this.setState({ userName: event.target.value });
    }


    render() {
        let loginLabel;
        if (this.state.loginAttempted) {
            if (this.state.isLoggedIn) {
                loginLabel = <label>Login successful</label>
            } else {
                loginLabel = <label>Login failed</label>
            }
        }

        return (
            <div>
                <form data-test="login-form" onSubmit={e => this.handleSubmit(e)}>
                    <input data-test="login-input" name="login" value={this.state.userName} onChange={e => this.setUserName(e)} /><br />
                    <input data-test="password-input" name="password" value={this.state.password} onChange={e => this.setPassword(e)} type="password" /><br />
                    <input data-test="submit-button" type="submit" value="Login" /><br />
                </form>
                {loginLabel}
            </div>

        )
    }
}

它工作得很好,但我也想使用@testing-library/react 测试它我的测试看起来像这样:

import { fireEvent, waitForElement } from '@testing-library/react';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import { Login } from './login';
import { LoginService } from './services/LoginService';


describe('Login component tests', () => {
    let container: HTMLDivElement;
    const loginServiceSpy = jest.spyOn(LoginService.prototype, 'login');

    beforeEach(() => {
        container = document.createElement('div');
        document.body.appendChild(container);
        act(() => {
            ReactDOM.render(<Login />, container);
        });
    })
    afterEach(() => {
        document.body.removeChild(container as HTMLDivElement);
        container.remove();
    });


    it('renders correctly status label', async () => {
        loginServiceSpy.mockResolvedValueOnce(false);
        const button = container.querySelectorAll('input')[2];
        fireEvent.click(button);
        const label = await waitForElement(() => {
            container.querySelector('label');
        }); // THIS query times out and test fails
        expect(label).toBeInTheDocument();
    });
});

我怎样才能使这个异步测试工作?如果没有异步功能,则container.querySelector('label')可以工作。谢谢!

标签: reactjstypescriptjestjs

解决方案


我自己想通了。我在滥用 waitForElement。正确的使用方法是:

        const label = await waitForElement(() =>
            container.querySelector('label')
        )

推荐阅读