使用 jest 和 vue-test-utils2 在 vue3 typescript 单元测试中模拟 axios(已解决)
Mocking axios in a vue3 typescript unit test using jest and vue-test-utils2 (Solved)
我的组件调用
this.axios.get()
在挂载时将 vuex-store 变量传递给 api。 api returns 一个数组作为响应,组件在用实际内容交换加载元素后显示一些返回的数据。
在我的单元测试中,我想模拟 axios-request 的结果,等待 loading- 和 content-element 之间的转换,然后最后检查内容的有效性。但是,测试失败并输出:
Cannot read property 'get' of undefined
并突出显示 this.axios。
这是我期望的工作 (based on this guide):
... some imports etc. ...
const mockAxios = { whatIExpectToGet };
jest.mock("axios", () => ({
get: jest.fn(() => mockAxios)
}));
it("description of the test", async () => {
const wrapper = mount(MyComponent);
... code continues ...
当然,我是通过这个访问 axios,而不是像他们在指南中那样直接访问。但是,由于我找不到与此相关的任何提及,我认为这无关紧要?
我也试过像这样模拟 axios:
... imports etc. ...
const axios = {
get: Promise.resolve({ whatIExpectToGet })
};
it("description of the test", async () => {
const wrapper = mount(MyComponent, {
global: {
mocks: [ axios ]
}
});
... code continues ...
显然有类似问题的人使用 localVue.use() 来注入东西,but that's no longer supported.
请问有没有好心人和聪明人为我指明正确的方向?
谢谢。
--------------------> 解决方案 <------------ ------
感谢 tony 19 这个问题已经解决了。
我最终使用异步函数来模拟 axios,因为 Promise.resolve()
对我不起作用:
import { shallowMount, flushPromises } from "@vue/test-utils";
import MyComponent from "@/components/MyComponent.vue";
describe("MyComponent.vue", () => {
const axios = {
get: async () => ({
data: { expectedData }
})
};
it("test description", async () => {
const wrapper = shallowMount(MyComponent, {
global: {
mocks: {
axios: axios
}
}
} as any);
expect(wrapper.html()).toContain("some_string_i_display_while_loading");
await flushPromises();
expect(wrapper.html()).toContain("some_string_i_display_after_getting_the_response");
});
});
使用 global.mocks
模拟 axios
是正确的方法,但您的尝试错误地使用了数组,而数组本应是对象:
const wrapper = mount(MyComponent, {
global: {
// mocks: [ axios ] ❌
mocks: { axios } ✅
}
})
注意 axios.get()
解析为 axios.Response
对象,该对象将响应数据存储在其 data
属性 中,因此您的 mock 也应该这样做。
这是一个完整的例子:
// MyComponent.vue
export default {
mounted() {
this.axios.get('foo').then(resp => this.foo = resp.data)
}
}
// MyComponent.spec.js
it('gets foo', () => {
const wrapper = mount(MyComponent, {
global: {
mocks: {
axios: {
get: Promise.resolve({ data: { foo: true }})
// OR use an async function, which internally returns a Promise
get: async () => ({ data: { foo: true }})
}
}
}
}
})
我的组件调用
this.axios.get()
在挂载时将 vuex-store 变量传递给 api。 api returns 一个数组作为响应,组件在用实际内容交换加载元素后显示一些返回的数据。
在我的单元测试中,我想模拟 axios-request 的结果,等待 loading- 和 content-element 之间的转换,然后最后检查内容的有效性。但是,测试失败并输出:
Cannot read property 'get' of undefined
并突出显示 this.axios。
这是我期望的工作 (based on this guide):
... some imports etc. ...
const mockAxios = { whatIExpectToGet };
jest.mock("axios", () => ({
get: jest.fn(() => mockAxios)
}));
it("description of the test", async () => {
const wrapper = mount(MyComponent);
... code continues ...
当然,我是通过这个访问 axios,而不是像他们在指南中那样直接访问。但是,由于我找不到与此相关的任何提及,我认为这无关紧要?
我也试过像这样模拟 axios:
... imports etc. ...
const axios = {
get: Promise.resolve({ whatIExpectToGet })
};
it("description of the test", async () => {
const wrapper = mount(MyComponent, {
global: {
mocks: [ axios ]
}
});
... code continues ...
显然有类似问题的人使用 localVue.use() 来注入东西,but that's no longer supported.
请问有没有好心人和聪明人为我指明正确的方向? 谢谢。
--------------------> 解决方案 <------------ ------
感谢 tony 19 这个问题已经解决了。
我最终使用异步函数来模拟 axios,因为 Promise.resolve()
对我不起作用:
import { shallowMount, flushPromises } from "@vue/test-utils";
import MyComponent from "@/components/MyComponent.vue";
describe("MyComponent.vue", () => {
const axios = {
get: async () => ({
data: { expectedData }
})
};
it("test description", async () => {
const wrapper = shallowMount(MyComponent, {
global: {
mocks: {
axios: axios
}
}
} as any);
expect(wrapper.html()).toContain("some_string_i_display_while_loading");
await flushPromises();
expect(wrapper.html()).toContain("some_string_i_display_after_getting_the_response");
});
});
使用 global.mocks
模拟 axios
是正确的方法,但您的尝试错误地使用了数组,而数组本应是对象:
const wrapper = mount(MyComponent, {
global: {
// mocks: [ axios ] ❌
mocks: { axios } ✅
}
})
注意 axios.get()
解析为 axios.Response
对象,该对象将响应数据存储在其 data
属性 中,因此您的 mock 也应该这样做。
这是一个完整的例子:
// MyComponent.vue
export default {
mounted() {
this.axios.get('foo').then(resp => this.foo = resp.data)
}
}
// MyComponent.spec.js
it('gets foo', () => {
const wrapper = mount(MyComponent, {
global: {
mocks: {
axios: {
get: Promise.resolve({ data: { foo: true }})
// OR use an async function, which internally returns a Promise
get: async () => ({ data: { foo: true }})
}
}
}
}
})