unit-testing - Axios 捕获错误请求失败,状态码 404
问题描述
我正在测试一个使用 Axios 的登录组件。我尝试用 模拟 Axios axios-mock-adapter
,但是当我运行测试时,它仍然会出错:
Error: Request failed with status code 404
如何在测试中正确模拟 Axios?
login.spec.js:
import Vue from 'vue'
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Login from '../../src/components/global/login/Login.vue';
import Raven from "raven-js";
import jQuery from 'jquery'
import Vuex from 'vuex'
import router from '../../src/router'
var axios = require('axios');
var MockAdapter = require('axios-mock-adapter');
describe('Login.vue', () => {
let wrapper;
let componentInstance;
let mock;
beforeEach(() => {
global.requestAnimationFrame = setImmediate,
mock = new MockAdapter(axios)
wrapper = shallowMount(Login, {
router,
$: jQuery,
attachToDocument: true,
mocks: {
$t: () => { },
Raven: Raven,
},
data() {
return {
email: '',
password: '',
}
}
})
componentInstance = wrapper.vm;
})
afterEach(() => {
mock.reset()
})
it('calls `axios()` with `endpoint`, `method` and `body`', async () => {
const formData = {
email: 'example@gmail.com',
password: '111111'
};
let fakeData = { data: "fake response" }
mock.onPost(`${process.env.VUE_APP_BASE_URL}/login/`, formData).reply(200, fakeData);
wrapper.vm.email = 'example@gmail.com';
wrapper.vm.password = '111111';
wrapper.vm.doSigninNormal()
})
})
登录.vue
doSigninNormal() {
const formData = {
email: this.email,
password: this.password
};
this.$v.$touch()
if (this.$v.$invalid ) {
this.loading = false;
this.emailLostFocus = true;
this.passwordLostFocus = true;
$('html, body').animate({scrollTop:110}, 'slow')
} else {
axios.post("/login", formData, {
headers: { "X-localization": localStorage.getItem("lan") }
})
.then(res => {
if (!res.data.result) {
if (res.data.errors) {
for (var i = 0; i < res.data.errors.length; i++) {
this.$toaster.error(res.data.errors[i].message);
if (
res.data.errors[0].message == "Your email is not yet verified"
) {
this.showVerificationLinkButton = true;
}
if (res.data.errors[i].field === "email") {
this.$toaster.error(res.data.errors[i].message);
}
if (res.data.errors[i].field === "password") {
this.$toaster.error(res.data.errors[i].message);
}
}
}
this.loading = false;
this.$v.$reset();
} else {
this.loading = false;
Raven.setUserContext({
email: res.data.user.email,
id: res.data.user.id
});
this.$store.dispatch("login", res);
this.$v.$reset();
}
})
.catch((err) => {
console.log('catch', err);
});
}
}
解决方案
测试错误的登录 URL
根本问题是测试代码设置axios-mock-adapter
在与实际使用不同的 URL 上Login.vue
,因此请求没有被存根:
// login.spec.js:
mock.onPost(`${process.env.VUE_APP_BASE_URL}/login/`, formData).reply(200, fakeData)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Login.vue
axios.post("/login", formData)
^^^^^^
解决方法是让测试代码使用相同的 URL(即/login
):
// login.spec.js
mock.onPost("/login", formData).reply(200, fakeData)
需要等待 axios.post()
单元测试不会等待POST
请求,因此测试将无法可靠地验证调用或响应(没有 hack)。
修复方法是更新doSigninNormal()
以返回axios.post()
允许调用者等待结果的承诺:
// Login.vue
doSigninNormal() {
return axios.post(...)
}
// login.spec.js
await wrapper.vm.doSigninNormal()
expect(mock.history.post.length).toBe(1)
验证登录结果
为了验证结果,你可以声明一个本地数据 prop 来保存登录结果 1️⃣,更新doSigninNormal()
以处理响应(fakeData
在测试中被模拟),捕获结果 2️⃣。然后,只需在 await 之后检查该数据属性doSignInNormal()
。
// Login.vue
data() {
return {
...
result: '' 1️⃣
}
}
methods: {
doSignInNormal() {
return axios.post(...)
.then(resp => this.result = resp.data.result) 2️⃣
}
}
// login.spec.js
const result = await wrapper.vm.doSigninNormal()
expect(result).toBe(fakeData.result)
expect(wrapper.vm.result).toBe(fakeData.result)
推荐阅读
- python - 关于 XPath 选择器的问题(对于 Scrapy)
- php - Laravel 5.8 中未捕获的错误“找不到类”
- dart - 如何创建一个流,然后创建另一个流?
- amazon-web-services - 使用 DDB、Kinesis 和 SNS 的高级解决方案
- linux - 我想在 EFS 挂载路径中部署 github 代码
- javascript - ajax 没有激活,带我到另一个页面
- youtube-api - 无法从 youtube 数据 api 接收活动数据?
- django - 向 Django 表单动态添加隐藏输入会导致 KeyError
- typescript - 在 TypeScript 中,为什么 Symbols for Privacy 会向消费者抛出错误?
- python - 如何遍历 QTreeView 并为所有匹配的单元格着色?