用笑话和酶模拟反应组件的自定义服务
Mock a custom service with jest and enzyme for a react component
我有一个简单的组件,可以从 api 调用中加载一些用户,我在服务中对此进行了抽象。这是组件:
export const Dashboard: FunctionComponent = () => {
const [users, setUsers] = useState<IUser[]>([]);
const [isLoading, setIsLoading] = useState(true);
const userService: UserService = UserService.get();
useEffect(() => {
userService.getUsers()
.then((data) => {
console.log(data)
setIsLoading(false)
setUsers(data)
})
.catch((error) => {
console.log("Could not load users: ", error);
setIsLoading(false)
setUsers([]);
});
}, []);
return (
isLoading
?
<div data-testid="loading">
<h4>Loading...</h4>
</div>
:
<div data-testid="users">
<UserList users={users}/>
</div>
);
}
export default Dashboard;
我的服务是这样的:
export class UserService {
private static INSTANCE = new UserService();
private constructor() {}
public static get(): UserService {
return UserService.INSTANCE;
}
public async getUsers(): Promise<IUser[]> {
const response = await axios.get("api/users");
return response.data as IUsers[];
}
}
我将其提取到 .ts 文件中的原因是我计划在另一个组件中重用该服务,并在此处添加其他 api 调用。
所以现在我想为我的仪表板组件编写一个简单的测试,我将 UserService 模拟为 return 一个承诺,然后测试我的 data-testid=users
是否已呈现。
这是我的测试:
configure({adapter: new Adapter()});
describe("User dashboard component", () => {
let userService: UserService;
const users = [
{
id: "0c8593e8-8fa6-4d40-b555-5ef812477c70",
name: "John",
age: 25
}
];
beforeAll(() => {
userService = UserService.get();
});
test("renders component", () => {
userService.getUsers = () => {
return Promise.resolve(users);
};
const dashboard = shallow(<Dashboard />);
expect(dashboard.find(<Dashboard />)).toBeTruthy();
expect(dashboard.find('[data-testid="users"]').length).toEqual(1);
expect(toJson(dashboard)).toMatchSnapshot();
});
test("loading", () => {
const dashboard = shallow(<Dashboard />);
expect(dashboard.find('[data-testid="loading"]').length).toEqual(1);
expect(toJson(dashboard)).toMatchSnapshot();
});
});
我不想模拟 useState
挂钩,但显然我与用户解决 Promise 的部分没有任何作用。
我该如何实现?这里的最佳做法是什么?谢谢!
shallow
doesn't support useEffect
此时应该用mount
代替。
组件是异步呈现的,测试也应该是异步的。通过分配模拟方法是一种不好的做法,因为它们无法恢复,这导致测试 cross-contamination。一个使它异步的承诺应该公开以供链接。如果是间谍,可以通过 Jest 间谍 API.
检索
应该是:
jest.spyOn(userService, 'getUsers').mockImplementation(() => Promise.resolve(users));
const dashboard = mount(<Dashboard />);
expect(userService.getUsers).toBeCalledTimes(1);
await act(async () => {
await userService.getUsers.mock.results[0].value;
});
...
间谍应该在测试之间恢复和清除,以便测试不会相互影响。
我有一个简单的组件,可以从 api 调用中加载一些用户,我在服务中对此进行了抽象。这是组件:
export const Dashboard: FunctionComponent = () => {
const [users, setUsers] = useState<IUser[]>([]);
const [isLoading, setIsLoading] = useState(true);
const userService: UserService = UserService.get();
useEffect(() => {
userService.getUsers()
.then((data) => {
console.log(data)
setIsLoading(false)
setUsers(data)
})
.catch((error) => {
console.log("Could not load users: ", error);
setIsLoading(false)
setUsers([]);
});
}, []);
return (
isLoading
?
<div data-testid="loading">
<h4>Loading...</h4>
</div>
:
<div data-testid="users">
<UserList users={users}/>
</div>
);
}
export default Dashboard;
我的服务是这样的:
export class UserService {
private static INSTANCE = new UserService();
private constructor() {}
public static get(): UserService {
return UserService.INSTANCE;
}
public async getUsers(): Promise<IUser[]> {
const response = await axios.get("api/users");
return response.data as IUsers[];
}
}
我将其提取到 .ts 文件中的原因是我计划在另一个组件中重用该服务,并在此处添加其他 api 调用。
所以现在我想为我的仪表板组件编写一个简单的测试,我将 UserService 模拟为 return 一个承诺,然后测试我的 data-testid=users
是否已呈现。
这是我的测试:
configure({adapter: new Adapter()});
describe("User dashboard component", () => {
let userService: UserService;
const users = [
{
id: "0c8593e8-8fa6-4d40-b555-5ef812477c70",
name: "John",
age: 25
}
];
beforeAll(() => {
userService = UserService.get();
});
test("renders component", () => {
userService.getUsers = () => {
return Promise.resolve(users);
};
const dashboard = shallow(<Dashboard />);
expect(dashboard.find(<Dashboard />)).toBeTruthy();
expect(dashboard.find('[data-testid="users"]').length).toEqual(1);
expect(toJson(dashboard)).toMatchSnapshot();
});
test("loading", () => {
const dashboard = shallow(<Dashboard />);
expect(dashboard.find('[data-testid="loading"]').length).toEqual(1);
expect(toJson(dashboard)).toMatchSnapshot();
});
});
我不想模拟 useState
挂钩,但显然我与用户解决 Promise 的部分没有任何作用。
我该如何实现?这里的最佳做法是什么?谢谢!
shallow
doesn't support useEffect
此时应该用mount
代替。
组件是异步呈现的,测试也应该是异步的。通过分配模拟方法是一种不好的做法,因为它们无法恢复,这导致测试 cross-contamination。一个使它异步的承诺应该公开以供链接。如果是间谍,可以通过 Jest 间谍 API.
检索应该是:
jest.spyOn(userService, 'getUsers').mockImplementation(() => Promise.resolve(users));
const dashboard = mount(<Dashboard />);
expect(userService.getUsers).toBeCalledTimes(1);
await act(async () => {
await userService.getUsers.mock.results[0].value;
});
...
间谍应该在测试之间恢复和清除,以便测试不会相互影响。