我正在测试一个使用Axios的登录组件.我试着用axios-mock-adapter模拟Axios,但当我运行测试时,它仍然会出错:

Error: Request failed with status code 404

如何在测试中正确模拟Axios?

登录.规格js:

import Vue from 'vue'
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Login from '../../src/components/global/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('登录.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

根本问题是,测试代码在与Login.vue中实际使用的URL不同的URL上设置了axios-mock-adapter,因此请求没有存根:

// 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请求,因此测试无法可靠地验证呼叫或响应(没有黑客攻击).

解决方案是更新doSigninNormal()以返回axios.post()promise ,允许呼叫者等待结果:

// Login.vue
doSigninNormal() {
  return axios.post(...)
}

// login.spec.js
await wrapper.vm.doSigninNormal()
expect(mock.history.post.length).toBe(1)

验证登录结果

为了验证结果,可以声明一个本地数据属性来保存登录结果1️⃣, 更新doSigninNormal()以处理响应(在测试中用fakeData模拟),捕获结果2️⃣. 然后,在等待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)

Edit Mocking Axios calls with axios-mock-adapter

Vue.js相关问答推荐

Vue路由路径匹配行为

vue 不重新渲染数据更改

Nuxt 和 Vite 有什么区别?

如何通过 setup() 发出多个参数?

Vuetify 扩展面板,面板标题左侧带有图标

在组件上的 Vue 3 中获取 URL 查询参数

有条件地在 Vue 中添加一个 CSS 类

Vue 和 TypeScript 所需的props

如果我观看解构的props,Vue 3 手表将无法正常工作

Vue.js 如果在视图中

验证子组件Vue vee-validate

如何从 bootstrap-vue 模态监听事件?

如何在 VUE 应用中使用 sass?

Vue 3 组合 API,如何在 setup() 函数中获取上下文父属性?

如何在 Vue3 设置标签中定义组件名称?

Vuex 存储数据总是驻留在内存中?

Vue.js 中的 CSS 框架

laravel vuejs/axios put request Formdata 为空

Vue.js 3 - 替换/更新react性对象而不会失go react性

Mapbox 事件监听器