我正在尝试使用Jest测试React组件的状态。 在ComponentDidUpdate上,如果有人登录并使用用户名更新state.user,它将在服务器上获取用户名。 如果没有用户登录,则会将state.pleaseLogin切换为true。
import React from "react";
import "./Header.css";
import "whatwg-fetch";
import LoggedInNav from "./LoggedInNav";
import LoggedOutNav from "./LoggedOutNav";
import urls from "../../urls";
import getUser from "../fetch/getUser";
export default class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
user: null,
pleaseLogin: false
};
this.handleGetUser = this.handleGetUser.bind(this);
}
handleGetUser() {
getUser().then(res => {
if (res.hasOwnProperty("username")) {
this.setState({
user: res.username
});
} else {
this.setState({
pleaseLogin: true
});
}
});
}
componentDidMount() {
this.handleGetUser();
}
render() {
let nav;
if (this.state.user) {
nav = <LoggedInNav user={this.state.user} />;
} else if (this.state.pleaseLogin) {
nav = <LoggedOutNav />;
} else {
nav = null;
}
return (
<header className="app-header">
<h1 className="header-brand">Watchers</h1>
{nav}
</header>
);
}
}
以下是getUser()的代码,用于在服务器上获取用户名:
export default () => {
return fetch(`${BASE_URL}/api/user/user_data`, {
credentials: "include"
})
.then(res => res.json())
.catch(error => {
console.log(error);
return error;
});
};
我手动模拟了API调用。该文件名为“getUser.js”,位于 mocks 文件夹中,紧挨着原始的“getUser.js”,如下所示:
export default () => {
return Promise.resolve({
username: 'Username'
})
}
然后测试:
import React, { Component } from "react";
import Enzyme, { shallow, mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import Header from "../react/components/Header";
import getUser from "../react/fetch/getUser";
Enzyme.configure({ adapter: new Adapter() });
jest.mock("../react/fetch/getUser");
const wrapper = mount(<Header />);
describe("<Header/>", () => {
describe("component class", () => {
it("should update state.user after componentDidMount()", () => {
return getUser().then(() => {
expect(wrapper.state()).toEqual({
user: "Username",
pleaseLogin: false
});
});
});
});
});
测试通过,状态发生了变化,state.user现在等于“Username”。 如果我更改我的模拟模块并使其返回一个空对象,它也可以正常工作,并且state.pleaseLogin切换为true。但是我必须手动测试这两种情况。 我尝试使用jest.mock('... module',()=&gt; {})直接在我的测试文件中模拟这两个不同的实现,并使用jest.doMock('... module',()= &gt; {})但是当我运行测试时状态不会更新;虽然它与手动模拟。我不确定问题的来源,也许这与异步性或在Jest中嘲笑有关?
答案 0 :(得分:1)
我找到了两种不同的测试方法。
由于模拟模块仅包含一个函数,因此手动模拟可能不是最佳解决方案。不过这是我写测试的方式:
1。 __模拟__ 文件夹中的手动模拟
// In the example, the function getUser is exported with 'export default'.
module.exports = jest.fn(() => Promise.resolve({}))
// If the function is exported with 'export const getUser = () => {}':
module.exports = {
getUser: jest.fn(() => Promise.resolve({}))
}
<强>测试强>
jest.mock("../react/fetch/getUser");
const getUser = require("../react/fetch/getUser");
// If function exported with 'export const getUser = () => {}':
// const {getUser} = require("../react/fetch/getUser");
describe("<Header/>", () => {
it("should update state.user after componentDidMount()", () => {
getUser.mockImplementation(() =>
Promise.resolve({ username: "Username" })
);
const wrapper = shallow(<Header />);
expect.assertions(1);
return (
getUser()
.then(() => {
expect(wrapper.state()).toEqual({
user: "Username",
pleaseLogin: false
});
})
);
});
it("should update state.pleaseLogin after componentDidMount()", () => {
getUser.mockImplementation(() => Promise.resolve({}));
const wrapper = mount(<Header />);
return (
getUser()
.then(() => {
expect(wrapper.state()).toEqual({
user: null,
pleaseLogin: true
});
})
);
});
});
2。创建模拟函数以在测试代码中使用
测试
// If function exported with 'export default'
jest.mock("../react/fetch/getUser", () => jest.fn());
const getUser = require("../react/fetch/getUser");
// Else
// jest.mock("../react/fetch/getUser", () => ({getUser: jest.fn()}));
// const {getUser} = require("../react/fetch/getUser")
describe("<Header/>", () => {
it("should update state.user after componentDidMount()", () => {
const promise = Promise.resolve({
username: "Username"
});
getUser.mockImplementation(() => promise);
const wrapper = shallow(<Header />);
expect.assertions(1);
return getUser().then(() => {
expect(wrapper.state()).toEqual({
user: "Username",
pleaseLogin: false
});
});
});
});
值得注意的一些事情:
我试图在测试中使用mock和doMock失败。它可能与此问题有关:https://github.com/facebook/jest/issues/2582
当您需要定义时,mockImplementation方法很有用 从另一个创建的模拟函数的默认实现 模块
然而,mockImplementationOnce()将在此测试中抛出错误
必须在模拟之后调用Enzyme shallow()或mount()才能使用该实现。否则我们得到&#39; TypeError:无法读取属性&#39;然后&#39;未定义&#39;
需要退回承诺。如果没有&#39;返回&#39;,期望&#39;那么&#39;将被跳过,因为我们不等待异步调用返回。
Jest Docs:&#34;请务必退还承诺 - 如果省略此退货 声明,您的测试将在fetchData完成之前完成。&#34;
您可以查看以下链接,了解如果省略return,会发生什么:https://github.com/facebook/jest/issues/1924