如何用 Jest 模拟 API 调用(放大 API)

How to mock an API call with Jest (Amplify API)

我目前正在使用 AWS Amplify API 开展一个项目。 我正在尝试测试我正在执行 post API 调用的组件(在 checkCredentials 方法中),但想模拟它以测试我的组件的行为,而不是 API 呼叫.

这是我的组件:

const LoginPage = () => {
    const [{username, password}, updateCredentials] = React.useState({username: '', password: ''})
    const [errorMsg, setMsg] = useState('');
    const navigate = useNavigate();
    let invalidLoginMessage = errorMsg

    const checkCredentials = async (event: React.FormEvent) => {
        event.preventDefault();
        try {
            const loginData = await API.post('api', '/login/', {body: {username: username, password: password} })
            if (loginData.message === 'Login Successful'){
                console.log(loginData)
                authStatus.handleLogin(username);
                navigate("/home");
            }
        } catch (err) {console.log('Login Error', {err})} {setMsg("Informations invalides! Merci d'utiliser une adresse @ingeno.ca.")}    
    }

    return(
        <div className="withPadding">
            <form onSubmit={checkCredentials}>
                <div>Merci de vous authentifier afin d'utiliser l'application!</div>
                <label htmlFor="username">Nom d'utilisateur</label>
                <input placeholder='E-mail' data-testid="usernameInput" id="user" value={username} onChange={(event) => updateCredentials({
                    username: event.target.value,
                    password
                })} />
                <label htmlFor="password">Mot de passe</label>
                <input placeholder='Password' data-testid="passwordInput" id="password" type="password" value = {password} onChange={(event) => updateCredentials({
                    username,
                    password: event.target.value,
                })} />
                <Button data-testid="boutonLogin" type = "submit" className="btn-sm">Se connecter</Button>
                <br />
                <h4 style={{ color: 'red' }}>{invalidLoginMessage}</h4>
            </form>
        </div>
    )
} 

这是我当前的测试:

it('should show "invalid credentials" message when invalid credentials', () => {
      render(
        <Router>
          <LoginPage />
        </Router>)

      API.post = jest.fn().mockImplementation( () => { 
          return JSON.parse('{ "message": "Login Error"}')
      });

      const message = screen.getByText(errorMessage)
      const usernameInput = screen.getByPlaceholderText("E-mail")
      const passwordInput = screen.getByPlaceholderText("Password")
      fireEvent.change(usernameInput, {target: {value: invalidTestUser}})
      fireEvent.change(passwordInput, {target: {value: password}})
      userEvent.click(screen.getByTestId("boutonLogin"))

      expect((usernameInput as HTMLInputElement).value).toBe("testusername")
      expect((passwordInput as HTMLInputElement).value).toBe("12345")
      expect(message).toBeInTheDocument();
   })

我收到以下错误:

 TestingLibraryElementError: Unable to find an element with the text: Informations invalides! Merci d'utiliser une adresse @ingeno.ca.. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

现在我想知道我的 API 模拟是否足够,如果不够,如何使用 AWS Amplify API 来完成这样的事情?我发现很难知道测试失败是因为模拟不好还是页面没有及时更新以显示文本。

编辑

我尝试了一些东西,并且非常确定我的 API 调用模拟是我的测试未通过的原因。通过在不调用 API 的情况下创建类似的方法,测试顺利通过,因此文本出现了。不过,我仍然不确定如何模拟 API 调用。

感谢您的帮助。

可能是登录页面还在使用真实的API

我经常做这样的事情

// Mock the library before importing it, 
// and before importing Component Under Test

jest.mock('API');

import API from 'api';
import {mocked} from "ts-jest/utils";

const mockAPI = mocked(API);

mockAPI.post.mockImplementation( () => { 
    return JSON.parse('{ "message": "Login Error"}')
});

我已经为我的申请弄明白了。

jest.mock('aws-amplify');

const A_SUCCESS_RESPONSE = { response: 'ok' };
const AN_ERROR_RESPONSE = { response: 'something went wrong' };
const GOOD_USER_NAME = 'good-user-name';
const GOOD_PASSWORD = 'good-password';

it('success example', async () => {
    mocked(API.post).mockResolvedValue(A_SUCCESS_RESPONSE);

    const response = await API.post('api', '/login/', { body: { username: GOOD_USER_NAME, password: GOOD_PASSWORD } });

    expect(response).toEqual(A_SUCCESS_RESPONSE);
});

it('error example', async () => {
    mocked(API.post).mockRejectedValue(AN_ERROR_RESPONSE);
    try {
        await API.post('api', '/login/', { body: { username: GOOD_USER_NAME, password: GOOD_PASSWORD } });
    } catch (error) {
        expect(error).toEqual(AN_ERROR_RESPONSE);
    }
});

您需要先模拟 aws-amplify 模块,然后使用 mocked 模拟特定请求的已解决或拒绝的值以测试您的组件。